Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
[pandora-kernel.git] / 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                 EX_TABLE(0b,0b)
130                 : "+d" (_addr), "+d" (_rc)
131                 : "d" (subcode) : "cc", "memory");
132         return _rc;
133 }
134
135 /* SYSFS */
136
137 #define DEFINE_IPL_ATTR_RO(_prefix, _name, _format, _value)             \
138 static ssize_t sys_##_prefix##_##_name##_show(struct subsystem *subsys, \
139                 char *page)                                             \
140 {                                                                       \
141         return sprintf(page, _format, _value);                          \
142 }                                                                       \
143 static struct subsys_attribute sys_##_prefix##_##_name##_attr =         \
144         __ATTR(_name, S_IRUGO, sys_##_prefix##_##_name##_show, NULL);
145
146 #define DEFINE_IPL_ATTR_RW(_prefix, _name, _fmt_out, _fmt_in, _value)   \
147 static ssize_t sys_##_prefix##_##_name##_show(struct subsystem *subsys, \
148                 char *page)                                             \
149 {                                                                       \
150         return sprintf(page, _fmt_out,                                  \
151                         (unsigned long long) _value);                   \
152 }                                                                       \
153 static ssize_t sys_##_prefix##_##_name##_store(struct subsystem *subsys,\
154                 const char *buf, size_t len)                            \
155 {                                                                       \
156         unsigned long long value;                                       \
157         if (sscanf(buf, _fmt_in, &value) != 1)                          \
158                 return -EINVAL;                                         \
159         _value = value;                                                 \
160         return len;                                                     \
161 }                                                                       \
162 static struct subsys_attribute sys_##_prefix##_##_name##_attr =         \
163         __ATTR(_name,(S_IRUGO | S_IWUSR),                               \
164                         sys_##_prefix##_##_name##_show,                 \
165                         sys_##_prefix##_##_name##_store);
166
167 static void make_attrs_ro(struct attribute **attrs)
168 {
169         while (*attrs) {
170                 (*attrs)->mode = S_IRUGO;
171                 attrs++;
172         }
173 }
174
175 /*
176  * ipl section
177  */
178
179 static enum ipl_type ipl_get_type(void)
180 {
181         struct ipl_parameter_block *ipl = IPL_PARMBLOCK_START;
182
183         if (!(ipl_flags & IPL_DEVNO_VALID))
184                 return IPL_TYPE_UNKNOWN;
185         if (!(ipl_flags & IPL_PARMBLOCK_VALID))
186                 return IPL_TYPE_CCW;
187         if (ipl->hdr.version > IPL_MAX_SUPPORTED_VERSION)
188                 return IPL_TYPE_UNKNOWN;
189         if (ipl->hdr.pbt != DIAG308_IPL_TYPE_FCP)
190                 return IPL_TYPE_UNKNOWN;
191         return IPL_TYPE_FCP;
192 }
193
194 static ssize_t ipl_type_show(struct subsystem *subsys, char *page)
195 {
196         return sprintf(page, "%s\n", ipl_type_str(ipl_get_type()));
197 }
198
199 static struct subsys_attribute sys_ipl_type_attr = __ATTR_RO(ipl_type);
200
201 static ssize_t sys_ipl_device_show(struct subsystem *subsys, char *page)
202 {
203         struct ipl_parameter_block *ipl = IPL_PARMBLOCK_START;
204
205         switch (ipl_get_type()) {
206         case IPL_TYPE_CCW:
207                 return sprintf(page, "0.0.%04x\n", ipl_devno);
208         case IPL_TYPE_FCP:
209                 return sprintf(page, "0.0.%04x\n", ipl->ipl_info.fcp.devno);
210         default:
211                 return 0;
212         }
213 }
214
215 static struct subsys_attribute sys_ipl_device_attr =
216         __ATTR(device, S_IRUGO, sys_ipl_device_show, NULL);
217
218 static ssize_t ipl_parameter_read(struct kobject *kobj, char *buf, loff_t off,
219                                   size_t count)
220 {
221         unsigned int size = IPL_PARMBLOCK_SIZE;
222
223         if (off > size)
224                 return 0;
225         if (off + count > size)
226                 count = size - off;
227         memcpy(buf, (void *)IPL_PARMBLOCK_START + off, count);
228         return count;
229 }
230
231 static struct bin_attribute ipl_parameter_attr = {
232         .attr = {
233                 .name = "binary_parameter",
234                 .mode = S_IRUGO,
235                 .owner = THIS_MODULE,
236         },
237         .size = PAGE_SIZE,
238         .read = &ipl_parameter_read,
239 };
240
241 static ssize_t ipl_scp_data_read(struct kobject *kobj, char *buf, loff_t off,
242         size_t count)
243 {
244         unsigned int size = IPL_PARMBLOCK_START->ipl_info.fcp.scp_data_len;
245         void *scp_data = &IPL_PARMBLOCK_START->ipl_info.fcp.scp_data;
246
247         if (off > size)
248                 return 0;
249         if (off + count > size)
250                 count = size - off;
251         memcpy(buf, scp_data + off, count);
252         return count;
253 }
254
255 static struct bin_attribute ipl_scp_data_attr = {
256         .attr = {
257                 .name = "scp_data",
258                 .mode = S_IRUGO,
259                 .owner = THIS_MODULE,
260         },
261         .size = PAGE_SIZE,
262         .read = &ipl_scp_data_read,
263 };
264
265 /* FCP ipl device attributes */
266
267 DEFINE_IPL_ATTR_RO(ipl_fcp, wwpn, "0x%016llx\n", (unsigned long long)
268                    IPL_PARMBLOCK_START->ipl_info.fcp.wwpn);
269 DEFINE_IPL_ATTR_RO(ipl_fcp, lun, "0x%016llx\n", (unsigned long long)
270                    IPL_PARMBLOCK_START->ipl_info.fcp.lun);
271 DEFINE_IPL_ATTR_RO(ipl_fcp, bootprog, "%lld\n", (unsigned long long)
272                    IPL_PARMBLOCK_START->ipl_info.fcp.bootprog);
273 DEFINE_IPL_ATTR_RO(ipl_fcp, br_lba, "%lld\n", (unsigned long long)
274                    IPL_PARMBLOCK_START->ipl_info.fcp.br_lba);
275
276 static struct attribute *ipl_fcp_attrs[] = {
277         &sys_ipl_type_attr.attr,
278         &sys_ipl_device_attr.attr,
279         &sys_ipl_fcp_wwpn_attr.attr,
280         &sys_ipl_fcp_lun_attr.attr,
281         &sys_ipl_fcp_bootprog_attr.attr,
282         &sys_ipl_fcp_br_lba_attr.attr,
283         NULL,
284 };
285
286 static struct attribute_group ipl_fcp_attr_group = {
287         .attrs = ipl_fcp_attrs,
288 };
289
290 /* CCW ipl device attributes */
291
292 static struct attribute *ipl_ccw_attrs[] = {
293         &sys_ipl_type_attr.attr,
294         &sys_ipl_device_attr.attr,
295         NULL,
296 };
297
298 static struct attribute_group ipl_ccw_attr_group = {
299         .attrs = ipl_ccw_attrs,
300 };
301
302 /* UNKNOWN ipl device attributes */
303
304 static struct attribute *ipl_unknown_attrs[] = {
305         &sys_ipl_type_attr.attr,
306         NULL,
307 };
308
309 static struct attribute_group ipl_unknown_attr_group = {
310         .attrs = ipl_unknown_attrs,
311 };
312
313 static decl_subsys(ipl, NULL, NULL);
314
315 /*
316  * reipl section
317  */
318
319 /* FCP reipl device attributes */
320
321 DEFINE_IPL_ATTR_RW(reipl_fcp, wwpn, "0x%016llx\n", "%016llx\n",
322                    reipl_block_fcp->ipl_info.fcp.wwpn);
323 DEFINE_IPL_ATTR_RW(reipl_fcp, lun, "0x%016llx\n", "%016llx\n",
324                    reipl_block_fcp->ipl_info.fcp.lun);
325 DEFINE_IPL_ATTR_RW(reipl_fcp, bootprog, "%lld\n", "%lld\n",
326                    reipl_block_fcp->ipl_info.fcp.bootprog);
327 DEFINE_IPL_ATTR_RW(reipl_fcp, br_lba, "%lld\n", "%lld\n",
328                    reipl_block_fcp->ipl_info.fcp.br_lba);
329 DEFINE_IPL_ATTR_RW(reipl_fcp, device, "0.0.%04llx\n", "0.0.%llx\n",
330                    reipl_block_fcp->ipl_info.fcp.devno);
331
332 static struct attribute *reipl_fcp_attrs[] = {
333         &sys_reipl_fcp_device_attr.attr,
334         &sys_reipl_fcp_wwpn_attr.attr,
335         &sys_reipl_fcp_lun_attr.attr,
336         &sys_reipl_fcp_bootprog_attr.attr,
337         &sys_reipl_fcp_br_lba_attr.attr,
338         NULL,
339 };
340
341 static struct attribute_group reipl_fcp_attr_group = {
342         .name  = IPL_FCP_STR,
343         .attrs = reipl_fcp_attrs,
344 };
345
346 /* CCW reipl device attributes */
347
348 DEFINE_IPL_ATTR_RW(reipl_ccw, device, "0.0.%04llx\n", "0.0.%llx\n",
349         reipl_block_ccw->ipl_info.ccw.devno);
350
351 static struct attribute *reipl_ccw_attrs[] = {
352         &sys_reipl_ccw_device_attr.attr,
353         NULL,
354 };
355
356 static struct attribute_group reipl_ccw_attr_group = {
357         .name  = IPL_CCW_STR,
358         .attrs = reipl_ccw_attrs,
359 };
360
361 /* reipl type */
362
363 static int reipl_set_type(enum ipl_type type)
364 {
365         if (!(reipl_capabilities & type))
366                 return -EINVAL;
367
368         switch(type) {
369         case IPL_TYPE_CCW:
370                 if (MACHINE_IS_VM)
371                         reipl_method = IPL_METHOD_CCW_VM;
372                 else
373                         reipl_method = IPL_METHOD_CCW_CIO;
374                 break;
375         case IPL_TYPE_FCP:
376                 if (diag308_set_works)
377                         reipl_method = IPL_METHOD_FCP_RW_DIAG;
378                 else if (MACHINE_IS_VM)
379                         reipl_method = IPL_METHOD_FCP_RO_VM;
380                 else
381                         reipl_method = IPL_METHOD_FCP_RO_DIAG;
382                 break;
383         default:
384                 reipl_method = IPL_METHOD_NONE;
385         }
386         reipl_type = type;
387         return 0;
388 }
389
390 static ssize_t reipl_type_show(struct subsystem *subsys, char *page)
391 {
392         return sprintf(page, "%s\n", ipl_type_str(reipl_type));
393 }
394
395 static ssize_t reipl_type_store(struct subsystem *subsys, const char *buf,
396                                 size_t len)
397 {
398         int rc = -EINVAL;
399
400         if (strncmp(buf, IPL_CCW_STR, strlen(IPL_CCW_STR)) == 0)
401                 rc = reipl_set_type(IPL_TYPE_CCW);
402         else if (strncmp(buf, IPL_FCP_STR, strlen(IPL_FCP_STR)) == 0)
403                 rc = reipl_set_type(IPL_TYPE_FCP);
404         return (rc != 0) ? rc : len;
405 }
406
407 static struct subsys_attribute reipl_type_attr =
408                 __ATTR(reipl_type, 0644, reipl_type_show, reipl_type_store);
409
410 static decl_subsys(reipl, NULL, NULL);
411
412 /*
413  * dump section
414  */
415
416 /* FCP dump device attributes */
417
418 DEFINE_IPL_ATTR_RW(dump_fcp, wwpn, "0x%016llx\n", "%016llx\n",
419                    dump_block_fcp->ipl_info.fcp.wwpn);
420 DEFINE_IPL_ATTR_RW(dump_fcp, lun, "0x%016llx\n", "%016llx\n",
421                    dump_block_fcp->ipl_info.fcp.lun);
422 DEFINE_IPL_ATTR_RW(dump_fcp, bootprog, "%lld\n", "%lld\n",
423                    dump_block_fcp->ipl_info.fcp.bootprog);
424 DEFINE_IPL_ATTR_RW(dump_fcp, br_lba, "%lld\n", "%lld\n",
425                    dump_block_fcp->ipl_info.fcp.br_lba);
426 DEFINE_IPL_ATTR_RW(dump_fcp, device, "0.0.%04llx\n", "0.0.%llx\n",
427                    dump_block_fcp->ipl_info.fcp.devno);
428
429 static struct attribute *dump_fcp_attrs[] = {
430         &sys_dump_fcp_device_attr.attr,
431         &sys_dump_fcp_wwpn_attr.attr,
432         &sys_dump_fcp_lun_attr.attr,
433         &sys_dump_fcp_bootprog_attr.attr,
434         &sys_dump_fcp_br_lba_attr.attr,
435         NULL,
436 };
437
438 static struct attribute_group dump_fcp_attr_group = {
439         .name  = IPL_FCP_STR,
440         .attrs = dump_fcp_attrs,
441 };
442
443 /* CCW dump device attributes */
444
445 DEFINE_IPL_ATTR_RW(dump_ccw, device, "0.0.%04llx\n", "0.0.%llx\n",
446                    dump_block_ccw->ipl_info.ccw.devno);
447
448 static struct attribute *dump_ccw_attrs[] = {
449         &sys_dump_ccw_device_attr.attr,
450         NULL,
451 };
452
453 static struct attribute_group dump_ccw_attr_group = {
454         .name  = IPL_CCW_STR,
455         .attrs = dump_ccw_attrs,
456 };
457
458 /* dump type */
459
460 static int dump_set_type(enum ipl_type type)
461 {
462         if (!(dump_capabilities & type))
463                 return -EINVAL;
464         switch(type) {
465         case IPL_TYPE_CCW:
466                 if (MACHINE_IS_VM)
467                         dump_method = IPL_METHOD_CCW_VM;
468                 else
469                         dump_method = IPL_METHOD_CCW_CIO;
470                 break;
471         case IPL_TYPE_FCP:
472                 dump_method = IPL_METHOD_FCP_RW_DIAG;
473                 break;
474         default:
475                 dump_method = IPL_METHOD_NONE;
476         }
477         dump_type = type;
478         return 0;
479 }
480
481 static ssize_t dump_type_show(struct subsystem *subsys, char *page)
482 {
483         return sprintf(page, "%s\n", ipl_type_str(dump_type));
484 }
485
486 static ssize_t dump_type_store(struct subsystem *subsys, const char *buf,
487                                size_t len)
488 {
489         int rc = -EINVAL;
490
491         if (strncmp(buf, IPL_NONE_STR, strlen(IPL_NONE_STR)) == 0)
492                 rc = dump_set_type(IPL_TYPE_NONE);
493         else if (strncmp(buf, IPL_CCW_STR, strlen(IPL_CCW_STR)) == 0)
494                 rc = dump_set_type(IPL_TYPE_CCW);
495         else if (strncmp(buf, IPL_FCP_STR, strlen(IPL_FCP_STR)) == 0)
496                 rc = dump_set_type(IPL_TYPE_FCP);
497         return (rc != 0) ? rc : len;
498 }
499
500 static struct subsys_attribute dump_type_attr =
501                 __ATTR(dump_type, 0644, dump_type_show, dump_type_store);
502
503 static decl_subsys(dump, NULL, NULL);
504
505 #ifdef CONFIG_SMP
506 static void dump_smp_stop_all(void)
507 {
508         int cpu;
509         preempt_disable();
510         for_each_online_cpu(cpu) {
511                 if (cpu == smp_processor_id())
512                         continue;
513                 while (signal_processor(cpu, sigp_stop) == sigp_busy)
514                         udelay(10);
515         }
516         preempt_enable();
517 }
518 #else
519 #define dump_smp_stop_all() do { } while (0)
520 #endif
521
522 /*
523  * Shutdown actions section
524  */
525
526 static decl_subsys(shutdown_actions, NULL, NULL);
527
528 /* on panic */
529
530 static ssize_t on_panic_show(struct subsystem *subsys, char *page)
531 {
532         return sprintf(page, "%s\n", shutdown_action_str(on_panic_action));
533 }
534
535 static ssize_t on_panic_store(struct subsystem *subsys, const char *buf,
536                               size_t len)
537 {
538         if (strncmp(buf, SHUTDOWN_REIPL_STR, strlen(SHUTDOWN_REIPL_STR)) == 0)
539                 on_panic_action = SHUTDOWN_REIPL;
540         else if (strncmp(buf, SHUTDOWN_DUMP_STR,
541                          strlen(SHUTDOWN_DUMP_STR)) == 0)
542                 on_panic_action = SHUTDOWN_DUMP;
543         else if (strncmp(buf, SHUTDOWN_STOP_STR,
544                          strlen(SHUTDOWN_STOP_STR)) == 0)
545                 on_panic_action = SHUTDOWN_STOP;
546         else
547                 return -EINVAL;
548
549         return len;
550 }
551
552 static struct subsys_attribute on_panic_attr =
553                 __ATTR(on_panic, 0644, on_panic_show, on_panic_store);
554
555 static void print_fcp_block(struct ipl_parameter_block *fcp_block)
556 {
557         printk(KERN_EMERG "wwpn:      %016llx\n",
558                 (unsigned long long)fcp_block->ipl_info.fcp.wwpn);
559         printk(KERN_EMERG "lun:       %016llx\n",
560                 (unsigned long long)fcp_block->ipl_info.fcp.lun);
561         printk(KERN_EMERG "bootprog:  %lld\n",
562                 (unsigned long long)fcp_block->ipl_info.fcp.bootprog);
563         printk(KERN_EMERG "br_lba:    %lld\n",
564                 (unsigned long long)fcp_block->ipl_info.fcp.br_lba);
565         printk(KERN_EMERG "device:    %llx\n",
566                 (unsigned long long)fcp_block->ipl_info.fcp.devno);
567         printk(KERN_EMERG "opt:       %x\n", fcp_block->ipl_info.fcp.opt);
568 }
569
570 void do_reipl(void)
571 {
572         struct ccw_dev_id devid;
573         static char buf[100];
574
575         switch (reipl_type) {
576         case IPL_TYPE_CCW:
577                 printk(KERN_EMERG "reboot on ccw device: 0.0.%04x\n",
578                         reipl_block_ccw->ipl_info.ccw.devno);
579                 break;
580         case IPL_TYPE_FCP:
581                 printk(KERN_EMERG "reboot on fcp device:\n");
582                 print_fcp_block(reipl_block_fcp);
583                 break;
584         default:
585                 break;
586         }
587
588         switch (reipl_method) {
589         case IPL_METHOD_CCW_CIO:
590                 devid.devno = reipl_block_ccw->ipl_info.ccw.devno;
591                 devid.ssid  = 0;
592                 reipl_ccw_dev(&devid);
593                 break;
594         case IPL_METHOD_CCW_VM:
595                 sprintf(buf, "IPL %X", reipl_block_ccw->ipl_info.ccw.devno);
596                 cpcmd(buf, NULL, 0, NULL);
597                 break;
598         case IPL_METHOD_CCW_DIAG:
599                 diag308(DIAG308_SET, reipl_block_ccw);
600                 diag308(DIAG308_IPL, NULL);
601                 break;
602         case IPL_METHOD_FCP_RW_DIAG:
603                 diag308(DIAG308_SET, reipl_block_fcp);
604                 diag308(DIAG308_IPL, NULL);
605                 break;
606         case IPL_METHOD_FCP_RO_DIAG:
607                 diag308(DIAG308_IPL, NULL);
608                 break;
609         case IPL_METHOD_FCP_RO_VM:
610                 cpcmd("IPL", NULL, 0, NULL);
611                 break;
612         case IPL_METHOD_NONE:
613         default:
614                 if (MACHINE_IS_VM)
615                         cpcmd("IPL", NULL, 0, NULL);
616                 diag308(DIAG308_IPL, NULL);
617                 break;
618         }
619         panic("reipl failed!\n");
620 }
621
622 static void do_dump(void)
623 {
624         struct ccw_dev_id devid;
625         static char buf[100];
626
627         switch (dump_type) {
628         case IPL_TYPE_CCW:
629                 printk(KERN_EMERG "Automatic dump on ccw device: 0.0.%04x\n",
630                        dump_block_ccw->ipl_info.ccw.devno);
631                 break;
632         case IPL_TYPE_FCP:
633                 printk(KERN_EMERG "Automatic dump on fcp device:\n");
634                 print_fcp_block(dump_block_fcp);
635                 break;
636         default:
637                 return;
638         }
639
640         switch (dump_method) {
641         case IPL_METHOD_CCW_CIO:
642                 dump_smp_stop_all();
643                 devid.devno = dump_block_ccw->ipl_info.ccw.devno;
644                 devid.ssid  = 0;
645                 reipl_ccw_dev(&devid);
646                 break;
647         case IPL_METHOD_CCW_VM:
648                 dump_smp_stop_all();
649                 sprintf(buf, "STORE STATUS");
650                 cpcmd(buf, NULL, 0, NULL);
651                 sprintf(buf, "IPL %X", dump_block_ccw->ipl_info.ccw.devno);
652                 cpcmd(buf, NULL, 0, NULL);
653                 break;
654         case IPL_METHOD_CCW_DIAG:
655                 diag308(DIAG308_SET, dump_block_ccw);
656                 diag308(DIAG308_DUMP, NULL);
657                 break;
658         case IPL_METHOD_FCP_RW_DIAG:
659                 diag308(DIAG308_SET, dump_block_fcp);
660                 diag308(DIAG308_DUMP, NULL);
661                 break;
662         case IPL_METHOD_NONE:
663         default:
664                 return;
665         }
666         printk(KERN_EMERG "Dump failed!\n");
667 }
668
669 /* init functions */
670
671 static int __init ipl_register_fcp_files(void)
672 {
673         int rc;
674
675         rc = sysfs_create_group(&ipl_subsys.kset.kobj,
676                                 &ipl_fcp_attr_group);
677         if (rc)
678                 goto out;
679         rc = sysfs_create_bin_file(&ipl_subsys.kset.kobj,
680                                    &ipl_parameter_attr);
681         if (rc)
682                 goto out_ipl_parm;
683         rc = sysfs_create_bin_file(&ipl_subsys.kset.kobj,
684                                    &ipl_scp_data_attr);
685         if (!rc)
686                 goto out;
687
688         sysfs_remove_bin_file(&ipl_subsys.kset.kobj, &ipl_parameter_attr);
689
690 out_ipl_parm:
691         sysfs_remove_group(&ipl_subsys.kset.kobj, &ipl_fcp_attr_group);
692 out:
693         return rc;
694 }
695
696 static int __init ipl_init(void)
697 {
698         int rc;
699
700         rc = firmware_register(&ipl_subsys);
701         if (rc)
702                 return rc;
703         switch (ipl_get_type()) {
704         case IPL_TYPE_CCW:
705                 rc = sysfs_create_group(&ipl_subsys.kset.kobj,
706                                         &ipl_ccw_attr_group);
707                 break;
708         case IPL_TYPE_FCP:
709                 rc = ipl_register_fcp_files();
710                 break;
711         default:
712                 rc = sysfs_create_group(&ipl_subsys.kset.kobj,
713                                         &ipl_unknown_attr_group);
714                 break;
715         }
716         if (rc)
717                 firmware_unregister(&ipl_subsys);
718         return rc;
719 }
720
721 static void __init reipl_probe(void)
722 {
723         void *buffer;
724
725         buffer = (void *) get_zeroed_page(GFP_KERNEL);
726         if (!buffer)
727                 return;
728         if (diag308(DIAG308_STORE, buffer) == DIAG308_RC_OK)
729                 diag308_set_works = 1;
730         free_page((unsigned long)buffer);
731 }
732
733 static int __init reipl_ccw_init(void)
734 {
735         int rc;
736
737         reipl_block_ccw = (void *) get_zeroed_page(GFP_KERNEL);
738         if (!reipl_block_ccw)
739                 return -ENOMEM;
740         rc = sysfs_create_group(&reipl_subsys.kset.kobj, &reipl_ccw_attr_group);
741         if (rc) {
742                 free_page((unsigned long)reipl_block_ccw);
743                 return rc;
744         }
745         reipl_block_ccw->hdr.len = IPL_PARM_BLK_CCW_LEN;
746         reipl_block_ccw->hdr.version = IPL_PARM_BLOCK_VERSION;
747         reipl_block_ccw->hdr.blk0_len = sizeof(reipl_block_ccw->ipl_info.ccw);
748         reipl_block_ccw->hdr.pbt = DIAG308_IPL_TYPE_CCW;
749         if (ipl_get_type() == IPL_TYPE_CCW)
750                 reipl_block_ccw->ipl_info.ccw.devno = ipl_devno;
751         reipl_capabilities |= IPL_TYPE_CCW;
752         return 0;
753 }
754
755 static int __init reipl_fcp_init(void)
756 {
757         int rc;
758
759         if ((!diag308_set_works) && (ipl_get_type() != IPL_TYPE_FCP))
760                 return 0;
761         if ((!diag308_set_works) && (ipl_get_type() == IPL_TYPE_FCP))
762                 make_attrs_ro(reipl_fcp_attrs);
763
764         reipl_block_fcp = (void *) get_zeroed_page(GFP_KERNEL);
765         if (!reipl_block_fcp)
766                 return -ENOMEM;
767         rc = sysfs_create_group(&reipl_subsys.kset.kobj, &reipl_fcp_attr_group);
768         if (rc) {
769                 free_page((unsigned long)reipl_block_fcp);
770                 return rc;
771         }
772         if (ipl_get_type() == IPL_TYPE_FCP) {
773                 memcpy(reipl_block_fcp, IPL_PARMBLOCK_START, PAGE_SIZE);
774         } else {
775                 reipl_block_fcp->hdr.len = IPL_PARM_BLK_FCP_LEN;
776                 reipl_block_fcp->hdr.version = IPL_PARM_BLOCK_VERSION;
777                 reipl_block_fcp->hdr.blk0_len =
778                         sizeof(reipl_block_fcp->ipl_info.fcp);
779                 reipl_block_fcp->hdr.pbt = DIAG308_IPL_TYPE_FCP;
780                 reipl_block_fcp->ipl_info.fcp.opt = DIAG308_IPL_OPT_IPL;
781         }
782         reipl_capabilities |= IPL_TYPE_FCP;
783         return 0;
784 }
785
786 static int __init reipl_init(void)
787 {
788         int rc;
789
790         rc = firmware_register(&reipl_subsys);
791         if (rc)
792                 return rc;
793         rc = subsys_create_file(&reipl_subsys, &reipl_type_attr);
794         if (rc) {
795                 firmware_unregister(&reipl_subsys);
796                 return rc;
797         }
798         rc = reipl_ccw_init();
799         if (rc)
800                 return rc;
801         rc = reipl_fcp_init();
802         if (rc)
803                 return rc;
804         rc = reipl_set_type(ipl_get_type());
805         if (rc)
806                 return rc;
807         return 0;
808 }
809
810 static int __init dump_ccw_init(void)
811 {
812         int rc;
813
814         dump_block_ccw = (void *) get_zeroed_page(GFP_KERNEL);
815         if (!dump_block_ccw)
816                 return -ENOMEM;
817         rc = sysfs_create_group(&dump_subsys.kset.kobj, &dump_ccw_attr_group);
818         if (rc) {
819                 free_page((unsigned long)dump_block_ccw);
820                 return rc;
821         }
822         dump_block_ccw->hdr.len = IPL_PARM_BLK_CCW_LEN;
823         dump_block_ccw->hdr.version = IPL_PARM_BLOCK_VERSION;
824         dump_block_ccw->hdr.blk0_len = sizeof(reipl_block_ccw->ipl_info.ccw);
825         dump_block_ccw->hdr.pbt = DIAG308_IPL_TYPE_CCW;
826         dump_capabilities |= IPL_TYPE_CCW;
827         return 0;
828 }
829
830 extern char s390_readinfo_sccb[];
831
832 static int __init dump_fcp_init(void)
833 {
834         int rc;
835
836         if(!(s390_readinfo_sccb[91] & 0x2))
837                 return 0; /* LDIPL DUMP is not installed */
838         if (!diag308_set_works)
839                 return 0;
840         dump_block_fcp = (void *) get_zeroed_page(GFP_KERNEL);
841         if (!dump_block_fcp)
842                 return -ENOMEM;
843         rc = sysfs_create_group(&dump_subsys.kset.kobj, &dump_fcp_attr_group);
844         if (rc) {
845                 free_page((unsigned long)dump_block_fcp);
846                 return rc;
847         }
848         dump_block_fcp->hdr.len = IPL_PARM_BLK_FCP_LEN;
849         dump_block_fcp->hdr.version = IPL_PARM_BLOCK_VERSION;
850         dump_block_fcp->hdr.blk0_len = sizeof(dump_block_fcp->ipl_info.fcp);
851         dump_block_fcp->hdr.pbt = DIAG308_IPL_TYPE_FCP;
852         dump_block_fcp->ipl_info.fcp.opt = DIAG308_IPL_OPT_DUMP;
853         dump_capabilities |= IPL_TYPE_FCP;
854         return 0;
855 }
856
857 #define SHUTDOWN_ON_PANIC_PRIO 0
858
859 static int shutdown_on_panic_notify(struct notifier_block *self,
860                                     unsigned long event, void *data)
861 {
862         if (on_panic_action == SHUTDOWN_DUMP)
863                 do_dump();
864         else if (on_panic_action == SHUTDOWN_REIPL)
865                 do_reipl();
866         return NOTIFY_OK;
867 }
868
869 static struct notifier_block shutdown_on_panic_nb = {
870         .notifier_call = shutdown_on_panic_notify,
871         .priority = SHUTDOWN_ON_PANIC_PRIO
872 };
873
874 static int __init dump_init(void)
875 {
876         int rc;
877
878         rc = firmware_register(&dump_subsys);
879         if (rc)
880                 return rc;
881         rc = subsys_create_file(&dump_subsys, &dump_type_attr);
882         if (rc) {
883                 firmware_unregister(&dump_subsys);
884                 return rc;
885         }
886         rc = dump_ccw_init();
887         if (rc)
888                 return rc;
889         rc = dump_fcp_init();
890         if (rc)
891                 return rc;
892         dump_set_type(IPL_TYPE_NONE);
893         return 0;
894 }
895
896 static int __init shutdown_actions_init(void)
897 {
898         int rc;
899
900         rc = firmware_register(&shutdown_actions_subsys);
901         if (rc)
902                 return rc;
903         rc = subsys_create_file(&shutdown_actions_subsys, &on_panic_attr);
904         if (rc) {
905                 firmware_unregister(&shutdown_actions_subsys);
906                 return rc;
907         }
908         atomic_notifier_chain_register(&panic_notifier_list,
909                                        &shutdown_on_panic_nb);
910         return 0;
911 }
912
913 static int __init s390_ipl_init(void)
914 {
915         int rc;
916
917         reipl_probe();
918         rc = ipl_init();
919         if (rc)
920                 return rc;
921         rc = reipl_init();
922         if (rc)
923                 return rc;
924         rc = dump_init();
925         if (rc)
926                 return rc;
927         rc = shutdown_actions_init();
928         if (rc)
929                 return rc;
930         return 0;
931 }
932
933 __initcall(s390_ipl_init);