snsc_event.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. /*
  2. * SN Platform system controller communication support
  3. *
  4. * This file is subject to the terms and conditions of the GNU General Public
  5. * License. See the file "COPYING" in the main directory of this archive
  6. * for more details.
  7. *
  8. * Copyright (C) 2004-2006 Silicon Graphics, Inc. All rights reserved.
  9. */
  10. /*
  11. * System controller event handler
  12. *
  13. * These routines deal with environmental events arriving from the
  14. * system controllers.
  15. */
  16. #include <linux/interrupt.h>
  17. #include <linux/sched.h>
  18. #include <linux/byteorder/generic.h>
  19. #include <asm/sn/sn_sal.h>
  20. #include <asm/unaligned.h>
  21. #include "snsc.h"
  22. static struct subch_data_s *event_sd;
  23. void scdrv_event(unsigned long);
  24. DECLARE_TASKLET(sn_sysctl_event, scdrv_event, 0);
  25. /*
  26. * scdrv_event_interrupt
  27. *
  28. * Pull incoming environmental events off the physical link to the
  29. * system controller and put them in a temporary holding area in SAL.
  30. * Schedule scdrv_event() to move them along to their ultimate
  31. * destination.
  32. */
  33. static irqreturn_t
  34. scdrv_event_interrupt(int irq, void *subch_data)
  35. {
  36. struct subch_data_s *sd = subch_data;
  37. unsigned long flags;
  38. int status;
  39. spin_lock_irqsave(&sd->sd_rlock, flags);
  40. status = ia64_sn_irtr_intr(sd->sd_nasid, sd->sd_subch);
  41. if ((status > 0) && (status & SAL_IROUTER_INTR_RECV)) {
  42. tasklet_schedule(&sn_sysctl_event);
  43. }
  44. spin_unlock_irqrestore(&sd->sd_rlock, flags);
  45. return IRQ_HANDLED;
  46. }
  47. /*
  48. * scdrv_parse_event
  49. *
  50. * Break an event (as read from SAL) into useful pieces so we can decide
  51. * what to do with it.
  52. */
  53. static int
  54. scdrv_parse_event(char *event, int *src, int *code, int *esp_code, char *desc)
  55. {
  56. char *desc_end;
  57. __be32 from_buf;
  58. /* record event source address */
  59. from_buf = get_unaligned((__be32 *)event);
  60. *src = be32_to_cpup(&from_buf);
  61. event += 4; /* move on to event code */
  62. /* record the system controller's event code */
  63. from_buf = get_unaligned((__be32 *)event);
  64. *code = be32_to_cpup(&from_buf);
  65. event += 4; /* move on to event arguments */
  66. /* how many arguments are in the packet? */
  67. if (*event++ != 2) {
  68. /* if not 2, give up */
  69. return -1;
  70. }
  71. /* parse out the ESP code */
  72. if (*event++ != IR_ARG_INT) {
  73. /* not an integer argument, so give up */
  74. return -1;
  75. }
  76. from_buf = get_unaligned((__be32 *)event);
  77. *esp_code = be32_to_cpup(&from_buf);
  78. event += 4;
  79. /* parse out the event description */
  80. if (*event++ != IR_ARG_ASCII) {
  81. /* not an ASCII string, so give up */
  82. return -1;
  83. }
  84. event[CHUNKSIZE-1] = '\0'; /* ensure this string ends! */
  85. event += 2; /* skip leading CR/LF */
  86. desc_end = desc + sprintf(desc, "%s", event);
  87. /* strip trailing CR/LF (if any) */
  88. for (desc_end--;
  89. (desc_end != desc) && ((*desc_end == 0xd) || (*desc_end == 0xa));
  90. desc_end--) {
  91. *desc_end = '\0';
  92. }
  93. return 0;
  94. }
  95. /*
  96. * scdrv_event_severity
  97. *
  98. * Figure out how urgent a message we should write to the console/syslog
  99. * via printk.
  100. */
  101. static char *
  102. scdrv_event_severity(int code)
  103. {
  104. int ev_class = (code & EV_CLASS_MASK);
  105. int ev_severity = (code & EV_SEVERITY_MASK);
  106. char *pk_severity = KERN_NOTICE;
  107. switch (ev_class) {
  108. case EV_CLASS_POWER:
  109. switch (ev_severity) {
  110. case EV_SEVERITY_POWER_LOW_WARNING:
  111. case EV_SEVERITY_POWER_HIGH_WARNING:
  112. pk_severity = KERN_WARNING;
  113. break;
  114. case EV_SEVERITY_POWER_HIGH_FAULT:
  115. case EV_SEVERITY_POWER_LOW_FAULT:
  116. pk_severity = KERN_ALERT;
  117. break;
  118. }
  119. break;
  120. case EV_CLASS_FAN:
  121. switch (ev_severity) {
  122. case EV_SEVERITY_FAN_WARNING:
  123. pk_severity = KERN_WARNING;
  124. break;
  125. case EV_SEVERITY_FAN_FAULT:
  126. pk_severity = KERN_CRIT;
  127. break;
  128. }
  129. break;
  130. case EV_CLASS_TEMP:
  131. switch (ev_severity) {
  132. case EV_SEVERITY_TEMP_ADVISORY:
  133. pk_severity = KERN_WARNING;
  134. break;
  135. case EV_SEVERITY_TEMP_CRITICAL:
  136. pk_severity = KERN_CRIT;
  137. break;
  138. case EV_SEVERITY_TEMP_FAULT:
  139. pk_severity = KERN_ALERT;
  140. break;
  141. }
  142. break;
  143. case EV_CLASS_ENV:
  144. pk_severity = KERN_ALERT;
  145. break;
  146. case EV_CLASS_TEST_FAULT:
  147. pk_severity = KERN_ALERT;
  148. break;
  149. case EV_CLASS_TEST_WARNING:
  150. pk_severity = KERN_WARNING;
  151. break;
  152. case EV_CLASS_PWRD_NOTIFY:
  153. pk_severity = KERN_ALERT;
  154. break;
  155. }
  156. return pk_severity;
  157. }
  158. /*
  159. * scdrv_dispatch_event
  160. *
  161. * Do the right thing with an incoming event. That's often nothing
  162. * more than printing it to the system log. For power-down notifications
  163. * we start a graceful shutdown.
  164. */
  165. static void
  166. scdrv_dispatch_event(char *event, int len)
  167. {
  168. static int snsc_shutting_down = 0;
  169. int code, esp_code, src, class;
  170. char desc[CHUNKSIZE];
  171. char *severity;
  172. if (scdrv_parse_event(event, &src, &code, &esp_code, desc) < 0) {
  173. /* ignore uninterpretible event */
  174. return;
  175. }
  176. /* how urgent is the message? */
  177. severity = scdrv_event_severity(code);
  178. class = (code & EV_CLASS_MASK);
  179. if (class == EV_CLASS_PWRD_NOTIFY || code == ENV_PWRDN_PEND) {
  180. struct task_struct *p;
  181. if (snsc_shutting_down)
  182. return;
  183. snsc_shutting_down = 1;
  184. /* give a message for each type of event */
  185. if (class == EV_CLASS_PWRD_NOTIFY)
  186. printk(KERN_NOTICE "Power off indication received."
  187. " Sending SIGPWR to init...\n");
  188. else if (code == ENV_PWRDN_PEND)
  189. printk(KERN_CRIT "WARNING: Shutting down the system"
  190. " due to a critical environmental condition."
  191. " Sending SIGPWR to init...\n");
  192. /* give a SIGPWR signal to init proc */
  193. kill_cad_pid(SIGPWR, 0);
  194. } else {
  195. /* print to system log */
  196. printk("%s|$(0x%x)%s\n", severity, esp_code, desc);
  197. }
  198. }
  199. /*
  200. * scdrv_event
  201. *
  202. * Called as a tasklet when an event arrives from the L1. Read the event
  203. * from where it's temporarily stored in SAL and call scdrv_dispatch_event()
  204. * to send it on its way. Keep trying to read events until SAL indicates
  205. * that there are no more immediately available.
  206. */
  207. void
  208. scdrv_event(unsigned long dummy)
  209. {
  210. int status;
  211. int len;
  212. unsigned long flags;
  213. struct subch_data_s *sd = event_sd;
  214. /* anything to read? */
  215. len = CHUNKSIZE;
  216. spin_lock_irqsave(&sd->sd_rlock, flags);
  217. status = ia64_sn_irtr_recv(sd->sd_nasid, sd->sd_subch,
  218. sd->sd_rb, &len);
  219. while (!(status < 0)) {
  220. spin_unlock_irqrestore(&sd->sd_rlock, flags);
  221. scdrv_dispatch_event(sd->sd_rb, len);
  222. len = CHUNKSIZE;
  223. spin_lock_irqsave(&sd->sd_rlock, flags);
  224. status = ia64_sn_irtr_recv(sd->sd_nasid, sd->sd_subch,
  225. sd->sd_rb, &len);
  226. }
  227. spin_unlock_irqrestore(&sd->sd_rlock, flags);
  228. }
  229. /*
  230. * scdrv_event_init
  231. *
  232. * Sets up a system controller subchannel to begin receiving event
  233. * messages. This is sort of a specialized version of scdrv_open()
  234. * in drivers/char/sn_sysctl.c.
  235. */
  236. void
  237. scdrv_event_init(struct sysctl_data_s *scd)
  238. {
  239. int rv;
  240. event_sd = kzalloc(sizeof (struct subch_data_s), GFP_KERNEL);
  241. if (event_sd == NULL) {
  242. printk(KERN_WARNING "%s: couldn't allocate subchannel info"
  243. " for event monitoring\n", __FUNCTION__);
  244. return;
  245. }
  246. /* initialize subch_data_s fields */
  247. event_sd->sd_nasid = scd->scd_nasid;
  248. spin_lock_init(&event_sd->sd_rlock);
  249. /* ask the system controllers to send events to this node */
  250. event_sd->sd_subch = ia64_sn_sysctl_event_init(scd->scd_nasid);
  251. if (event_sd->sd_subch < 0) {
  252. kfree(event_sd);
  253. printk(KERN_WARNING "%s: couldn't open event subchannel\n",
  254. __FUNCTION__);
  255. return;
  256. }
  257. /* hook event subchannel up to the system controller interrupt */
  258. rv = request_irq(SGI_UART_VECTOR, scdrv_event_interrupt,
  259. IRQF_SHARED | IRQF_DISABLED,
  260. "system controller events", event_sd);
  261. if (rv) {
  262. printk(KERN_WARNING "%s: irq request failed (%d)\n",
  263. __FUNCTION__, rv);
  264. ia64_sn_irtr_close(event_sd->sd_nasid, event_sd->sd_subch);
  265. kfree(event_sd);
  266. return;
  267. }
  268. }