ipl.c 28 KB

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