📄 s390io.c
字号:
/* * drivers/s390/s390io.c * S/390 common I/O routines * * S390 version * Copyright (C) 1999, 2000 IBM Deutschland Entwicklung GmbH, * IBM Corporation * Author(s): Ingo Adlung (adlung@de.ibm.com) * Cornelia Huck (cohuck@de.ibm.com) * ChangeLog: 01/07/2001 Blacklist cleanup (djbarrow@de.ibm.com,barrow_dj@yahoo.com) * 01/04/2001 Holger Smolinski (smolinsk@de.ibm.com) * Fixed lost interrupts and do_adapter_IO * xx/xx/xxxx nnn multiple changes not reflected * 03/12/2001 Ingo Adlung blacklist= - changed to cio_ignore= * 03/14/2001 Ingo Adlung disable interrupts before start_IO * in Path Group processing * 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 * xx/xx/xxxx some bugfixes & cleanups * 08/02/2001 Cornelia Huck not already known devices can be blacklisted * by piping to /proc/cio_ignore * 09/xx/2001 couple more fixes * 10/29/2001 Cornelia Huck Blacklisting reworked again * 10/29/2001 Cornelia Huck improved utilization of debug feature */#include <linux/module.h>#include <linux/config.h>#include <linux/errno.h>#include <linux/kernel_stat.h>#include <linux/signal.h>#include <linux/sched.h>#include <linux/interrupt.h>#include <linux/slab.h>#include <linux/string.h>#include <linux/smp.h>#include <linux/threads.h>#include <linux/smp_lock.h>#include <linux/init.h>#include <linux/bootmem.h>#ifdef CONFIG_PROC_FS#include <linux/proc_fs.h>#endif #include <asm/system.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/bitops.h>#include <asm/smp.h>#include <asm/pgtable.h>#include <asm/delay.h>#include <asm/processor.h>#include <asm/lowcore.h>#include <asm/idals.h>#include <asm/uaccess.h> #include <asm/cpcmd.h>#include <asm/s390io.h>#include <asm/s390dyn.h>#include <asm/s390mach.h>#include <asm/debug.h>#include <asm/queue.h>#ifndef TRUE#define TRUE 1#define FALSE 0#endif#define SANITY_CHECK(irq) do { \if (irq > highest_subchannel || irq < 0) \ return (-ENODEV); \ if (ioinfo[irq] == INVALID_STORAGE_AREA) \ return (-ENODEV); \ } while(0) #undef CONFIG_DEBUG_IO#define CONFIG_DEBUG_CRWunsigned int highest_subchannel;ioinfo_t *ioinfo_head = NULL;ioinfo_t *ioinfo_tail = NULL;ioinfo_t *ioinfo[__MAX_SUBCHANNELS] = { [0 ... (__MAX_SUBCHANNELS-1)] = INVALID_STORAGE_AREA};static atomic_t sync_isc = ATOMIC_INIT(-1);static int sync_isc_cnt = 0; // synchronous irq processing lockstatic spinlock_t adapter_lock = SPIN_LOCK_UNLOCKED; // adapter interrupt lockstatic psw_t io_sync_wait; // wait PSW for sync IO, prot. by sync_iscstatic int cons_dev = -1; // identify console devicestatic int init_IRQ_complete = 0;static int cio_show_msg = 0;static schib_t *p_init_schib = NULL;static irb_t *p_init_irb = NULL;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);#ifdef CONFIG_PROC_FSstatic void s390_redo_validation(void);#endifstatic 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);static int s390_SensePGID( int irq, __u8 lpm, pgid_t *pgid);static int s390_process_IRQ( unsigned int irq );static int enable_subchannel( unsigned int irq);static int disable_subchannel( unsigned int irq);#ifdef CONFIG_PROC_FSstatic int chan_proc_init( void );#endif static inline void do_adapter_IO( __u32 intparm );int s390_DevicePathVerification( int irq, __u8 domask );int s390_register_adapter_interrupt( adapter_int_handler_t handler );int s390_unregister_adapter_interrupt( adapter_int_handler_t handler );extern int do_none(unsigned int irq, int cpu, struct pt_regs * regs);extern int enable_none(unsigned int irq);extern int disable_none(unsigned int irq);asmlinkage void do_IRQ( struct pt_regs regs );#ifdef CONFIG_PROC_FS#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);#endifint cio_notoper_msg = 1;#ifdef CONFIG_PROC_FSint cio_proc_devinfo = 0; /* switch off the /proc/deviceinfo/ stuff by default until problems are dealt with */#endifunsigned long s390_irq_count[NR_CPUS]; /* trace how many irqs have occured per cpu... */int cio_count_irqs = 1; /* toggle use here... *//* * "Blacklisting" of certain devices: * Device numbers given in the commandline as cio_ignore=... won't be known to Linux * These can be single devices or ranges of devices * * 10/23/01 reworked to get rid of lists */static unsigned long bl_dev[2048] = {0,}; static spinlock_t blacklist_lock = SPIN_LOCK_UNLOCKED;static int highest_ignored = 0;static int nr_ignored = 0;/* * Function: blacklist_range_add * Blacklist the devices from-to */static inline void blacklist_range_add( int from, int to,int locked){ unsigned long flags; int i; if (to && (from>to)) { printk(KERN_WARNING "Invalid blacklist range %x to %x, skipping\n", from, to); return; } if(!locked) spin_lock_irqsave( &blacklist_lock, flags ); if (!to) to = from; for (i=from;i<=to;i++) { set_bit(i,&bl_dev); nr_ignored++; } if (to>=highest_ignored) highest_ignored = to; if(!locked) spin_unlock_irqrestore( &blacklist_lock, flags );}/* * Function: blacklist_range_remove * Removes a range from the blacklist chain */static inline void blacklist_range_remove( int from, int to ){ long flags; int i; spin_lock_irqsave( &blacklist_lock, flags ); for (i=from;i<=to;i++) { clear_bit(i,&bl_dev); nr_ignored--; } if (to == highest_ignored) for (highest_ignored=from;(highest_ignored>0) && (!test_bit(highest_ignored,&bl_dev));highest_ignored--); spin_unlock_irqrestore( &blacklist_lock, flags );}/* Parsing the commandline for blacklist parameters *//* * Variable to hold the blacklisted devices given by the parameter line * cio_ignore=... */char *blacklist[256] = {NULL, };/* * Get the cio_ignore=... items from the parameter line */static void blacklist_split_parm_string (char *str){ char *tmp = str; int count = 0; do { char *end; int len; end = strchr (tmp, ','); if (end == NULL) { len = strlen (tmp) + 1; } else { len = (long) end - (long) tmp + 1; *end = '\0'; end++; } blacklist[count] = alloc_bootmem (len * sizeof (char) ); if (blacklist == NULL) { printk (KERN_WARNING "can't store cio_ignore= parameter no %d\n", count + 1); break; } memset (blacklist[count], 0, len * sizeof (char)); memcpy (blacklist[count], tmp, len * sizeof (char)); count++; tmp = end; } while (tmp != NULL && *tmp != '\0');}/* * The blacklist parameters as one concatenated string */static char blacklist_parm_string[1024] __initdata = {0,};/* * function: blacklist_strtoul * Strip leading '0x' and interpret the values as Hex */static inline int blacklist_strtoul (char *str, char **stra){ char *temp = str; int val; if (*temp == '0') { temp++; /* strip leading zero */ if (*temp == 'x') temp++; /* strip leading x */ } val = simple_strtoul (temp, &temp, 16); /* interpret anything as hex */ *stra = temp; return val;}/* * Function: blacklist_parse * Parse the parameters given to cio_ignore=... * Add the blacklisted devices to the blacklist chain */static inline void blacklist_parse( char **str ){ char *temp; int from, to; while (*str) { temp = *str; from = 0; to = 0; from = blacklist_strtoul( temp, &temp ); if (*temp == '-') { temp++; to = blacklist_strtoul( temp, &temp ); } blacklist_range_add( from, to, 0 );#ifdef CONFIG_DEBUG_IO printk( KERN_INFO "Blacklisted range from %X to %X\n", from, to );#endif str++; }}/* * Initialisation of blacklist */void __init blacklist_init( void ){#ifdef CONFIG_DEBUG_IO printk( KERN_DEBUG "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 );}/* * Get all the blacklist parameters from parameter line */void __init blacklist_setup (char *str, int *ints){ int len = strlen (blacklist_parm_string); if (len != 0) { strcat (blacklist_parm_string, ","); } strcat (blacklist_parm_string, str);}int __init blacklist_call_setup (char *str){ int dummy;#ifdef CONFIG_DEBUG_IO printk( KERN_DEBUG "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 */ return 1;}__setup ("cio_ignore=", blacklist_call_setup);/* Checking if devices are blacklisted *//* * Function: is_blacklisted * Returns 1 if the given devicenumber can be found in the blacklist, otherwise 0. */static inline int is_blacklisted( int devno ){ long flags; int retval=0; spin_lock_irqsave( &blacklist_lock, flags ); if (test_bit(devno,&bl_dev)) retval=1; spin_unlock_irqrestore( &blacklist_lock, flags ); return retval;}/* * Function: blacklist_free_all_ranges * set all blacklisted devices free... */void blacklist_free_all_ranges(void) { unsigned long flags; int i; spin_lock_irqsave( &blacklist_lock, flags ); for (i=0;i<=highest_ignored;i++) clear_bit(i,&bl_dev); highest_ignored = 0; nr_ignored = 0; spin_unlock_irqrestore( &blacklist_lock, flags );}#ifdef CONFIG_PROC_FS/* * 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; long flags; int err = 0; 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; } blacklist_range_remove( from, to ); kfree(param); } s390_redo_validation(); } } else if (strstr(tmp, "add ")) { for (i=0;i<4;i++){ tmp++; } 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; } spin_lock_irqsave( &blacklist_lock, flags ); /* * Don't allow for already known devices to be * blacklisted * The criterion is a bit dumb, devices which once were * there but are already gone are also caught... */ err = 0; for (i=0; i<=highest_subchannel; i++) { if (ioinfo[i]!=INVALID_STORAGE_AREA) { if ( (ioinfo[i]->schib.pmcw.dev >= from) && (ioinfo[i]->schib.pmcw.dev <= to) ) { printk(KERN_WARNING "cio_ignore: Won't blacklist " "already known devices, skipping range " "%x to %x\n", from, to); err = 1; break; } } } if (!err) blacklist_range_add(from, to, 1); spin_unlock_irqrestore( &blacklist_lock, flags ); kfree(param); } } else { printk( KERN_WARNING "cio_ignore: Parse error; try using 'free all|<devno-range>,<devno-range>,...'\n"); printk( KERN_WARNING "or 'add <devno-range>,<devno-range>,...'\n"); }}#endif/* 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){ s32 cnt1,cnt2,maxcnt2; u32 *currptr=(__u32 *)ptr; printk("\n%s\n",str); for(cnt1=0;cnt1<cnt;cnt1+=16) { printk("%08lX ",(unsigned long)currptr); maxcnt2=cnt-cnt1; if(maxcnt2>16) maxcnt2=16; for(cnt2=0;cnt2<maxcnt2;cnt2+=4) printk("%08X ",*currptr++); printk("\n");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -