ipl.c 27 KB

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