Commit ebbde003 authored by Martin Schwidefsky's avatar Martin Schwidefsky Committed by Linus Torvalds

[PATCH] s390 update (24/27): boot sequence.

Rework boot sequence on s390:

Traditionally, device detection os s390 is done completely
at a _very_ early stage during bootup (from init_irq(),
i.e. before memory management or the console are there).

This has always been a bad idea, but now it broke even more
since the linux driver model requires devices detection
to take place after the core_initcalls are done.

We now do only a small amount of scanning (probably
less in the future) at the early stage, the bulk of it
is done from a proper subsys_initcall(). This requires
some changes in related areas:

- the machine check handler initialization is split in
  two halves, since we want to catch major machine malfunctions
  as early as possible, but device machine checks can only
  be caught after the channel subsystem is up.

- some functions that are called from the css initialization
  made some assumptions of when to use kmalloc or bootmem_alloc,
  which were broken anyway. We fix this here and hopefully
  can get rid of bootmem_alloc for the css completely in the future.

- the debug logging feature for s390 was not used for functions
  in the initialization before, since it requires the memory
  management to be working. Now that we can be sure that it
  works, some special cases can be removed.

Now that these changes are done, a partial implementation of the
device model for the channel subsystem is possible, but at this
point, none of the device drivers make use of that yet.
parent 2abb6c50
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <asm/semaphore.h> #include <asm/semaphore.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h>
#include <asm/debug.h> #include <asm/debug.h>
...@@ -146,7 +147,7 @@ static debug_info_t *debug_area_first = NULL; ...@@ -146,7 +147,7 @@ static debug_info_t *debug_area_first = NULL;
static debug_info_t *debug_area_last = NULL; static debug_info_t *debug_area_last = NULL;
DECLARE_MUTEX(debug_lock); DECLARE_MUTEX(debug_lock);
static int initialized = 0; static int initialized;
static struct file_operations debug_file_ops = { static struct file_operations debug_file_ops = {
read: debug_output, read: debug_output,
...@@ -591,7 +592,7 @@ debug_info_t *debug_register ...@@ -591,7 +592,7 @@ debug_info_t *debug_register
MOD_INC_USE_COUNT; MOD_INC_USE_COUNT;
if (!initialized) if (!initialized)
debug_init(); BUG();
down(&debug_lock); down(&debug_lock);
/* create new debug_info */ /* create new debug_info */
...@@ -828,18 +829,16 @@ debug_entry_t *debug_sprintf_exception(debug_info_t* id, ...@@ -828,18 +829,16 @@ debug_entry_t *debug_sprintf_exception(debug_info_t* id,
* - is called exactly once to initialize the debug feature * - is called exactly once to initialize the debug feature
*/ */
int debug_init(void) static int __init debug_init(void)
{ {
int rc = 0; int rc = 0;
down(&debug_lock); down(&debug_lock);
if (!initialized) {
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
debug_proc_root_entry = proc_mkdir(DEBUG_DIR_ROOT, NULL); debug_proc_root_entry = proc_mkdir(DEBUG_DIR_ROOT, NULL);
#endif /* CONFIG_PROC_FS */ #endif /* CONFIG_PROC_FS */
printk(KERN_INFO "debug: Initialization complete\n"); printk(KERN_INFO "debug: Initialization complete\n");
initialized = 1; initialized = 1;
}
up(&debug_lock); up(&debug_lock);
return rc; return rc;
...@@ -1173,27 +1172,9 @@ int debug_sprintf_format_fn(debug_info_t * id, struct debug_view *view, ...@@ -1173,27 +1172,9 @@ int debug_sprintf_format_fn(debug_info_t * id, struct debug_view *view,
} }
/* /*
* init_module: * clean up module
*/
#ifdef MODULE
int init_module(void)
{
int rc = 0;
#ifdef DEBUG
printk("debug_module_init: \n");
#endif
rc = debug_init();
if (rc)
printk(KERN_INFO "debug: an error occurred with debug_init\n");
return rc;
}
/*
* cleanup_module:
*/ */
void __exit debug_exit(void)
void cleanup_module(void)
{ {
#ifdef DEBUG #ifdef DEBUG
printk("debug_cleanup_module: \n"); printk("debug_cleanup_module: \n");
...@@ -1204,7 +1185,12 @@ void cleanup_module(void) ...@@ -1204,7 +1185,12 @@ void cleanup_module(void)
return; return;
} }
#endif /* MODULE */ /*
* module definitions
*/
core_initcall(debug_init);
module_exit(debug_exit);
MODULE_LICENSE("GPL");
EXPORT_SYMBOL(debug_register); EXPORT_SYMBOL(debug_register);
EXPORT_SYMBOL(debug_unregister); EXPORT_SYMBOL(debug_unregister);
......
...@@ -78,7 +78,7 @@ static struct resource data_resource = { "Kernel data", 0, 0 }; ...@@ -78,7 +78,7 @@ static struct resource data_resource = { "Kernel data", 0, 0 };
/* /*
* cpu_init() initializes state that is per-CPU. * cpu_init() initializes state that is per-CPU.
*/ */
void __init cpu_init (void) void __devinit cpu_init (void)
{ {
int nr = smp_processor_id(); int nr = smp_processor_id();
int addr = hard_smp_processor_id(); int addr = hard_smp_processor_id();
......
...@@ -454,7 +454,7 @@ extern void init_cpu_timer(void); ...@@ -454,7 +454,7 @@ extern void init_cpu_timer(void);
extern int pfault_init(void); extern int pfault_init(void);
extern int pfault_token(void); extern int pfault_token(void);
int __init start_secondary(void *cpuvoid) int __devinit start_secondary(void *cpuvoid)
{ {
/* Setup the cpu */ /* Setup the cpu */
cpu_init(); cpu_init();
...@@ -474,7 +474,7 @@ int __init start_secondary(void *cpuvoid) ...@@ -474,7 +474,7 @@ int __init start_secondary(void *cpuvoid)
return cpu_idle(NULL); return cpu_idle(NULL);
} }
static struct task_struct *__init fork_by_hand(void) static struct task_struct *__devinit fork_by_hand(void)
{ {
struct pt_regs regs; struct pt_regs regs;
/* don't care about the psw and regs settings since we'll never /* don't care about the psw and regs settings since we'll never
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <asm/semaphore.h> #include <asm/semaphore.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h>
#include <asm/debug.h> #include <asm/debug.h>
...@@ -146,7 +147,7 @@ static debug_info_t *debug_area_first = NULL; ...@@ -146,7 +147,7 @@ static debug_info_t *debug_area_first = NULL;
static debug_info_t *debug_area_last = NULL; static debug_info_t *debug_area_last = NULL;
DECLARE_MUTEX(debug_lock); DECLARE_MUTEX(debug_lock);
static int initialized = 0; static int initialized;
static struct file_operations debug_file_ops = { static struct file_operations debug_file_ops = {
read: debug_output, read: debug_output,
...@@ -591,7 +592,7 @@ debug_info_t *debug_register ...@@ -591,7 +592,7 @@ debug_info_t *debug_register
MOD_INC_USE_COUNT; MOD_INC_USE_COUNT;
if (!initialized) if (!initialized)
debug_init(); BUG();
down(&debug_lock); down(&debug_lock);
/* create new debug_info */ /* create new debug_info */
...@@ -828,18 +829,16 @@ debug_entry_t *debug_sprintf_exception(debug_info_t* id, ...@@ -828,18 +829,16 @@ debug_entry_t *debug_sprintf_exception(debug_info_t* id,
* - is called exactly once to initialize the debug feature * - is called exactly once to initialize the debug feature
*/ */
int debug_init(void) static int __init debug_init(void)
{ {
int rc = 0; int rc = 0;
down(&debug_lock); down(&debug_lock);
if (!initialized) {
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
debug_proc_root_entry = proc_mkdir(DEBUG_DIR_ROOT, NULL); debug_proc_root_entry = proc_mkdir(DEBUG_DIR_ROOT, NULL);
#endif /* CONFIG_PROC_FS */ #endif /* CONFIG_PROC_FS */
printk(KERN_INFO "debug: Initialization complete\n"); printk(KERN_INFO "debug: Initialization complete\n");
initialized = 1; initialized = 1;
}
up(&debug_lock); up(&debug_lock);
return rc; return rc;
...@@ -1173,27 +1172,9 @@ int debug_sprintf_format_fn(debug_info_t * id, struct debug_view *view, ...@@ -1173,27 +1172,9 @@ int debug_sprintf_format_fn(debug_info_t * id, struct debug_view *view,
} }
/* /*
* init_module: * clean up module
*/
#ifdef MODULE
int init_module(void)
{
int rc = 0;
#ifdef DEBUG
printk("debug_module_init: \n");
#endif
rc = debug_init();
if (rc)
printk(KERN_INFO "debug: an error occurred with debug_init\n");
return rc;
}
/*
* cleanup_module:
*/ */
void __exit debug_exit(void)
void cleanup_module(void)
{ {
#ifdef DEBUG #ifdef DEBUG
printk("debug_cleanup_module: \n"); printk("debug_cleanup_module: \n");
...@@ -1204,7 +1185,12 @@ void cleanup_module(void) ...@@ -1204,7 +1185,12 @@ void cleanup_module(void)
return; return;
} }
#endif /* MODULE */ /*
* module definitions
*/
core_initcall(debug_init);
module_exit(debug_exit);
MODULE_LICENSE("GPL");
EXPORT_SYMBOL(debug_register); EXPORT_SYMBOL(debug_register);
EXPORT_SYMBOL(debug_unregister); EXPORT_SYMBOL(debug_unregister);
......
...@@ -78,7 +78,7 @@ static struct resource data_resource = { "Kernel data", 0, 0 }; ...@@ -78,7 +78,7 @@ static struct resource data_resource = { "Kernel data", 0, 0 };
/* /*
* cpu_init() initializes state that is per-CPU. * cpu_init() initializes state that is per-CPU.
*/ */
void __init cpu_init (void) void __devinit cpu_init (void)
{ {
int nr = smp_processor_id(); int nr = smp_processor_id();
int addr = hard_smp_processor_id(); int addr = hard_smp_processor_id();
......
...@@ -435,7 +435,7 @@ void __init smp_check_cpus(unsigned int max_cpus) ...@@ -435,7 +435,7 @@ void __init smp_check_cpus(unsigned int max_cpus)
extern void init_cpu_timer(void); extern void init_cpu_timer(void);
extern int pfault_init(void); extern int pfault_init(void);
int __init start_secondary(void *cpuvoid) int __devinit start_secondary(void *cpuvoid)
{ {
/* Setup the cpu */ /* Setup the cpu */
cpu_init(); cpu_init();
...@@ -455,7 +455,7 @@ int __init start_secondary(void *cpuvoid) ...@@ -455,7 +455,7 @@ int __init start_secondary(void *cpuvoid)
return cpu_idle(NULL); return cpu_idle(NULL);
} }
static struct task_struct * __init fork_by_hand(void) static struct task_struct * __devinit fork_by_hand(void)
{ {
struct pt_regs regs; struct pt_regs regs;
/* don't care about the psw and regs settings since we'll never /* don't care about the psw and regs settings since we'll never
......
...@@ -7,8 +7,9 @@ export-objs := s390dyn.o qdio.o ...@@ -7,8 +7,9 @@ export-objs := s390dyn.o qdio.o
obj-$(CONFIG_QDIO) += qdio.o obj-$(CONFIG_QDIO) += qdio.o
obj-y += s390mach.o s390dyn.o sysinfo.o obj-y += s390mach.o s390dyn.o sysinfo.o
obj-y += block/ char/ misc/ net/ cio/ obj-y += cio/ block/ char/ misc/ net/
drivers-y += drivers/s390/built-in.o drivers-y += drivers/s390/built-in.o
include $(TOPDIR)/Rules.make include $(TOPDIR)/Rules.make
...@@ -693,13 +693,12 @@ static int raw3215_startup(raw3215_info *raw) ...@@ -693,13 +693,12 @@ static int raw3215_startup(raw3215_info *raw)
if (raw->flags & RAW3215_ACTIVE) if (raw->flags & RAW3215_ACTIVE)
return 0; return 0;
if (request_irq(raw->irq, raw3215_irq, SA_INTERRUPT, if (s390_request_console_irq(raw->irq, raw3215_irq, SA_INTERRUPT,
"3215 terminal driver", &raw->devstat) != 0) "3215 terminal driver", &raw->devstat) != 0)
return -1; return -1;
raw->line_pos = 0; raw->line_pos = 0;
raw->flags |= RAW3215_ACTIVE; raw->flags |= RAW3215_ACTIVE;
s390irq_spin_lock_irqsave(raw->irq, flags); s390irq_spin_lock_irqsave(raw->irq, flags);
set_cons_dev(raw->irq);
raw3215_try_io(raw); raw3215_try_io(raw);
s390irq_spin_unlock_irqrestore(raw->irq, flags); s390irq_spin_unlock_irqrestore(raw->irq, flags);
...@@ -1064,7 +1063,6 @@ void __init con3215_init(void) ...@@ -1064,7 +1063,6 @@ void __init con3215_init(void)
/* Check if 3215 is to be the console */ /* Check if 3215 is to be the console */
if (!CONSOLE_IS_3215) if (!CONSOLE_IS_3215)
return; return;
irq = raw3215_find_dev(0);
/* Set the console mode for VM */ /* Set the console mode for VM */
if (MACHINE_IS_VM) { if (MACHINE_IS_VM) {
...@@ -1072,6 +1070,22 @@ void __init con3215_init(void) ...@@ -1072,6 +1070,22 @@ void __init con3215_init(void)
cpcmd("TERM AUTOCR OFF", NULL, 0); cpcmd("TERM AUTOCR OFF", NULL, 0);
} }
if (console_device != -1) {
/* use the device number that was specified on the
* command line */
irq = raw3215_find_dev(0);
} else if (MACHINE_IS_VM) {
/* under VM, the console is at device number 0009
* by default, so try that */
irq = get_irq_by_devno(0x0009);
} else {
/* unlike in 2.4, we cannot autoprobe here, since
* the channel subsystem is not fully initialized.
* With some luck, the HWC console can take over */
printk(KERN_WARNING "3215 console not found\n");
return;
}
/* allocate 3215 request structures */ /* allocate 3215 request structures */
raw3215_freelist = NULL; raw3215_freelist = NULL;
spin_lock_init(&raw3215_freelist_lock); spin_lock_init(&raw3215_freelist_lock);
......
/* /*
* drivers/s390/cio/cio_debug.c * drivers/s390/cio/cio_debug.c
* S/390 common I/O routines -- message ids for debugging * S/390 common I/O routines -- message ids for debugging
* $Revision: 1.4 $ * $Revision: 1.5 $
* *
* Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH, * Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
* IBM Corporation * IBM Corporation
...@@ -69,4 +69,4 @@ cio_debug_init (void) ...@@ -69,4 +69,4 @@ cio_debug_init (void)
return ret; return ret;
} }
__initcall (cio_debug_init); arch_initcall (cio_debug_init);
/* /*
* drivers/s390/cio/requestirq.c * drivers/s390/cio/requestirq.c
* S/390 common I/O routines -- * S/390 common I/O routines --
* $Revision: 1.7 $ * $Revision: 1.12 $
* *
* Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH, * Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
* IBM Corporation * IBM Corporation
...@@ -122,6 +122,34 @@ s390_request_irq (unsigned int irq, ...@@ -122,6 +122,34 @@ s390_request_irq (unsigned int irq,
NULL, irqflags, devname, dev_id); NULL, irqflags, devname, dev_id);
} }
int
s390_request_console_irq (int irq,
void (*handler) (int, void *, struct pt_regs *),
unsigned long irqflags,
const char *devname,
void *dev_id)
{
int ret;
unsigned long flags;
s390_device_recognition_irq (irq);
ret = s390_request_irq_special (irq, (io_handler_func_t) handler,
NULL, irqflags, devname, dev_id);
if (ret)
goto out;
s390irq_spin_lock_irqsave(irq, flags);
ret = set_cons_dev(irq);
s390irq_spin_unlock_irqrestore(irq, flags);
if (ret)
free_irq(irq, dev_id);
out:
return ret;
}
/* /*
* request_irq wrapper * request_irq wrapper
*/ */
...@@ -151,7 +179,7 @@ s390_free_irq (unsigned int irq, void *dev_id) ...@@ -151,7 +179,7 @@ s390_free_irq (unsigned int irq, void *dev_id)
s390irq_spin_lock_irqsave (irq, flags); s390irq_spin_lock_irqsave (irq, flags);
CIO_DEBUG_NOCONS(irq,KERN_DEBUG, printk, 2, CIO_DEBUG_NOCONS(irq,KERN_DEBUG, DBG, 2,
"Trying to free IRQ %d\n", "Trying to free IRQ %d\n",
irq); irq);
......
/* /*
* drivers/s390/cio/s390io.c * drivers/s390/cio/s390io.c
* S/390 common I/O routines * S/390 common I/O routines
* $Revision: 1.11 $ * $Revision: 1.33 $
* *
* S390 version * S390 version
* Copyright (C) 1999, 2000 IBM Deutschland Entwicklung GmbH, * Copyright (C) 1999, 2000 IBM Deutschland Entwicklung GmbH,
...@@ -75,9 +75,8 @@ static schib_t p_init_schib; ...@@ -75,9 +75,8 @@ static schib_t p_init_schib;
static __u64 irq_IPL_TOD; // FIXME: can be on stack static __u64 irq_IPL_TOD; // FIXME: can be on stack
static void s390_process_subchannels (void); static void s390_process_subchannels (void);
static void s390_device_recognition_all (void);
static int s390_SenseID (int irq, senseid_t * sid, __u8 lpm); 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_SetPGID (int irq, __u8 lpm);
static int s390_SensePGID (int irq, __u8 lpm, pgid_t * pgid); static int s390_SensePGID (int irq, __u8 lpm, pgid_t * pgid);
/* FIXME: intermixed with proc.c */ /* FIXME: intermixed with proc.c */
...@@ -86,7 +85,6 @@ unsigned long s390_irq_count[NR_CPUS]; /* trace how many irqs have occured per c ...@@ -86,7 +85,6 @@ unsigned long s390_irq_count[NR_CPUS]; /* trace how many irqs have occured per c
int cio_show_msg; int cio_show_msg;
static int cio_notoper_msg = 1; static int cio_notoper_msg = 1;
static int cio_sid_with_pgid; /* if we need a PGID for SenseID, switch this on */
static int __init static int __init
cio_setup (char *parm) cio_setup (char *parm)
...@@ -125,25 +123,6 @@ cio_notoper_setup (char *parm) ...@@ -125,25 +123,6 @@ cio_notoper_setup (char *parm)
__setup ("cio_notoper_msg=", cio_notoper_setup); __setup ("cio_notoper_msg=", cio_notoper_setup);
static int __init
cio_pgid_setup (char *parm)
{
if (!strcmp (parm, "yes")) {
cio_sid_with_pgid = 1;
} else if (!strcmp (parm, "no")) {
cio_sid_with_pgid = 0;
} else {
printk (KERN_ERR
"cio_pgid_setup : invalid cio_msg parameter '%s'",
parm);
}
return 1;
}
__setup ("cio_sid_with_pgid=", cio_pgid_setup);
/* This function is replacing the init_IRQ function in /* This function is replacing the init_IRQ function in
* arch/s390(x)/kernel/irq.c and is called early during * arch/s390(x)/kernel/irq.c and is called early during
* bootup. Anything called from here must be careful * bootup. Anything called from here must be careful
...@@ -199,8 +178,6 @@ s390_init_IRQ (void) ...@@ -199,8 +178,6 @@ s390_init_IRQ (void)
cr6 = 0x10000000; cr6 = 0x10000000;
__ctl_load (cr6, 6, 6); __ctl_load (cr6, 6, 6);
s390_device_recognition_all ();
init_IRQ_complete = 1; init_IRQ_complete = 1;
local_irq_restore (flags); local_irq_restore (flags);
...@@ -226,6 +203,51 @@ init_IRQ_handler (int irq, void *dev_id, struct pt_regs *regs) ...@@ -226,6 +203,51 @@ init_IRQ_handler (int irq, void *dev_id, struct pt_regs *regs)
/* this is a dummy handler only ... */ /* this is a dummy handler only ... */
} }
/*
* diag210 is used under VM to get information about a virtual device
*/
#ifdef CONFIG_ARCH_S390X
int diag210(diag210_t * addr)
{
/*
* diag 210 needs its data below the 2GB border, so we
* use a static data area to be sure
*/
static diag210_t diag210_tmp;
static spinlock_t diag210_lock = SPIN_LOCK_UNLOCKED;
unsigned long flags;
int ccode;
spin_lock_irqsave(&diag210_lock, flags);
diag210_tmp = *addr;
asm volatile (
" sam31\n"
" diag %1,0,0x210\n"
" sam64\n"
" ipm %0\n"
" srl %0,28"
: "=d" (ccode) : "a" (__pa(&diag210_tmp)) : "cc", "memory" );
*addr = diag210_tmp;
spin_unlock_irqrestore(&diag210_lock, flags);
return ccode;
}
#else
int diag210(diag210_t * addr)
{
int ccode;
asm volatile (
" diag %1,0,0x210\n"
" ipm %0\n"
" srl %0,28"
: "=d" (ccode) : "a" (__pa(addr)) : "cc", "memory" );
return ccode;
}
#endif
/* /*
* Input : * Input :
...@@ -234,31 +256,28 @@ init_IRQ_handler (int irq, void *dev_id, struct pt_regs *regs) ...@@ -234,31 +256,28 @@ init_IRQ_handler (int irq, void *dev_id, struct pt_regs *regs)
* Output : none * Output : none
*/ */
static inline void static inline void
_VM_virtual_device_info (__u16 devno, senseid_t * ps) VM_virtual_device_info (__u16 devno, senseid_t * ps)
{ {
diag210_t *p_diag_data; diag210_t diag_data;
int ccode; int ccode;
int error = 0; int error = 0;
CIO_TRACE_EVENT (4, "VMvdinf"); CIO_TRACE_EVENT (4, "VMvdinf");
if (init_IRQ_complete) { diag_data = (diag210_t) {
p_diag_data = kmalloc (sizeof (diag210_t), GFP_DMA); .vrdcdvno = devno,
} else { .vrdclen = sizeof (diag_data),
p_diag_data = alloc_bootmem_low (sizeof (diag210_t)); };
}
p_diag_data->vrdcdvno = devno; ccode = diag210 (&diag_data);
p_diag_data->vrdclen = sizeof (diag210_t);
ccode = diag210 ((diag210_t *) virt_to_phys (p_diag_data));
ps->reserved = 0xff; ps->reserved = 0xff;
switch (p_diag_data->vrdcvcla) { /* FIXME: this would be much nicer if it were table driven */
switch (diag_data.vrdcvcla) {
case 0x80: case 0x80:
switch (p_diag_data->vrdcvtyp) { switch (diag_data.vrdcvtyp) {
case 00: case 00:
ps->cu_type = 0x3215; ps->cu_type = 0x3215;
...@@ -277,7 +296,7 @@ _VM_virtual_device_info (__u16 devno, senseid_t * ps) ...@@ -277,7 +296,7 @@ _VM_virtual_device_info (__u16 devno, senseid_t * ps)
case 0x40: case 0x40:
switch (p_diag_data->vrdcvtyp) { switch (diag_data.vrdcvtyp) {
case 0xC0: case 0xC0:
ps->cu_type = 0x5080; ps->cu_type = 0x5080;
...@@ -314,7 +333,7 @@ _VM_virtual_device_info (__u16 devno, senseid_t * ps) ...@@ -314,7 +333,7 @@ _VM_virtual_device_info (__u16 devno, senseid_t * ps)
case 0x20: case 0x20:
switch (p_diag_data->vrdcvtyp) { switch (diag_data.vrdcvtyp) {
case 0x84: case 0x84:
ps->cu_type = 0x3505; ps->cu_type = 0x3505;
...@@ -345,7 +364,7 @@ _VM_virtual_device_info (__u16 devno, senseid_t * ps) ...@@ -345,7 +364,7 @@ _VM_virtual_device_info (__u16 devno, senseid_t * ps)
case 0x10: case 0x10:
switch (p_diag_data->vrdcvtyp) { switch (diag_data.vrdcvtyp) {
case 0x84: case 0x84:
ps->cu_type = 0x3525; ps->cu_type = 0x3525;
...@@ -422,7 +441,7 @@ _VM_virtual_device_info (__u16 devno, senseid_t * ps) ...@@ -422,7 +441,7 @@ _VM_virtual_device_info (__u16 devno, senseid_t * ps)
case 0x08: case 0x08:
switch (p_diag_data->vrdcvtyp) { switch (diag_data.vrdcvtyp) {
case 0x82: case 0x82:
ps->cu_type = 0x3422; ps->cu_type = 0x3422;
...@@ -477,7 +496,7 @@ _VM_virtual_device_info (__u16 devno, senseid_t * ps) ...@@ -477,7 +496,7 @@ _VM_virtual_device_info (__u16 devno, senseid_t * ps)
case 02: /* special device class ... */ case 02: /* special device class ... */
switch (p_diag_data->vrdcvtyp) { switch (diag_data.vrdcvtyp) {
case 0x20: /* OSA */ case 0x20: /* OSA */
ps->cu_type = 0x3088; ps->cu_type = 0x3088;
...@@ -502,13 +521,6 @@ _VM_virtual_device_info (__u16 devno, senseid_t * ps) ...@@ -502,13 +521,6 @@ _VM_virtual_device_info (__u16 devno, senseid_t * ps)
} }
if (init_IRQ_complete) {
kfree (p_diag_data);
} else {
free_bootmem ((unsigned long) p_diag_data, sizeof (diag210_t));
}
if (error) if (error)
CIO_DEBUG_ALWAYS(KERN_ERR, 0, CIO_DEBUG_ALWAYS(KERN_ERR, 0,
"DIAG X'210' for " "DIAG X'210' for "
...@@ -519,12 +531,11 @@ _VM_virtual_device_info (__u16 devno, senseid_t * ps) ...@@ -519,12 +531,11 @@ _VM_virtual_device_info (__u16 devno, senseid_t * ps)
"rdev model: %02X\n", "rdev model: %02X\n",
devno, devno,
ccode, ccode,
p_diag_data->vrdcvcla, diag_data.vrdcvcla,
p_diag_data->vrdcvtyp, diag_data.vrdcvtyp,
p_diag_data->vrdcrccl, diag_data.vrdcrccl,
p_diag_data->vrdccrty, diag_data.vrdccrty,
p_diag_data->vrdccrmd); diag_data.vrdccrmd);
} }
/* /*
...@@ -553,7 +564,7 @@ _VM_virtual_device_info (__u16 devno, senseid_t * ps) ...@@ -553,7 +564,7 @@ _VM_virtual_device_info (__u16 devno, senseid_t * ps)
int int
read_dev_chars (int irq, void **buffer, int length) read_dev_chars (int irq, void **buffer, int length)
{ {
unsigned int flags; unsigned long flags;
ccw1_t *rdc_ccw; ccw1_t *rdc_ccw;
devstat_t devstat; devstat_t devstat;
char *rdc_buf; char *rdc_buf;
...@@ -661,9 +672,11 @@ read_dev_chars (int irq, void **buffer, int length) ...@@ -661,9 +672,11 @@ read_dev_chars (int irq, void **buffer, int length)
} }
} else {
local_irq_restore(flags);
} }
return (ret); return ret;
} }
/* /*
...@@ -698,7 +711,7 @@ read_conf_data (int irq, void **buffer, int *length, __u8 lpm) ...@@ -698,7 +711,7 @@ read_conf_data (int irq, void **buffer, int *length, __u8 lpm)
* scan for RCD command in extended SenseID data * scan for RCD command in extended SenseID data
*/ */
for (ciw_cnt = 0; (found == 0) && (ciw_cnt < 62); ciw_cnt++) { for (ciw_cnt = 0; (found == 0) && (ciw_cnt < MAX_CIWS); ciw_cnt++) {
if (ioinfo[irq]->senseid.ciw[ciw_cnt].ct == CIW_TYPE_RCD) { if (ioinfo[irq]->senseid.ciw[ciw_cnt].ct == CIW_TYPE_RCD) {
/* /*
* paranoia check ... * paranoia check ...
...@@ -817,11 +830,10 @@ read_conf_data (int irq, void **buffer, int *length, __u8 lpm) ...@@ -817,11 +830,10 @@ read_conf_data (int irq, void **buffer, int *length, __u8 lpm)
} while (retry); } while (retry);
} }
local_irq_restore (flags);
} }
local_irq_restore(flags);
/* /*
* on success we update the user input parms * on success we update the user input parms
*/ */
...@@ -867,8 +879,8 @@ read_conf_data (int irq, void **buffer, int *length, __u8 lpm) ...@@ -867,8 +879,8 @@ read_conf_data (int irq, void **buffer, int *length, __u8 lpm)
void void
s390_device_recognition_irq (int irq) s390_device_recognition_irq (int irq)
{ {
int ret;
char dbf_txt[15]; char dbf_txt[15];
devstat_t devstat;
sprintf (dbf_txt, "devrec%x", irq); sprintf (dbf_txt, "devrec%x", irq);
CIO_TRACE_EVENT (4, dbf_txt); CIO_TRACE_EVENT (4, dbf_txt);
...@@ -877,52 +889,78 @@ s390_device_recognition_irq (int irq) ...@@ -877,52 +889,78 @@ s390_device_recognition_irq (int irq)
* We issue the SenseID command on I/O subchannels we think are * We issue the SenseID command on I/O subchannels we think are
* operational only. * operational only.
*/ */
if ((ioinfo[irq] != INVALID_STORAGE_AREA) if ((ioinfo[irq]->st) || (!ioinfo[irq]->ui.flags.oper))
&& (!ioinfo[irq]->st) goto out;
&& (ioinfo[irq]->schib.pmcw.st == 0)
&& (ioinfo[irq]->ui.flags.oper == 1)) {
int irq_ret;
devstat_t devstat;
irq_ret = request_irq (irq, if (request_irq (irq, init_IRQ_handler, SA_PROBE, "INIT", &devstat))
init_IRQ_handler, goto out;
SA_PROBE, "INIT", &devstat);
if (!irq_ret) { if (enable_cpu_sync_isc(irq))
ret = enable_cpu_sync_isc (irq); goto out_freeirq;
if (!ret) {
ioinfo[irq]->ui.flags.unknown = 0; ioinfo[irq]->ui.flags.unknown = 0;
memset (&ioinfo[irq]->senseid, '\0', memset (&ioinfo[irq]->senseid, '\0', sizeof (senseid_t));
sizeof (senseid_t));
s390_SenseID (irq, &ioinfo[irq]->senseid, 0xff);
if (cio_sid_with_pgid) { disable_cpu_sync_isc(irq);
out_freeirq:
free_irq (irq, &devstat);
out:
return;
}
ret = s390_DevicePathVerification(irq,0); static int
css_bus_match (struct device *dev, struct device_driver *drv)
{
struct subchannel *ioinfo;
struct subchannel_driver *sdrv;
if (ret == -EOPNOTSUPP) ioinfo = list_entry (dev, struct subchannel, dev);
/* sdrv = list_entry (drv, struct subchannel_driver, drv);
* Doesn't prevent us from proceeding
*/
ret = 0;
}
/* return (ioinfo->st == sdrv->st);
* we'll fallthrough here if we don't want }
* to do SPID before SID
*/
if (!ret) {
s390_SenseID (irq, &ioinfo[irq]->senseid, 0xff);
}
disable_cpu_sync_isc (irq);
} struct bus_type css_bus_type = {
.name = "css",
.match = &css_bus_match,
};
free_irq (irq, &devstat); static struct device css_bus_device = {
.name = "Channel Subsystem",
.bus_id = "css0",
};
} /*
} * s390_register_subchannel
*
* initializes the struct device member of a subchannel and gives it to
* the device driver core
*/
static __devinit void
s390_register_subchannel (struct subchannel *ioinfo)
{
static const char *subchannel_types[] = {
"I/O Subchannel",
"CHSC Subchannel",
"Message Subchannel",
"ADM Subchannel",
"undefined subchannel type 4",
"undefined subchannel type 5",
"undefined subchannel type 6",
"undefined subchannel type 7",
};
strncpy (ioinfo->dev.name, subchannel_types[ioinfo->st], DEVICE_NAME_SIZE);
snprintf (ioinfo->dev.bus_id, DEVICE_ID_SIZE, "0:%04x", ioinfo->irq);
ioinfo->dev.bus = &css_bus_type;
ioinfo->dev.parent = &css_bus_device;
if (device_register(&ioinfo->dev))
printk(KERN_WARNING "failed to register subchannel %04x\n", ioinfo->irq);
} }
/* /*
...@@ -931,19 +969,43 @@ s390_device_recognition_irq (int irq) ...@@ -931,19 +969,43 @@ s390_device_recognition_irq (int irq)
* Used for system wide device recognition. * Used for system wide device recognition.
* *
*/ */
static void __init static int __init
s390_device_recognition_all (void) s390_probe_css (void)
{ {
int irq = 0; /* let's start with subchannel 0 ... */ int ret;
int irq;
do { printk (KERN_INFO "probing %d subchannels...\n", highest_subchannel+1);
if ((ret = bus_register(&css_bus_type)))
goto out;
if ((ret = device_register(&css_bus_device)))
goto out_unregister;
for (irq = 0; irq <= highest_subchannel; irq++) {
if (ioinfo[irq] == INVALID_STORAGE_AREA)
continue;
printk(KERN_INFO "subchannel %04x: devno %04x, ",
irq, ioinfo[irq]->devno);
if (irq != cons_dev) /* console has already been probed */
s390_device_recognition_irq (irq); s390_device_recognition_irq (irq);
irq++; s390_register_subchannel(ioinfo[irq]);
printk("control unit type %04x\n", ioinfo[irq]->senseid.cu_type);
}
} while (irq <= highest_subchannel); out_unregister:
if (ret)
put_bus(&css_bus_type);
out:
return ret;
} }
subsys_initcall(s390_probe_css);
/* /*
* s390_process_subchannels * s390_process_subchannels
* *
...@@ -1301,7 +1363,13 @@ s390_validate_subchannel (int irq, int enable) ...@@ -1301,7 +1363,13 @@ s390_validate_subchannel (int irq, int enable)
static int static int
s390_SenseID (int irq, senseid_t * sid, __u8 lpm) s390_SenseID (int irq, senseid_t * sid, __u8 lpm)
{ {
ccw1_t *sense_ccw; /* ccw area for SenseID command */ /* SenseID may be called during console initialization,
* before we have a working kmalloc, using a static
* ccw area is the least evil workaround */
static ccw1_t sense_ccw[2]; /* ccw area for SenseID command */
static spinlock_t sid_lock /* lock to protect sense_ccw */
= SPIN_LOCK_UNLOCKED;
senseid_t isid; /* internal sid */ senseid_t isid; /* internal sid */
devstat_t devstat; /* required by request_irq() */ devstat_t devstat; /* required by request_irq() */
__u8 pathmask; /* calulate path mask */ __u8 pathmask; /* calulate path mask */
...@@ -1318,6 +1386,7 @@ s390_SenseID (int irq, senseid_t * sid, __u8 lpm) ...@@ -1318,6 +1386,7 @@ s390_SenseID (int irq, senseid_t * sid, __u8 lpm)
char dbf_txt[15]; char dbf_txt[15];
int i; int i;
int failure = 0; /* nothing went wrong yet */ int failure = 0; /* nothing went wrong yet */
unsigned long flags;
if (ioinfo[irq]->ui.flags.oper == 0) { if (ioinfo[irq]->ui.flags.oper == 0) {
return -ENODEV; return -ENODEV;
...@@ -1327,44 +1396,27 @@ s390_SenseID (int irq, senseid_t * sid, __u8 lpm) ...@@ -1327,44 +1396,27 @@ s390_SenseID (int irq, senseid_t * sid, __u8 lpm)
sprintf (dbf_txt, "snsID%x", irq); sprintf (dbf_txt, "snsID%x", irq);
CIO_TRACE_EVENT (4, dbf_txt); CIO_TRACE_EVENT (4, dbf_txt);
inlreq = 0; /* to make the compiler quiet... */
if (!ioinfo[irq]->ui.flags.ready) { if (!ioinfo[irq]->ui.flags.ready) {
inlreq = 1;
pdevstat = &devstat;
/* /*
* Perform SENSE ID command processing. We have to request device * Perform SENSE ID command processing. We have to request device
* ownership and provide a dummy I/O handler. We issue sync. I/O * ownership and provide a dummy I/O handler. We issue sync. I/O
* requests and evaluate the devstat area on return therefore * requests and evaluate the devstat area on return therefore
* we don't need a real I/O handler in place. * we don't need a real I/O handler in place.
*/ */
irq_ret = if ((irq_ret = request_irq (irq, init_IRQ_handler,
request_irq (irq, init_IRQ_handler, SA_PROBE, "SID", SA_PROBE, "SID", &devstat)))
&devstat); return irq_ret;
if (irq_ret == 0)
inlreq = 1;
} else { } else {
inlreq = 0; inlreq = 0;
irq_ret = 0;
pdevstat = ioinfo[irq]->irq_desc.dev_id;
} }
if (irq_ret) { pdevstat = ioinfo[irq]->irq_desc.dev_id;
return irq_ret;
}
spin_lock_irqsave(&sid_lock, flags);
s390irq_spin_lock (irq); s390irq_spin_lock (irq);
if (init_IRQ_complete) {
sense_ccw = kmalloc (2 * sizeof (ccw1_t), GFP_DMA);
} else {
sense_ccw = alloc_bootmem_low (2 * sizeof (ccw1_t));
}
/* more than one path installed ? */ /* more than one path installed ? */
if (ioinfo[irq]->schib.pmcw.pim != 0x80) { if (ioinfo[irq]->schib.pmcw.pim != 0x80) {
sense_ccw[0].cmd_code = CCW_CMD_SUSPEND_RECONN; sense_ccw[0].cmd_code = CCW_CMD_SUSPEND_RECONN;
...@@ -1584,14 +1636,8 @@ s390_SenseID (int irq, senseid_t * sid, __u8 lpm) ...@@ -1584,14 +1636,8 @@ s390_SenseID (int irq, senseid_t * sid, __u8 lpm)
} }
if (init_IRQ_complete) {
kfree (sense_ccw);
} else {
free_bootmem ((unsigned long) sense_ccw, 2 * sizeof (ccw1_t));
}
s390irq_spin_unlock (irq); s390irq_spin_unlock (irq);
spin_unlock_irqrestore(&sid_lock, flags);
/* /*
* If we installed the irq action handler we have to * If we installed the irq action handler we have to
...@@ -1606,7 +1652,7 @@ s390_SenseID (int irq, senseid_t * sid, __u8 lpm) ...@@ -1606,7 +1652,7 @@ s390_SenseID (int irq, senseid_t * sid, __u8 lpm)
*/ */
if ((sid->cu_type == 0xFFFF) if ((sid->cu_type == 0xFFFF)
&& (MACHINE_IS_VM)) { && (MACHINE_IS_VM)) {
_VM_virtual_device_info (ioinfo[irq]->schib.pmcw.dev, sid); VM_virtual_device_info (ioinfo[irq]->schib.pmcw.dev, sid);
} }
if (sid->cu_type == 0xFFFF) { if (sid->cu_type == 0xFFFF) {
...@@ -1622,43 +1668,18 @@ s390_SenseID (int irq, senseid_t * sid, __u8 lpm) ...@@ -1622,43 +1668,18 @@ s390_SenseID (int irq, senseid_t * sid, __u8 lpm)
ioinfo[irq]->schib.pmcw.dev, irq); ioinfo[irq]->schib.pmcw.dev, irq);
ioinfo[irq]->ui.flags.unknown = 1; ioinfo[irq]->ui.flags.unknown = 1;
return -ENODEV;
} }
/* /*
* Issue device info message if unit was operational . * Issue device info message if unit was operational .
*/ */
if (!ioinfo[irq]->ui.flags.unknown) { CIO_DEBUG_IFMSG(KERN_INFO, 2, "SenseID : device %04X reports: "
if (sid->dev_type != 0) { "CU Type/Mod = %04X/%02X, Dev Type/Mod = %04X/%02X\n",
ioinfo[irq]->schib.pmcw.dev, sid->cu_type, sid->cu_model,
CIO_DEBUG_IFMSG(KERN_INFO, 2, sid->dev_type, sid->dev_model);
"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 {
CIO_DEBUG_IFMSG(KERN_INFO, 2,
"SenseID : device %04X reports:"
" Dev Type/Mod = %04X/%02X\n",
ioinfo[irq]->schib.pmcw.dev,
sid->cu_type,
sid->cu_model);
}
}
if (!ioinfo[irq]->ui.flags.unknown)
irq_ret = 0;
else
irq_ret = -ENODEV;
return (irq_ret); return 0;
} }
/* /*
...@@ -1683,7 +1704,6 @@ s390_DevicePathVerification (int irq, __u8 usermask) ...@@ -1683,7 +1704,6 @@ s390_DevicePathVerification (int irq, __u8 usermask)
int i; int i;
pgid_t pgid; pgid_t pgid;
__u8 dev_path; __u8 dev_path;
int first = 1;
char dbf_txt[15]; char dbf_txt[15];
...@@ -1803,7 +1823,6 @@ s390_DevicePathVerification (int irq, __u8 usermask) ...@@ -1803,7 +1823,6 @@ s390_DevicePathVerification (int irq, __u8 usermask)
memcpy (&ioinfo[irq]->pgid, &global_pgid, sizeof (pgid_t)); memcpy (&ioinfo[irq]->pgid, &global_pgid, sizeof (pgid_t));
ioinfo[irq]->ui.flags.pgid = 1; ioinfo[irq]->ui.flags.pgid = 1;
} }
memcpy (&pgid, &ioinfo[irq]->pgid, sizeof (pgid_t));
for (i = 0; i < 8 && !ret; i++) { for (i = 0; i < 8 && !ret; i++) {
pathmask = 0x80 >> i; pathmask = 0x80 >> i;
...@@ -1811,36 +1830,29 @@ s390_DevicePathVerification (int irq, __u8 usermask) ...@@ -1811,36 +1830,29 @@ s390_DevicePathVerification (int irq, __u8 usermask)
domask = dev_path & pathmask; domask = dev_path & pathmask;
if (domask) { if (domask) {
ret = s390_SetPGID (irq, domask, &pgid); if (MACHINE_IS_VM) {
/* /*
* For the *first* path we are prepared * If we are running under VM, try to obtain
* for recovery * VM's PGID by SensePGID
*
* - If we fail setting the PGID we assume its
* using a different PGID already (VM) we
* try to sense.
*/ */
if (ret == -EOPNOTSUPP && first) {
*(int *) &pgid = 0; *(int *) &pgid = 0;
ret = s390_SensePGID (irq, domask, &pgid); if (!s390_SensePGID (irq, domask, &pgid))
first = 0;
if (ret == 0) {
/* /*
* Check whether we retrieved * Check whether we retrieved
* a reasonable PGID ... * a reasonable PGID ...
*/ */
if (pgid.inf.ps.state1 == if (pgid.inf.ps.state1 ==
SNID_STATE1_GROUPED) { SNID_STATE1_GROUPED)
memcpy (&ioinfo[irq]->pgid, memcpy (&ioinfo[irq]->pgid,
&pgid, sizeof (pgid_t)); &pgid, sizeof (pgid_t));
} else { /* ungrouped or garbage ... */
ret = -EOPNOTSUPP;
} }
} else {
ret = s390_SetPGID (irq, domask);
if (ret == -EOPNOTSUPP) {
ioinfo[irq]->ui.flags.pgid_supp = 0; ioinfo[irq]->ui.flags.pgid_supp = 0;
CIO_DEBUG(KERN_WARNING, 2, CIO_DEBUG(KERN_WARNING, 2,
...@@ -1850,7 +1862,6 @@ s390_DevicePathVerification (int irq, __u8 usermask) ...@@ -1850,7 +1862,6 @@ s390_DevicePathVerification (int irq, __u8 usermask)
irq, irq,
ioinfo[irq]->schib.pmcw.dev); ioinfo[irq]->schib.pmcw.dev);
}
} else if (ret == -EIO) { } else if (ret == -EIO) {
CIO_DEBUG(KERN_ERR, 2, CIO_DEBUG(KERN_ERR, 2,
...@@ -1873,13 +1884,20 @@ s390_DevicePathVerification (int irq, __u8 usermask) ...@@ -1873,13 +1884,20 @@ s390_DevicePathVerification (int irq, __u8 usermask)
ret = 0; ret = 0;
} else { } else if (ret == -ENODEV) {
CIO_DEBUG(KERN_ERR, 2, CIO_DEBUG(KERN_ERR, 2,
"PathVerification(%04X) - " "PathVerification(%04X) "
"Unexpected error on device %04X\n", "- Device %04X is no longer there?!?\n",
irq, ioinfo[irq]->schib.pmcw.dev); irq, ioinfo[irq]->schib.pmcw.dev);
} else if (ret) {
CIO_DEBUG(KERN_ERR, 2,
"PathVerification(%04X) - "
"Unexpected error %d on device %04X\n",
irq, ret, ioinfo[irq]->schib.pmcw.dev);
ioinfo[irq]->ui.flags.pgid_supp = 0; ioinfo[irq]->ui.flags.pgid_supp = 0;
} }
} }
...@@ -1895,7 +1913,7 @@ s390_DevicePathVerification (int irq, __u8 usermask) ...@@ -1895,7 +1913,7 @@ s390_DevicePathVerification (int irq, __u8 usermask)
* *
*/ */
static int static int
s390_SetPGID (int irq, __u8 lpm, pgid_t * pgid) s390_SetPGID (int irq, __u8 lpm)
{ {
ccw1_t *spid_ccw; /* ccw area for SPID command */ ccw1_t *spid_ccw; /* ccw area for SPID command */
devstat_t devstat; /* required by request_irq() */ devstat_t devstat; /* required by request_irq() */
...@@ -1953,11 +1971,11 @@ s390_SetPGID (int irq, __u8 lpm, pgid_t * pgid) ...@@ -1953,11 +1971,11 @@ s390_SetPGID (int irq, __u8 lpm, pgid_t * pgid)
spid_ccw[0].flags = CCW_FLAG_SLI | CCW_FLAG_CC; spid_ccw[0].flags = CCW_FLAG_SLI | CCW_FLAG_CC;
spid_ccw[1].cmd_code = CCW_CMD_SET_PGID; spid_ccw[1].cmd_code = CCW_CMD_SET_PGID;
spid_ccw[1].cda = (__u32) virt_to_phys (pgid); spid_ccw[1].cda = (__u32) virt_to_phys (&ioinfo[irq]->pgid);
spid_ccw[1].count = sizeof (pgid_t); spid_ccw[1].count = sizeof (pgid_t);
spid_ccw[1].flags = CCW_FLAG_SLI; spid_ccw[1].flags = CCW_FLAG_SLI;
pgid->inf.fc = SPID_FUNC_MULTI_PATH | SPID_FUNC_ESTABLISH; ioinfo[irq]->pgid.inf.fc = SPID_FUNC_MULTI_PATH | SPID_FUNC_ESTABLISH;
/* /*
* We now issue a SetPGID request. In case of BUSY * We now issue a SetPGID request. In case of BUSY
...@@ -2011,13 +2029,13 @@ s390_SetPGID (int irq, __u8 lpm, pgid_t * pgid) ...@@ -2011,13 +2029,13 @@ s390_SetPGID (int irq, __u8 lpm, pgid_t * pgid)
spid_ccw[0].cmd_code = spid_ccw[0].cmd_code =
CCW_CMD_SET_PGID; CCW_CMD_SET_PGID;
spid_ccw[0].cda = (__u32) spid_ccw[0].cda = (__u32)
virt_to_phys (pgid); virt_to_phys (&ioinfo[irq]->pgid);
spid_ccw[0].count = spid_ccw[0].count =
sizeof (pgid_t); sizeof (pgid_t);
spid_ccw[0].flags = spid_ccw[0].flags =
CCW_FLAG_SLI; CCW_FLAG_SLI;
pgid->inf.fc = ioinfo[irq]->pgid.inf.fc =
SPID_FUNC_SINGLE_PATH SPID_FUNC_SINGLE_PATH
| SPID_FUNC_ESTABLISH; | SPID_FUNC_ESTABLISH;
mpath = 0; mpath = 0;
...@@ -2071,6 +2089,7 @@ s390_SetPGID (int irq, __u8 lpm, pgid_t * pgid) ...@@ -2071,6 +2089,7 @@ s390_SetPGID (int irq, __u8 lpm, pgid_t * pgid)
retry = 0; retry = 0;
ioinfo[irq]->opm &= ~lpm; ioinfo[irq]->opm &= ~lpm;
switch_off_chpids(irq, lpm);
irq_ret = -EAGAIN; irq_ret = -EAGAIN;
} }
...@@ -2133,6 +2152,7 @@ s390_SensePGID (int irq, __u8 lpm, pgid_t * pgid) ...@@ -2133,6 +2152,7 @@ s390_SensePGID (int irq, __u8 lpm, pgid_t * pgid)
devstat_t devstat; /* required by request_irq() */ devstat_t devstat; /* required by request_irq() */
devstat_t *pdevstat = &devstat; devstat_t *pdevstat = &devstat;
char dbf_txt[15]; char dbf_txt[15];
pgid_t * tmp_pgid;
int irq_ret = 0; /* return code */ int irq_ret = 0; /* return code */
int retry = 5; /* retry count */ int retry = 5; /* retry count */
...@@ -2174,13 +2194,14 @@ s390_SensePGID (int irq, __u8 lpm, pgid_t * pgid) ...@@ -2174,13 +2194,14 @@ s390_SensePGID (int irq, __u8 lpm, pgid_t * pgid)
if (init_IRQ_complete) { if (init_IRQ_complete) {
snid_ccw = kmalloc (sizeof (ccw1_t), GFP_DMA); snid_ccw = kmalloc (sizeof (ccw1_t), GFP_DMA);
tmp_pgid = kmalloc (sizeof (pgid_t), GFP_DMA);
} else { } else {
snid_ccw = alloc_bootmem_low (sizeof (ccw1_t)); snid_ccw = alloc_bootmem_low (sizeof (ccw1_t));
tmp_pgid = alloc_bootmem_low (sizeof (pgid_t));
} }
snid_ccw->cmd_code = CCW_CMD_SENSE_PGID; snid_ccw->cmd_code = CCW_CMD_SENSE_PGID;
snid_ccw->cda = (__u32) virt_to_phys (pgid); snid_ccw->cda = (__u32) virt_to_phys (tmp_pgid);
snid_ccw->count = sizeof (pgid_t); snid_ccw->count = sizeof (pgid_t);
snid_ccw->flags = CCW_FLAG_SLI; snid_ccw->flags = CCW_FLAG_SLI;
...@@ -2256,6 +2277,7 @@ s390_SensePGID (int irq, __u8 lpm, pgid_t * pgid) ...@@ -2256,6 +2277,7 @@ s390_SensePGID (int irq, __u8 lpm, pgid_t * pgid)
} else { } else {
retry = 0; /* success ... */ retry = 0; /* success ... */
irq_ret = 0; irq_ret = 0;
memcpy(pgid, tmp_pgid, sizeof(pgid_t));
} }
} else if (irq_ret != -ENODEV) { /* -EIO, or -EBUSY */ } else if (irq_ret != -ENODEV) { /* -EIO, or -EBUSY */
...@@ -2290,9 +2312,10 @@ s390_SensePGID (int irq, __u8 lpm, pgid_t * pgid) ...@@ -2290,9 +2312,10 @@ s390_SensePGID (int irq, __u8 lpm, pgid_t * pgid)
if (init_IRQ_complete) { if (init_IRQ_complete) {
kfree (snid_ccw); kfree (snid_ccw);
kfree (tmp_pgid);
} else { } else {
free_bootmem ((unsigned long) snid_ccw, sizeof (ccw1_t)); free_bootmem ((unsigned long) snid_ccw, sizeof (ccw1_t));
free_bootmem ((unsigned long) tmp_pgid, sizeof (tmp_pgid));
} }
s390irq_spin_unlock_irqrestore (irq, flags); s390irq_spin_unlock_irqrestore (irq, flags);
...@@ -2311,13 +2334,11 @@ s390_SensePGID (int irq, __u8 lpm, pgid_t * pgid) ...@@ -2311,13 +2334,11 @@ s390_SensePGID (int irq, __u8 lpm, pgid_t * pgid)
* Function: s390_send_nop * Function: s390_send_nop
* *
* sends a nop CCW to the specified subchannel down the given path(s) * sends a nop CCW to the specified subchannel down the given path(s)
* FIXME: why not put nop_ccw on the stack, it's only 64 bits?
*/ */
int int
s390_send_nop(int irq, __u8 lpm) s390_send_nop(int irq, __u8 lpm)
{ {
char dbf_txt[15]; char dbf_txt[15];
ccw1_t *nop_ccw;
devstat_t devstat; devstat_t devstat;
devstat_t *pdevstat = &devstat; devstat_t *pdevstat = &devstat;
unsigned long flags; unsigned long flags;
...@@ -2325,6 +2346,14 @@ s390_send_nop(int irq, __u8 lpm) ...@@ -2325,6 +2346,14 @@ s390_send_nop(int irq, __u8 lpm)
int irq_ret = 0; int irq_ret = 0;
int inlreq = 0; int inlreq = 0;
/* static allocation is necessary because nop_ccw has to be below
* the 2GB border. locking is not required since it nop_ccw is
* never modified */
static ccw1_t nop_ccw = {
.cmd_code = CCW_CMD_NOOP,
.flags = CCW_FLAG_SLI,
};
if (!ioinfo[irq]->ui.flags.oper) if (!ioinfo[irq]->ui.flags.oper)
/* no sense in trying */ /* no sense in trying */
return -ENODEV; return -ENODEV;
...@@ -2352,19 +2381,9 @@ s390_send_nop(int irq, __u8 lpm) ...@@ -2352,19 +2381,9 @@ s390_send_nop(int irq, __u8 lpm)
s390irq_spin_lock_irqsave (irq, flags); s390irq_spin_lock_irqsave (irq, flags);
if (init_IRQ_complete)
nop_ccw = kmalloc (sizeof (ccw1_t), GFP_DMA);
else
nop_ccw = alloc_bootmem_low (sizeof (ccw1_t));
nop_ccw->cmd_code = CCW_CMD_NOOP;
nop_ccw->cda = 0;
nop_ccw->count = 0;
nop_ccw->flags = CCW_FLAG_SLI;
memset (pdevstat, '\0', sizeof (devstat_t)); memset (pdevstat, '\0', sizeof (devstat_t));
irq_ret = s390_start_IO (irq, nop_ccw, 0xE2D5D6D7, lpm, irq_ret = s390_start_IO (irq, &nop_ccw, 0xE2D5D6D7, lpm,
DOIO_WAIT_FOR_INTERRUPT DOIO_WAIT_FOR_INTERRUPT
| DOIO_TIMEOUT | DOIO_TIMEOUT
| DOIO_DONT_CALL_INTHDLR | DOIO_DONT_CALL_INTHDLR
...@@ -2376,11 +2395,6 @@ s390_send_nop(int irq, __u8 lpm) ...@@ -2376,11 +2395,6 @@ s390_send_nop(int irq, __u8 lpm)
cancel_IO(irq); cancel_IO(irq);
} }
if (init_IRQ_complete)
kfree (nop_ccw);
else
free_bootmem ((unsigned long) nop_ccw, sizeof (ccw1_t));
s390irq_spin_unlock_irqrestore (irq, flags); s390irq_spin_unlock_irqrestore (irq, flags);
if (inlreq) if (inlreq)
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/completion.h>
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
#include <linux/smp.h> #include <linux/smp.h>
#endif #endif
...@@ -51,6 +52,7 @@ static spinlock_t mchchk_queue_lock = SPIN_LOCK_UNLOCKED; ...@@ -51,6 +52,7 @@ static spinlock_t mchchk_queue_lock = SPIN_LOCK_UNLOCKED;
static spinlock_t crw_queue_lock = SPIN_LOCK_UNLOCKED; static spinlock_t crw_queue_lock = SPIN_LOCK_UNLOCKED;
static struct semaphore s_sem; static struct semaphore s_sem;
static DECLARE_COMPLETION(mchchk_thread_active);
#ifdef CONFIG_MACHCHK_WARNING #ifdef CONFIG_MACHCHK_WARNING
static int mchchk_wng_posted = 0; static int mchchk_wng_posted = 0;
...@@ -103,14 +105,15 @@ s390_init_machine_check(void) ...@@ -103,14 +105,15 @@ s390_init_machine_check(void)
kernel_thread(s390_machine_check_handler, &s_sem, kernel_thread(s390_machine_check_handler, &s_sem,
CLONE_FS | CLONE_FILES); CLONE_FS | CLONE_FILES);
wait_for_completion(&mchchk_thread_active);
ctl_clear_bit(14, 25); /* disable damage MCH */ ctl_clear_bit(14, 25); /* disable damage MCH */
ctl_set_bit(14, 26); /* enable degradation MCH */ ctl_set_bit(14, 26); /* enable degradation MCH */
ctl_set_bit(14, 27); /* enable system recovery MCH */ ctl_set_bit(14, 27); /* enable system recovery MCH */
ctl_set_bit(14, 28); /* enable channel report MCH */
#ifdef CONFIG_MACHCK_WARNING #ifdef CONFIG_MACHCHK_WARNING
ctl_set_bit(14, 24); /* enable warning MCH */ ctl_set_bit(14, 24); /* enable warning MCH */
#endif #endif
...@@ -127,6 +130,30 @@ s390_init_machine_check(void) ...@@ -127,6 +130,30 @@ s390_init_machine_check(void)
return; return;
} }
/*
* initialize the machine check handler really early to be able to
* catch all machine checks that happen during boot
*/
static int __init
machine_check_init (void)
{
s390_init_machine_check();
return 0;
}
arch_initcall(machine_check_init);
/*
* Machine checks for the channel subsystem must be enabled
* after the channel subsystem is initialized
*/
static int __init
machine_check_crw_init (void)
{
ctl_set_bit(14, 28); /* enable channel report MCH */
return 0;
}
device_initcall (machine_check_crw_init);
static void static void
s390_handle_damage(char *msg) s390_handle_damage(char *msg)
{ {
...@@ -244,6 +271,8 @@ s390_machine_check_handler(void *parm) ...@@ -244,6 +271,8 @@ s390_machine_check_handler(void *parm)
DBG(KERN_NOTICE "mach_handler : ready\n"); DBG(KERN_NOTICE "mach_handler : ready\n");
complete(&mchchk_thread_active);
do { do {
DBG(KERN_NOTICE "mach_handler : waiting for wakeup\n"); DBG(KERN_NOTICE "mach_handler : waiting for wakeup\n");
......
...@@ -637,6 +637,12 @@ int s390_request_irq_special( int irq, ...@@ -637,6 +637,12 @@ int s390_request_irq_special( int irq,
const char *devname, const char *devname,
void *dev_id); void *dev_id);
extern int s390_request_console_irq (int irq,
void (*handler) (int, void *, struct pt_regs *),
unsigned long irqflags,
const char *devname,
void *dev_id);
extern int set_cons_dev(int irq); extern int set_cons_dev(int irq);
extern int wait_cons_dev(int irq); extern int wait_cons_dev(int irq);
extern schib_t *s390_get_schib( int irq ); extern schib_t *s390_get_schib( int irq );
...@@ -860,28 +866,8 @@ typedef struct { ...@@ -860,28 +866,8 @@ typedef struct {
__u32 vrdccrft : 8; /* real device feature (output) */ __u32 vrdccrft : 8; /* real device feature (output) */
} __attribute__ ((packed,aligned(4))) diag210_t; } __attribute__ ((packed,aligned(4))) diag210_t;
void VM_virtual_device_info( __u16 devno, /* device number */ extern int diag210( diag210_t * addr);
senseid_t *ps ); /* ptr to senseID data */
extern __inline__ int diag210( diag210_t * addr)
{
int ccode;
__asm__ __volatile__(
#ifdef CONFIG_ARCH_S390X
" sam31\n"
" diag %1,0,0x210\n"
" sam64\n"
#else
" diag %1,0,0x210\n"
#endif
" ipm %0\n"
" srl %0,28"
: "=d" (ccode)
: "a" (addr)
: "cc" );
return ccode;
}
extern __inline__ int chsc( chsc_area_t * chsc_area) extern __inline__ int chsc( chsc_area_t * chsc_area)
{ {
int cc; int cc;
......
...@@ -9,22 +9,25 @@ ...@@ -9,22 +9,25 @@
#ifndef __s390io_h #ifndef __s390io_h
#define __s390io_h #define __s390io_h
#include <linux/device.h>
/* /*
* IRQ data structure used by I/O subroutines * IRQ data structure used by I/O subroutines
* *
* Note : If bit flags are added, the "unused" value must be * Note : If bit flags are added, the "unused" value must be
* decremented accordingly ! * decremented accordingly !
*/ */
typedef struct _ioinfo { typedef struct subchannel {
unsigned int irq; /* aka. subchannel number */ unsigned int irq; /* aka. subchannel number */
spinlock_t irq_lock; /* irq lock */ spinlock_t irq_lock; /* irq lock */
void *private_data; /* pointer to private data */
struct _ioinfo *prev;
struct _ioinfo *next;
__u8 st; /* subchannel type */ __u8 st; /* subchannel type */
void *private_data; /* pointer to private data */
struct subchannel *prev;
struct subchannel *next;
union { union {
unsigned int info; unsigned int info;
struct { struct {
...@@ -78,8 +81,26 @@ typedef struct _ioinfo { ...@@ -78,8 +81,26 @@ typedef struct _ioinfo {
unsigned long qflag; /* queued flags */ unsigned long qflag; /* queued flags */
__u8 qlpm; /* queued logical path mask */ __u8 qlpm; /* queued logical path mask */
ssd_info_t ssd_info; /* subchannel description */ ssd_info_t ssd_info; /* subchannel description */
struct device dev; /* entry in device tree */
} __attribute__ ((aligned(8))) ioinfo_t;
} __attribute__ ((aligned(8))) ioinfo_t; /*
* There are four different subchannel types, but we are currently
* only interested in I/O subchannels. This means there is only
* one subchannel_driver, other subchannels belonging to css_bus_type
* are simply ignored.
*/
struct subchannel_driver {
enum {
SUBCHANNEL_TYPE_IO = 0,
SUBCHANNEL_TYPE_CHSC = 1,
SUBCHANNEL_TYPE_MESSAGE = 2,
SUBCHANNEL_TYPE_ADM = 3,
} st; /* subchannel type */
struct device_driver drv; /* entry in driver tree */
};
extern struct bus_type css_bus_type;
#define IOINFO_FLAGS_BUSY 0x80000000 #define IOINFO_FLAGS_BUSY 0x80000000
#define IOINFO_FLAGS_OPER 0x40000000 #define IOINFO_FLAGS_OPER 0x40000000
......
...@@ -637,6 +637,12 @@ int s390_request_irq_special( int irq, ...@@ -637,6 +637,12 @@ int s390_request_irq_special( int irq,
const char *devname, const char *devname,
void *dev_id); void *dev_id);
extern int s390_request_console_irq (int irq,
void (*handler) (int, void *, struct pt_regs *),
unsigned long irqflags,
const char *devname,
void *dev_id);
extern int set_cons_dev(int irq); extern int set_cons_dev(int irq);
extern int wait_cons_dev(int irq); extern int wait_cons_dev(int irq);
extern schib_t *s390_get_schib( int irq ); extern schib_t *s390_get_schib( int irq );
...@@ -860,28 +866,8 @@ typedef struct { ...@@ -860,28 +866,8 @@ typedef struct {
__u32 vrdccrft : 8; /* real device feature (output) */ __u32 vrdccrft : 8; /* real device feature (output) */
} __attribute__ ((packed,aligned(4))) diag210_t; } __attribute__ ((packed,aligned(4))) diag210_t;
void VM_virtual_device_info( __u16 devno, /* device number */ extern int diag210( diag210_t * addr);
senseid_t *ps ); /* ptr to senseID data */
extern __inline__ int diag210( diag210_t * addr)
{
int ccode;
__asm__ __volatile__(
#ifdef CONFIG_ARCH_S390X
" sam31\n"
" diag %1,0,0x210\n"
" sam64\n"
#else
" diag %1,0,0x210\n"
#endif
" ipm %0\n"
" srl %0,28"
: "=d" (ccode)
: "a" (addr)
: "cc" );
return ccode;
}
extern __inline__ int chsc( chsc_area_t * chsc_area) extern __inline__ int chsc( chsc_area_t * chsc_area)
{ {
int cc; int cc;
......
...@@ -9,22 +9,25 @@ ...@@ -9,22 +9,25 @@
#ifndef __s390io_h #ifndef __s390io_h
#define __s390io_h #define __s390io_h
#include <linux/device.h>
/* /*
* IRQ data structure used by I/O subroutines * IRQ data structure used by I/O subroutines
* *
* Note : If bit flags are added, the "unused" value must be * Note : If bit flags are added, the "unused" value must be
* decremented accordingly ! * decremented accordingly !
*/ */
typedef struct _ioinfo { typedef struct subchannel {
unsigned int irq; /* aka. subchannel number */ unsigned int irq; /* aka. subchannel number */
spinlock_t irq_lock; /* irq lock */ spinlock_t irq_lock; /* irq lock */
void *private_data; /* pointer to private data */
struct _ioinfo *prev;
struct _ioinfo *next;
__u8 st; /* subchannel type */ __u8 st; /* subchannel type */
void *private_data; /* pointer to private data */
struct subchannel *prev;
struct subchannel *next;
union { union {
unsigned int info; unsigned int info;
struct { struct {
...@@ -78,8 +81,26 @@ typedef struct _ioinfo { ...@@ -78,8 +81,26 @@ typedef struct _ioinfo {
unsigned long qflag; /* queued flags */ unsigned long qflag; /* queued flags */
__u8 qlpm; /* queued logical path mask */ __u8 qlpm; /* queued logical path mask */
ssd_info_t ssd_info; /* subchannel description */ ssd_info_t ssd_info; /* subchannel description */
struct device dev; /* entry in device tree */
} __attribute__ ((aligned(8))) ioinfo_t;
} __attribute__ ((aligned(8))) ioinfo_t; /*
* There are four different subchannel types, but we are currently
* only interested in I/O subchannels. This means there is only
* one subchannel_driver, other subchannels belonging to css_bus_type
* are simply ignored.
*/
struct subchannel_driver {
enum {
SUBCHANNEL_TYPE_IO = 0,
SUBCHANNEL_TYPE_CHSC = 1,
SUBCHANNEL_TYPE_MESSAGE = 2,
SUBCHANNEL_TYPE_ADM = 3,
} st; /* subchannel type */
struct device_driver drv; /* entry in driver tree */
};
extern struct bus_type css_bus_type;
#define IOINFO_FLAGS_BUSY 0x80000000 #define IOINFO_FLAGS_BUSY 0x80000000
#define IOINFO_FLAGS_OPER 0x40000000 #define IOINFO_FLAGS_OPER 0x40000000
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment