ipl.c 27 KB

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