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