ipl.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080
  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. #ifdef CONFIG_SMP
  488. static void dump_smp_stop_all(void)
  489. {
  490. int cpu;
  491. preempt_disable();
  492. for_each_online_cpu(cpu) {
  493. if (cpu == smp_processor_id())
  494. continue;
  495. while (signal_processor(cpu, sigp_stop) == sigp_busy)
  496. udelay(10);
  497. }
  498. preempt_enable();
  499. }
  500. #else
  501. #define dump_smp_stop_all() do { } while (0)
  502. #endif
  503. /*
  504. * Shutdown actions section
  505. */
  506. static decl_subsys(shutdown_actions, NULL, NULL);
  507. /* on panic */
  508. static ssize_t on_panic_show(struct subsystem *subsys, char *page)
  509. {
  510. return sprintf(page, "%s\n", shutdown_action_str(on_panic_action));
  511. }
  512. static ssize_t on_panic_store(struct subsystem *subsys, const char *buf,
  513. size_t len)
  514. {
  515. if (strncmp(buf, SHUTDOWN_REIPL_STR, strlen(SHUTDOWN_REIPL_STR)) == 0)
  516. on_panic_action = SHUTDOWN_REIPL;
  517. else if (strncmp(buf, SHUTDOWN_DUMP_STR,
  518. strlen(SHUTDOWN_DUMP_STR)) == 0)
  519. on_panic_action = SHUTDOWN_DUMP;
  520. else if (strncmp(buf, SHUTDOWN_STOP_STR,
  521. strlen(SHUTDOWN_STOP_STR)) == 0)
  522. on_panic_action = SHUTDOWN_STOP;
  523. else
  524. return -EINVAL;
  525. return len;
  526. }
  527. static struct subsys_attribute on_panic_attr =
  528. __ATTR(on_panic, 0644, on_panic_show, on_panic_store);
  529. static void print_fcp_block(struct ipl_parameter_block *fcp_block)
  530. {
  531. printk(KERN_EMERG "wwpn: %016llx\n",
  532. (unsigned long long)fcp_block->ipl_info.fcp.wwpn);
  533. printk(KERN_EMERG "lun: %016llx\n",
  534. (unsigned long long)fcp_block->ipl_info.fcp.lun);
  535. printk(KERN_EMERG "bootprog: %lld\n",
  536. (unsigned long long)fcp_block->ipl_info.fcp.bootprog);
  537. printk(KERN_EMERG "br_lba: %lld\n",
  538. (unsigned long long)fcp_block->ipl_info.fcp.br_lba);
  539. printk(KERN_EMERG "device: %llx\n",
  540. (unsigned long long)fcp_block->ipl_info.fcp.devno);
  541. printk(KERN_EMERG "opt: %x\n", fcp_block->ipl_info.fcp.opt);
  542. }
  543. void do_reipl(void)
  544. {
  545. struct ccw_dev_id devid;
  546. static char buf[100];
  547. char loadparm[LOADPARM_LEN + 1];
  548. switch (reipl_type) {
  549. case IPL_TYPE_CCW:
  550. reipl_get_ascii_loadparm(loadparm);
  551. printk(KERN_EMERG "reboot on ccw device: 0.0.%04x\n",
  552. reipl_block_ccw->ipl_info.ccw.devno);
  553. printk(KERN_EMERG "loadparm = '%s'\n", loadparm);
  554. break;
  555. case IPL_TYPE_FCP:
  556. printk(KERN_EMERG "reboot on fcp device:\n");
  557. print_fcp_block(reipl_block_fcp);
  558. break;
  559. default:
  560. break;
  561. }
  562. switch (reipl_method) {
  563. case IPL_METHOD_CCW_CIO:
  564. devid.devno = reipl_block_ccw->ipl_info.ccw.devno;
  565. if (ipl_get_type() == IPL_TYPE_CCW && devid.devno == ipl_devno)
  566. diag308(DIAG308_IPL, NULL);
  567. devid.ssid = 0;
  568. reipl_ccw_dev(&devid);
  569. break;
  570. case IPL_METHOD_CCW_VM:
  571. if (strlen(loadparm) == 0)
  572. sprintf(buf, "IPL %X",
  573. reipl_block_ccw->ipl_info.ccw.devno);
  574. else
  575. sprintf(buf, "IPL %X LOADPARM '%s'",
  576. reipl_block_ccw->ipl_info.ccw.devno, loadparm);
  577. __cpcmd(buf, NULL, 0, NULL);
  578. break;
  579. case IPL_METHOD_CCW_DIAG:
  580. diag308(DIAG308_SET, reipl_block_ccw);
  581. diag308(DIAG308_IPL, NULL);
  582. break;
  583. case IPL_METHOD_FCP_RW_DIAG:
  584. diag308(DIAG308_SET, reipl_block_fcp);
  585. diag308(DIAG308_IPL, NULL);
  586. break;
  587. case IPL_METHOD_FCP_RO_DIAG:
  588. diag308(DIAG308_IPL, NULL);
  589. break;
  590. case IPL_METHOD_FCP_RO_VM:
  591. __cpcmd("IPL", NULL, 0, NULL);
  592. break;
  593. case IPL_METHOD_NONE:
  594. default:
  595. if (MACHINE_IS_VM)
  596. __cpcmd("IPL", NULL, 0, NULL);
  597. diag308(DIAG308_IPL, NULL);
  598. break;
  599. }
  600. printk(KERN_EMERG "reboot failed!\n");
  601. signal_processor(smp_processor_id(), sigp_stop_and_store_status);
  602. }
  603. static void do_dump(void)
  604. {
  605. struct ccw_dev_id devid;
  606. static char buf[100];
  607. switch (dump_type) {
  608. case IPL_TYPE_CCW:
  609. printk(KERN_EMERG "Automatic dump on ccw device: 0.0.%04x\n",
  610. dump_block_ccw->ipl_info.ccw.devno);
  611. break;
  612. case IPL_TYPE_FCP:
  613. printk(KERN_EMERG "Automatic dump on fcp device:\n");
  614. print_fcp_block(dump_block_fcp);
  615. break;
  616. default:
  617. return;
  618. }
  619. switch (dump_method) {
  620. case IPL_METHOD_CCW_CIO:
  621. dump_smp_stop_all();
  622. devid.devno = dump_block_ccw->ipl_info.ccw.devno;
  623. devid.ssid = 0;
  624. reipl_ccw_dev(&devid);
  625. break;
  626. case IPL_METHOD_CCW_VM:
  627. dump_smp_stop_all();
  628. sprintf(buf, "STORE STATUS");
  629. __cpcmd(buf, NULL, 0, NULL);
  630. sprintf(buf, "IPL %X", dump_block_ccw->ipl_info.ccw.devno);
  631. __cpcmd(buf, NULL, 0, NULL);
  632. break;
  633. case IPL_METHOD_CCW_DIAG:
  634. diag308(DIAG308_SET, dump_block_ccw);
  635. diag308(DIAG308_DUMP, NULL);
  636. break;
  637. case IPL_METHOD_FCP_RW_DIAG:
  638. diag308(DIAG308_SET, dump_block_fcp);
  639. diag308(DIAG308_DUMP, NULL);
  640. break;
  641. case IPL_METHOD_NONE:
  642. default:
  643. return;
  644. }
  645. printk(KERN_EMERG "Dump failed!\n");
  646. }
  647. /* init functions */
  648. static int __init ipl_register_fcp_files(void)
  649. {
  650. int rc;
  651. rc = sysfs_create_group(&ipl_subsys.kset.kobj,
  652. &ipl_fcp_attr_group);
  653. if (rc)
  654. goto out;
  655. rc = sysfs_create_bin_file(&ipl_subsys.kset.kobj,
  656. &ipl_parameter_attr);
  657. if (rc)
  658. goto out_ipl_parm;
  659. rc = sysfs_create_bin_file(&ipl_subsys.kset.kobj,
  660. &ipl_scp_data_attr);
  661. if (!rc)
  662. goto out;
  663. sysfs_remove_bin_file(&ipl_subsys.kset.kobj, &ipl_parameter_attr);
  664. out_ipl_parm:
  665. sysfs_remove_group(&ipl_subsys.kset.kobj, &ipl_fcp_attr_group);
  666. out:
  667. return rc;
  668. }
  669. static int __init ipl_init(void)
  670. {
  671. int rc;
  672. rc = firmware_register(&ipl_subsys);
  673. if (rc)
  674. return rc;
  675. switch (ipl_get_type()) {
  676. case IPL_TYPE_CCW:
  677. rc = sysfs_create_group(&ipl_subsys.kset.kobj,
  678. &ipl_ccw_attr_group);
  679. break;
  680. case IPL_TYPE_FCP:
  681. rc = ipl_register_fcp_files();
  682. break;
  683. default:
  684. rc = sysfs_create_group(&ipl_subsys.kset.kobj,
  685. &ipl_unknown_attr_group);
  686. break;
  687. }
  688. if (rc)
  689. firmware_unregister(&ipl_subsys);
  690. return rc;
  691. }
  692. static void __init reipl_probe(void)
  693. {
  694. void *buffer;
  695. buffer = (void *) get_zeroed_page(GFP_KERNEL);
  696. if (!buffer)
  697. return;
  698. if (diag308(DIAG308_STORE, buffer) == DIAG308_RC_OK)
  699. diag308_set_works = 1;
  700. free_page((unsigned long)buffer);
  701. }
  702. static int __init reipl_ccw_init(void)
  703. {
  704. int rc;
  705. reipl_block_ccw = (void *) get_zeroed_page(GFP_KERNEL);
  706. if (!reipl_block_ccw)
  707. return -ENOMEM;
  708. rc = sysfs_create_group(&reipl_subsys.kset.kobj, &reipl_ccw_attr_group);
  709. if (rc) {
  710. free_page((unsigned long)reipl_block_ccw);
  711. return rc;
  712. }
  713. reipl_block_ccw->hdr.len = IPL_PARM_BLK_CCW_LEN;
  714. reipl_block_ccw->hdr.version = IPL_PARM_BLOCK_VERSION;
  715. reipl_block_ccw->hdr.blk0_len = sizeof(reipl_block_ccw->ipl_info.ccw);
  716. reipl_block_ccw->hdr.pbt = DIAG308_IPL_TYPE_CCW;
  717. /* check if read scp info worked and set loadparm */
  718. if (SCCB_VALID)
  719. memcpy(reipl_block_ccw->ipl_info.ccw.load_param,
  720. SCCB_LOADPARM, LOADPARM_LEN);
  721. else
  722. /* read scp info failed: set empty loadparm (EBCDIC blanks) */
  723. memset(reipl_block_ccw->ipl_info.ccw.load_param, 0x40,
  724. LOADPARM_LEN);
  725. /* FIXME: check for diag308_set_works when enabling diag ccw reipl */
  726. if (!MACHINE_IS_VM)
  727. sys_reipl_ccw_loadparm_attr.attr.mode = S_IRUGO;
  728. if (ipl_get_type() == IPL_TYPE_CCW)
  729. reipl_block_ccw->ipl_info.ccw.devno = ipl_devno;
  730. reipl_capabilities |= IPL_TYPE_CCW;
  731. return 0;
  732. }
  733. static int __init reipl_fcp_init(void)
  734. {
  735. int rc;
  736. if ((!diag308_set_works) && (ipl_get_type() != IPL_TYPE_FCP))
  737. return 0;
  738. if ((!diag308_set_works) && (ipl_get_type() == IPL_TYPE_FCP))
  739. make_attrs_ro(reipl_fcp_attrs);
  740. reipl_block_fcp = (void *) get_zeroed_page(GFP_KERNEL);
  741. if (!reipl_block_fcp)
  742. return -ENOMEM;
  743. rc = sysfs_create_group(&reipl_subsys.kset.kobj, &reipl_fcp_attr_group);
  744. if (rc) {
  745. free_page((unsigned long)reipl_block_fcp);
  746. return rc;
  747. }
  748. if (ipl_get_type() == IPL_TYPE_FCP) {
  749. memcpy(reipl_block_fcp, IPL_PARMBLOCK_START, PAGE_SIZE);
  750. } else {
  751. reipl_block_fcp->hdr.len = IPL_PARM_BLK_FCP_LEN;
  752. reipl_block_fcp->hdr.version = IPL_PARM_BLOCK_VERSION;
  753. reipl_block_fcp->hdr.blk0_len =
  754. sizeof(reipl_block_fcp->ipl_info.fcp);
  755. reipl_block_fcp->hdr.pbt = DIAG308_IPL_TYPE_FCP;
  756. reipl_block_fcp->ipl_info.fcp.opt = DIAG308_IPL_OPT_IPL;
  757. }
  758. reipl_capabilities |= IPL_TYPE_FCP;
  759. return 0;
  760. }
  761. static int __init reipl_init(void)
  762. {
  763. int rc;
  764. rc = firmware_register(&reipl_subsys);
  765. if (rc)
  766. return rc;
  767. rc = subsys_create_file(&reipl_subsys, &reipl_type_attr);
  768. if (rc) {
  769. firmware_unregister(&reipl_subsys);
  770. return rc;
  771. }
  772. rc = reipl_ccw_init();
  773. if (rc)
  774. return rc;
  775. rc = reipl_fcp_init();
  776. if (rc)
  777. return rc;
  778. rc = reipl_set_type(ipl_get_type());
  779. if (rc)
  780. return rc;
  781. return 0;
  782. }
  783. static int __init dump_ccw_init(void)
  784. {
  785. int rc;
  786. dump_block_ccw = (void *) get_zeroed_page(GFP_KERNEL);
  787. if (!dump_block_ccw)
  788. return -ENOMEM;
  789. rc = sysfs_create_group(&dump_subsys.kset.kobj, &dump_ccw_attr_group);
  790. if (rc) {
  791. free_page((unsigned long)dump_block_ccw);
  792. return rc;
  793. }
  794. dump_block_ccw->hdr.len = IPL_PARM_BLK_CCW_LEN;
  795. dump_block_ccw->hdr.version = IPL_PARM_BLOCK_VERSION;
  796. dump_block_ccw->hdr.blk0_len = sizeof(reipl_block_ccw->ipl_info.ccw);
  797. dump_block_ccw->hdr.pbt = DIAG308_IPL_TYPE_CCW;
  798. dump_capabilities |= IPL_TYPE_CCW;
  799. return 0;
  800. }
  801. static int __init dump_fcp_init(void)
  802. {
  803. int rc;
  804. if(!(SCCB_FLAG & 0x2) || !SCCB_VALID)
  805. return 0; /* LDIPL DUMP is not installed */
  806. if (!diag308_set_works)
  807. return 0;
  808. dump_block_fcp = (void *) get_zeroed_page(GFP_KERNEL);
  809. if (!dump_block_fcp)
  810. return -ENOMEM;
  811. rc = sysfs_create_group(&dump_subsys.kset.kobj, &dump_fcp_attr_group);
  812. if (rc) {
  813. free_page((unsigned long)dump_block_fcp);
  814. return rc;
  815. }
  816. dump_block_fcp->hdr.len = IPL_PARM_BLK_FCP_LEN;
  817. dump_block_fcp->hdr.version = IPL_PARM_BLOCK_VERSION;
  818. dump_block_fcp->hdr.blk0_len = sizeof(dump_block_fcp->ipl_info.fcp);
  819. dump_block_fcp->hdr.pbt = DIAG308_IPL_TYPE_FCP;
  820. dump_block_fcp->ipl_info.fcp.opt = DIAG308_IPL_OPT_DUMP;
  821. dump_capabilities |= IPL_TYPE_FCP;
  822. return 0;
  823. }
  824. #define SHUTDOWN_ON_PANIC_PRIO 0
  825. static int shutdown_on_panic_notify(struct notifier_block *self,
  826. unsigned long event, void *data)
  827. {
  828. if (on_panic_action == SHUTDOWN_DUMP)
  829. do_dump();
  830. else if (on_panic_action == SHUTDOWN_REIPL)
  831. do_reipl();
  832. return NOTIFY_OK;
  833. }
  834. static struct notifier_block shutdown_on_panic_nb = {
  835. .notifier_call = shutdown_on_panic_notify,
  836. .priority = SHUTDOWN_ON_PANIC_PRIO
  837. };
  838. static int __init dump_init(void)
  839. {
  840. int rc;
  841. rc = firmware_register(&dump_subsys);
  842. if (rc)
  843. return rc;
  844. rc = subsys_create_file(&dump_subsys, &dump_type_attr);
  845. if (rc) {
  846. firmware_unregister(&dump_subsys);
  847. return rc;
  848. }
  849. rc = dump_ccw_init();
  850. if (rc)
  851. return rc;
  852. rc = dump_fcp_init();
  853. if (rc)
  854. return rc;
  855. dump_set_type(IPL_TYPE_NONE);
  856. return 0;
  857. }
  858. static int __init shutdown_actions_init(void)
  859. {
  860. int rc;
  861. rc = firmware_register(&shutdown_actions_subsys);
  862. if (rc)
  863. return rc;
  864. rc = subsys_create_file(&shutdown_actions_subsys, &on_panic_attr);
  865. if (rc) {
  866. firmware_unregister(&shutdown_actions_subsys);
  867. return rc;
  868. }
  869. atomic_notifier_chain_register(&panic_notifier_list,
  870. &shutdown_on_panic_nb);
  871. return 0;
  872. }
  873. static int __init s390_ipl_init(void)
  874. {
  875. int rc;
  876. reipl_probe();
  877. rc = ipl_init();
  878. if (rc)
  879. return rc;
  880. rc = reipl_init();
  881. if (rc)
  882. return rc;
  883. rc = dump_init();
  884. if (rc)
  885. return rc;
  886. rc = shutdown_actions_init();
  887. if (rc)
  888. return rc;
  889. return 0;
  890. }
  891. __initcall(s390_ipl_init);
  892. static LIST_HEAD(rcall);
  893. static DEFINE_MUTEX(rcall_mutex);
  894. void register_reset_call(struct reset_call *reset)
  895. {
  896. mutex_lock(&rcall_mutex);
  897. list_add(&reset->list, &rcall);
  898. mutex_unlock(&rcall_mutex);
  899. }
  900. EXPORT_SYMBOL_GPL(register_reset_call);
  901. void unregister_reset_call(struct reset_call *reset)
  902. {
  903. mutex_lock(&rcall_mutex);
  904. list_del(&reset->list);
  905. mutex_unlock(&rcall_mutex);
  906. }
  907. EXPORT_SYMBOL_GPL(unregister_reset_call);
  908. static void do_reset_calls(void)
  909. {
  910. struct reset_call *reset;
  911. list_for_each_entry(reset, &rcall, list)
  912. reset->fn();
  913. }
  914. extern void reset_mcck_handler(void);
  915. void s390_reset_system(void)
  916. {
  917. struct _lowcore *lc;
  918. /* Disable all interrupts/machine checks */
  919. __load_psw_mask(PSW_KERNEL_BITS & ~PSW_MASK_MCHECK);
  920. /* Stack for interrupt/machine check handler */
  921. lc = (struct _lowcore *)(unsigned long) store_prefix();
  922. lc->panic_stack = S390_lowcore.panic_stack;
  923. /* Disable prefixing */
  924. set_prefix(0);
  925. /* Disable lowcore protection */
  926. __ctl_clear_bit(0,28);
  927. /* Set new machine check handler */
  928. S390_lowcore.mcck_new_psw.mask = PSW_KERNEL_BITS & ~PSW_MASK_MCHECK;
  929. S390_lowcore.mcck_new_psw.addr =
  930. PSW_ADDR_AMODE | (unsigned long) &reset_mcck_handler;
  931. do_reset_calls();
  932. }