ipl.c 26 KB

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