ipl.c 26 KB

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