7e560814de
1. Multipath devices for which SetPGID is not supported are not handled well. Use NOP ccws for path verification (sans path grouping) when SetPGID is not supported. 2. Check for PGIDs already set with SensePGID on _all_ paths (not just the first one) and try to find a common one. Moan if no common PGID can be found (and use NOP verification). If no PGIDs have been set, use the css global PGID (as before). (Rationale: SetPGID will get a command reject if the PGID it tries to set does not match the already set PGID.) 3. Immediately before reboot, issue RESET CHANNEL PATH (rcp) on all chpids. This will remove the old PGIDs. rcp will generate solicited CRWs which can be savely ignored by the machine check handler (all other actions create unsolicited CRWs). Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
108 lines
2.3 KiB
C
108 lines
2.3 KiB
C
/*
|
|
* arch/s390/kernel/machine_kexec.c
|
|
*
|
|
* (C) Copyright IBM Corp. 2005
|
|
*
|
|
* Author(s): Rolf Adelsberger <adelsberger@de.ibm.com>
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* s390_machine_kexec.c - handle the transition of Linux booting another kernel
|
|
* on the S390 architecture.
|
|
*/
|
|
|
|
#include <linux/device.h>
|
|
#include <linux/mm.h>
|
|
#include <linux/kexec.h>
|
|
#include <linux/delay.h>
|
|
#include <asm/cio.h>
|
|
#include <asm/setup.h>
|
|
#include <asm/pgtable.h>
|
|
#include <asm/pgalloc.h>
|
|
#include <asm/system.h>
|
|
#include <asm/smp.h>
|
|
|
|
static void kexec_halt_all_cpus(void *);
|
|
|
|
typedef void (*relocate_kernel_t) (kimage_entry_t *, unsigned long);
|
|
|
|
extern const unsigned char relocate_kernel[];
|
|
extern const unsigned long long relocate_kernel_len;
|
|
|
|
int
|
|
machine_kexec_prepare(struct kimage *image)
|
|
{
|
|
unsigned long reboot_code_buffer;
|
|
|
|
/* We don't support anything but the default image type for now. */
|
|
if (image->type != KEXEC_TYPE_DEFAULT)
|
|
return -EINVAL;
|
|
|
|
/* Get the destination where the assembler code should be copied to.*/
|
|
reboot_code_buffer = page_to_pfn(image->control_code_page)<<PAGE_SHIFT;
|
|
|
|
/* Then copy it */
|
|
memcpy((void *) reboot_code_buffer, relocate_kernel,
|
|
relocate_kernel_len);
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
machine_kexec_cleanup(struct kimage *image)
|
|
{
|
|
}
|
|
|
|
void
|
|
machine_shutdown(void)
|
|
{
|
|
printk(KERN_INFO "kexec: machine_shutdown called\n");
|
|
}
|
|
|
|
NORET_TYPE void
|
|
machine_kexec(struct kimage *image)
|
|
{
|
|
clear_all_subchannels();
|
|
cio_reset_channel_paths();
|
|
|
|
/* Disable lowcore protection */
|
|
ctl_clear_bit(0,28);
|
|
|
|
on_each_cpu(kexec_halt_all_cpus, image, 0, 0);
|
|
for (;;);
|
|
}
|
|
|
|
extern void pfault_fini(void);
|
|
|
|
static void
|
|
kexec_halt_all_cpus(void *kernel_image)
|
|
{
|
|
static atomic_t cpuid = ATOMIC_INIT(-1);
|
|
int cpu;
|
|
struct kimage *image;
|
|
relocate_kernel_t data_mover;
|
|
|
|
#ifdef CONFIG_PFAULT
|
|
if (MACHINE_IS_VM)
|
|
pfault_fini();
|
|
#endif
|
|
|
|
if (atomic_cmpxchg(&cpuid, -1, smp_processor_id()) != -1)
|
|
signal_processor(smp_processor_id(), sigp_stop);
|
|
|
|
/* Wait for all other cpus to enter stopped state */
|
|
for_each_online_cpu(cpu) {
|
|
if (cpu == smp_processor_id())
|
|
continue;
|
|
while (!smp_cpu_not_running(cpu))
|
|
cpu_relax();
|
|
}
|
|
|
|
image = (struct kimage *) kernel_image;
|
|
data_mover = (relocate_kernel_t)
|
|
(page_to_pfn(image->control_code_page) << PAGE_SHIFT);
|
|
|
|
/* Call the moving routine */
|
|
(*data_mover) (&image->head, image->start);
|
|
}
|