aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Holzheu <holzheu@de.ibm.com>2006-09-20 09:58:49 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2006-09-20 09:58:49 -0400
commitff6b8ea68f4b7353f88b97024f28127e2148aa00 (patch)
tree67ebb74cbbc042d99325ff33c3f80e4b3e0a1c42
parent331c982d4a6b43cdc0d056956a1cae8a7d6237bf (diff)
[S390] ipl/dump on panic.
It is now possible to specify a ccw/fcp dump device which is used to automatically create a system dump in case of a kernel panic. The dump device can be configured under /sys/firmware/dump. In addition it is now possible to specify a ccw/fcp device which is used for the next reboot of Linux. The reipl device can be configured under /sys/firmware/reipl. Signed-off-by: Michael Holzheu <holzheu@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r--arch/s390/kernel/Makefile2
-rw-r--r--arch/s390/kernel/head31.S3
-rw-r--r--arch/s390/kernel/head64.S3
-rw-r--r--arch/s390/kernel/ipl.c942
-rw-r--r--arch/s390/kernel/reipl.S33
-rw-r--r--arch/s390/kernel/reipl64.S34
-rw-r--r--arch/s390/kernel/reipl_diag.c39
-rw-r--r--arch/s390/kernel/setup.c220
-rw-r--r--arch/s390/kernel/smp.c10
-rw-r--r--drivers/s390/cio/cio.c50
-rw-r--r--include/asm-s390/cio.h7
-rw-r--r--include/asm-s390/lowcore.h13
-rw-r--r--include/asm-s390/setup.h54
13 files changed, 1099 insertions, 311 deletions
diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile
index 33a5069c0e16..aa978978d3d1 100644
--- a/arch/s390/kernel/Makefile
+++ b/arch/s390/kernel/Makefile
@@ -6,7 +6,7 @@ EXTRA_AFLAGS := -traditional
6 6
7obj-y := bitmap.o traps.o time.o process.o \ 7obj-y := bitmap.o traps.o time.o process.o \
8 setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \ 8 setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \
9 semaphore.o s390_ext.o debug.o profile.o irq.o reipl_diag.o 9 semaphore.o s390_ext.o debug.o profile.o irq.o ipl.o
10 10
11obj-y += $(if $(CONFIG_64BIT),entry64.o,entry.o) 11obj-y += $(if $(CONFIG_64BIT),entry64.o,entry.o)
12obj-y += $(if $(CONFIG_64BIT),reipl64.o,reipl.o) 12obj-y += $(if $(CONFIG_64BIT),reipl64.o,reipl.o)
diff --git a/arch/s390/kernel/head31.S b/arch/s390/kernel/head31.S
index 0e46077d7140..d8bb68a72527 100644
--- a/arch/s390/kernel/head31.S
+++ b/arch/s390/kernel/head31.S
@@ -38,6 +38,7 @@ startup:basr %r13,0 # get base
38startup_continue: 38startup_continue:
39 basr %r13,0 # get base 39 basr %r13,0 # get base
40.LPG1: GET_IPL_DEVICE 40.LPG1: GET_IPL_DEVICE
41 mvi __LC_AR_MODE_ID,0 # set ESA flag (mode 0)
41 lctl %c0,%c15,.Lctl-.LPG1(%r13) # load control registers 42 lctl %c0,%c15,.Lctl-.LPG1(%r13) # load control registers
42 l %r12,.Lparmaddr-.LPG1(%r13) # pointer to parameter area 43 l %r12,.Lparmaddr-.LPG1(%r13) # pointer to parameter area
43 # move IPL device to lowcore 44 # move IPL device to lowcore
@@ -274,6 +275,8 @@ startup_continue:
274.Lparmaddr: .long PARMAREA 275.Lparmaddr: .long PARMAREA
275.Lsccbaddr: .long .Lsccb 276.Lsccbaddr: .long .Lsccb
276 .org 0x12000 277 .org 0x12000
278.globl s390_readinfo_sccb
279s390_readinfo_sccb:
277.Lsccb: 280.Lsccb:
278 .hword 0x1000 # length, one page 281 .hword 0x1000 # length, one page
279 .byte 0x00,0x00,0x00 282 .byte 0x00,0x00,0x00
diff --git a/arch/s390/kernel/head64.S b/arch/s390/kernel/head64.S
index 3e0341acd04e..c2005101fee1 100644
--- a/arch/s390/kernel/head64.S
+++ b/arch/s390/kernel/head64.S
@@ -41,6 +41,7 @@ startup_continue:
41 srl %r13,1 41 srl %r13,1
42 GET_IPL_DEVICE 42 GET_IPL_DEVICE
43 lhi %r1,1 # mode 1 = esame 43 lhi %r1,1 # mode 1 = esame
44 mvi __LC_AR_MODE_ID,1 # set esame flag
44 slr %r0,%r0 # set cpuid to zero 45 slr %r0,%r0 # set cpuid to zero
45 sigp %r1,%r0,0x12 # switch to esame mode 46 sigp %r1,%r0,0x12 # switch to esame mode
46 sam64 # switch to 64 bit mode 47 sam64 # switch to 64 bit mode
@@ -269,6 +270,8 @@ startup_continue:
269 .quad PARMAREA 270 .quad PARMAREA
270 271
271 .org 0x12000 272 .org 0x12000
273.globl s390_readinfo_sccb
274s390_readinfo_sccb:
272.Lsccb: 275.Lsccb:
273 .hword 0x1000 # length, one page 276 .hword 0x1000 # length, one page
274 .byte 0x00,0x00,0x00 277 .byte 0x00,0x00,0x00
diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c
new file mode 100644
index 000000000000..105ee15a2b31
--- /dev/null
+++ b/arch/s390/kernel/ipl.c
@@ -0,0 +1,942 @@
1/*
2 * arch/s390/kernel/ipl.c
3 * ipl/reipl/dump support for Linux on s390.
4 *
5 * Copyright (C) IBM Corp. 2005,2006
6 * Author(s): Michael Holzheu <holzheu@de.ibm.com>
7 * Heiko Carstens <heiko.carstens@de.ibm.com>
8 * Volker Sameske <sameske@de.ibm.com>
9 */
10
11#include <linux/types.h>
12#include <linux/module.h>
13#include <linux/device.h>
14#include <linux/delay.h>
15#include <linux/reboot.h>
16#include <asm/smp.h>
17#include <asm/setup.h>
18#include <asm/cpcmd.h>
19#include <asm/cio.h>
20
21#define IPL_PARM_BLOCK_VERSION 0
22
23enum ipl_type {
24 IPL_TYPE_NONE = 1,
25 IPL_TYPE_UNKNOWN = 2,
26 IPL_TYPE_CCW = 4,
27 IPL_TYPE_FCP = 8,
28};
29
30#define IPL_NONE_STR "none"
31#define IPL_UNKNOWN_STR "unknown"
32#define IPL_CCW_STR "ccw"
33#define IPL_FCP_STR "fcp"
34
35static char *ipl_type_str(enum ipl_type type)
36{
37 switch (type) {
38 case IPL_TYPE_NONE:
39 return IPL_NONE_STR;
40 case IPL_TYPE_CCW:
41 return IPL_CCW_STR;
42 case IPL_TYPE_FCP:
43 return IPL_FCP_STR;
44 case IPL_TYPE_UNKNOWN:
45 default:
46 return IPL_UNKNOWN_STR;
47 }
48}
49
50enum ipl_method {
51 IPL_METHOD_NONE,
52 IPL_METHOD_CCW_CIO,
53 IPL_METHOD_CCW_DIAG,
54 IPL_METHOD_CCW_VM,
55 IPL_METHOD_FCP_RO_DIAG,
56 IPL_METHOD_FCP_RW_DIAG,
57 IPL_METHOD_FCP_RO_VM,
58};
59
60enum shutdown_action {
61 SHUTDOWN_REIPL,
62 SHUTDOWN_DUMP,
63 SHUTDOWN_STOP,
64};
65
66#define SHUTDOWN_REIPL_STR "reipl"
67#define SHUTDOWN_DUMP_STR "dump"
68#define SHUTDOWN_STOP_STR "stop"
69
70static char *shutdown_action_str(enum shutdown_action action)
71{
72 switch (action) {
73 case SHUTDOWN_REIPL:
74 return SHUTDOWN_REIPL_STR;
75 case SHUTDOWN_DUMP:
76 return SHUTDOWN_DUMP_STR;
77 case SHUTDOWN_STOP:
78 return SHUTDOWN_STOP_STR;
79 default:
80 BUG();
81 }
82}
83
84enum diag308_subcode {
85 DIAG308_IPL = 3,
86 DIAG308_DUMP = 4,
87 DIAG308_SET = 5,
88 DIAG308_STORE = 6,
89};
90
91enum diag308_ipl_type {
92 DIAG308_IPL_TYPE_FCP = 0,
93 DIAG308_IPL_TYPE_CCW = 2,
94};
95
96enum diag308_opt {
97 DIAG308_IPL_OPT_IPL = 0x10,
98 DIAG308_IPL_OPT_DUMP = 0x20,
99};
100
101enum diag308_rc {
102 DIAG308_RC_OK = 1,
103};
104
105static int diag308_set_works = 0;
106
107static int reipl_capabilities = IPL_TYPE_UNKNOWN;
108static enum ipl_type reipl_type = IPL_TYPE_UNKNOWN;
109static enum ipl_method reipl_method = IPL_METHOD_NONE;
110static struct ipl_parameter_block *reipl_block_fcp;
111static struct ipl_parameter_block *reipl_block_ccw;
112
113static int dump_capabilities = IPL_TYPE_NONE;
114static enum ipl_type dump_type = IPL_TYPE_NONE;
115static enum ipl_method dump_method = IPL_METHOD_NONE;
116static struct ipl_parameter_block *dump_block_fcp;
117static struct ipl_parameter_block *dump_block_ccw;
118
119static enum shutdown_action on_panic_action = SHUTDOWN_STOP;
120
121static int diag308(unsigned long subcode, void *addr)
122{
123 register unsigned long _addr asm("0") = (unsigned long)addr;
124 register unsigned long _rc asm("1") = 0;
125
126 asm volatile (
127 " diag %0,%2,0x308\n"
128 "0: \n"
129 ".section __ex_table,\"a\"\n"
130#ifdef CONFIG_64BIT
131 " .align 8\n"
132 " .quad 0b, 0b\n"
133#else
134 " .align 4\n"
135 " .long 0b, 0b\n"
136#endif
137 ".previous\n"
138 : "+d" (_addr), "+d" (_rc)
139 : "d" (subcode) : "cc", "memory" );
140
141 return _rc;
142}
143
144/* SYSFS */
145
146#define DEFINE_IPL_ATTR_RO(_prefix, _name, _format, _value) \
147static ssize_t sys_##_prefix##_##_name##_show(struct subsystem *subsys, \
148 char *page) \
149{ \
150 return sprintf(page, _format, _value); \
151} \
152static struct subsys_attribute sys_##_prefix##_##_name##_attr = \
153 __ATTR(_name, S_IRUGO, sys_##_prefix##_##_name##_show, NULL);
154
155#define DEFINE_IPL_ATTR_RW(_prefix, _name, _fmt_out, _fmt_in, _value) \
156static ssize_t sys_##_prefix##_##_name##_show(struct subsystem *subsys, \
157 char *page) \
158{ \
159 return sprintf(page, _fmt_out, \
160 (unsigned long long) _value); \
161} \
162static ssize_t sys_##_prefix##_##_name##_store(struct subsystem *subsys,\
163 const char *buf, size_t len) \
164{ \
165 unsigned long long value; \
166 if (sscanf(buf, _fmt_in, &value) != 1) \
167 return -EINVAL; \
168 _value = value; \
169 return len; \
170} \
171static struct subsys_attribute sys_##_prefix##_##_name##_attr = \
172 __ATTR(_name,(S_IRUGO | S_IWUSR), \
173 sys_##_prefix##_##_name##_show, \
174 sys_##_prefix##_##_name##_store);
175
176static void make_attrs_ro(struct attribute **attrs)
177{
178 while (*attrs) {
179 (*attrs)->mode = S_IRUGO;
180 attrs++;
181 }
182}
183
184/*
185 * ipl section
186 */
187
188static enum ipl_type ipl_get_type(void)
189{
190 struct ipl_parameter_block *ipl = IPL_PARMBLOCK_START;
191
192 if (!IPL_DEVNO_VALID)
193 return IPL_TYPE_UNKNOWN;
194 if (!IPL_PARMBLOCK_VALID)
195 return IPL_TYPE_CCW;
196 if (ipl->hdr.version > IPL_MAX_SUPPORTED_VERSION)
197 return IPL_TYPE_UNKNOWN;
198 if (ipl->hdr.pbt != DIAG308_IPL_TYPE_FCP)
199 return IPL_TYPE_UNKNOWN;
200 return IPL_TYPE_FCP;
201}
202
203static ssize_t ipl_type_show(struct subsystem *subsys, char *page)
204{
205 return sprintf(page, "%s\n", ipl_type_str(ipl_get_type()));
206}
207
208static struct subsys_attribute sys_ipl_type_attr = __ATTR_RO(ipl_type);
209
210static ssize_t sys_ipl_device_show(struct subsystem *subsys, char *page)
211{
212 struct ipl_parameter_block *ipl = IPL_PARMBLOCK_START;
213
214 switch (ipl_get_type()) {
215 case IPL_TYPE_CCW:
216 return sprintf(page, "0.0.%04x\n", ipl_devno);
217 case IPL_TYPE_FCP:
218 return sprintf(page, "0.0.%04x\n", ipl->ipl_info.fcp.devno);
219 default:
220 return 0;
221 }
222}
223
224static struct subsys_attribute sys_ipl_device_attr =
225 __ATTR(device, S_IRUGO, sys_ipl_device_show, NULL);
226
227static ssize_t ipl_parameter_read(struct kobject *kobj, char *buf, loff_t off,
228 size_t count)
229{
230 unsigned int size = IPL_PARMBLOCK_SIZE;
231
232 if (off > size)
233 return 0;
234 if (off + count > size)
235 count = size - off;
236 memcpy(buf, (void *)IPL_PARMBLOCK_START + off, count);
237 return count;
238}
239
240static struct bin_attribute ipl_parameter_attr = {
241 .attr = {
242 .name = "binary_parameter",
243 .mode = S_IRUGO,
244 .owner = THIS_MODULE,
245 },
246 .size = PAGE_SIZE,
247 .read = &ipl_parameter_read,
248};
249
250static ssize_t ipl_scp_data_read(struct kobject *kobj, char *buf, loff_t off,
251 size_t count)
252{
253 unsigned int size = IPL_PARMBLOCK_START->ipl_info.fcp.scp_data_len;
254 void *scp_data = &IPL_PARMBLOCK_START->ipl_info.fcp.scp_data;
255
256 if (off > size)
257 return 0;
258 if (off + count > size)
259 count = size - off;
260 memcpy(buf, scp_data + off, count);
261 return count;
262}
263
264static struct bin_attribute ipl_scp_data_attr = {
265 .attr = {
266 .name = "scp_data",
267 .mode = S_IRUGO,
268 .owner = THIS_MODULE,
269 },
270 .size = PAGE_SIZE,
271 .read = &ipl_scp_data_read,
272};
273
274/* FCP ipl device attributes */
275
276DEFINE_IPL_ATTR_RO(ipl_fcp, wwpn, "0x%016llx\n", (unsigned long long)
277 IPL_PARMBLOCK_START->ipl_info.fcp.wwpn);
278DEFINE_IPL_ATTR_RO(ipl_fcp, lun, "0x%016llx\n", (unsigned long long)
279 IPL_PARMBLOCK_START->ipl_info.fcp.lun);
280DEFINE_IPL_ATTR_RO(ipl_fcp, bootprog, "%lld\n", (unsigned long long)
281 IPL_PARMBLOCK_START->ipl_info.fcp.bootprog);
282DEFINE_IPL_ATTR_RO(ipl_fcp, br_lba, "%lld\n", (unsigned long long)
283 IPL_PARMBLOCK_START->ipl_info.fcp.br_lba);
284
285static struct attribute *ipl_fcp_attrs[] = {
286 &sys_ipl_type_attr.attr,
287 &sys_ipl_device_attr.attr,
288 &sys_ipl_fcp_wwpn_attr.attr,
289 &sys_ipl_fcp_lun_attr.attr,
290 &sys_ipl_fcp_bootprog_attr.attr,
291 &sys_ipl_fcp_br_lba_attr.attr,
292 NULL,
293};
294
295static struct attribute_group ipl_fcp_attr_group = {
296 .attrs = ipl_fcp_attrs,
297};
298
299/* CCW ipl device attributes */
300
301static struct attribute *ipl_ccw_attrs[] = {
302 &sys_ipl_type_attr.attr,
303 &sys_ipl_device_attr.attr,
304 NULL,
305};
306
307static struct attribute_group ipl_ccw_attr_group = {
308 .attrs = ipl_ccw_attrs,
309};
310
311/* UNKNOWN ipl device attributes */
312
313static struct attribute *ipl_unknown_attrs[] = {
314 &sys_ipl_type_attr.attr,
315 NULL,
316};
317
318static struct attribute_group ipl_unknown_attr_group = {
319 .attrs = ipl_unknown_attrs,
320};
321
322static decl_subsys(ipl, NULL, NULL);
323
324/*
325 * reipl section
326 */
327
328/* FCP reipl device attributes */
329
330DEFINE_IPL_ATTR_RW(reipl_fcp, wwpn, "0x%016llx\n", "%016llx\n",
331 reipl_block_fcp->ipl_info.fcp.wwpn);
332DEFINE_IPL_ATTR_RW(reipl_fcp, lun, "0x%016llx\n", "%016llx\n",
333 reipl_block_fcp->ipl_info.fcp.lun);
334DEFINE_IPL_ATTR_RW(reipl_fcp, bootprog, "%lld\n", "%lld\n",
335 reipl_block_fcp->ipl_info.fcp.bootprog);
336DEFINE_IPL_ATTR_RW(reipl_fcp, br_lba, "%lld\n", "%lld\n",
337 reipl_block_fcp->ipl_info.fcp.br_lba);
338DEFINE_IPL_ATTR_RW(reipl_fcp, device, "0.0.%04llx\n", "0.0.%llx\n",
339 reipl_block_fcp->ipl_info.fcp.devno);
340
341static struct attribute *reipl_fcp_attrs[] = {
342 &sys_reipl_fcp_device_attr.attr,
343 &sys_reipl_fcp_wwpn_attr.attr,
344 &sys_reipl_fcp_lun_attr.attr,
345 &sys_reipl_fcp_bootprog_attr.attr,
346 &sys_reipl_fcp_br_lba_attr.attr,
347 NULL,
348};
349
350static struct attribute_group reipl_fcp_attr_group = {
351 .name = IPL_FCP_STR,
352 .attrs = reipl_fcp_attrs,
353};
354
355/* CCW reipl device attributes */
356
357DEFINE_IPL_ATTR_RW(reipl_ccw, device, "0.0.%04llx\n", "0.0.%llx\n",
358 reipl_block_ccw->ipl_info.ccw.devno);
359
360static struct attribute *reipl_ccw_attrs[] = {
361 &sys_reipl_ccw_device_attr.attr,
362 NULL,
363};
364
365static struct attribute_group reipl_ccw_attr_group = {
366 .name = IPL_CCW_STR,
367 .attrs = reipl_ccw_attrs,
368};
369
370/* reipl type */
371
372static int reipl_set_type(enum ipl_type type)
373{
374 if (!(reipl_capabilities & type))
375 return -EINVAL;
376
377 switch(type) {
378 case IPL_TYPE_CCW:
379 if (MACHINE_IS_VM)
380 reipl_method = IPL_METHOD_CCW_VM;
381 else
382 reipl_method = IPL_METHOD_CCW_CIO;
383 break;
384 case IPL_TYPE_FCP:
385 if (diag308_set_works)
386 reipl_method = IPL_METHOD_FCP_RW_DIAG;
387 else if (MACHINE_IS_VM)
388 reipl_method = IPL_METHOD_FCP_RO_VM;
389 else
390 reipl_method = IPL_METHOD_FCP_RO_DIAG;
391 break;
392 default:
393 reipl_method = IPL_METHOD_NONE;
394 }
395 reipl_type = type;
396 return 0;
397}
398
399static ssize_t reipl_type_show(struct subsystem *subsys, char *page)
400{
401 return sprintf(page, "%s\n", ipl_type_str(reipl_type));
402}
403
404static ssize_t reipl_type_store(struct subsystem *subsys, const char *buf,
405 size_t len)
406{
407 int rc = -EINVAL;
408
409 if (strncmp(buf, IPL_CCW_STR, strlen(IPL_CCW_STR)) == 0)
410 rc = reipl_set_type(IPL_TYPE_CCW);
411 else if (strncmp(buf, IPL_FCP_STR, strlen(IPL_FCP_STR)) == 0)
412 rc = reipl_set_type(IPL_TYPE_FCP);
413 return (rc != 0) ? rc : len;
414}
415
416static struct subsys_attribute reipl_type_attr =
417 __ATTR(reipl_type, 0644, reipl_type_show, reipl_type_store);
418
419static decl_subsys(reipl, NULL, NULL);
420
421/*
422 * dump section
423 */
424
425/* FCP dump device attributes */
426
427DEFINE_IPL_ATTR_RW(dump_fcp, wwpn, "0x%016llx\n", "%016llx\n",
428 dump_block_fcp->ipl_info.fcp.wwpn);
429DEFINE_IPL_ATTR_RW(dump_fcp, lun, "0x%016llx\n", "%016llx\n",
430 dump_block_fcp->ipl_info.fcp.lun);
431DEFINE_IPL_ATTR_RW(dump_fcp, bootprog, "%lld\n", "%lld\n",
432 dump_block_fcp->ipl_info.fcp.bootprog);
433DEFINE_IPL_ATTR_RW(dump_fcp, br_lba, "%lld\n", "%lld\n",
434 dump_block_fcp->ipl_info.fcp.br_lba);
435DEFINE_IPL_ATTR_RW(dump_fcp, device, "0.0.%04llx\n", "0.0.%llx\n",
436 dump_block_fcp->ipl_info.fcp.devno);
437
438static struct attribute *dump_fcp_attrs[] = {
439 &sys_dump_fcp_device_attr.attr,
440 &sys_dump_fcp_wwpn_attr.attr,
441 &sys_dump_fcp_lun_attr.attr,
442 &sys_dump_fcp_bootprog_attr.attr,
443 &sys_dump_fcp_br_lba_attr.attr,
444 NULL,
445};
446
447static struct attribute_group dump_fcp_attr_group = {
448 .name = IPL_FCP_STR,
449 .attrs = dump_fcp_attrs,
450};
451
452/* CCW dump device attributes */
453
454DEFINE_IPL_ATTR_RW(dump_ccw, device, "0.0.%04llx\n", "0.0.%llx\n",
455 dump_block_ccw->ipl_info.ccw.devno);
456
457static struct attribute *dump_ccw_attrs[] = {
458 &sys_dump_ccw_device_attr.attr,
459 NULL,
460};
461
462static struct attribute_group dump_ccw_attr_group = {
463 .name = IPL_CCW_STR,
464 .attrs = dump_ccw_attrs,
465};
466
467/* dump type */
468
469static int dump_set_type(enum ipl_type type)
470{
471 if (!(dump_capabilities & type))
472 return -EINVAL;
473 switch(type) {
474 case IPL_TYPE_CCW:
475 if (MACHINE_IS_VM)
476 dump_method = IPL_METHOD_CCW_VM;
477 else
478 dump_method = IPL_METHOD_CCW_CIO;
479 break;
480 case IPL_TYPE_FCP:
481 dump_method = IPL_METHOD_FCP_RW_DIAG;
482 break;
483 default:
484 dump_method = IPL_METHOD_NONE;
485 }
486 dump_type = type;
487 return 0;
488}
489
490static ssize_t dump_type_show(struct subsystem *subsys, char *page)
491{
492 return sprintf(page, "%s\n", ipl_type_str(dump_type));
493}
494
495static ssize_t dump_type_store(struct subsystem *subsys, const char *buf,
496 size_t len)
497{
498 int rc = -EINVAL;
499
500 if (strncmp(buf, IPL_NONE_STR, strlen(IPL_NONE_STR)) == 0)
501 rc = dump_set_type(IPL_TYPE_NONE);
502 else if (strncmp(buf, IPL_CCW_STR, strlen(IPL_CCW_STR)) == 0)
503 rc = dump_set_type(IPL_TYPE_CCW);
504 else if (strncmp(buf, IPL_FCP_STR, strlen(IPL_FCP_STR)) == 0)
505 rc = dump_set_type(IPL_TYPE_FCP);
506 return (rc != 0) ? rc : len;
507}
508
509static struct subsys_attribute dump_type_attr =
510 __ATTR(dump_type, 0644, dump_type_show, dump_type_store);
511
512static decl_subsys(dump, NULL, NULL);
513
514#ifdef CONFIG_SMP
515static void dump_smp_stop_all(void)
516{
517 int cpu;
518 preempt_disable();
519 for_each_online_cpu(cpu) {
520 if (cpu == smp_processor_id())
521 continue;
522 while (signal_processor(cpu, sigp_stop) == sigp_busy)
523 udelay(10);
524 }
525 preempt_enable();
526}
527#else
528#define dump_smp_stop_all() do { } while (0)
529#endif
530
531/*
532 * Shutdown actions section
533 */
534
535static decl_subsys(shutdown_actions, NULL, NULL);
536
537/* on panic */
538
539static ssize_t on_panic_show(struct subsystem *subsys, char *page)
540{
541 return sprintf(page, "%s\n", shutdown_action_str(on_panic_action));
542}
543
544static ssize_t on_panic_store(struct subsystem *subsys, const char *buf,
545 size_t len)
546{
547 if (strncmp(buf, SHUTDOWN_REIPL_STR, strlen(SHUTDOWN_REIPL_STR)) == 0)
548 on_panic_action = SHUTDOWN_REIPL;
549 else if (strncmp(buf, SHUTDOWN_DUMP_STR,
550 strlen(SHUTDOWN_DUMP_STR)) == 0)
551 on_panic_action = SHUTDOWN_DUMP;
552 else if (strncmp(buf, SHUTDOWN_STOP_STR,
553 strlen(SHUTDOWN_STOP_STR)) == 0)
554 on_panic_action = SHUTDOWN_STOP;
555 else
556 return -EINVAL;
557
558 return len;
559}
560
561static struct subsys_attribute on_panic_attr =
562 __ATTR(on_panic, 0644, on_panic_show, on_panic_store);
563
564static void print_fcp_block(struct ipl_parameter_block *fcp_block)
565{
566 printk(KERN_EMERG "wwpn: %016llx\n",
567 (unsigned long long)fcp_block->ipl_info.fcp.wwpn);
568 printk(KERN_EMERG "lun: %016llx\n",
569 (unsigned long long)fcp_block->ipl_info.fcp.lun);
570 printk(KERN_EMERG "bootprog: %lld\n",
571 (unsigned long long)fcp_block->ipl_info.fcp.bootprog);
572 printk(KERN_EMERG "br_lba: %lld\n",
573 (unsigned long long)fcp_block->ipl_info.fcp.br_lba);
574 printk(KERN_EMERG "device: %llx\n",
575 (unsigned long long)fcp_block->ipl_info.fcp.devno);
576 printk(KERN_EMERG "opt: %x\n", fcp_block->ipl_info.fcp.opt);
577}
578
579void do_reipl(void)
580{
581 struct ccw_dev_id devid;
582 static char buf[100];
583
584 switch (reipl_type) {
585 case IPL_TYPE_CCW:
586 printk(KERN_EMERG "reboot on ccw device: 0.0.%04x\n",
587 reipl_block_ccw->ipl_info.ccw.devno);
588 break;
589 case IPL_TYPE_FCP:
590 printk(KERN_EMERG "reboot on fcp device:\n");
591 print_fcp_block(reipl_block_fcp);
592 break;
593 default:
594 break;
595 }
596
597 switch (reipl_method) {
598 case IPL_METHOD_CCW_CIO:
599 devid.devno = reipl_block_ccw->ipl_info.ccw.devno;
600 devid.ssid = 0;
601 reipl_ccw_dev(&devid);
602 break;
603 case IPL_METHOD_CCW_VM:
604 sprintf(buf, "IPL %X", reipl_block_ccw->ipl_info.ccw.devno);
605 cpcmd(buf, NULL, 0, NULL);
606 break;
607 case IPL_METHOD_CCW_DIAG:
608 diag308(DIAG308_SET, reipl_block_ccw);
609 diag308(DIAG308_IPL, NULL);
610 break;
611 case IPL_METHOD_FCP_RW_DIAG:
612 diag308(DIAG308_SET, reipl_block_fcp);
613 diag308(DIAG308_IPL, NULL);
614 break;
615 case IPL_METHOD_FCP_RO_DIAG:
616 diag308(DIAG308_IPL, NULL);
617 break;
618 case IPL_METHOD_FCP_RO_VM:
619 cpcmd("IPL", NULL, 0, NULL);
620 break;
621 case IPL_METHOD_NONE:
622 default:
623 if (MACHINE_IS_VM)
624 cpcmd("IPL", NULL, 0, NULL);
625 diag308(DIAG308_IPL, NULL);
626 break;
627 }
628 panic("reipl failed!\n");
629}
630
631static void do_dump(void)
632{
633 struct ccw_dev_id devid;
634 static char buf[100];
635
636 switch (dump_type) {
637 case IPL_TYPE_CCW:
638 printk(KERN_EMERG "Automatic dump on ccw device: 0.0.%04x\n",
639 dump_block_ccw->ipl_info.ccw.devno);
640 break;
641 case IPL_TYPE_FCP:
642 printk(KERN_EMERG "Automatic dump on fcp device:\n");
643 print_fcp_block(dump_block_fcp);
644 break;
645 default:
646 return;
647 }
648
649 switch (dump_method) {
650 case IPL_METHOD_CCW_CIO:
651 dump_smp_stop_all();
652 devid.devno = dump_block_ccw->ipl_info.ccw.devno;
653 devid.ssid = 0;
654 reipl_ccw_dev(&devid);
655 break;
656 case IPL_METHOD_CCW_VM:
657 dump_smp_stop_all();
658 sprintf(buf, "STORE STATUS");
659 cpcmd(buf, NULL, 0, NULL);
660 sprintf(buf, "IPL %X", dump_block_ccw->ipl_info.ccw.devno);
661 cpcmd(buf, NULL, 0, NULL);
662 break;
663 case IPL_METHOD_CCW_DIAG:
664 diag308(DIAG308_SET, dump_block_ccw);
665 diag308(DIAG308_DUMP, NULL);
666 break;
667 case IPL_METHOD_FCP_RW_DIAG:
668 diag308(DIAG308_SET, dump_block_fcp);
669 diag308(DIAG308_DUMP, NULL);
670 break;
671 case IPL_METHOD_NONE:
672 default:
673 return;
674 }
675 printk(KERN_EMERG "Dump failed!\n");
676}
677
678/* init functions */
679
680static int __init ipl_register_fcp_files(void)
681{
682 int rc;
683
684 rc = sysfs_create_group(&ipl_subsys.kset.kobj,
685 &ipl_fcp_attr_group);
686 if (rc)
687 goto out;
688 rc = sysfs_create_bin_file(&ipl_subsys.kset.kobj,
689 &ipl_parameter_attr);
690 if (rc)
691 goto out_ipl_parm;
692 rc = sysfs_create_bin_file(&ipl_subsys.kset.kobj,
693 &ipl_scp_data_attr);
694 if (!rc)
695 goto out;
696
697 sysfs_remove_bin_file(&ipl_subsys.kset.kobj, &ipl_parameter_attr);
698
699out_ipl_parm:
700 sysfs_remove_group(&ipl_subsys.kset.kobj, &ipl_fcp_attr_group);
701out:
702 return rc;
703}
704
705static int __init ipl_init(void)
706{
707 int rc;
708
709 rc = firmware_register(&ipl_subsys);
710 if (rc)
711 return rc;
712 switch (ipl_get_type()) {
713 case IPL_TYPE_CCW:
714 rc = sysfs_create_group(&ipl_subsys.kset.kobj,
715 &ipl_ccw_attr_group);
716 break;
717 case IPL_TYPE_FCP:
718 rc = ipl_register_fcp_files();
719 break;
720 default:
721 rc = sysfs_create_group(&ipl_subsys.kset.kobj,
722 &ipl_unknown_attr_group);
723 break;
724 }
725 if (rc)
726 firmware_unregister(&ipl_subsys);
727 return rc;
728}
729
730static void __init reipl_probe(void)
731{
732 void *buffer;
733
734 buffer = (void *) get_zeroed_page(GFP_KERNEL);
735 if (!buffer)
736 return;
737 if (diag308(DIAG308_STORE, buffer) == DIAG308_RC_OK)
738 diag308_set_works = 1;
739 free_page((unsigned long)buffer);
740}
741
742static int __init reipl_ccw_init(void)
743{
744 int rc;
745
746 reipl_block_ccw = (void *) get_zeroed_page(GFP_KERNEL);
747 if (!reipl_block_ccw)
748 return -ENOMEM;
749 rc = sysfs_create_group(&reipl_subsys.kset.kobj, &reipl_ccw_attr_group);
750 if (rc) {
751 free_page((unsigned long)reipl_block_ccw);
752 return rc;
753 }
754 reipl_block_ccw->hdr.len = IPL_PARM_BLK_CCW_LEN;
755 reipl_block_ccw->hdr.version = IPL_PARM_BLOCK_VERSION;
756 reipl_block_ccw->hdr.blk0_len = sizeof(reipl_block_ccw->ipl_info.ccw);
757 reipl_block_ccw->hdr.pbt = DIAG308_IPL_TYPE_CCW;
758 if (ipl_get_type() == IPL_TYPE_CCW)
759 reipl_block_ccw->ipl_info.ccw.devno = ipl_devno;
760 reipl_capabilities |= IPL_TYPE_CCW;
761 return 0;
762}
763
764static int __init reipl_fcp_init(void)
765{
766 int rc;
767
768 if ((!diag308_set_works) && (ipl_get_type() != IPL_TYPE_FCP))
769 return 0;
770 if ((!diag308_set_works) && (ipl_get_type() == IPL_TYPE_FCP))
771 make_attrs_ro(reipl_fcp_attrs);
772
773 reipl_block_fcp = (void *) get_zeroed_page(GFP_KERNEL);
774 if (!reipl_block_fcp)
775 return -ENOMEM;
776 rc = sysfs_create_group(&reipl_subsys.kset.kobj, &reipl_fcp_attr_group);
777 if (rc) {
778 free_page((unsigned long)reipl_block_fcp);
779 return rc;
780 }
781 if (ipl_get_type() == IPL_TYPE_FCP) {
782 memcpy(reipl_block_fcp, IPL_PARMBLOCK_START, PAGE_SIZE);
783 } else {
784 reipl_block_fcp->hdr.len = IPL_PARM_BLK_FCP_LEN;
785 reipl_block_fcp->hdr.version = IPL_PARM_BLOCK_VERSION;
786 reipl_block_fcp->hdr.blk0_len =
787 sizeof(reipl_block_fcp->ipl_info.fcp);
788 reipl_block_fcp->hdr.pbt = DIAG308_IPL_TYPE_FCP;
789 reipl_block_fcp->ipl_info.fcp.opt = DIAG308_IPL_OPT_IPL;
790 }
791 reipl_capabilities |= IPL_TYPE_FCP;
792 return 0;
793}
794
795static int __init reipl_init(void)
796{
797 int rc;
798
799 rc = firmware_register(&reipl_subsys);
800 if (rc)
801 return rc;
802 rc = subsys_create_file(&reipl_subsys, &reipl_type_attr);
803 if (rc) {
804 firmware_unregister(&reipl_subsys);
805 return rc;
806 }
807 rc = reipl_ccw_init();
808 if (rc)
809 return rc;
810 rc = reipl_fcp_init();
811 if (rc)
812 return rc;
813 rc = reipl_set_type(ipl_get_type());
814 if (rc)
815 return rc;
816 return 0;
817}
818
819static int __init dump_ccw_init(void)
820{
821 int rc;
822
823 dump_block_ccw = (void *) get_zeroed_page(GFP_KERNEL);
824 if (!dump_block_ccw)
825 return -ENOMEM;
826 rc = sysfs_create_group(&dump_subsys.kset.kobj, &dump_ccw_attr_group);
827 if (rc) {
828 free_page((unsigned long)dump_block_ccw);
829 return rc;
830 }
831 dump_block_ccw->hdr.len = IPL_PARM_BLK_CCW_LEN;
832 dump_block_ccw->hdr.version = IPL_PARM_BLOCK_VERSION;
833 dump_block_ccw->hdr.blk0_len = sizeof(reipl_block_ccw->ipl_info.ccw);
834 dump_block_ccw->hdr.pbt = DIAG308_IPL_TYPE_CCW;
835 dump_capabilities |= IPL_TYPE_CCW;
836 return 0;
837}
838
839extern char s390_readinfo_sccb[];
840
841static int __init dump_fcp_init(void)
842{
843 int rc;
844
845 if(!(s390_readinfo_sccb[91] & 0x2))
846 return 0; /* LDIPL DUMP is not installed */
847 if (!diag308_set_works)
848 return 0;
849 dump_block_fcp = (void *) get_zeroed_page(GFP_KERNEL);
850 if (!dump_block_fcp)
851 return -ENOMEM;
852 rc = sysfs_create_group(&dump_subsys.kset.kobj, &dump_fcp_attr_group);
853 if (rc) {
854 free_page((unsigned long)dump_block_fcp);
855 return rc;
856 }
857 dump_block_fcp->hdr.len = IPL_PARM_BLK_FCP_LEN;
858 dump_block_fcp->hdr.version = IPL_PARM_BLOCK_VERSION;
859 dump_block_fcp->hdr.blk0_len = sizeof(dump_block_fcp->ipl_info.fcp);
860 dump_block_fcp->hdr.pbt = DIAG308_IPL_TYPE_FCP;
861 dump_block_fcp->ipl_info.fcp.opt = DIAG308_IPL_OPT_DUMP;
862 dump_capabilities |= IPL_TYPE_FCP;
863 return 0;
864}
865
866#define SHUTDOWN_ON_PANIC_PRIO 0
867
868static int shutdown_on_panic_notify(struct notifier_block *self,
869 unsigned long event, void *data)
870{
871 if (on_panic_action == SHUTDOWN_DUMP)
872 do_dump();
873 else if (on_panic_action == SHUTDOWN_REIPL)
874 do_reipl();
875 return NOTIFY_OK;
876}
877
878static struct notifier_block shutdown_on_panic_nb = {
879 .notifier_call = shutdown_on_panic_notify,
880 .priority = SHUTDOWN_ON_PANIC_PRIO
881};
882
883static int __init dump_init(void)
884{
885 int rc;
886
887 rc = firmware_register(&dump_subsys);
888 if (rc)
889 return rc;
890 rc = subsys_create_file(&dump_subsys, &dump_type_attr);
891 if (rc) {
892 firmware_unregister(&dump_subsys);
893 return rc;
894 }
895 rc = dump_ccw_init();
896 if (rc)
897 return rc;
898 rc = dump_fcp_init();
899 if (rc)
900 return rc;
901 dump_set_type(IPL_TYPE_NONE);
902 return 0;
903}
904
905static int __init shutdown_actions_init(void)
906{
907 int rc;
908
909 rc = firmware_register(&shutdown_actions_subsys);
910 if (rc)
911 return rc;
912 rc = subsys_create_file(&shutdown_actions_subsys, &on_panic_attr);
913 if (rc) {
914 firmware_unregister(&shutdown_actions_subsys);
915 return rc;
916 }
917 atomic_notifier_chain_register(&panic_notifier_list,
918 &shutdown_on_panic_nb);
919 return 0;
920}
921
922static int __init s390_ipl_init(void)
923{
924 int rc;
925
926 reipl_probe();
927 rc = ipl_init();
928 if (rc)
929 return rc;
930 rc = reipl_init();
931 if (rc)
932 return rc;
933 rc = dump_init();
934 if (rc)
935 return rc;
936 rc = shutdown_actions_init();
937 if (rc)
938 return rc;
939 return 0;
940}
941
942__initcall(s390_ipl_init);
diff --git a/arch/s390/kernel/reipl.S b/arch/s390/kernel/reipl.S
index 658e5ac484f9..4562cdbce8eb 100644
--- a/arch/s390/kernel/reipl.S
+++ b/arch/s390/kernel/reipl.S
@@ -8,13 +8,30 @@
8 8
9#include <asm/lowcore.h> 9#include <asm/lowcore.h>
10 10
11 .globl do_reipl 11 .globl do_reipl_asm
12do_reipl: basr %r13,0 12do_reipl_asm: basr %r13,0
13.Lpg0: lpsw .Lnewpsw-.Lpg0(%r13) 13.Lpg0: lpsw .Lnewpsw-.Lpg0(%r13)
14.Lpg1: lctl %c6,%c6,.Lall-.Lpg0(%r13) 14
15 stctl %c0,%c0,.Lctlsave-.Lpg0(%r13) 15 # switch off lowcore protection
16 ni .Lctlsave-.Lpg0(%r13),0xef 16
17 lctl %c0,%c0,.Lctlsave-.Lpg0(%r13) 17.Lpg1: stctl %c0,%c0,.Lctlsave1-.Lpg0(%r13)
18 stctl %c0,%c0,.Lctlsave2-.Lpg0(%r13)
19 ni .Lctlsave1-.Lpg0(%r13),0xef
20 lctl %c0,%c0,.Lctlsave1-.Lpg0(%r13)
21
22 # do store status of all registers
23
24 stm %r0,%r15,__LC_GPREGS_SAVE_AREA
25 stctl %c0,%c15,__LC_CREGS_SAVE_AREA
26 mvc __LC_CREGS_SAVE_AREA(4),.Lctlsave2-.Lpg0(%r13)
27 stam %a0,%a15,__LC_AREGS_SAVE_AREA
28 stpx __LC_PREFIX_SAVE_AREA
29 stckc .Lclkcmp-.Lpg0(%r13)
30 mvc __LC_CLOCK_COMP_SAVE_AREA(8),.Lclkcmp-.Lpg0(%r13)
31 stpt __LC_CPU_TIMER_SAVE_AREA
32 st %r13, __LC_PSW_SAVE_AREA+4
33
34 lctl %c6,%c6,.Lall-.Lpg0(%r13)
18 lr %r1,%r2 35 lr %r1,%r2
19 mvc __LC_PGM_NEW_PSW(8),.Lpcnew-.Lpg0(%r13) 36 mvc __LC_PGM_NEW_PSW(8),.Lpcnew-.Lpg0(%r13)
20 stsch .Lschib-.Lpg0(%r13) 37 stsch .Lschib-.Lpg0(%r13)
@@ -46,9 +63,11 @@ do_reipl: basr %r13,0
46.Ldisab: st %r14,.Ldispsw+4-.Lpg0(%r13) 63.Ldisab: st %r14,.Ldispsw+4-.Lpg0(%r13)
47 lpsw .Ldispsw-.Lpg0(%r13) 64 lpsw .Ldispsw-.Lpg0(%r13)
48 .align 8 65 .align 8
66.Lclkcmp: .quad 0x0000000000000000
49.Lall: .long 0xff000000 67.Lall: .long 0xff000000
50.Lnull: .long 0x00000000 68.Lnull: .long 0x00000000
51.Lctlsave: .long 0x00000000 69.Lctlsave1: .long 0x00000000
70.Lctlsave2: .long 0x00000000
52 .align 8 71 .align 8
53.Lnewpsw: .long 0x00080000,0x80000000+.Lpg1 72.Lnewpsw: .long 0x00080000,0x80000000+.Lpg1
54.Lpcnew: .long 0x00080000,0x80000000+.Lecs 73.Lpcnew: .long 0x00080000,0x80000000+.Lecs
diff --git a/arch/s390/kernel/reipl64.S b/arch/s390/kernel/reipl64.S
index 4d090d60f3ef..95bd1e234f63 100644
--- a/arch/s390/kernel/reipl64.S
+++ b/arch/s390/kernel/reipl64.S
@@ -8,13 +8,30 @@
8 */ 8 */
9 9
10#include <asm/lowcore.h> 10#include <asm/lowcore.h>
11 .globl do_reipl 11 .globl do_reipl_asm
12do_reipl: basr %r13,0 12do_reipl_asm: basr %r13,0
13.Lpg0: lpswe .Lnewpsw-.Lpg0(%r13) 13
14 # do store status of all registers
15
16.Lpg0: stg %r1,.Lregsave-.Lpg0(%r13)
17 lghi %r1,0x1000
18 stmg %r0,%r15,__LC_GPREGS_SAVE_AREA-0x1000(%r1)
19 lg %r0,.Lregsave-.Lpg0(%r13)
20 stg %r0,__LC_GPREGS_SAVE_AREA-0x1000+8(%r1)
21 stctg %c0,%c15,__LC_CREGS_SAVE_AREA-0x1000(%r1)
22 stam %a0,%a15,__LC_AREGS_SAVE_AREA-0x1000(%r1)
23 stpx __LC_PREFIX_SAVE_AREA-0x1000(%r1)
24 stfpc __LC_FP_CREG_SAVE_AREA-0x1000(%r1)
25 stckc .Lclkcmp-.Lpg0(%r13)
26 mvc __LC_CLOCK_COMP_SAVE_AREA-0x1000(8,%r1),.Lclkcmp-.Lpg0(%r13)
27 stpt __LC_CPU_TIMER_SAVE_AREA-0x1000(%r1)
28 stg %r13, __LC_PSW_SAVE_AREA-0x1000+8(%r1)
29
30 lpswe .Lnewpsw-.Lpg0(%r13)
14.Lpg1: lctlg %c6,%c6,.Lall-.Lpg0(%r13) 31.Lpg1: lctlg %c6,%c6,.Lall-.Lpg0(%r13)
15 stctg %c0,%c0,.Lctlsave-.Lpg0(%r13) 32 stctg %c0,%c0,.Lregsave-.Lpg0(%r13)
16 ni .Lctlsave+4-.Lpg0(%r13),0xef 33 ni .Lregsave+4-.Lpg0(%r13),0xef
17 lctlg %c0,%c0,.Lctlsave-.Lpg0(%r13) 34 lctlg %c0,%c0,.Lregsave-.Lpg0(%r13)
18 lgr %r1,%r2 35 lgr %r1,%r2
19 mvc __LC_PGM_NEW_PSW(16),.Lpcnew-.Lpg0(%r13) 36 mvc __LC_PGM_NEW_PSW(16),.Lpcnew-.Lpg0(%r13)
20 stsch .Lschib-.Lpg0(%r13) 37 stsch .Lschib-.Lpg0(%r13)
@@ -50,8 +67,9 @@ do_reipl: basr %r13,0
50 st %r14,.Ldispsw+12-.Lpg0(%r13) 67 st %r14,.Ldispsw+12-.Lpg0(%r13)
51 lpswe .Ldispsw-.Lpg0(%r13) 68 lpswe .Ldispsw-.Lpg0(%r13)
52 .align 8 69 .align 8
70.Lclkcmp: .quad 0x0000000000000000
53.Lall: .quad 0x00000000ff000000 71.Lall: .quad 0x00000000ff000000
54.Lctlsave: .quad 0x0000000000000000 72.Lregsave: .quad 0x0000000000000000
55.Lnull: .long 0x0000000000000000 73.Lnull: .long 0x0000000000000000
56 .align 16 74 .align 16
57/* 75/*
@@ -92,5 +110,3 @@ do_reipl: basr %r13,0
92 .long 0x00000000,0x00000000 110 .long 0x00000000,0x00000000
93 .long 0x00000000,0x00000000 111 .long 0x00000000,0x00000000
94 112
95
96
diff --git a/arch/s390/kernel/reipl_diag.c b/arch/s390/kernel/reipl_diag.c
deleted file mode 100644
index 1f33951ba439..000000000000
--- a/arch/s390/kernel/reipl_diag.c
+++ /dev/null
@@ -1,39 +0,0 @@
1/*
2 * This file contains the implementation of the
3 * Linux re-IPL support
4 *
5 * (C) Copyright IBM Corp. 2005
6 *
7 * Author(s): Volker Sameske (sameske@de.ibm.com)
8 *
9 */
10
11#include <linux/kernel.h>
12
13static unsigned int reipl_diag_rc1;
14static unsigned int reipl_diag_rc2;
15
16/*
17 * re-IPL the system using the last used IPL parameters
18 */
19void reipl_diag(void)
20{
21 asm volatile (
22 " la %%r4,0\n"
23 " la %%r5,0\n"
24 " diag %%r4,%2,0x308\n"
25 "0:\n"
26 " st %%r4,%0\n"
27 " st %%r5,%1\n"
28 ".section __ex_table,\"a\"\n"
29#ifdef CONFIG_64BIT
30 " .align 8\n"
31 " .quad 0b, 0b\n"
32#else
33 " .align 4\n"
34 " .long 0b, 0b\n"
35#endif
36 ".previous\n"
37 : "=m" (reipl_diag_rc1), "=m" (reipl_diag_rc2)
38 : "d" (3) : "cc", "4", "5" );
39}
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
index 89051e8a5d8d..f2a9165ca4f8 100644
--- a/arch/s390/kernel/setup.c
+++ b/arch/s390/kernel/setup.c
@@ -285,16 +285,9 @@ void (*_machine_power_off)(void) = machine_power_off_smp;
285/* 285/*
286 * Reboot, halt and power_off routines for non SMP. 286 * Reboot, halt and power_off routines for non SMP.
287 */ 287 */
288extern void reipl(unsigned long devno);
289extern void reipl_diag(void);
290static void do_machine_restart_nonsmp(char * __unused) 288static void do_machine_restart_nonsmp(char * __unused)
291{ 289{
292 reipl_diag(); 290 do_reipl();
293
294 if (MACHINE_IS_VM)
295 cpcmd ("IPL", NULL, 0, NULL);
296 else
297 reipl (0x10000 | S390_lowcore.ipl_device);
298} 291}
299 292
300static void do_machine_halt_nonsmp(void) 293static void do_machine_halt_nonsmp(void)
@@ -755,214 +748,3 @@ struct seq_operations cpuinfo_op = {
755 .show = show_cpuinfo, 748 .show = show_cpuinfo,
756}; 749};
757 750
758#define DEFINE_IPL_ATTR(_name, _format, _value) \
759static ssize_t ipl_##_name##_show(struct subsystem *subsys, \
760 char *page) \
761{ \
762 return sprintf(page, _format, _value); \
763} \
764static struct subsys_attribute ipl_##_name##_attr = \
765 __ATTR(_name, S_IRUGO, ipl_##_name##_show, NULL);
766
767DEFINE_IPL_ATTR(wwpn, "0x%016llx\n", (unsigned long long)
768 IPL_PARMBLOCK_START->fcp.wwpn);
769DEFINE_IPL_ATTR(lun, "0x%016llx\n", (unsigned long long)
770 IPL_PARMBLOCK_START->fcp.lun);
771DEFINE_IPL_ATTR(bootprog, "%lld\n", (unsigned long long)
772 IPL_PARMBLOCK_START->fcp.bootprog);
773DEFINE_IPL_ATTR(br_lba, "%lld\n", (unsigned long long)
774 IPL_PARMBLOCK_START->fcp.br_lba);
775
776enum ipl_type_type {
777 ipl_type_unknown,
778 ipl_type_ccw,
779 ipl_type_fcp,
780};
781
782static enum ipl_type_type
783get_ipl_type(void)
784{
785 struct ipl_parameter_block *ipl = IPL_PARMBLOCK_START;
786
787 if (!IPL_DEVNO_VALID)
788 return ipl_type_unknown;
789 if (!IPL_PARMBLOCK_VALID)
790 return ipl_type_ccw;
791 if (ipl->hdr.header.version > IPL_MAX_SUPPORTED_VERSION)
792 return ipl_type_unknown;
793 if (ipl->fcp.pbt != IPL_TYPE_FCP)
794 return ipl_type_unknown;
795 return ipl_type_fcp;
796}
797
798static ssize_t
799ipl_type_show(struct subsystem *subsys, char *page)
800{
801 switch (get_ipl_type()) {
802 case ipl_type_ccw:
803 return sprintf(page, "ccw\n");
804 case ipl_type_fcp:
805 return sprintf(page, "fcp\n");
806 default:
807 return sprintf(page, "unknown\n");
808 }
809}
810
811static struct subsys_attribute ipl_type_attr = __ATTR_RO(ipl_type);
812
813static ssize_t
814ipl_device_show(struct subsystem *subsys, char *page)
815{
816 struct ipl_parameter_block *ipl = IPL_PARMBLOCK_START;
817
818 switch (get_ipl_type()) {
819 case ipl_type_ccw:
820 return sprintf(page, "0.0.%04x\n", ipl_devno);
821 case ipl_type_fcp:
822 return sprintf(page, "0.0.%04x\n", ipl->fcp.devno);
823 default:
824 return 0;
825 }
826}
827
828static struct subsys_attribute ipl_device_attr =
829 __ATTR(device, S_IRUGO, ipl_device_show, NULL);
830
831static struct attribute *ipl_fcp_attrs[] = {
832 &ipl_type_attr.attr,
833 &ipl_device_attr.attr,
834 &ipl_wwpn_attr.attr,
835 &ipl_lun_attr.attr,
836 &ipl_bootprog_attr.attr,
837 &ipl_br_lba_attr.attr,
838 NULL,
839};
840
841static struct attribute_group ipl_fcp_attr_group = {
842 .attrs = ipl_fcp_attrs,
843};
844
845static struct attribute *ipl_ccw_attrs[] = {
846 &ipl_type_attr.attr,
847 &ipl_device_attr.attr,
848 NULL,
849};
850
851static struct attribute_group ipl_ccw_attr_group = {
852 .attrs = ipl_ccw_attrs,
853};
854
855static struct attribute *ipl_unknown_attrs[] = {
856 &ipl_type_attr.attr,
857 NULL,
858};
859
860static struct attribute_group ipl_unknown_attr_group = {
861 .attrs = ipl_unknown_attrs,
862};
863
864static ssize_t
865ipl_parameter_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
866{
867 unsigned int size = IPL_PARMBLOCK_SIZE;
868
869 if (off > size)
870 return 0;
871 if (off + count > size)
872 count = size - off;
873
874 memcpy(buf, (void *) IPL_PARMBLOCK_START + off, count);
875 return count;
876}
877
878static struct bin_attribute ipl_parameter_attr = {
879 .attr = {
880 .name = "binary_parameter",
881 .mode = S_IRUGO,
882 .owner = THIS_MODULE,
883 },
884 .size = PAGE_SIZE,
885 .read = &ipl_parameter_read,
886};
887
888static ssize_t
889ipl_scp_data_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
890{
891 unsigned int size = IPL_PARMBLOCK_START->fcp.scp_data_len;
892 void *scp_data = &IPL_PARMBLOCK_START->fcp.scp_data;
893
894 if (off > size)
895 return 0;
896 if (off + count > size)
897 count = size - off;
898
899 memcpy(buf, scp_data + off, count);
900 return count;
901}
902
903static struct bin_attribute ipl_scp_data_attr = {
904 .attr = {
905 .name = "scp_data",
906 .mode = S_IRUGO,
907 .owner = THIS_MODULE,
908 },
909 .size = PAGE_SIZE,
910 .read = &ipl_scp_data_read,
911};
912
913static decl_subsys(ipl, NULL, NULL);
914
915static int ipl_register_fcp_files(void)
916{
917 int rc;
918
919 rc = sysfs_create_group(&ipl_subsys.kset.kobj,
920 &ipl_fcp_attr_group);
921 if (rc)
922 goto out;
923 rc = sysfs_create_bin_file(&ipl_subsys.kset.kobj,
924 &ipl_parameter_attr);
925 if (rc)
926 goto out_ipl_parm;
927 rc = sysfs_create_bin_file(&ipl_subsys.kset.kobj,
928 &ipl_scp_data_attr);
929 if (!rc)
930 goto out;
931
932 sysfs_remove_bin_file(&ipl_subsys.kset.kobj, &ipl_parameter_attr);
933
934out_ipl_parm:
935 sysfs_remove_group(&ipl_subsys.kset.kobj, &ipl_fcp_attr_group);
936out:
937 return rc;
938}
939
940static int __init
941ipl_device_sysfs_register(void) {
942 int rc;
943
944 rc = firmware_register(&ipl_subsys);
945 if (rc)
946 goto out;
947
948 switch (get_ipl_type()) {
949 case ipl_type_ccw:
950 rc = sysfs_create_group(&ipl_subsys.kset.kobj,
951 &ipl_ccw_attr_group);
952 break;
953 case ipl_type_fcp:
954 rc = ipl_register_fcp_files();
955 break;
956 default:
957 rc = sysfs_create_group(&ipl_subsys.kset.kobj,
958 &ipl_unknown_attr_group);
959 break;
960 }
961
962 if (rc)
963 firmware_unregister(&ipl_subsys);
964out:
965 return rc;
966}
967
968__initcall(ipl_device_sysfs_register);
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
index 8e03219eea76..b2e6f4c8d382 100644
--- a/arch/s390/kernel/smp.c
+++ b/arch/s390/kernel/smp.c
@@ -59,9 +59,6 @@ static struct task_struct *current_set[NR_CPUS];
59extern char vmhalt_cmd[]; 59extern char vmhalt_cmd[];
60extern char vmpoff_cmd[]; 60extern char vmpoff_cmd[];
61 61
62extern void reipl(unsigned long devno);
63extern void reipl_diag(void);
64
65static void smp_ext_bitcall(int, ec_bit_sig); 62static void smp_ext_bitcall(int, ec_bit_sig);
66static void smp_ext_bitcall_others(ec_bit_sig); 63static void smp_ext_bitcall_others(ec_bit_sig);
67 64
@@ -279,12 +276,7 @@ static void do_machine_restart(void * __unused)
279 * interrupted by an external interrupt and s390irq 276 * interrupted by an external interrupt and s390irq
280 * locks are always held disabled). 277 * locks are always held disabled).
281 */ 278 */
282 reipl_diag(); 279 do_reipl();
283
284 if (MACHINE_IS_VM)
285 cpcmd ("IPL", NULL, 0, NULL);
286 else
287 reipl (0x10000 | S390_lowcore.ipl_device);
288} 280}
289 281
290void machine_restart_smp(char * __unused) 282void machine_restart_smp(char * __unused)
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index 89320c1ad825..050963f15802 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -841,14 +841,26 @@ __clear_subchannel_easy(struct subchannel_id schid)
841 return -EBUSY; 841 return -EBUSY;
842} 842}
843 843
844extern void do_reipl(unsigned long devno); 844struct sch_match_id {
845static int 845 struct subchannel_id schid;
846__shutdown_subchannel_easy(struct subchannel_id schid, void *data) 846 struct ccw_dev_id devid;
847 int rc;
848};
849
850static int __shutdown_subchannel_easy_and_match(struct subchannel_id schid,
851 void *data)
847{ 852{
848 struct schib schib; 853 struct schib schib;
854 struct sch_match_id *match_id = data;
849 855
850 if (stsch_err(schid, &schib)) 856 if (stsch_err(schid, &schib))
851 return -ENXIO; 857 return -ENXIO;
858 if (match_id && schib.pmcw.dnv &&
859 (schib.pmcw.dev == match_id->devid.devno) &&
860 (schid.ssid == match_id->devid.ssid)) {
861 match_id->schid = schid;
862 match_id->rc = 0;
863 }
852 if (!schib.pmcw.ena) 864 if (!schib.pmcw.ena)
853 return 0; 865 return 0;
854 switch(__disable_subchannel_easy(schid, &schib)) { 866 switch(__disable_subchannel_easy(schid, &schib)) {
@@ -864,18 +876,36 @@ __shutdown_subchannel_easy(struct subchannel_id schid, void *data)
864 return 0; 876 return 0;
865} 877}
866 878
867void 879static int clear_all_subchannels_and_match(struct ccw_dev_id *devid,
868clear_all_subchannels(void) 880 struct subchannel_id *schid)
869{ 881{
882 struct sch_match_id match_id;
883
884 match_id.devid = *devid;
885 match_id.rc = -ENODEV;
870 local_irq_disable(); 886 local_irq_disable();
871 for_each_subchannel(__shutdown_subchannel_easy, NULL); 887 for_each_subchannel(__shutdown_subchannel_easy_and_match, &match_id);
888 if (match_id.rc == 0)
889 *schid = match_id.schid;
890 return match_id.rc;
872} 891}
873 892
893
894void clear_all_subchannels(void)
895{
896 local_irq_disable();
897 for_each_subchannel(__shutdown_subchannel_easy_and_match, NULL);
898}
899
900extern void do_reipl_asm(__u32 schid);
901
874/* Make sure all subchannels are quiet before we re-ipl an lpar. */ 902/* Make sure all subchannels are quiet before we re-ipl an lpar. */
875void 903void reipl_ccw_dev(struct ccw_dev_id *devid)
876reipl(unsigned long devno)
877{ 904{
878 clear_all_subchannels(); 905 struct subchannel_id schid;
906
907 if (clear_all_subchannels_and_match(devid, &schid))
908 panic("IPL Device not found\n");
879 cio_reset_channel_paths(); 909 cio_reset_channel_paths();
880 do_reipl(devno); 910 do_reipl_asm(*((__u32*)&schid));
881} 911}
diff --git a/include/asm-s390/cio.h b/include/asm-s390/cio.h
index 28fdd6e2b8ba..da063cd5f0a0 100644
--- a/include/asm-s390/cio.h
+++ b/include/asm-s390/cio.h
@@ -270,6 +270,11 @@ struct diag210 {
270 __u32 vrdccrft : 8; /* real device feature (output) */ 270 __u32 vrdccrft : 8; /* real device feature (output) */
271} __attribute__ ((packed,aligned(4))); 271} __attribute__ ((packed,aligned(4)));
272 272
273struct ccw_dev_id {
274 u8 ssid;
275 u16 devno;
276};
277
273extern int diag210(struct diag210 *addr); 278extern int diag210(struct diag210 *addr);
274 279
275extern void wait_cons_dev(void); 280extern void wait_cons_dev(void);
@@ -280,6 +285,8 @@ extern void cio_reset_channel_paths(void);
280 285
281extern void css_schedule_reprobe(void); 286extern void css_schedule_reprobe(void);
282 287
288extern void reipl_ccw_dev(struct ccw_dev_id *id);
289
283#endif 290#endif
284 291
285#endif 292#endif
diff --git a/include/asm-s390/lowcore.h b/include/asm-s390/lowcore.h
index 596c8b172104..2e3d4cca5e21 100644
--- a/include/asm-s390/lowcore.h
+++ b/include/asm-s390/lowcore.h
@@ -47,6 +47,7 @@
47#define __LC_PER_ATMID 0x096 47#define __LC_PER_ATMID 0x096
48#define __LC_PER_ADDRESS 0x098 48#define __LC_PER_ADDRESS 0x098
49#define __LC_PER_ACCESS_ID 0x0A1 49#define __LC_PER_ACCESS_ID 0x0A1
50#define __LC_AR_MODE_ID 0x0A3
50 51
51#define __LC_SUBCHANNEL_ID 0x0B8 52#define __LC_SUBCHANNEL_ID 0x0B8
52#define __LC_SUBCHANNEL_NR 0x0BA 53#define __LC_SUBCHANNEL_NR 0x0BA
@@ -106,18 +107,28 @@
106#define __LC_INT_CLOCK 0xDE8 107#define __LC_INT_CLOCK 0xDE8
107#endif /* __s390x__ */ 108#endif /* __s390x__ */
108 109
109#define __LC_PANIC_MAGIC 0xE00
110 110
111#define __LC_PANIC_MAGIC 0xE00
111#ifndef __s390x__ 112#ifndef __s390x__
112#define __LC_PFAULT_INTPARM 0x080 113#define __LC_PFAULT_INTPARM 0x080
113#define __LC_CPU_TIMER_SAVE_AREA 0x0D8 114#define __LC_CPU_TIMER_SAVE_AREA 0x0D8
115#define __LC_CLOCK_COMP_SAVE_AREA 0x0E0
116#define __LC_PSW_SAVE_AREA 0x100
117#define __LC_PREFIX_SAVE_AREA 0x108
114#define __LC_AREGS_SAVE_AREA 0x120 118#define __LC_AREGS_SAVE_AREA 0x120
119#define __LC_FPREGS_SAVE_AREA 0x160
115#define __LC_GPREGS_SAVE_AREA 0x180 120#define __LC_GPREGS_SAVE_AREA 0x180
116#define __LC_CREGS_SAVE_AREA 0x1C0 121#define __LC_CREGS_SAVE_AREA 0x1C0
117#else /* __s390x__ */ 122#else /* __s390x__ */
118#define __LC_PFAULT_INTPARM 0x11B8 123#define __LC_PFAULT_INTPARM 0x11B8
124#define __LC_FPREGS_SAVE_AREA 0x1200
119#define __LC_GPREGS_SAVE_AREA 0x1280 125#define __LC_GPREGS_SAVE_AREA 0x1280
126#define __LC_PSW_SAVE_AREA 0x1300
127#define __LC_PREFIX_SAVE_AREA 0x1318
128#define __LC_FP_CREG_SAVE_AREA 0x131C
129#define __LC_TODREG_SAVE_AREA 0x1324
120#define __LC_CPU_TIMER_SAVE_AREA 0x1328 130#define __LC_CPU_TIMER_SAVE_AREA 0x1328
131#define __LC_CLOCK_COMP_SAVE_AREA 0x1331
121#define __LC_AREGS_SAVE_AREA 0x1340 132#define __LC_AREGS_SAVE_AREA 0x1340
122#define __LC_CREGS_SAVE_AREA 0x1380 133#define __LC_CREGS_SAVE_AREA 0x1380
123#endif /* __s390x__ */ 134#endif /* __s390x__ */
diff --git a/include/asm-s390/setup.h b/include/asm-s390/setup.h
index 02c96d57f0cf..4a1126d8439a 100644
--- a/include/asm-s390/setup.h
+++ b/include/asm-s390/setup.h
@@ -68,39 +68,59 @@ extern unsigned int console_irq;
68#define SET_CONSOLE_3215 do { console_mode = 2; } while (0) 68#define SET_CONSOLE_3215 do { console_mode = 2; } while (0)
69#define SET_CONSOLE_3270 do { console_mode = 3; } while (0) 69#define SET_CONSOLE_3270 do { console_mode = 3; } while (0)
70 70
71struct ipl_list_header { 71
72 u32 length; 72struct ipl_list_hdr {
73 u8 reserved[3]; 73 u32 len;
74 u8 reserved1[3];
74 u8 version; 75 u8 version;
76 u32 blk0_len;
77 u8 pbt;
78 u8 flags;
79 u16 reserved2;
75} __attribute__((packed)); 80} __attribute__((packed));
76 81
77struct ipl_block_fcp { 82struct ipl_block_fcp {
78 u32 length; 83 u8 reserved1[313-1];
79 u8 pbt; 84 u8 opt;
80 u8 reserved1[322-1]; 85 u8 reserved2[3];
86 u16 reserved3;
81 u16 devno; 87 u16 devno;
82 u8 reserved2[4]; 88 u8 reserved4[4];
83 u64 wwpn; 89 u64 wwpn;
84 u64 lun; 90 u64 lun;
85 u32 bootprog; 91 u32 bootprog;
86 u8 reserved3[12]; 92 u8 reserved5[12];
87 u64 br_lba; 93 u64 br_lba;
88 u32 scp_data_len; 94 u32 scp_data_len;
89 u8 reserved4[260]; 95 u8 reserved6[260];
90 u8 scp_data[]; 96 u8 scp_data[];
91} __attribute__((packed)); 97} __attribute__((packed));
92 98
99struct ipl_block_ccw {
100 u8 load_param[8];
101 u8 reserved1[84];
102 u8 reserved2[2];
103 u16 devno;
104 u8 vm_flags;
105 u8 reserved3[3];
106 u32 vm_parm_len;
107} __attribute__((packed));
108
93struct ipl_parameter_block { 109struct ipl_parameter_block {
110 struct ipl_list_hdr hdr;
94 union { 111 union {
95 u32 length; 112 struct ipl_block_fcp fcp;
96 struct ipl_list_header header; 113 struct ipl_block_ccw ccw;
97 } hdr; 114 } ipl_info;
98 struct ipl_block_fcp fcp;
99} __attribute__((packed)); 115} __attribute__((packed));
100 116
101#define IPL_MAX_SUPPORTED_VERSION (0) 117#define IPL_PARM_BLK_FCP_LEN (sizeof(struct ipl_list_hdr) + \
118 sizeof(struct ipl_block_fcp))
102 119
103#define IPL_TYPE_FCP (0) 120#define IPL_PARM_BLK_CCW_LEN (sizeof(struct ipl_list_hdr) + \
121 sizeof(struct ipl_block_ccw))
122
123#define IPL_MAX_SUPPORTED_VERSION (0)
104 124
105/* 125/*
106 * IPL validity flags and parameters as detected in head.S 126 * IPL validity flags and parameters as detected in head.S
@@ -108,12 +128,14 @@ struct ipl_parameter_block {
108extern u32 ipl_parameter_flags; 128extern u32 ipl_parameter_flags;
109extern u16 ipl_devno; 129extern u16 ipl_devno;
110 130
131void do_reipl(void);
132
111#define IPL_DEVNO_VALID (ipl_parameter_flags & 1) 133#define IPL_DEVNO_VALID (ipl_parameter_flags & 1)
112#define IPL_PARMBLOCK_VALID (ipl_parameter_flags & 2) 134#define IPL_PARMBLOCK_VALID (ipl_parameter_flags & 2)
113 135
114#define IPL_PARMBLOCK_START ((struct ipl_parameter_block *) \ 136#define IPL_PARMBLOCK_START ((struct ipl_parameter_block *) \
115 IPL_PARMBLOCK_ORIGIN) 137 IPL_PARMBLOCK_ORIGIN)
116#define IPL_PARMBLOCK_SIZE (IPL_PARMBLOCK_START->hdr.length) 138#define IPL_PARMBLOCK_SIZE (IPL_PARMBLOCK_START->hdr.len)
117 139
118#else /* __ASSEMBLY__ */ 140#else /* __ASSEMBLY__ */
119 141