ipl.c 25 KB

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