ipl.c 27 KB

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