ipl.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942
  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 <asm/smp.h>
  16. #include <asm/setup.h>
  17. #include <asm/cpcmd.h>
  18. #include <asm/cio.h>
  19. #define IPL_PARM_BLOCK_VERSION 0
  20. enum ipl_type {
  21. IPL_TYPE_NONE = 1,
  22. IPL_TYPE_UNKNOWN = 2,
  23. IPL_TYPE_CCW = 4,
  24. IPL_TYPE_FCP = 8,
  25. };
  26. #define IPL_NONE_STR "none"
  27. #define IPL_UNKNOWN_STR "unknown"
  28. #define IPL_CCW_STR "ccw"
  29. #define IPL_FCP_STR "fcp"
  30. static char *ipl_type_str(enum ipl_type type)
  31. {
  32. switch (type) {
  33. case IPL_TYPE_NONE:
  34. return IPL_NONE_STR;
  35. case IPL_TYPE_CCW:
  36. return IPL_CCW_STR;
  37. case IPL_TYPE_FCP:
  38. return IPL_FCP_STR;
  39. case IPL_TYPE_UNKNOWN:
  40. default:
  41. return IPL_UNKNOWN_STR;
  42. }
  43. }
  44. enum ipl_method {
  45. IPL_METHOD_NONE,
  46. IPL_METHOD_CCW_CIO,
  47. IPL_METHOD_CCW_DIAG,
  48. IPL_METHOD_CCW_VM,
  49. IPL_METHOD_FCP_RO_DIAG,
  50. IPL_METHOD_FCP_RW_DIAG,
  51. IPL_METHOD_FCP_RO_VM,
  52. };
  53. enum shutdown_action {
  54. SHUTDOWN_REIPL,
  55. SHUTDOWN_DUMP,
  56. SHUTDOWN_STOP,
  57. };
  58. #define SHUTDOWN_REIPL_STR "reipl"
  59. #define SHUTDOWN_DUMP_STR "dump"
  60. #define SHUTDOWN_STOP_STR "stop"
  61. static char *shutdown_action_str(enum shutdown_action action)
  62. {
  63. switch (action) {
  64. case SHUTDOWN_REIPL:
  65. return SHUTDOWN_REIPL_STR;
  66. case SHUTDOWN_DUMP:
  67. return SHUTDOWN_DUMP_STR;
  68. case SHUTDOWN_STOP:
  69. return SHUTDOWN_STOP_STR;
  70. default:
  71. BUG();
  72. }
  73. }
  74. enum diag308_subcode {
  75. DIAG308_IPL = 3,
  76. DIAG308_DUMP = 4,
  77. DIAG308_SET = 5,
  78. DIAG308_STORE = 6,
  79. };
  80. enum diag308_ipl_type {
  81. DIAG308_IPL_TYPE_FCP = 0,
  82. DIAG308_IPL_TYPE_CCW = 2,
  83. };
  84. enum diag308_opt {
  85. DIAG308_IPL_OPT_IPL = 0x10,
  86. DIAG308_IPL_OPT_DUMP = 0x20,
  87. };
  88. enum diag308_rc {
  89. DIAG308_RC_OK = 1,
  90. };
  91. static int diag308_set_works = 0;
  92. static int reipl_capabilities = IPL_TYPE_UNKNOWN;
  93. static enum ipl_type reipl_type = IPL_TYPE_UNKNOWN;
  94. static enum ipl_method reipl_method = IPL_METHOD_NONE;
  95. static struct ipl_parameter_block *reipl_block_fcp;
  96. static struct ipl_parameter_block *reipl_block_ccw;
  97. static int dump_capabilities = IPL_TYPE_NONE;
  98. static enum ipl_type dump_type = IPL_TYPE_NONE;
  99. static enum ipl_method dump_method = IPL_METHOD_NONE;
  100. static struct ipl_parameter_block *dump_block_fcp;
  101. static struct ipl_parameter_block *dump_block_ccw;
  102. static enum shutdown_action on_panic_action = SHUTDOWN_STOP;
  103. static int diag308(unsigned long subcode, void *addr)
  104. {
  105. register unsigned long _addr asm("0") = (unsigned long)addr;
  106. register unsigned long _rc asm("1") = 0;
  107. asm volatile (
  108. " diag %0,%2,0x308\n"
  109. "0: \n"
  110. ".section __ex_table,\"a\"\n"
  111. #ifdef CONFIG_64BIT
  112. " .align 8\n"
  113. " .quad 0b, 0b\n"
  114. #else
  115. " .align 4\n"
  116. " .long 0b, 0b\n"
  117. #endif
  118. ".previous\n"
  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 struct attribute *ipl_ccw_attrs[] = {
  258. &sys_ipl_type_attr.attr,
  259. &sys_ipl_device_attr.attr,
  260. NULL,
  261. };
  262. static struct attribute_group ipl_ccw_attr_group = {
  263. .attrs = ipl_ccw_attrs,
  264. };
  265. /* UNKNOWN ipl device attributes */
  266. static struct attribute *ipl_unknown_attrs[] = {
  267. &sys_ipl_type_attr.attr,
  268. NULL,
  269. };
  270. static struct attribute_group ipl_unknown_attr_group = {
  271. .attrs = ipl_unknown_attrs,
  272. };
  273. static decl_subsys(ipl, NULL, NULL);
  274. /*
  275. * reipl section
  276. */
  277. /* FCP reipl device attributes */
  278. DEFINE_IPL_ATTR_RW(reipl_fcp, wwpn, "0x%016llx\n", "%016llx\n",
  279. reipl_block_fcp->ipl_info.fcp.wwpn);
  280. DEFINE_IPL_ATTR_RW(reipl_fcp, lun, "0x%016llx\n", "%016llx\n",
  281. reipl_block_fcp->ipl_info.fcp.lun);
  282. DEFINE_IPL_ATTR_RW(reipl_fcp, bootprog, "%lld\n", "%lld\n",
  283. reipl_block_fcp->ipl_info.fcp.bootprog);
  284. DEFINE_IPL_ATTR_RW(reipl_fcp, br_lba, "%lld\n", "%lld\n",
  285. reipl_block_fcp->ipl_info.fcp.br_lba);
  286. DEFINE_IPL_ATTR_RW(reipl_fcp, device, "0.0.%04llx\n", "0.0.%llx\n",
  287. reipl_block_fcp->ipl_info.fcp.devno);
  288. static struct attribute *reipl_fcp_attrs[] = {
  289. &sys_reipl_fcp_device_attr.attr,
  290. &sys_reipl_fcp_wwpn_attr.attr,
  291. &sys_reipl_fcp_lun_attr.attr,
  292. &sys_reipl_fcp_bootprog_attr.attr,
  293. &sys_reipl_fcp_br_lba_attr.attr,
  294. NULL,
  295. };
  296. static struct attribute_group reipl_fcp_attr_group = {
  297. .name = IPL_FCP_STR,
  298. .attrs = reipl_fcp_attrs,
  299. };
  300. /* CCW reipl device attributes */
  301. DEFINE_IPL_ATTR_RW(reipl_ccw, device, "0.0.%04llx\n", "0.0.%llx\n",
  302. reipl_block_ccw->ipl_info.ccw.devno);
  303. static struct attribute *reipl_ccw_attrs[] = {
  304. &sys_reipl_ccw_device_attr.attr,
  305. NULL,
  306. };
  307. static struct attribute_group reipl_ccw_attr_group = {
  308. .name = IPL_CCW_STR,
  309. .attrs = reipl_ccw_attrs,
  310. };
  311. /* reipl type */
  312. static int reipl_set_type(enum ipl_type type)
  313. {
  314. if (!(reipl_capabilities & type))
  315. return -EINVAL;
  316. switch(type) {
  317. case IPL_TYPE_CCW:
  318. if (MACHINE_IS_VM)
  319. reipl_method = IPL_METHOD_CCW_VM;
  320. else
  321. reipl_method = IPL_METHOD_CCW_CIO;
  322. break;
  323. case IPL_TYPE_FCP:
  324. if (diag308_set_works)
  325. reipl_method = IPL_METHOD_FCP_RW_DIAG;
  326. else if (MACHINE_IS_VM)
  327. reipl_method = IPL_METHOD_FCP_RO_VM;
  328. else
  329. reipl_method = IPL_METHOD_FCP_RO_DIAG;
  330. break;
  331. default:
  332. reipl_method = IPL_METHOD_NONE;
  333. }
  334. reipl_type = type;
  335. return 0;
  336. }
  337. static ssize_t reipl_type_show(struct subsystem *subsys, char *page)
  338. {
  339. return sprintf(page, "%s\n", ipl_type_str(reipl_type));
  340. }
  341. static ssize_t reipl_type_store(struct subsystem *subsys, const char *buf,
  342. size_t len)
  343. {
  344. int rc = -EINVAL;
  345. if (strncmp(buf, IPL_CCW_STR, strlen(IPL_CCW_STR)) == 0)
  346. rc = reipl_set_type(IPL_TYPE_CCW);
  347. else if (strncmp(buf, IPL_FCP_STR, strlen(IPL_FCP_STR)) == 0)
  348. rc = reipl_set_type(IPL_TYPE_FCP);
  349. return (rc != 0) ? rc : len;
  350. }
  351. static struct subsys_attribute reipl_type_attr =
  352. __ATTR(reipl_type, 0644, reipl_type_show, reipl_type_store);
  353. static decl_subsys(reipl, NULL, NULL);
  354. /*
  355. * dump section
  356. */
  357. /* FCP dump device attributes */
  358. DEFINE_IPL_ATTR_RW(dump_fcp, wwpn, "0x%016llx\n", "%016llx\n",
  359. dump_block_fcp->ipl_info.fcp.wwpn);
  360. DEFINE_IPL_ATTR_RW(dump_fcp, lun, "0x%016llx\n", "%016llx\n",
  361. dump_block_fcp->ipl_info.fcp.lun);
  362. DEFINE_IPL_ATTR_RW(dump_fcp, bootprog, "%lld\n", "%lld\n",
  363. dump_block_fcp->ipl_info.fcp.bootprog);
  364. DEFINE_IPL_ATTR_RW(dump_fcp, br_lba, "%lld\n", "%lld\n",
  365. dump_block_fcp->ipl_info.fcp.br_lba);
  366. DEFINE_IPL_ATTR_RW(dump_fcp, device, "0.0.%04llx\n", "0.0.%llx\n",
  367. dump_block_fcp->ipl_info.fcp.devno);
  368. static struct attribute *dump_fcp_attrs[] = {
  369. &sys_dump_fcp_device_attr.attr,
  370. &sys_dump_fcp_wwpn_attr.attr,
  371. &sys_dump_fcp_lun_attr.attr,
  372. &sys_dump_fcp_bootprog_attr.attr,
  373. &sys_dump_fcp_br_lba_attr.attr,
  374. NULL,
  375. };
  376. static struct attribute_group dump_fcp_attr_group = {
  377. .name = IPL_FCP_STR,
  378. .attrs = dump_fcp_attrs,
  379. };
  380. /* CCW dump device attributes */
  381. DEFINE_IPL_ATTR_RW(dump_ccw, device, "0.0.%04llx\n", "0.0.%llx\n",
  382. dump_block_ccw->ipl_info.ccw.devno);
  383. static struct attribute *dump_ccw_attrs[] = {
  384. &sys_dump_ccw_device_attr.attr,
  385. NULL,
  386. };
  387. static struct attribute_group dump_ccw_attr_group = {
  388. .name = IPL_CCW_STR,
  389. .attrs = dump_ccw_attrs,
  390. };
  391. /* dump type */
  392. static int dump_set_type(enum ipl_type type)
  393. {
  394. if (!(dump_capabilities & type))
  395. return -EINVAL;
  396. switch(type) {
  397. case IPL_TYPE_CCW:
  398. if (MACHINE_IS_VM)
  399. dump_method = IPL_METHOD_CCW_VM;
  400. else
  401. dump_method = IPL_METHOD_CCW_CIO;
  402. break;
  403. case IPL_TYPE_FCP:
  404. dump_method = IPL_METHOD_FCP_RW_DIAG;
  405. break;
  406. default:
  407. dump_method = IPL_METHOD_NONE;
  408. }
  409. dump_type = type;
  410. return 0;
  411. }
  412. static ssize_t dump_type_show(struct subsystem *subsys, char *page)
  413. {
  414. return sprintf(page, "%s\n", ipl_type_str(dump_type));
  415. }
  416. static ssize_t dump_type_store(struct subsystem *subsys, const char *buf,
  417. size_t len)
  418. {
  419. int rc = -EINVAL;
  420. if (strncmp(buf, IPL_NONE_STR, strlen(IPL_NONE_STR)) == 0)
  421. rc = dump_set_type(IPL_TYPE_NONE);
  422. else if (strncmp(buf, IPL_CCW_STR, strlen(IPL_CCW_STR)) == 0)
  423. rc = dump_set_type(IPL_TYPE_CCW);
  424. else if (strncmp(buf, IPL_FCP_STR, strlen(IPL_FCP_STR)) == 0)
  425. rc = dump_set_type(IPL_TYPE_FCP);
  426. return (rc != 0) ? rc : len;
  427. }
  428. static struct subsys_attribute dump_type_attr =
  429. __ATTR(dump_type, 0644, dump_type_show, dump_type_store);
  430. static decl_subsys(dump, NULL, NULL);
  431. #ifdef CONFIG_SMP
  432. static void dump_smp_stop_all(void)
  433. {
  434. int cpu;
  435. preempt_disable();
  436. for_each_online_cpu(cpu) {
  437. if (cpu == smp_processor_id())
  438. continue;
  439. while (signal_processor(cpu, sigp_stop) == sigp_busy)
  440. udelay(10);
  441. }
  442. preempt_enable();
  443. }
  444. #else
  445. #define dump_smp_stop_all() do { } while (0)
  446. #endif
  447. /*
  448. * Shutdown actions section
  449. */
  450. static decl_subsys(shutdown_actions, NULL, NULL);
  451. /* on panic */
  452. static ssize_t on_panic_show(struct subsystem *subsys, char *page)
  453. {
  454. return sprintf(page, "%s\n", shutdown_action_str(on_panic_action));
  455. }
  456. static ssize_t on_panic_store(struct subsystem *subsys, const char *buf,
  457. size_t len)
  458. {
  459. if (strncmp(buf, SHUTDOWN_REIPL_STR, strlen(SHUTDOWN_REIPL_STR)) == 0)
  460. on_panic_action = SHUTDOWN_REIPL;
  461. else if (strncmp(buf, SHUTDOWN_DUMP_STR,
  462. strlen(SHUTDOWN_DUMP_STR)) == 0)
  463. on_panic_action = SHUTDOWN_DUMP;
  464. else if (strncmp(buf, SHUTDOWN_STOP_STR,
  465. strlen(SHUTDOWN_STOP_STR)) == 0)
  466. on_panic_action = SHUTDOWN_STOP;
  467. else
  468. return -EINVAL;
  469. return len;
  470. }
  471. static struct subsys_attribute on_panic_attr =
  472. __ATTR(on_panic, 0644, on_panic_show, on_panic_store);
  473. static void print_fcp_block(struct ipl_parameter_block *fcp_block)
  474. {
  475. printk(KERN_EMERG "wwpn: %016llx\n",
  476. (unsigned long long)fcp_block->ipl_info.fcp.wwpn);
  477. printk(KERN_EMERG "lun: %016llx\n",
  478. (unsigned long long)fcp_block->ipl_info.fcp.lun);
  479. printk(KERN_EMERG "bootprog: %lld\n",
  480. (unsigned long long)fcp_block->ipl_info.fcp.bootprog);
  481. printk(KERN_EMERG "br_lba: %lld\n",
  482. (unsigned long long)fcp_block->ipl_info.fcp.br_lba);
  483. printk(KERN_EMERG "device: %llx\n",
  484. (unsigned long long)fcp_block->ipl_info.fcp.devno);
  485. printk(KERN_EMERG "opt: %x\n", fcp_block->ipl_info.fcp.opt);
  486. }
  487. void do_reipl(void)
  488. {
  489. struct ccw_dev_id devid;
  490. static char buf[100];
  491. switch (reipl_type) {
  492. case IPL_TYPE_CCW:
  493. printk(KERN_EMERG "reboot on ccw device: 0.0.%04x\n",
  494. reipl_block_ccw->ipl_info.ccw.devno);
  495. break;
  496. case IPL_TYPE_FCP:
  497. printk(KERN_EMERG "reboot on fcp device:\n");
  498. print_fcp_block(reipl_block_fcp);
  499. break;
  500. default:
  501. break;
  502. }
  503. switch (reipl_method) {
  504. case IPL_METHOD_CCW_CIO:
  505. devid.devno = reipl_block_ccw->ipl_info.ccw.devno;
  506. devid.ssid = 0;
  507. reipl_ccw_dev(&devid);
  508. break;
  509. case IPL_METHOD_CCW_VM:
  510. sprintf(buf, "IPL %X", reipl_block_ccw->ipl_info.ccw.devno);
  511. cpcmd(buf, NULL, 0, NULL);
  512. break;
  513. case IPL_METHOD_CCW_DIAG:
  514. diag308(DIAG308_SET, reipl_block_ccw);
  515. diag308(DIAG308_IPL, NULL);
  516. break;
  517. case IPL_METHOD_FCP_RW_DIAG:
  518. diag308(DIAG308_SET, reipl_block_fcp);
  519. diag308(DIAG308_IPL, NULL);
  520. break;
  521. case IPL_METHOD_FCP_RO_DIAG:
  522. diag308(DIAG308_IPL, NULL);
  523. break;
  524. case IPL_METHOD_FCP_RO_VM:
  525. cpcmd("IPL", NULL, 0, NULL);
  526. break;
  527. case IPL_METHOD_NONE:
  528. default:
  529. if (MACHINE_IS_VM)
  530. cpcmd("IPL", NULL, 0, NULL);
  531. diag308(DIAG308_IPL, NULL);
  532. break;
  533. }
  534. panic("reipl failed!\n");
  535. }
  536. static void do_dump(void)
  537. {
  538. struct ccw_dev_id devid;
  539. static char buf[100];
  540. switch (dump_type) {
  541. case IPL_TYPE_CCW:
  542. printk(KERN_EMERG "Automatic dump on ccw device: 0.0.%04x\n",
  543. dump_block_ccw->ipl_info.ccw.devno);
  544. break;
  545. case IPL_TYPE_FCP:
  546. printk(KERN_EMERG "Automatic dump on fcp device:\n");
  547. print_fcp_block(dump_block_fcp);
  548. break;
  549. default:
  550. return;
  551. }
  552. switch (dump_method) {
  553. case IPL_METHOD_CCW_CIO:
  554. dump_smp_stop_all();
  555. devid.devno = dump_block_ccw->ipl_info.ccw.devno;
  556. devid.ssid = 0;
  557. reipl_ccw_dev(&devid);
  558. break;
  559. case IPL_METHOD_CCW_VM:
  560. dump_smp_stop_all();
  561. sprintf(buf, "STORE STATUS");
  562. cpcmd(buf, NULL, 0, NULL);
  563. sprintf(buf, "IPL %X", dump_block_ccw->ipl_info.ccw.devno);
  564. cpcmd(buf, NULL, 0, NULL);
  565. break;
  566. case IPL_METHOD_CCW_DIAG:
  567. diag308(DIAG308_SET, dump_block_ccw);
  568. diag308(DIAG308_DUMP, NULL);
  569. break;
  570. case IPL_METHOD_FCP_RW_DIAG:
  571. diag308(DIAG308_SET, dump_block_fcp);
  572. diag308(DIAG308_DUMP, NULL);
  573. break;
  574. case IPL_METHOD_NONE:
  575. default:
  576. return;
  577. }
  578. printk(KERN_EMERG "Dump failed!\n");
  579. }
  580. /* init functions */
  581. static int __init ipl_register_fcp_files(void)
  582. {
  583. int rc;
  584. rc = sysfs_create_group(&ipl_subsys.kset.kobj,
  585. &ipl_fcp_attr_group);
  586. if (rc)
  587. goto out;
  588. rc = sysfs_create_bin_file(&ipl_subsys.kset.kobj,
  589. &ipl_parameter_attr);
  590. if (rc)
  591. goto out_ipl_parm;
  592. rc = sysfs_create_bin_file(&ipl_subsys.kset.kobj,
  593. &ipl_scp_data_attr);
  594. if (!rc)
  595. goto out;
  596. sysfs_remove_bin_file(&ipl_subsys.kset.kobj, &ipl_parameter_attr);
  597. out_ipl_parm:
  598. sysfs_remove_group(&ipl_subsys.kset.kobj, &ipl_fcp_attr_group);
  599. out:
  600. return rc;
  601. }
  602. static int __init ipl_init(void)
  603. {
  604. int rc;
  605. rc = firmware_register(&ipl_subsys);
  606. if (rc)
  607. return rc;
  608. switch (ipl_get_type()) {
  609. case IPL_TYPE_CCW:
  610. rc = sysfs_create_group(&ipl_subsys.kset.kobj,
  611. &ipl_ccw_attr_group);
  612. break;
  613. case IPL_TYPE_FCP:
  614. rc = ipl_register_fcp_files();
  615. break;
  616. default:
  617. rc = sysfs_create_group(&ipl_subsys.kset.kobj,
  618. &ipl_unknown_attr_group);
  619. break;
  620. }
  621. if (rc)
  622. firmware_unregister(&ipl_subsys);
  623. return rc;
  624. }
  625. static void __init reipl_probe(void)
  626. {
  627. void *buffer;
  628. buffer = (void *) get_zeroed_page(GFP_KERNEL);
  629. if (!buffer)
  630. return;
  631. if (diag308(DIAG308_STORE, buffer) == DIAG308_RC_OK)
  632. diag308_set_works = 1;
  633. free_page((unsigned long)buffer);
  634. }
  635. static int __init reipl_ccw_init(void)
  636. {
  637. int rc;
  638. reipl_block_ccw = (void *) get_zeroed_page(GFP_KERNEL);
  639. if (!reipl_block_ccw)
  640. return -ENOMEM;
  641. rc = sysfs_create_group(&reipl_subsys.kset.kobj, &reipl_ccw_attr_group);
  642. if (rc) {
  643. free_page((unsigned long)reipl_block_ccw);
  644. return rc;
  645. }
  646. reipl_block_ccw->hdr.len = IPL_PARM_BLK_CCW_LEN;
  647. reipl_block_ccw->hdr.version = IPL_PARM_BLOCK_VERSION;
  648. reipl_block_ccw->hdr.blk0_len = sizeof(reipl_block_ccw->ipl_info.ccw);
  649. reipl_block_ccw->hdr.pbt = DIAG308_IPL_TYPE_CCW;
  650. if (ipl_get_type() == IPL_TYPE_CCW)
  651. reipl_block_ccw->ipl_info.ccw.devno = ipl_devno;
  652. reipl_capabilities |= IPL_TYPE_CCW;
  653. return 0;
  654. }
  655. static int __init reipl_fcp_init(void)
  656. {
  657. int rc;
  658. if ((!diag308_set_works) && (ipl_get_type() != IPL_TYPE_FCP))
  659. return 0;
  660. if ((!diag308_set_works) && (ipl_get_type() == IPL_TYPE_FCP))
  661. make_attrs_ro(reipl_fcp_attrs);
  662. reipl_block_fcp = (void *) get_zeroed_page(GFP_KERNEL);
  663. if (!reipl_block_fcp)
  664. return -ENOMEM;
  665. rc = sysfs_create_group(&reipl_subsys.kset.kobj, &reipl_fcp_attr_group);
  666. if (rc) {
  667. free_page((unsigned long)reipl_block_fcp);
  668. return rc;
  669. }
  670. if (ipl_get_type() == IPL_TYPE_FCP) {
  671. memcpy(reipl_block_fcp, IPL_PARMBLOCK_START, PAGE_SIZE);
  672. } else {
  673. reipl_block_fcp->hdr.len = IPL_PARM_BLK_FCP_LEN;
  674. reipl_block_fcp->hdr.version = IPL_PARM_BLOCK_VERSION;
  675. reipl_block_fcp->hdr.blk0_len =
  676. sizeof(reipl_block_fcp->ipl_info.fcp);
  677. reipl_block_fcp->hdr.pbt = DIAG308_IPL_TYPE_FCP;
  678. reipl_block_fcp->ipl_info.fcp.opt = DIAG308_IPL_OPT_IPL;
  679. }
  680. reipl_capabilities |= IPL_TYPE_FCP;
  681. return 0;
  682. }
  683. static int __init reipl_init(void)
  684. {
  685. int rc;
  686. rc = firmware_register(&reipl_subsys);
  687. if (rc)
  688. return rc;
  689. rc = subsys_create_file(&reipl_subsys, &reipl_type_attr);
  690. if (rc) {
  691. firmware_unregister(&reipl_subsys);
  692. return rc;
  693. }
  694. rc = reipl_ccw_init();
  695. if (rc)
  696. return rc;
  697. rc = reipl_fcp_init();
  698. if (rc)
  699. return rc;
  700. rc = reipl_set_type(ipl_get_type());
  701. if (rc)
  702. return rc;
  703. return 0;
  704. }
  705. static int __init dump_ccw_init(void)
  706. {
  707. int rc;
  708. dump_block_ccw = (void *) get_zeroed_page(GFP_KERNEL);
  709. if (!dump_block_ccw)
  710. return -ENOMEM;
  711. rc = sysfs_create_group(&dump_subsys.kset.kobj, &dump_ccw_attr_group);
  712. if (rc) {
  713. free_page((unsigned long)dump_block_ccw);
  714. return rc;
  715. }
  716. dump_block_ccw->hdr.len = IPL_PARM_BLK_CCW_LEN;
  717. dump_block_ccw->hdr.version = IPL_PARM_BLOCK_VERSION;
  718. dump_block_ccw->hdr.blk0_len = sizeof(reipl_block_ccw->ipl_info.ccw);
  719. dump_block_ccw->hdr.pbt = DIAG308_IPL_TYPE_CCW;
  720. dump_capabilities |= IPL_TYPE_CCW;
  721. return 0;
  722. }
  723. extern char s390_readinfo_sccb[];
  724. static int __init dump_fcp_init(void)
  725. {
  726. int rc;
  727. if(!(s390_readinfo_sccb[91] & 0x2))
  728. return 0; /* LDIPL DUMP is not installed */
  729. if (!diag308_set_works)
  730. return 0;
  731. dump_block_fcp = (void *) get_zeroed_page(GFP_KERNEL);
  732. if (!dump_block_fcp)
  733. return -ENOMEM;
  734. rc = sysfs_create_group(&dump_subsys.kset.kobj, &dump_fcp_attr_group);
  735. if (rc) {
  736. free_page((unsigned long)dump_block_fcp);
  737. return rc;
  738. }
  739. dump_block_fcp->hdr.len = IPL_PARM_BLK_FCP_LEN;
  740. dump_block_fcp->hdr.version = IPL_PARM_BLOCK_VERSION;
  741. dump_block_fcp->hdr.blk0_len = sizeof(dump_block_fcp->ipl_info.fcp);
  742. dump_block_fcp->hdr.pbt = DIAG308_IPL_TYPE_FCP;
  743. dump_block_fcp->ipl_info.fcp.opt = DIAG308_IPL_OPT_DUMP;
  744. dump_capabilities |= IPL_TYPE_FCP;
  745. return 0;
  746. }
  747. #define SHUTDOWN_ON_PANIC_PRIO 0
  748. static int shutdown_on_panic_notify(struct notifier_block *self,
  749. unsigned long event, void *data)
  750. {
  751. if (on_panic_action == SHUTDOWN_DUMP)
  752. do_dump();
  753. else if (on_panic_action == SHUTDOWN_REIPL)
  754. do_reipl();
  755. return NOTIFY_OK;
  756. }
  757. static struct notifier_block shutdown_on_panic_nb = {
  758. .notifier_call = shutdown_on_panic_notify,
  759. .priority = SHUTDOWN_ON_PANIC_PRIO
  760. };
  761. static int __init dump_init(void)
  762. {
  763. int rc;
  764. rc = firmware_register(&dump_subsys);
  765. if (rc)
  766. return rc;
  767. rc = subsys_create_file(&dump_subsys, &dump_type_attr);
  768. if (rc) {
  769. firmware_unregister(&dump_subsys);
  770. return rc;
  771. }
  772. rc = dump_ccw_init();
  773. if (rc)
  774. return rc;
  775. rc = dump_fcp_init();
  776. if (rc)
  777. return rc;
  778. dump_set_type(IPL_TYPE_NONE);
  779. return 0;
  780. }
  781. static int __init shutdown_actions_init(void)
  782. {
  783. int rc;
  784. rc = firmware_register(&shutdown_actions_subsys);
  785. if (rc)
  786. return rc;
  787. rc = subsys_create_file(&shutdown_actions_subsys, &on_panic_attr);
  788. if (rc) {
  789. firmware_unregister(&shutdown_actions_subsys);
  790. return rc;
  791. }
  792. atomic_notifier_chain_register(&panic_notifier_list,
  793. &shutdown_on_panic_nb);
  794. return 0;
  795. }
  796. static int __init s390_ipl_init(void)
  797. {
  798. int rc;
  799. reipl_probe();
  800. rc = ipl_init();
  801. if (rc)
  802. return rc;
  803. rc = reipl_init();
  804. if (rc)
  805. return rc;
  806. rc = dump_init();
  807. if (rc)
  808. return rc;
  809. rc = shutdown_actions_init();
  810. if (rc)
  811. return rc;
  812. return 0;
  813. }
  814. __initcall(s390_ipl_init);