[S390] Calibrate delay and bogomips.
[linux-block.git] / arch / s390 / kernel / ipl.c
CommitLineData
ff6b8ea6
MH
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>
03a4d208 16#include <linux/ctype.h>
ff6b8ea6
MH
17#include <asm/smp.h>
18#include <asm/setup.h>
19#include <asm/cpcmd.h>
20#include <asm/cio.h>
03a4d208 21#include <asm/ebcdic.h>
15e9b586 22#include <asm/reset.h>
ff6b8ea6
MH
23
24#define IPL_PARM_BLOCK_VERSION 0
03a4d208
MH
25#define LOADPARM_LEN 8
26
27extern 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])
ff6b8ea6
MH
31
32enum ipl_type {
33 IPL_TYPE_NONE = 1,
34 IPL_TYPE_UNKNOWN = 2,
35 IPL_TYPE_CCW = 4,
36 IPL_TYPE_FCP = 8,
fe355b7f 37 IPL_TYPE_NSS = 16,
ff6b8ea6
MH
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"
fe355b7f 44#define IPL_NSS_STR "nss"
ff6b8ea6
MH
45
46static 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;
fe355b7f
HY
55 case IPL_TYPE_NSS:
56 return IPL_NSS_STR;
ff6b8ea6
MH
57 case IPL_TYPE_UNKNOWN:
58 default:
59 return IPL_UNKNOWN_STR;
60 }
61}
62
63enum 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,
fe355b7f 71 IPL_METHOD_NSS,
ff6b8ea6
MH
72};
73
74enum 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
84static 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
98enum diag308_subcode {
99 DIAG308_IPL = 3,
100 DIAG308_DUMP = 4,
101 DIAG308_SET = 5,
102 DIAG308_STORE = 6,
103};
104
105enum diag308_ipl_type {
106 DIAG308_IPL_TYPE_FCP = 0,
107 DIAG308_IPL_TYPE_CCW = 2,
108};
109
110enum diag308_opt {
111 DIAG308_IPL_OPT_IPL = 0x10,
112 DIAG308_IPL_OPT_DUMP = 0x20,
113};
114
115enum diag308_rc {
116 DIAG308_RC_OK = 1,
117};
118
119static int diag308_set_works = 0;
120
121static int reipl_capabilities = IPL_TYPE_UNKNOWN;
fe355b7f 122
ff6b8ea6
MH
123static enum ipl_type reipl_type = IPL_TYPE_UNKNOWN;
124static enum ipl_method reipl_method = IPL_METHOD_NONE;
125static struct ipl_parameter_block *reipl_block_fcp;
126static struct ipl_parameter_block *reipl_block_ccw;
127
fe355b7f
HY
128static char reipl_nss_name[NSS_NAME_SIZE + 1];
129
ff6b8ea6
MH
130static int dump_capabilities = IPL_TYPE_NONE;
131static enum ipl_type dump_type = IPL_TYPE_NONE;
132static enum ipl_method dump_method = IPL_METHOD_NONE;
133static struct ipl_parameter_block *dump_block_fcp;
134static struct ipl_parameter_block *dump_block_ccw;
135
136static enum shutdown_action on_panic_action = SHUTDOWN_STOP;
137
138static int diag308(unsigned long subcode, void *addr)
139{
94c12cc7 140 register unsigned long _addr asm("0") = (unsigned long) addr;
ff6b8ea6
MH
141 register unsigned long _rc asm("1") = 0;
142
94c12cc7
MS
143 asm volatile(
144 " diag %0,%2,0x308\n"
145 "0:\n"
146 EX_TABLE(0b,0b)
ff6b8ea6 147 : "+d" (_addr), "+d" (_rc)
94c12cc7 148 : "d" (subcode) : "cc", "memory");
ff6b8ea6
MH
149 return _rc;
150}
151
152/* SYSFS */
153
154#define DEFINE_IPL_ATTR_RO(_prefix, _name, _format, _value) \
155static ssize_t sys_##_prefix##_##_name##_show(struct subsystem *subsys, \
156 char *page) \
157{ \
158 return sprintf(page, _format, _value); \
159} \
160static 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) \
164static 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} \
170static 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} \
179static 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
fe355b7f
HY
184#define DEFINE_IPL_ATTR_STR_RW(_prefix, _name, _fmt_out, _fmt_in, _value)\
185static ssize_t sys_##_prefix##_##_name##_show(struct subsystem *subsys, \
186 char *page) \
187{ \
188 return sprintf(page, _fmt_out, _value); \
189} \
190static 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} \
197static 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
ff6b8ea6
MH
202static 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
214static enum ipl_type ipl_get_type(void)
215{
216 struct ipl_parameter_block *ipl = IPL_PARMBLOCK_START;
217
fe355b7f
HY
218 if (ipl_flags & IPL_NSS_VALID)
219 return IPL_TYPE_NSS;
e87bfe51 220 if (!(ipl_flags & IPL_DEVNO_VALID))
ff6b8ea6 221 return IPL_TYPE_UNKNOWN;
e87bfe51 222 if (!(ipl_flags & IPL_PARMBLOCK_VALID))
ff6b8ea6
MH
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
231static 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
236static struct subsys_attribute sys_ipl_type_attr = __ATTR_RO(ipl_type);
237
238static 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
252static struct subsys_attribute sys_ipl_device_attr =
253 __ATTR(device, S_IRUGO, sys_ipl_device_show, NULL);
254
255static 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
268static 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
278static 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
292static 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
304DEFINE_IPL_ATTR_RO(ipl_fcp, wwpn, "0x%016llx\n", (unsigned long long)
305 IPL_PARMBLOCK_START->ipl_info.fcp.wwpn);
306DEFINE_IPL_ATTR_RO(ipl_fcp, lun, "0x%016llx\n", (unsigned long long)
307 IPL_PARMBLOCK_START->ipl_info.fcp.lun);
308DEFINE_IPL_ATTR_RO(ipl_fcp, bootprog, "%lld\n", (unsigned long long)
309 IPL_PARMBLOCK_START->ipl_info.fcp.bootprog);
310DEFINE_IPL_ATTR_RO(ipl_fcp, br_lba, "%lld\n", (unsigned long long)
311 IPL_PARMBLOCK_START->ipl_info.fcp.br_lba);
312
313static 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
323static struct attribute_group ipl_fcp_attr_group = {
324 .attrs = ipl_fcp_attrs,
325};
326
327/* CCW ipl device attributes */
328
03a4d208
MH
329static 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
341static struct subsys_attribute sys_ipl_ccw_loadparm_attr =
342 __ATTR(loadparm, 0444, ipl_ccw_loadparm_show, NULL);
343
ff6b8ea6
MH
344static struct attribute *ipl_ccw_attrs[] = {
345 &sys_ipl_type_attr.attr,
346 &sys_ipl_device_attr.attr,
03a4d208 347 &sys_ipl_ccw_loadparm_attr.attr,
ff6b8ea6
MH
348 NULL,
349};
350
351static struct attribute_group ipl_ccw_attr_group = {
352 .attrs = ipl_ccw_attrs,
353};
354
fe355b7f
HY
355/* NSS ipl device attributes */
356
357DEFINE_IPL_ATTR_RO(ipl_nss, name, "%s\n", kernel_nss_name);
358
359static struct attribute *ipl_nss_attrs[] = {
360 &sys_ipl_type_attr.attr,
361 &sys_ipl_nss_name_attr.attr,
362 NULL,
363};
364
365static struct attribute_group ipl_nss_attr_group = {
366 .attrs = ipl_nss_attrs,
367};
368
ff6b8ea6
MH
369/* UNKNOWN ipl device attributes */
370
371static struct attribute *ipl_unknown_attrs[] = {
372 &sys_ipl_type_attr.attr,
373 NULL,
374};
375
376static struct attribute_group ipl_unknown_attr_group = {
377 .attrs = ipl_unknown_attrs,
378};
379
380static decl_subsys(ipl, NULL, NULL);
381
382/*
383 * reipl section
384 */
385
386/* FCP reipl device attributes */
387
388DEFINE_IPL_ATTR_RW(reipl_fcp, wwpn, "0x%016llx\n", "%016llx\n",
389 reipl_block_fcp->ipl_info.fcp.wwpn);
390DEFINE_IPL_ATTR_RW(reipl_fcp, lun, "0x%016llx\n", "%016llx\n",
391 reipl_block_fcp->ipl_info.fcp.lun);
392DEFINE_IPL_ATTR_RW(reipl_fcp, bootprog, "%lld\n", "%lld\n",
393 reipl_block_fcp->ipl_info.fcp.bootprog);
394DEFINE_IPL_ATTR_RW(reipl_fcp, br_lba, "%lld\n", "%lld\n",
395 reipl_block_fcp->ipl_info.fcp.br_lba);
396DEFINE_IPL_ATTR_RW(reipl_fcp, device, "0.0.%04llx\n", "0.0.%llx\n",
397 reipl_block_fcp->ipl_info.fcp.devno);
398
399static 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
408static 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
415DEFINE_IPL_ATTR_RW(reipl_ccw, device, "0.0.%04llx\n", "0.0.%llx\n",
416 reipl_block_ccw->ipl_info.ccw.devno);
417
03a4d208
MH
418static 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
427static 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
435static 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
462static struct subsys_attribute sys_reipl_ccw_loadparm_attr =
463 __ATTR(loadparm, 0644, reipl_ccw_loadparm_show,
464 reipl_ccw_loadparm_store);
465
ff6b8ea6
MH
466static struct attribute *reipl_ccw_attrs[] = {
467 &sys_reipl_ccw_device_attr.attr,
03a4d208 468 &sys_reipl_ccw_loadparm_attr.attr,
ff6b8ea6
MH
469 NULL,
470};
471
472static struct attribute_group reipl_ccw_attr_group = {
473 .name = IPL_CCW_STR,
474 .attrs = reipl_ccw_attrs,
475};
476
fe355b7f
HY
477
478/* NSS reipl device attributes */
479
480DEFINE_IPL_ATTR_STR_RW(reipl_nss, name, "%s\n", "%s\n", reipl_nss_name);
481
482static struct attribute *reipl_nss_attrs[] = {
483 &sys_reipl_nss_name_attr.attr,
484 NULL,
485};
486
487static struct attribute_group reipl_nss_attr_group = {
488 .name = IPL_NSS_STR,
489 .attrs = reipl_nss_attrs,
490};
491
ff6b8ea6
MH
492/* reipl type */
493
494static 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;
fe355b7f
HY
514 case IPL_TYPE_NSS:
515 reipl_method = IPL_METHOD_NSS;
516 break;
ff6b8ea6
MH
517 default:
518 reipl_method = IPL_METHOD_NONE;
519 }
520 reipl_type = type;
521 return 0;
522}
523
524static ssize_t reipl_type_show(struct subsystem *subsys, char *page)
525{
526 return sprintf(page, "%s\n", ipl_type_str(reipl_type));
527}
528
529static 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);
fe355b7f
HY
538 else if (strncmp(buf, IPL_NSS_STR, strlen(IPL_NSS_STR)) == 0)
539 rc = reipl_set_type(IPL_TYPE_NSS);
ff6b8ea6
MH
540 return (rc != 0) ? rc : len;
541}
542
543static struct subsys_attribute reipl_type_attr =
544 __ATTR(reipl_type, 0644, reipl_type_show, reipl_type_store);
545
546static decl_subsys(reipl, NULL, NULL);
547
548/*
549 * dump section
550 */
551
552/* FCP dump device attributes */
553
554DEFINE_IPL_ATTR_RW(dump_fcp, wwpn, "0x%016llx\n", "%016llx\n",
555 dump_block_fcp->ipl_info.fcp.wwpn);
556DEFINE_IPL_ATTR_RW(dump_fcp, lun, "0x%016llx\n", "%016llx\n",
557 dump_block_fcp->ipl_info.fcp.lun);
558DEFINE_IPL_ATTR_RW(dump_fcp, bootprog, "%lld\n", "%lld\n",
559 dump_block_fcp->ipl_info.fcp.bootprog);
560DEFINE_IPL_ATTR_RW(dump_fcp, br_lba, "%lld\n", "%lld\n",
561 dump_block_fcp->ipl_info.fcp.br_lba);
562DEFINE_IPL_ATTR_RW(dump_fcp, device, "0.0.%04llx\n", "0.0.%llx\n",
563 dump_block_fcp->ipl_info.fcp.devno);
564
565static 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
574static 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
581DEFINE_IPL_ATTR_RW(dump_ccw, device, "0.0.%04llx\n", "0.0.%llx\n",
582 dump_block_ccw->ipl_info.ccw.devno);
583
584static struct attribute *dump_ccw_attrs[] = {
585 &sys_dump_ccw_device_attr.attr,
586 NULL,
587};
588
589static struct attribute_group dump_ccw_attr_group = {
590 .name = IPL_CCW_STR,
591 .attrs = dump_ccw_attrs,
592};
593
594/* dump type */
595
596static 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
617static ssize_t dump_type_show(struct subsystem *subsys, char *page)
618{
619 return sprintf(page, "%s\n", ipl_type_str(dump_type));
620}
621
622static 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
636static struct subsys_attribute dump_type_attr =
637 __ATTR(dump_type, 0644, dump_type_show, dump_type_store);
638
639static decl_subsys(dump, NULL, NULL);
640
ff6b8ea6
MH
641/*
642 * Shutdown actions section
643 */
644
645static decl_subsys(shutdown_actions, NULL, NULL);
646
647/* on panic */
648
649static 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
654static 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
671static struct subsys_attribute on_panic_attr =
672 __ATTR(on_panic, 0644, on_panic_show, on_panic_store);
673
ff6b8ea6
MH
674void do_reipl(void)
675{
676 struct ccw_dev_id devid;
677 static char buf[100];
03a4d208 678 char loadparm[LOADPARM_LEN + 1];
ff6b8ea6 679
ff6b8ea6
MH
680 switch (reipl_method) {
681 case IPL_METHOD_CCW_CIO:
682 devid.devno = reipl_block_ccw->ipl_info.ccw.devno;
5986b0e8
MH
683 if (ipl_get_type() == IPL_TYPE_CCW && devid.devno == ipl_devno)
684 diag308(DIAG308_IPL, NULL);
ff6b8ea6
MH
685 devid.ssid = 0;
686 reipl_ccw_dev(&devid);
687 break;
688 case IPL_METHOD_CCW_VM:
58be9441 689 reipl_get_ascii_loadparm(loadparm);
03a4d208
MH
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);
740b5706 696 __cpcmd(buf, NULL, 0, NULL);
ff6b8ea6
MH
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:
740b5706 710 __cpcmd("IPL", NULL, 0, NULL);
ff6b8ea6 711 break;
fe355b7f
HY
712 case IPL_METHOD_NSS:
713 sprintf(buf, "IPL %s", reipl_nss_name);
714 __cpcmd(buf, NULL, 0, NULL);
715 break;
ff6b8ea6
MH
716 case IPL_METHOD_NONE:
717 default:
718 if (MACHINE_IS_VM)
740b5706 719 __cpcmd("IPL", NULL, 0, NULL);
ff6b8ea6
MH
720 diag308(DIAG308_IPL, NULL);
721 break;
722 }
3902e476 723 signal_processor(smp_processor_id(), sigp_stop_and_store_status);
ff6b8ea6
MH
724}
725
726static void do_dump(void)
727{
728 struct ccw_dev_id devid;
729 static char buf[100];
730
ff6b8ea6
MH
731 switch (dump_method) {
732 case IPL_METHOD_CCW_CIO:
c6b5b847 733 smp_send_stop();
ff6b8ea6
MH
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:
c6b5b847 739 smp_send_stop();
ff6b8ea6 740 sprintf(buf, "STORE STATUS");
740b5706 741 __cpcmd(buf, NULL, 0, NULL);
ff6b8ea6 742 sprintf(buf, "IPL %X", dump_block_ccw->ipl_info.ccw.devno);
740b5706 743 __cpcmd(buf, NULL, 0, NULL);
ff6b8ea6
MH
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
762static 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
781out_ipl_parm:
782 sysfs_remove_group(&ipl_subsys.kset.kobj, &ipl_fcp_attr_group);
783out:
784 return rc;
785}
786
787static 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;
fe355b7f
HY
802 case IPL_TYPE_NSS:
803 rc = sysfs_create_group(&ipl_subsys.kset.kobj,
804 &ipl_nss_attr_group);
805 break;
ff6b8ea6
MH
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
816static 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
fe355b7f
HY
828static 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
ff6b8ea6
MH
842static 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;
03a4d208
MH
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;
ff6b8ea6
MH
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
875static 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
906static 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();
fe355b7f
HY
922 if (rc)
923 return rc;
924 rc = reipl_nss_init();
ff6b8ea6
MH
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
933static 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
ff6b8ea6
MH
953static int __init dump_fcp_init(void)
954{
955 int rc;
956
03a4d208 957 if(!(SCCB_FLAG & 0x2) || !SCCB_VALID)
ff6b8ea6
MH
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
980static 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
990static struct notifier_block shutdown_on_panic_nb = {
991 .notifier_call = shutdown_on_panic_notify,
992 .priority = SHUTDOWN_ON_PANIC_PRIO
993};
994
995static 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
1017static 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
1034static 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);
15e9b586
HC
1055
1056static LIST_HEAD(rcall);
1057static DEFINE_MUTEX(rcall_mutex);
1058
1059void 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}
1065EXPORT_SYMBOL_GPL(register_reset_call);
1066
1067void unregister_reset_call(struct reset_call *reset)
1068{
1069 mutex_lock(&rcall_mutex);
1070 list_del(&reset->list);
1071 mutex_unlock(&rcall_mutex);
1072}
1073EXPORT_SYMBOL_GPL(unregister_reset_call);
1074
1075static 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
1083extern void reset_mcck_handler(void);
a45e1414 1084extern void reset_pgm_handler(void);
da1cf23e 1085extern __u32 dump_prefix_page;
15e9b586
HC
1086
1087void s390_reset_system(void)
1088{
1089 struct _lowcore *lc;
1090
15e9b586 1091 lc = (struct _lowcore *)(unsigned long) store_prefix();
a45e1414
MH
1092
1093 /* Stack for interrupt/machine check handler */
15e9b586
HC
1094 lc->panic_stack = S390_lowcore.panic_stack;
1095
da1cf23e
MH
1096 /* Save prefix page address for dump case */
1097 dump_prefix_page = (unsigned long) lc;
1098
15e9b586
HC
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 */
c1821c2e 1106 S390_lowcore.mcck_new_psw.mask = psw_kernel_bits & ~PSW_MASK_MCHECK;
15e9b586
HC
1107 S390_lowcore.mcck_new_psw.addr =
1108 PSW_ADDR_AMODE | (unsigned long) &reset_mcck_handler;
a45e1414
MH
1109
1110 /* Set new program check handler */
c1821c2e 1111 S390_lowcore.program_new_psw.mask = psw_kernel_bits & ~PSW_MASK_MCHECK;
a45e1414
MH
1112 S390_lowcore.program_new_psw.addr =
1113 PSW_ADDR_AMODE | (unsigned long) &reset_pgm_handler;
1114
15e9b586
HC
1115 do_reset_calls();
1116}