snsc_event.c 7.2 KB

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