ipl.c 27 KB

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