[S390] boot from NSS support
[linux-block.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 <linux/ctype.h>
17 #include <asm/smp.h>
18 #include <asm/setup.h>
19 #include <asm/cpcmd.h>
20 #include <asm/cio.h>
21 #include <asm/ebcdic.h>
22 #include <asm/reset.h>
23
24 #define IPL_PARM_BLOCK_VERSION 0
25 #define LOADPARM_LEN 8
26
27 extern char s390_readinfo_sccb[];
28 #define SCCB_VALID (*((__u16*)&s390_readinfo_sccb[6]) == 0x0010)
29 #define SCCB_LOADPARM (&s390_readinfo_sccb[24])
30 #define SCCB_FLAG (s390_readinfo_sccb[91])
31
32 enum ipl_type {
33         IPL_TYPE_NONE    = 1,
34         IPL_TYPE_UNKNOWN = 2,
35         IPL_TYPE_CCW     = 4,
36         IPL_TYPE_FCP     = 8,
37         IPL_TYPE_NSS     = 16,
38 };
39
40 #define IPL_NONE_STR     "none"
41 #define IPL_UNKNOWN_STR  "unknown"
42 #define IPL_CCW_STR      "ccw"
43 #define IPL_FCP_STR      "fcp"
44 #define IPL_NSS_STR      "nss"
45
46 static char *ipl_type_str(enum ipl_type type)
47 {
48         switch (type) {
49         case IPL_TYPE_NONE:
50                 return IPL_NONE_STR;
51         case IPL_TYPE_CCW:
52                 return IPL_CCW_STR;
53         case IPL_TYPE_FCP:
54                 return IPL_FCP_STR;
55         case IPL_TYPE_NSS:
56                 return IPL_NSS_STR;
57         case IPL_TYPE_UNKNOWN:
58         default:
59                 return IPL_UNKNOWN_STR;
60         }
61 }
62
63 enum ipl_method {
64         IPL_METHOD_NONE,
65         IPL_METHOD_CCW_CIO,
66         IPL_METHOD_CCW_DIAG,
67         IPL_METHOD_CCW_VM,
68         IPL_METHOD_FCP_RO_DIAG,
69         IPL_METHOD_FCP_RW_DIAG,
70         IPL_METHOD_FCP_RO_VM,
71         IPL_METHOD_NSS,
72 };
73
74 enum shutdown_action {
75         SHUTDOWN_REIPL,
76         SHUTDOWN_DUMP,
77         SHUTDOWN_STOP,
78 };
79
80 #define SHUTDOWN_REIPL_STR "reipl"
81 #define SHUTDOWN_DUMP_STR  "dump"
82 #define SHUTDOWN_STOP_STR  "stop"
83
84 static char *shutdown_action_str(enum shutdown_action action)
85 {
86         switch (action) {
87         case SHUTDOWN_REIPL:
88                 return SHUTDOWN_REIPL_STR;
89         case SHUTDOWN_DUMP:
90                 return SHUTDOWN_DUMP_STR;
91         case SHUTDOWN_STOP:
92                 return SHUTDOWN_STOP_STR;
93         default:
94                 BUG();
95         }
96 }
97
98 enum diag308_subcode  {
99         DIAG308_IPL   = 3,
100         DIAG308_DUMP  = 4,
101         DIAG308_SET   = 5,
102         DIAG308_STORE = 6,
103 };
104
105 enum diag308_ipl_type {
106         DIAG308_IPL_TYPE_FCP = 0,
107         DIAG308_IPL_TYPE_CCW = 2,
108 };
109
110 enum diag308_opt {
111         DIAG308_IPL_OPT_IPL  = 0x10,
112         DIAG308_IPL_OPT_DUMP = 0x20,
113 };
114
115 enum diag308_rc {
116         DIAG308_RC_OK = 1,
117 };
118
119 static int diag308_set_works = 0;
120
121 static int reipl_capabilities = IPL_TYPE_UNKNOWN;
122
123 static enum ipl_type reipl_type = IPL_TYPE_UNKNOWN;
124 static enum ipl_method reipl_method = IPL_METHOD_NONE;
125 static struct ipl_parameter_block *reipl_block_fcp;
126 static struct ipl_parameter_block *reipl_block_ccw;
127
128 static char reipl_nss_name[NSS_NAME_SIZE + 1];
129
130 static int dump_capabilities = IPL_TYPE_NONE;
131 static enum ipl_type dump_type = IPL_TYPE_NONE;
132 static enum ipl_method dump_method = IPL_METHOD_NONE;
133 static struct ipl_parameter_block *dump_block_fcp;
134 static struct ipl_parameter_block *dump_block_ccw;
135
136 static enum shutdown_action on_panic_action = SHUTDOWN_STOP;
137
138 static int diag308(unsigned long subcode, void *addr)
139 {
140         register unsigned long _addr asm("0") = (unsigned long) addr;
141         register unsigned long _rc asm("1") = 0;
142
143         asm volatile(
144                 "       diag    %0,%2,0x308\n"
145                 "0:\n"
146                 EX_TABLE(0b,0b)
147                 : "+d" (_addr), "+d" (_rc)
148                 : "d" (subcode) : "cc", "memory");
149         return _rc;
150 }
151
152 /* SYSFS */
153
154 #define DEFINE_IPL_ATTR_RO(_prefix, _name, _format, _value)             \
155 static ssize_t sys_##_prefix##_##_name##_show(struct subsystem *subsys, \
156                 char *page)                                             \
157 {                                                                       \
158         return sprintf(page, _format, _value);                          \
159 }                                                                       \
160 static struct subsys_attribute sys_##_prefix##_##_name##_attr =         \
161         __ATTR(_name, S_IRUGO, sys_##_prefix##_##_name##_show, NULL);
162
163 #define DEFINE_IPL_ATTR_RW(_prefix, _name, _fmt_out, _fmt_in, _value)   \
164 static ssize_t sys_##_prefix##_##_name##_show(struct subsystem *subsys, \
165                 char *page)                                             \
166 {                                                                       \
167         return sprintf(page, _fmt_out,                                  \
168                         (unsigned long long) _value);                   \
169 }                                                                       \
170 static ssize_t sys_##_prefix##_##_name##_store(struct subsystem *subsys,\
171                 const char *buf, size_t len)                            \
172 {                                                                       \
173         unsigned long long value;                                       \
174         if (sscanf(buf, _fmt_in, &value) != 1)                          \
175                 return -EINVAL;                                         \
176         _value = value;                                                 \
177         return len;                                                     \
178 }                                                                       \
179 static struct subsys_attribute sys_##_prefix##_##_name##_attr =         \
180         __ATTR(_name,(S_IRUGO | S_IWUSR),                               \
181                         sys_##_prefix##_##_name##_show,                 \
182                         sys_##_prefix##_##_name##_store);
183
184 #define DEFINE_IPL_ATTR_STR_RW(_prefix, _name, _fmt_out, _fmt_in, _value)\
185 static ssize_t sys_##_prefix##_##_name##_show(struct subsystem *subsys, \
186                 char *page)                                             \
187 {                                                                       \
188         return sprintf(page, _fmt_out, _value);                         \
189 }                                                                       \
190 static ssize_t sys_##_prefix##_##_name##_store(struct subsystem *subsys,\
191                 const char *buf, size_t len)                            \
192 {                                                                       \
193         if (sscanf(buf, _fmt_in, _value) != 1)                          \
194                 return -EINVAL;                                         \
195         return len;                                                     \
196 }                                                                       \
197 static struct subsys_attribute sys_##_prefix##_##_name##_attr =         \
198         __ATTR(_name,(S_IRUGO | S_IWUSR),                               \
199                         sys_##_prefix##_##_name##_show,                 \
200                         sys_##_prefix##_##_name##_store);
201
202 static void make_attrs_ro(struct attribute **attrs)
203 {
204         while (*attrs) {
205                 (*attrs)->mode = S_IRUGO;
206                 attrs++;
207         }
208 }
209
210 /*
211  * ipl section
212  */
213
214 static enum ipl_type ipl_get_type(void)
215 {
216         struct ipl_parameter_block *ipl = IPL_PARMBLOCK_START;
217
218         if (ipl_flags & IPL_NSS_VALID)
219                 return IPL_TYPE_NSS;
220         if (!(ipl_flags & IPL_DEVNO_VALID))
221                 return IPL_TYPE_UNKNOWN;
222         if (!(ipl_flags & IPL_PARMBLOCK_VALID))
223                 return IPL_TYPE_CCW;
224         if (ipl->hdr.version > IPL_MAX_SUPPORTED_VERSION)
225                 return IPL_TYPE_UNKNOWN;
226         if (ipl->hdr.pbt != DIAG308_IPL_TYPE_FCP)
227                 return IPL_TYPE_UNKNOWN;
228         return IPL_TYPE_FCP;
229 }
230
231 static ssize_t ipl_type_show(struct subsystem *subsys, char *page)
232 {
233         return sprintf(page, "%s\n", ipl_type_str(ipl_get_type()));
234 }
235
236 static struct subsys_attribute sys_ipl_type_attr = __ATTR_RO(ipl_type);
237
238 static ssize_t sys_ipl_device_show(struct subsystem *subsys, char *page)
239 {
240         struct ipl_parameter_block *ipl = IPL_PARMBLOCK_START;
241
242         switch (ipl_get_type()) {
243         case IPL_TYPE_CCW:
244                 return sprintf(page, "0.0.%04x\n", ipl_devno);
245         case IPL_TYPE_FCP:
246                 return sprintf(page, "0.0.%04x\n", ipl->ipl_info.fcp.devno);
247         default:
248                 return 0;
249         }
250 }
251
252 static struct subsys_attribute sys_ipl_device_attr =
253         __ATTR(device, S_IRUGO, sys_ipl_device_show, NULL);
254
255 static ssize_t ipl_parameter_read(struct kobject *kobj, char *buf, loff_t off,
256                                   size_t count)
257 {
258         unsigned int size = IPL_PARMBLOCK_SIZE;
259
260         if (off > size)
261                 return 0;
262         if (off + count > size)
263                 count = size - off;
264         memcpy(buf, (void *)IPL_PARMBLOCK_START + off, count);
265         return count;
266 }
267
268 static struct bin_attribute ipl_parameter_attr = {
269         .attr = {
270                 .name = "binary_parameter",
271                 .mode = S_IRUGO,
272                 .owner = THIS_MODULE,
273         },
274         .size = PAGE_SIZE,
275         .read = &ipl_parameter_read,
276 };
277
278 static ssize_t ipl_scp_data_read(struct kobject *kobj, char *buf, loff_t off,
279         size_t count)
280 {
281         unsigned int size = IPL_PARMBLOCK_START->ipl_info.fcp.scp_data_len;
282         void *scp_data = &IPL_PARMBLOCK_START->ipl_info.fcp.scp_data;
283
284         if (off > size)
285                 return 0;
286         if (off + count > size)
287                 count = size - off;
288         memcpy(buf, scp_data + off, count);
289         return count;
290 }
291
292 static struct bin_attribute ipl_scp_data_attr = {
293         .attr = {
294                 .name = "scp_data",
295                 .mode = S_IRUGO,
296                 .owner = THIS_MODULE,
297         },
298         .size = PAGE_SIZE,
299         .read = &ipl_scp_data_read,
300 };
301
302 /* FCP ipl device attributes */
303
304 DEFINE_IPL_ATTR_RO(ipl_fcp, wwpn, "0x%016llx\n", (unsigned long long)
305                    IPL_PARMBLOCK_START->ipl_info.fcp.wwpn);
306 DEFINE_IPL_ATTR_RO(ipl_fcp, lun, "0x%016llx\n", (unsigned long long)
307                    IPL_PARMBLOCK_START->ipl_info.fcp.lun);
308 DEFINE_IPL_ATTR_RO(ipl_fcp, bootprog, "%lld\n", (unsigned long long)
309                    IPL_PARMBLOCK_START->ipl_info.fcp.bootprog);
310 DEFINE_IPL_ATTR_RO(ipl_fcp, br_lba, "%lld\n", (unsigned long long)
311                    IPL_PARMBLOCK_START->ipl_info.fcp.br_lba);
312
313 static struct attribute *ipl_fcp_attrs[] = {
314         &sys_ipl_type_attr.attr,
315         &sys_ipl_device_attr.attr,
316         &sys_ipl_fcp_wwpn_attr.attr,
317         &sys_ipl_fcp_lun_attr.attr,
318         &sys_ipl_fcp_bootprog_attr.attr,
319         &sys_ipl_fcp_br_lba_attr.attr,
320         NULL,
321 };
322
323 static struct attribute_group ipl_fcp_attr_group = {
324         .attrs = ipl_fcp_attrs,
325 };
326
327 /* CCW ipl device attributes */
328
329 static ssize_t ipl_ccw_loadparm_show(struct subsystem *subsys, char *page)
330 {
331         char loadparm[LOADPARM_LEN + 1] = {};
332
333         if (!SCCB_VALID)
334                 return sprintf(page, "#unknown#\n");
335         memcpy(loadparm, SCCB_LOADPARM, LOADPARM_LEN);
336         EBCASC(loadparm, LOADPARM_LEN);
337         strstrip(loadparm);
338         return sprintf(page, "%s\n", loadparm);
339 }
340
341 static struct subsys_attribute sys_ipl_ccw_loadparm_attr =
342         __ATTR(loadparm, 0444, ipl_ccw_loadparm_show, NULL);
343
344 static struct attribute *ipl_ccw_attrs[] = {
345         &sys_ipl_type_attr.attr,
346         &sys_ipl_device_attr.attr,
347         &sys_ipl_ccw_loadparm_attr.attr,
348         NULL,
349 };
350
351 static struct attribute_group ipl_ccw_attr_group = {
352         .attrs = ipl_ccw_attrs,
353 };
354
355 /* NSS ipl device attributes */
356
357 DEFINE_IPL_ATTR_RO(ipl_nss, name, "%s\n", kernel_nss_name);
358
359 static struct attribute *ipl_nss_attrs[] = {
360         &sys_ipl_type_attr.attr,
361         &sys_ipl_nss_name_attr.attr,
362         NULL,
363 };
364
365 static struct attribute_group ipl_nss_attr_group = {
366         .attrs = ipl_nss_attrs,
367 };
368
369 /* UNKNOWN ipl device attributes */
370
371 static struct attribute *ipl_unknown_attrs[] = {
372         &sys_ipl_type_attr.attr,
373         NULL,
374 };
375
376 static struct attribute_group ipl_unknown_attr_group = {
377         .attrs = ipl_unknown_attrs,
378 };
379
380 static decl_subsys(ipl, NULL, NULL);
381
382 /*
383  * reipl section
384  */
385
386 /* FCP reipl device attributes */
387
388 DEFINE_IPL_ATTR_RW(reipl_fcp, wwpn, "0x%016llx\n", "%016llx\n",
389                    reipl_block_fcp->ipl_info.fcp.wwpn);
390 DEFINE_IPL_ATTR_RW(reipl_fcp, lun, "0x%016llx\n", "%016llx\n",
391                    reipl_block_fcp->ipl_info.fcp.lun);
392 DEFINE_IPL_ATTR_RW(reipl_fcp, bootprog, "%lld\n", "%lld\n",
393                    reipl_block_fcp->ipl_info.fcp.bootprog);
394 DEFINE_IPL_ATTR_RW(reipl_fcp, br_lba, "%lld\n", "%lld\n",
395                    reipl_block_fcp->ipl_info.fcp.br_lba);
396 DEFINE_IPL_ATTR_RW(reipl_fcp, device, "0.0.%04llx\n", "0.0.%llx\n",
397                    reipl_block_fcp->ipl_info.fcp.devno);
398
399 static struct attribute *reipl_fcp_attrs[] = {
400         &sys_reipl_fcp_device_attr.attr,
401         &sys_reipl_fcp_wwpn_attr.attr,
402         &sys_reipl_fcp_lun_attr.attr,
403         &sys_reipl_fcp_bootprog_attr.attr,
404         &sys_reipl_fcp_br_lba_attr.attr,
405         NULL,
406 };
407
408 static struct attribute_group reipl_fcp_attr_group = {
409         .name  = IPL_FCP_STR,
410         .attrs = reipl_fcp_attrs,
411 };
412
413 /* CCW reipl device attributes */
414
415 DEFINE_IPL_ATTR_RW(reipl_ccw, device, "0.0.%04llx\n", "0.0.%llx\n",
416         reipl_block_ccw->ipl_info.ccw.devno);
417
418 static void reipl_get_ascii_loadparm(char *loadparm)
419 {
420         memcpy(loadparm, &reipl_block_ccw->ipl_info.ccw.load_param,
421                LOADPARM_LEN);
422         EBCASC(loadparm, LOADPARM_LEN);
423         loadparm[LOADPARM_LEN] = 0;
424         strstrip(loadparm);
425 }
426
427 static ssize_t reipl_ccw_loadparm_show(struct subsystem *subsys, char *page)
428 {
429         char buf[LOADPARM_LEN + 1];
430
431         reipl_get_ascii_loadparm(buf);
432         return sprintf(page, "%s\n", buf);
433 }
434
435 static ssize_t reipl_ccw_loadparm_store(struct subsystem *subsys,
436                                         const char *buf, size_t len)
437 {
438         int i, lp_len;
439
440         /* ignore trailing newline */
441         lp_len = len;
442         if ((len > 0) && (buf[len - 1] == '\n'))
443                 lp_len--;
444         /* loadparm can have max 8 characters and must not start with a blank */
445         if ((lp_len > LOADPARM_LEN) || ((lp_len > 0) && (buf[0] == ' ')))
446                 return -EINVAL;
447         /* loadparm can only contain "a-z,A-Z,0-9,SP,." */
448         for (i = 0; i < lp_len; i++) {
449                 if (isalpha(buf[i]) || isdigit(buf[i]) || (buf[i] == ' ') ||
450                     (buf[i] == '.'))
451                         continue;
452                 return -EINVAL;
453         }
454         /* initialize loadparm with blanks */
455         memset(&reipl_block_ccw->ipl_info.ccw.load_param, ' ', LOADPARM_LEN);
456         /* copy and convert to ebcdic */
457         memcpy(&reipl_block_ccw->ipl_info.ccw.load_param, buf, lp_len);
458         ASCEBC(reipl_block_ccw->ipl_info.ccw.load_param, LOADPARM_LEN);
459         return len;
460 }
461
462 static struct subsys_attribute sys_reipl_ccw_loadparm_attr =
463         __ATTR(loadparm, 0644, reipl_ccw_loadparm_show,
464                reipl_ccw_loadparm_store);
465
466 static struct attribute *reipl_ccw_attrs[] = {
467         &sys_reipl_ccw_device_attr.attr,
468         &sys_reipl_ccw_loadparm_attr.attr,
469         NULL,
470 };
471
472 static struct attribute_group reipl_ccw_attr_group = {
473         .name  = IPL_CCW_STR,
474         .attrs = reipl_ccw_attrs,
475 };
476
477
478 /* NSS reipl device attributes */
479
480 DEFINE_IPL_ATTR_STR_RW(reipl_nss, name, "%s\n", "%s\n", reipl_nss_name);
481
482 static struct attribute *reipl_nss_attrs[] = {
483         &sys_reipl_nss_name_attr.attr,
484         NULL,
485 };
486
487 static struct attribute_group reipl_nss_attr_group = {
488         .name  = IPL_NSS_STR,
489         .attrs = reipl_nss_attrs,
490 };
491
492 /* reipl type */
493
494 static int reipl_set_type(enum ipl_type type)
495 {
496         if (!(reipl_capabilities & type))
497                 return -EINVAL;
498
499         switch(type) {
500         case IPL_TYPE_CCW:
501                 if (MACHINE_IS_VM)
502                         reipl_method = IPL_METHOD_CCW_VM;
503                 else
504                         reipl_method = IPL_METHOD_CCW_CIO;
505                 break;
506         case IPL_TYPE_FCP:
507                 if (diag308_set_works)
508                         reipl_method = IPL_METHOD_FCP_RW_DIAG;
509                 else if (MACHINE_IS_VM)
510                         reipl_method = IPL_METHOD_FCP_RO_VM;
511                 else
512                         reipl_method = IPL_METHOD_FCP_RO_DIAG;
513                 break;
514         case IPL_TYPE_NSS:
515                 reipl_method = IPL_METHOD_NSS;
516                 break;
517         default:
518                 reipl_method = IPL_METHOD_NONE;
519         }
520         reipl_type = type;
521         return 0;
522 }
523
524 static ssize_t reipl_type_show(struct subsystem *subsys, char *page)
525 {
526         return sprintf(page, "%s\n", ipl_type_str(reipl_type));
527 }
528
529 static ssize_t reipl_type_store(struct subsystem *subsys, const char *buf,
530                                 size_t len)
531 {
532         int rc = -EINVAL;
533
534         if (strncmp(buf, IPL_CCW_STR, strlen(IPL_CCW_STR)) == 0)
535                 rc = reipl_set_type(IPL_TYPE_CCW);
536         else if (strncmp(buf, IPL_FCP_STR, strlen(IPL_FCP_STR)) == 0)
537                 rc = reipl_set_type(IPL_TYPE_FCP);
538         else if (strncmp(buf, IPL_NSS_STR, strlen(IPL_NSS_STR)) == 0)
539                 rc = reipl_set_type(IPL_TYPE_NSS);
540         return (rc != 0) ? rc : len;
541 }
542
543 static struct subsys_attribute reipl_type_attr =
544                 __ATTR(reipl_type, 0644, reipl_type_show, reipl_type_store);
545
546 static decl_subsys(reipl, NULL, NULL);
547
548 /*
549  * dump section
550  */
551
552 /* FCP dump device attributes */
553
554 DEFINE_IPL_ATTR_RW(dump_fcp, wwpn, "0x%016llx\n", "%016llx\n",
555                    dump_block_fcp->ipl_info.fcp.wwpn);
556 DEFINE_IPL_ATTR_RW(dump_fcp, lun, "0x%016llx\n", "%016llx\n",
557                    dump_block_fcp->ipl_info.fcp.lun);
558 DEFINE_IPL_ATTR_RW(dump_fcp, bootprog, "%lld\n", "%lld\n",
559                    dump_block_fcp->ipl_info.fcp.bootprog);
560 DEFINE_IPL_ATTR_RW(dump_fcp, br_lba, "%lld\n", "%lld\n",
561                    dump_block_fcp->ipl_info.fcp.br_lba);
562 DEFINE_IPL_ATTR_RW(dump_fcp, device, "0.0.%04llx\n", "0.0.%llx\n",
563                    dump_block_fcp->ipl_info.fcp.devno);
564
565 static struct attribute *dump_fcp_attrs[] = {
566         &sys_dump_fcp_device_attr.attr,
567         &sys_dump_fcp_wwpn_attr.attr,
568         &sys_dump_fcp_lun_attr.attr,
569         &sys_dump_fcp_bootprog_attr.attr,
570         &sys_dump_fcp_br_lba_attr.attr,
571         NULL,
572 };
573
574 static struct attribute_group dump_fcp_attr_group = {
575         .name  = IPL_FCP_STR,
576         .attrs = dump_fcp_attrs,
577 };
578
579 /* CCW dump device attributes */
580
581 DEFINE_IPL_ATTR_RW(dump_ccw, device, "0.0.%04llx\n", "0.0.%llx\n",
582                    dump_block_ccw->ipl_info.ccw.devno);
583
584 static struct attribute *dump_ccw_attrs[] = {
585         &sys_dump_ccw_device_attr.attr,
586         NULL,
587 };
588
589 static struct attribute_group dump_ccw_attr_group = {
590         .name  = IPL_CCW_STR,
591         .attrs = dump_ccw_attrs,
592 };
593
594 /* dump type */
595
596 static int dump_set_type(enum ipl_type type)
597 {
598         if (!(dump_capabilities & type))
599                 return -EINVAL;
600         switch(type) {
601         case IPL_TYPE_CCW:
602                 if (MACHINE_IS_VM)
603                         dump_method = IPL_METHOD_CCW_VM;
604                 else
605                         dump_method = IPL_METHOD_CCW_CIO;
606                 break;
607         case IPL_TYPE_FCP:
608                 dump_method = IPL_METHOD_FCP_RW_DIAG;
609                 break;
610         default:
611                 dump_method = IPL_METHOD_NONE;
612         }
613         dump_type = type;
614         return 0;
615 }
616
617 static ssize_t dump_type_show(struct subsystem *subsys, char *page)
618 {
619         return sprintf(page, "%s\n", ipl_type_str(dump_type));
620 }
621
622 static ssize_t dump_type_store(struct subsystem *subsys, const char *buf,
623                                size_t len)
624 {
625         int rc = -EINVAL;
626
627         if (strncmp(buf, IPL_NONE_STR, strlen(IPL_NONE_STR)) == 0)
628                 rc = dump_set_type(IPL_TYPE_NONE);
629         else if (strncmp(buf, IPL_CCW_STR, strlen(IPL_CCW_STR)) == 0)
630                 rc = dump_set_type(IPL_TYPE_CCW);
631         else if (strncmp(buf, IPL_FCP_STR, strlen(IPL_FCP_STR)) == 0)
632                 rc = dump_set_type(IPL_TYPE_FCP);
633         return (rc != 0) ? rc : len;
634 }
635
636 static struct subsys_attribute dump_type_attr =
637                 __ATTR(dump_type, 0644, dump_type_show, dump_type_store);
638
639 static decl_subsys(dump, NULL, NULL);
640
641 /*
642  * Shutdown actions section
643  */
644
645 static decl_subsys(shutdown_actions, NULL, NULL);
646
647 /* on panic */
648
649 static ssize_t on_panic_show(struct subsystem *subsys, char *page)
650 {
651         return sprintf(page, "%s\n", shutdown_action_str(on_panic_action));
652 }
653
654 static ssize_t on_panic_store(struct subsystem *subsys, const char *buf,
655                               size_t len)
656 {
657         if (strncmp(buf, SHUTDOWN_REIPL_STR, strlen(SHUTDOWN_REIPL_STR)) == 0)
658                 on_panic_action = SHUTDOWN_REIPL;
659         else if (strncmp(buf, SHUTDOWN_DUMP_STR,
660                          strlen(SHUTDOWN_DUMP_STR)) == 0)
661                 on_panic_action = SHUTDOWN_DUMP;
662         else if (strncmp(buf, SHUTDOWN_STOP_STR,
663                          strlen(SHUTDOWN_STOP_STR)) == 0)
664                 on_panic_action = SHUTDOWN_STOP;
665         else
666                 return -EINVAL;
667
668         return len;
669 }
670
671 static struct subsys_attribute on_panic_attr =
672                 __ATTR(on_panic, 0644, on_panic_show, on_panic_store);
673
674 void do_reipl(void)
675 {
676         struct ccw_dev_id devid;
677         static char buf[100];
678         char loadparm[LOADPARM_LEN + 1];
679
680         switch (reipl_method) {
681         case IPL_METHOD_CCW_CIO:
682                 devid.devno = reipl_block_ccw->ipl_info.ccw.devno;
683                 if (ipl_get_type() == IPL_TYPE_CCW && devid.devno == ipl_devno)
684                         diag308(DIAG308_IPL, NULL);
685                 devid.ssid  = 0;
686                 reipl_ccw_dev(&devid);
687                 break;
688         case IPL_METHOD_CCW_VM:
689                 reipl_get_ascii_loadparm(loadparm);
690                 if (strlen(loadparm) == 0)
691                         sprintf(buf, "IPL %X",
692                                 reipl_block_ccw->ipl_info.ccw.devno);
693                 else
694                         sprintf(buf, "IPL %X LOADPARM '%s'",
695                                 reipl_block_ccw->ipl_info.ccw.devno, loadparm);
696                 __cpcmd(buf, NULL, 0, NULL);
697                 break;
698         case IPL_METHOD_CCW_DIAG:
699                 diag308(DIAG308_SET, reipl_block_ccw);
700                 diag308(DIAG308_IPL, NULL);
701                 break;
702         case IPL_METHOD_FCP_RW_DIAG:
703                 diag308(DIAG308_SET, reipl_block_fcp);
704                 diag308(DIAG308_IPL, NULL);
705                 break;
706         case IPL_METHOD_FCP_RO_DIAG:
707                 diag308(DIAG308_IPL, NULL);
708                 break;
709         case IPL_METHOD_FCP_RO_VM:
710                 __cpcmd("IPL", NULL, 0, NULL);
711                 break;
712         case IPL_METHOD_NSS:
713                 sprintf(buf, "IPL %s", reipl_nss_name);
714                 __cpcmd(buf, NULL, 0, NULL);
715                 break;
716         case IPL_METHOD_NONE:
717         default:
718                 if (MACHINE_IS_VM)
719                         __cpcmd("IPL", NULL, 0, NULL);
720                 diag308(DIAG308_IPL, NULL);
721                 break;
722         }
723         signal_processor(smp_processor_id(), sigp_stop_and_store_status);
724 }
725
726 static void do_dump(void)
727 {
728         struct ccw_dev_id devid;
729         static char buf[100];
730
731         switch (dump_method) {
732         case IPL_METHOD_CCW_CIO:
733                 smp_send_stop();
734                 devid.devno = dump_block_ccw->ipl_info.ccw.devno;
735                 devid.ssid  = 0;
736                 reipl_ccw_dev(&devid);
737                 break;
738         case IPL_METHOD_CCW_VM:
739                 smp_send_stop();
740                 sprintf(buf, "STORE STATUS");
741                 __cpcmd(buf, NULL, 0, NULL);
742                 sprintf(buf, "IPL %X", dump_block_ccw->ipl_info.ccw.devno);
743                 __cpcmd(buf, NULL, 0, NULL);
744                 break;
745         case IPL_METHOD_CCW_DIAG:
746                 diag308(DIAG308_SET, dump_block_ccw);
747                 diag308(DIAG308_DUMP, NULL);
748                 break;
749         case IPL_METHOD_FCP_RW_DIAG:
750                 diag308(DIAG308_SET, dump_block_fcp);
751                 diag308(DIAG308_DUMP, NULL);
752                 break;
753         case IPL_METHOD_NONE:
754         default:
755                 return;
756         }
757         printk(KERN_EMERG "Dump failed!\n");
758 }
759
760 /* init functions */
761
762 static int __init ipl_register_fcp_files(void)
763 {
764         int rc;
765
766         rc = sysfs_create_group(&ipl_subsys.kset.kobj,
767                                 &ipl_fcp_attr_group);
768         if (rc)
769                 goto out;
770         rc = sysfs_create_bin_file(&ipl_subsys.kset.kobj,
771                                    &ipl_parameter_attr);
772         if (rc)
773                 goto out_ipl_parm;
774         rc = sysfs_create_bin_file(&ipl_subsys.kset.kobj,
775                                    &ipl_scp_data_attr);
776         if (!rc)
777                 goto out;
778
779         sysfs_remove_bin_file(&ipl_subsys.kset.kobj, &ipl_parameter_attr);
780
781 out_ipl_parm:
782         sysfs_remove_group(&ipl_subsys.kset.kobj, &ipl_fcp_attr_group);
783 out:
784         return rc;
785 }
786
787 static int __init ipl_init(void)
788 {
789         int rc;
790
791         rc = firmware_register(&ipl_subsys);
792         if (rc)
793                 return rc;
794         switch (ipl_get_type()) {
795         case IPL_TYPE_CCW:
796                 rc = sysfs_create_group(&ipl_subsys.kset.kobj,
797                                         &ipl_ccw_attr_group);
798                 break;
799         case IPL_TYPE_FCP:
800                 rc = ipl_register_fcp_files();
801                 break;
802         case IPL_TYPE_NSS:
803                 rc = sysfs_create_group(&ipl_subsys.kset.kobj,
804                                         &ipl_nss_attr_group);
805                 break;
806         default:
807                 rc = sysfs_create_group(&ipl_subsys.kset.kobj,
808                                         &ipl_unknown_attr_group);
809                 break;
810         }
811         if (rc)
812                 firmware_unregister(&ipl_subsys);
813         return rc;
814 }
815
816 static void __init reipl_probe(void)
817 {
818         void *buffer;
819
820         buffer = (void *) get_zeroed_page(GFP_KERNEL);
821         if (!buffer)
822                 return;
823         if (diag308(DIAG308_STORE, buffer) == DIAG308_RC_OK)
824                 diag308_set_works = 1;
825         free_page((unsigned long)buffer);
826 }
827
828 static int __init reipl_nss_init(void)
829 {
830         int rc;
831
832         if (!MACHINE_IS_VM)
833                 return 0;
834         rc = sysfs_create_group(&reipl_subsys.kset.kobj, &reipl_nss_attr_group);
835         if (rc)
836                 return rc;
837         strncpy(reipl_nss_name, kernel_nss_name, NSS_NAME_SIZE + 1);
838         reipl_capabilities |= IPL_TYPE_NSS;
839         return 0;
840 }
841
842 static int __init reipl_ccw_init(void)
843 {
844         int rc;
845
846         reipl_block_ccw = (void *) get_zeroed_page(GFP_KERNEL);
847         if (!reipl_block_ccw)
848                 return -ENOMEM;
849         rc = sysfs_create_group(&reipl_subsys.kset.kobj, &reipl_ccw_attr_group);
850         if (rc) {
851                 free_page((unsigned long)reipl_block_ccw);
852                 return rc;
853         }
854         reipl_block_ccw->hdr.len = IPL_PARM_BLK_CCW_LEN;
855         reipl_block_ccw->hdr.version = IPL_PARM_BLOCK_VERSION;
856         reipl_block_ccw->hdr.blk0_len = sizeof(reipl_block_ccw->ipl_info.ccw);
857         reipl_block_ccw->hdr.pbt = DIAG308_IPL_TYPE_CCW;
858         /* check if read scp info worked and set loadparm */
859         if (SCCB_VALID)
860                 memcpy(reipl_block_ccw->ipl_info.ccw.load_param,
861                        SCCB_LOADPARM, LOADPARM_LEN);
862         else
863                 /* read scp info failed: set empty loadparm (EBCDIC blanks) */
864                 memset(reipl_block_ccw->ipl_info.ccw.load_param, 0x40,
865                        LOADPARM_LEN);
866         /* FIXME: check for diag308_set_works when enabling diag ccw reipl */
867         if (!MACHINE_IS_VM)
868                 sys_reipl_ccw_loadparm_attr.attr.mode = S_IRUGO;
869         if (ipl_get_type() == IPL_TYPE_CCW)
870                 reipl_block_ccw->ipl_info.ccw.devno = ipl_devno;
871         reipl_capabilities |= IPL_TYPE_CCW;
872         return 0;
873 }
874
875 static int __init reipl_fcp_init(void)
876 {
877         int rc;
878
879         if ((!diag308_set_works) && (ipl_get_type() != IPL_TYPE_FCP))
880                 return 0;
881         if ((!diag308_set_works) && (ipl_get_type() == IPL_TYPE_FCP))
882                 make_attrs_ro(reipl_fcp_attrs);
883
884         reipl_block_fcp = (void *) get_zeroed_page(GFP_KERNEL);
885         if (!reipl_block_fcp)
886                 return -ENOMEM;
887         rc = sysfs_create_group(&reipl_subsys.kset.kobj, &reipl_fcp_attr_group);
888         if (rc) {
889                 free_page((unsigned long)reipl_block_fcp);
890                 return rc;
891         }
892         if (ipl_get_type() == IPL_TYPE_FCP) {
893                 memcpy(reipl_block_fcp, IPL_PARMBLOCK_START, PAGE_SIZE);
894         } else {
895                 reipl_block_fcp->hdr.len = IPL_PARM_BLK_FCP_LEN;
896                 reipl_block_fcp->hdr.version = IPL_PARM_BLOCK_VERSION;
897                 reipl_block_fcp->hdr.blk0_len =
898                         sizeof(reipl_block_fcp->ipl_info.fcp);
899                 reipl_block_fcp->hdr.pbt = DIAG308_IPL_TYPE_FCP;
900                 reipl_block_fcp->ipl_info.fcp.opt = DIAG308_IPL_OPT_IPL;
901         }
902         reipl_capabilities |= IPL_TYPE_FCP;
903         return 0;
904 }
905
906 static int __init reipl_init(void)
907 {
908         int rc;
909
910         rc = firmware_register(&reipl_subsys);
911         if (rc)
912                 return rc;
913         rc = subsys_create_file(&reipl_subsys, &reipl_type_attr);
914         if (rc) {
915                 firmware_unregister(&reipl_subsys);
916                 return rc;
917         }
918         rc = reipl_ccw_init();
919         if (rc)
920                 return rc;
921         rc = reipl_fcp_init();
922         if (rc)
923                 return rc;
924         rc = reipl_nss_init();
925         if (rc)
926                 return rc;
927         rc = reipl_set_type(ipl_get_type());
928         if (rc)
929                 return rc;
930         return 0;
931 }
932
933 static int __init dump_ccw_init(void)
934 {
935         int rc;
936
937         dump_block_ccw = (void *) get_zeroed_page(GFP_KERNEL);
938         if (!dump_block_ccw)
939                 return -ENOMEM;
940         rc = sysfs_create_group(&dump_subsys.kset.kobj, &dump_ccw_attr_group);
941         if (rc) {
942                 free_page((unsigned long)dump_block_ccw);
943                 return rc;
944         }
945         dump_block_ccw->hdr.len = IPL_PARM_BLK_CCW_LEN;
946         dump_block_ccw->hdr.version = IPL_PARM_BLOCK_VERSION;
947         dump_block_ccw->hdr.blk0_len = sizeof(reipl_block_ccw->ipl_info.ccw);
948         dump_block_ccw->hdr.pbt = DIAG308_IPL_TYPE_CCW;
949         dump_capabilities |= IPL_TYPE_CCW;
950         return 0;
951 }
952
953 static int __init dump_fcp_init(void)
954 {
955         int rc;
956
957         if(!(SCCB_FLAG & 0x2) || !SCCB_VALID)
958                 return 0; /* LDIPL DUMP is not installed */
959         if (!diag308_set_works)
960                 return 0;
961         dump_block_fcp = (void *) get_zeroed_page(GFP_KERNEL);
962         if (!dump_block_fcp)
963                 return -ENOMEM;
964         rc = sysfs_create_group(&dump_subsys.kset.kobj, &dump_fcp_attr_group);
965         if (rc) {
966                 free_page((unsigned long)dump_block_fcp);
967                 return rc;
968         }
969         dump_block_fcp->hdr.len = IPL_PARM_BLK_FCP_LEN;
970         dump_block_fcp->hdr.version = IPL_PARM_BLOCK_VERSION;
971         dump_block_fcp->hdr.blk0_len = sizeof(dump_block_fcp->ipl_info.fcp);
972         dump_block_fcp->hdr.pbt = DIAG308_IPL_TYPE_FCP;
973         dump_block_fcp->ipl_info.fcp.opt = DIAG308_IPL_OPT_DUMP;
974         dump_capabilities |= IPL_TYPE_FCP;
975         return 0;
976 }
977
978 #define SHUTDOWN_ON_PANIC_PRIO 0
979
980 static int shutdown_on_panic_notify(struct notifier_block *self,
981                                     unsigned long event, void *data)
982 {
983         if (on_panic_action == SHUTDOWN_DUMP)
984                 do_dump();
985         else if (on_panic_action == SHUTDOWN_REIPL)
986                 do_reipl();
987         return NOTIFY_OK;
988 }
989
990 static struct notifier_block shutdown_on_panic_nb = {
991         .notifier_call = shutdown_on_panic_notify,
992         .priority = SHUTDOWN_ON_PANIC_PRIO
993 };
994
995 static int __init dump_init(void)
996 {
997         int rc;
998
999         rc = firmware_register(&dump_subsys);
1000         if (rc)
1001                 return rc;
1002         rc = subsys_create_file(&dump_subsys, &dump_type_attr);
1003         if (rc) {
1004                 firmware_unregister(&dump_subsys);
1005                 return rc;
1006         }
1007         rc = dump_ccw_init();
1008         if (rc)
1009                 return rc;
1010         rc = dump_fcp_init();
1011         if (rc)
1012                 return rc;
1013         dump_set_type(IPL_TYPE_NONE);
1014         return 0;
1015 }
1016
1017 static int __init shutdown_actions_init(void)
1018 {
1019         int rc;
1020
1021         rc = firmware_register(&shutdown_actions_subsys);
1022         if (rc)
1023                 return rc;
1024         rc = subsys_create_file(&shutdown_actions_subsys, &on_panic_attr);
1025         if (rc) {
1026                 firmware_unregister(&shutdown_actions_subsys);
1027                 return rc;
1028         }
1029         atomic_notifier_chain_register(&panic_notifier_list,
1030                                        &shutdown_on_panic_nb);
1031         return 0;
1032 }
1033
1034 static int __init s390_ipl_init(void)
1035 {
1036         int rc;
1037
1038         reipl_probe();
1039         rc = ipl_init();
1040         if (rc)
1041                 return rc;
1042         rc = reipl_init();
1043         if (rc)
1044                 return rc;
1045         rc = dump_init();
1046         if (rc)
1047                 return rc;
1048         rc = shutdown_actions_init();
1049         if (rc)
1050                 return rc;
1051         return 0;
1052 }
1053
1054 __initcall(s390_ipl_init);
1055
1056 static LIST_HEAD(rcall);
1057 static DEFINE_MUTEX(rcall_mutex);
1058
1059 void register_reset_call(struct reset_call *reset)
1060 {
1061         mutex_lock(&rcall_mutex);
1062         list_add(&reset->list, &rcall);
1063         mutex_unlock(&rcall_mutex);
1064 }
1065 EXPORT_SYMBOL_GPL(register_reset_call);
1066
1067 void unregister_reset_call(struct reset_call *reset)
1068 {
1069         mutex_lock(&rcall_mutex);
1070         list_del(&reset->list);
1071         mutex_unlock(&rcall_mutex);
1072 }
1073 EXPORT_SYMBOL_GPL(unregister_reset_call);
1074
1075 static void do_reset_calls(void)
1076 {
1077         struct reset_call *reset;
1078
1079         list_for_each_entry(reset, &rcall, list)
1080                 reset->fn();
1081 }
1082
1083 extern void reset_mcck_handler(void);
1084 extern void reset_pgm_handler(void);
1085 extern __u32 dump_prefix_page;
1086
1087 void s390_reset_system(void)
1088 {
1089         struct _lowcore *lc;
1090
1091         lc = (struct _lowcore *)(unsigned long) store_prefix();
1092
1093         /* Stack for interrupt/machine check handler */
1094         lc->panic_stack = S390_lowcore.panic_stack;
1095
1096         /* Save prefix page address for dump case */
1097         dump_prefix_page = (unsigned long) lc;
1098
1099         /* Disable prefixing */
1100         set_prefix(0);
1101
1102         /* Disable lowcore protection */
1103         __ctl_clear_bit(0,28);
1104
1105         /* Set new machine check handler */
1106         S390_lowcore.mcck_new_psw.mask = psw_kernel_bits & ~PSW_MASK_MCHECK;
1107         S390_lowcore.mcck_new_psw.addr =
1108                 PSW_ADDR_AMODE | (unsigned long) &reset_mcck_handler;
1109
1110         /* Set new program check handler */
1111         S390_lowcore.program_new_psw.mask = psw_kernel_bits & ~PSW_MASK_MCHECK;
1112         S390_lowcore.program_new_psw.addr =
1113                 PSW_ADDR_AMODE | (unsigned long) &reset_pgm_handler;
1114
1115         do_reset_calls();
1116 }