ipl.c 28 KB

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