Merge master.kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6
[linux-2.6] / arch / s390 / kernel / ipl.c
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
23 enum 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
35 static 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
50 enum 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
60 enum 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
70 static 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
84 enum diag308_subcode  {
85         DIAG308_IPL   = 3,
86         DIAG308_DUMP  = 4,
87         DIAG308_SET   = 5,
88         DIAG308_STORE = 6,
89 };
90
91 enum diag308_ipl_type {
92         DIAG308_IPL_TYPE_FCP = 0,
93         DIAG308_IPL_TYPE_CCW = 2,
94 };
95
96 enum diag308_opt {
97         DIAG308_IPL_OPT_IPL  = 0x10,
98         DIAG308_IPL_OPT_DUMP = 0x20,
99 };
100
101 enum diag308_rc {
102         DIAG308_RC_OK = 1,
103 };
104
105 static int diag308_set_works = 0;
106
107 static int reipl_capabilities = IPL_TYPE_UNKNOWN;
108 static enum ipl_type reipl_type = IPL_TYPE_UNKNOWN;
109 static enum ipl_method reipl_method = IPL_METHOD_NONE;
110 static struct ipl_parameter_block *reipl_block_fcp;
111 static struct ipl_parameter_block *reipl_block_ccw;
112
113 static int dump_capabilities = IPL_TYPE_NONE;
114 static enum ipl_type dump_type = IPL_TYPE_NONE;
115 static enum ipl_method dump_method = IPL_METHOD_NONE;
116 static struct ipl_parameter_block *dump_block_fcp;
117 static struct ipl_parameter_block *dump_block_ccw;
118
119 static enum shutdown_action on_panic_action = SHUTDOWN_STOP;
120
121 static 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)             \
147 static ssize_t sys_##_prefix##_##_name##_show(struct subsystem *subsys, \
148                 char *page)                                             \
149 {                                                                       \
150         return sprintf(page, _format, _value);                          \
151 }                                                                       \
152 static 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)   \
156 static 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 }                                                                       \
162 static 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 }                                                                       \
171 static 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
176 static 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
188 static enum ipl_type ipl_get_type(void)
189 {
190         struct ipl_parameter_block *ipl = IPL_PARMBLOCK_START;
191
192         if (!(ipl_flags & IPL_DEVNO_VALID))
193                 return IPL_TYPE_UNKNOWN;
194         if (!(ipl_flags & 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
203 static 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
208 static struct subsys_attribute sys_ipl_type_attr = __ATTR_RO(ipl_type);
209
210 static 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
224 static struct subsys_attribute sys_ipl_device_attr =
225         __ATTR(device, S_IRUGO, sys_ipl_device_show, NULL);
226
227 static 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
240 static 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
250 static 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
264 static 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
276 DEFINE_IPL_ATTR_RO(ipl_fcp, wwpn, "0x%016llx\n", (unsigned long long)
277                    IPL_PARMBLOCK_START->ipl_info.fcp.wwpn);
278 DEFINE_IPL_ATTR_RO(ipl_fcp, lun, "0x%016llx\n", (unsigned long long)
279                    IPL_PARMBLOCK_START->ipl_info.fcp.lun);
280 DEFINE_IPL_ATTR_RO(ipl_fcp, bootprog, "%lld\n", (unsigned long long)
281                    IPL_PARMBLOCK_START->ipl_info.fcp.bootprog);
282 DEFINE_IPL_ATTR_RO(ipl_fcp, br_lba, "%lld\n", (unsigned long long)
283                    IPL_PARMBLOCK_START->ipl_info.fcp.br_lba);
284
285 static 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
295 static struct attribute_group ipl_fcp_attr_group = {
296         .attrs = ipl_fcp_attrs,
297 };
298
299 /* CCW ipl device attributes */
300
301 static struct attribute *ipl_ccw_attrs[] = {
302         &sys_ipl_type_attr.attr,
303         &sys_ipl_device_attr.attr,
304         NULL,
305 };
306
307 static struct attribute_group ipl_ccw_attr_group = {
308         .attrs = ipl_ccw_attrs,
309 };
310
311 /* UNKNOWN ipl device attributes */
312
313 static struct attribute *ipl_unknown_attrs[] = {
314         &sys_ipl_type_attr.attr,
315         NULL,
316 };
317
318 static struct attribute_group ipl_unknown_attr_group = {
319         .attrs = ipl_unknown_attrs,
320 };
321
322 static decl_subsys(ipl, NULL, NULL);
323
324 /*
325  * reipl section
326  */
327
328 /* FCP reipl device attributes */
329
330 DEFINE_IPL_ATTR_RW(reipl_fcp, wwpn, "0x%016llx\n", "%016llx\n",
331                    reipl_block_fcp->ipl_info.fcp.wwpn);
332 DEFINE_IPL_ATTR_RW(reipl_fcp, lun, "0x%016llx\n", "%016llx\n",
333                    reipl_block_fcp->ipl_info.fcp.lun);
334 DEFINE_IPL_ATTR_RW(reipl_fcp, bootprog, "%lld\n", "%lld\n",
335                    reipl_block_fcp->ipl_info.fcp.bootprog);
336 DEFINE_IPL_ATTR_RW(reipl_fcp, br_lba, "%lld\n", "%lld\n",
337                    reipl_block_fcp->ipl_info.fcp.br_lba);
338 DEFINE_IPL_ATTR_RW(reipl_fcp, device, "0.0.%04llx\n", "0.0.%llx\n",
339                    reipl_block_fcp->ipl_info.fcp.devno);
340
341 static 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
350 static 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
357 DEFINE_IPL_ATTR_RW(reipl_ccw, device, "0.0.%04llx\n", "0.0.%llx\n",
358         reipl_block_ccw->ipl_info.ccw.devno);
359
360 static struct attribute *reipl_ccw_attrs[] = {
361         &sys_reipl_ccw_device_attr.attr,
362         NULL,
363 };
364
365 static struct attribute_group reipl_ccw_attr_group = {
366         .name  = IPL_CCW_STR,
367         .attrs = reipl_ccw_attrs,
368 };
369
370 /* reipl type */
371
372 static 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
399 static ssize_t reipl_type_show(struct subsystem *subsys, char *page)
400 {
401         return sprintf(page, "%s\n", ipl_type_str(reipl_type));
402 }
403
404 static 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
416 static struct subsys_attribute reipl_type_attr =
417                 __ATTR(reipl_type, 0644, reipl_type_show, reipl_type_store);
418
419 static decl_subsys(reipl, NULL, NULL);
420
421 /*
422  * dump section
423  */
424
425 /* FCP dump device attributes */
426
427 DEFINE_IPL_ATTR_RW(dump_fcp, wwpn, "0x%016llx\n", "%016llx\n",
428                    dump_block_fcp->ipl_info.fcp.wwpn);
429 DEFINE_IPL_ATTR_RW(dump_fcp, lun, "0x%016llx\n", "%016llx\n",
430                    dump_block_fcp->ipl_info.fcp.lun);
431 DEFINE_IPL_ATTR_RW(dump_fcp, bootprog, "%lld\n", "%lld\n",
432                    dump_block_fcp->ipl_info.fcp.bootprog);
433 DEFINE_IPL_ATTR_RW(dump_fcp, br_lba, "%lld\n", "%lld\n",
434                    dump_block_fcp->ipl_info.fcp.br_lba);
435 DEFINE_IPL_ATTR_RW(dump_fcp, device, "0.0.%04llx\n", "0.0.%llx\n",
436                    dump_block_fcp->ipl_info.fcp.devno);
437
438 static 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
447 static 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
454 DEFINE_IPL_ATTR_RW(dump_ccw, device, "0.0.%04llx\n", "0.0.%llx\n",
455                    dump_block_ccw->ipl_info.ccw.devno);
456
457 static struct attribute *dump_ccw_attrs[] = {
458         &sys_dump_ccw_device_attr.attr,
459         NULL,
460 };
461
462 static struct attribute_group dump_ccw_attr_group = {
463         .name  = IPL_CCW_STR,
464         .attrs = dump_ccw_attrs,
465 };
466
467 /* dump type */
468
469 static 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
490 static ssize_t dump_type_show(struct subsystem *subsys, char *page)
491 {
492         return sprintf(page, "%s\n", ipl_type_str(dump_type));
493 }
494
495 static 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
509 static struct subsys_attribute dump_type_attr =
510                 __ATTR(dump_type, 0644, dump_type_show, dump_type_store);
511
512 static decl_subsys(dump, NULL, NULL);
513
514 #ifdef CONFIG_SMP
515 static 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
535 static decl_subsys(shutdown_actions, NULL, NULL);
536
537 /* on panic */
538
539 static 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
544 static 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
561 static struct subsys_attribute on_panic_attr =
562                 __ATTR(on_panic, 0644, on_panic_show, on_panic_store);
563
564 static 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
579 void 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
631 static 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
680 static 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
699 out_ipl_parm:
700         sysfs_remove_group(&ipl_subsys.kset.kobj, &ipl_fcp_attr_group);
701 out:
702         return rc;
703 }
704
705 static 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
730 static 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
742 static 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
764 static 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
795 static 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
819 static 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
839 extern char s390_readinfo_sccb[];
840
841 static 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
868 static 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
878 static struct notifier_block shutdown_on_panic_nb = {
879         .notifier_call = shutdown_on_panic_notify,
880         .priority = SHUTDOWN_ON_PANIC_PRIO
881 };
882
883 static 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
905 static 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
922 static 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);