s390mach.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:14k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  *  arch/s390/kernel/s390mach.c
  3.  *   S/390 machine check handler,
  4.  *            currently only channel-reports are supported
  5.  *
  6.  *  S390 version
  7.  *    Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
  8.  *    Author(s): Ingo Adlung (adlung@de.ibm.com)
  9.  */
  10. #include <linux/config.h>
  11. #include <linux/spinlock.h>
  12. #include <linux/init.h>
  13. #include <linux/slab.h>
  14. #ifdef CONFIG_SMP
  15. #include <linux/smp.h>
  16. #endif
  17. #include <asm/irq.h>
  18. #include <asm/lowcore.h>
  19. #include <asm/semaphore.h>
  20. #include <asm/s390io.h>
  21. #include <asm/s390dyn.h>
  22. #include <asm/s390mach.h>
  23. #ifdef CONFIG_MACHCHK_WARNING
  24. #include <asm/signal.h>
  25. #endif
  26. extern void ctrl_alt_del(void);
  27. #define S390_MACHCHK_DEBUG
  28. static int         s390_machine_check_handler( void * parm );
  29. static void        s390_enqueue_mchchk( mache_t *mchchk );
  30. static mache_t    *s390_dequeue_mchchk( void );
  31. static void        s390_enqueue_free_mchchk( mache_t *mchchk );
  32. static mache_t    *s390_dequeue_free_mchchk( void );
  33. static int         s390_collect_crw_info( void );
  34. #ifdef CONFIG_MACHCHK_WARNING
  35. static int         s390_post_warning( void );
  36. #endif
  37. static mache_t    *mchchk_queue_head = NULL;
  38. static mache_t    *mchchk_queue_tail = NULL;
  39. static mache_t    *mchchk_queue_free = NULL;
  40. static crwe_t     *crw_buffer_anchor = NULL;
  41. static spinlock_t  mchchk_queue_lock = SPIN_LOCK_UNLOCKED;
  42. static spinlock_t  crw_queue_lock    = SPIN_LOCK_UNLOCKED;
  43. static struct semaphore s_sem;
  44. #ifdef CONFIG_MACHCHK_WARNING
  45. static int mchchk_wng_posted = 0;
  46. #endif
  47. /*
  48.  * s390_init_machine_check
  49.  *
  50.  * initialize machine check handling
  51.  */
  52. void s390_init_machine_check( void )
  53. {
  54. crwe_t  *pcrwe;  /* CRW buffer element pointer */
  55. mache_t *pmache;   /* machine check element pointer */
  56. init_MUTEX_LOCKED( &s_sem );
  57. pcrwe = kmalloc( MAX_CRW_PENDING * sizeof( crwe_t), GFP_KERNEL);
  58. if ( pcrwe )
  59. {
  60. int i;
  61. crw_buffer_anchor = pcrwe;
  62. for ( i=0; i < MAX_CRW_PENDING-1; i++)
  63. {
  64. pcrwe->crwe_next = (crwe_t *)((unsigned long)pcrwe + sizeof(crwe_t));
  65.     pcrwe            = pcrwe->crwe_next;
  66. } /* endfor */
  67. pcrwe->crwe_next = NULL;
  68. }
  69. else
  70. {
  71. panic( "s390_init_machine_check : unable to obtain memoryn");
  72. } /* endif */
  73. pmache = kmalloc( MAX_MACH_PENDING * sizeof( mache_t), GFP_KERNEL);
  74. if ( pmache )
  75. {
  76. int i;
  77. for ( i=0; i < MAX_MACH_PENDING; i++)
  78. {
  79. s390_enqueue_free_mchchk( pmache );
  80.    pmache = (mache_t *)((unsigned long)pmache + sizeof(mache_t));
  81. } /* endfor */
  82. }
  83. else
  84. {
  85. panic( "s390_init_machine_check : unable to obtain memoryn");
  86. } /* endif */
  87. #ifdef S390_MACHCHK_DEBUG
  88. printk( KERN_NOTICE "init_mach : starting machine check handlern");
  89. #endif
  90. kernel_thread( s390_machine_check_handler, &s_sem, CLONE_FS | CLONE_FILES);
  91. ctl_clear_bit( 14, 25 );  // disable damage MCH 
  92. ctl_set_bit( 14, 26 ); /* enable degradation MCH */
  93. ctl_set_bit( 14, 27 ); /* enable system recovery MCH */
  94. #if 1
  95.    ctl_set_bit( 14, 28 ); // enable channel report MCH
  96. #endif
  97. #ifdef CONFIG_MACHCK_WARNING
  98. ctl_set_bit( 14, 24);   /* enable warning MCH */
  99. #endif
  100. #ifdef S390_MACHCHK_DEBUG
  101. printk( KERN_DEBUG "init_mach : machine check buffer : head = %08Xn",
  102.             (unsigned)&mchchk_queue_head);
  103. printk( KERN_DEBUG "init_mach : machine check buffer : tail = %08Xn",
  104.             (unsigned)&mchchk_queue_tail);
  105. printk( KERN_DEBUG "init_mach : machine check buffer : free = %08Xn",
  106.             (unsigned)&mchchk_queue_free);
  107. printk( KERN_DEBUG "init_mach : CRW entry buffer anchor = %08Xn",
  108.             (unsigned)&crw_buffer_anchor);
  109. printk( KERN_DEBUG "init_mach : machine check handler readyn");
  110. #endif
  111. return;
  112. }
  113. static void s390_handle_damage(char * msg){
  114. unsigned long caller = (unsigned long) __builtin_return_address(0);
  115. printk(KERN_EMERG "%sn", msg);
  116. #ifdef CONFIG_SMP
  117. smp_send_stop();
  118. #endif
  119. disabled_wait(caller);
  120. return;
  121. }
  122. /*
  123.  * s390_do_machine_check
  124.  *
  125.  * mchine check pre-processor, collecting the machine check info,
  126.  *  queueing it and posting the machine check handler for processing.
  127.  */
  128. void s390_do_machine_check( void )
  129. {
  130. int      crw_count;
  131. mcic_t   mcic;
  132. #ifdef S390_MACHCHK_DEBUG
  133. printk( KERN_INFO "s390_do_machine_check : starting ...n");
  134. #endif
  135. memcpy( &mcic,
  136.         &S390_lowcore.mcck_interruption_code,
  137.         sizeof(__u64));
  138.  
  139. if (mcic.mcc.mcd.sd) /* system damage */
  140. s390_handle_damage("received system damage machine checkn");
  141. if (mcic.mcc.mcd.pd) /* instruction processing damage */
  142. s390_handle_damage("received instruction processing damage machine checkn");
  143. if (mcic.mcc.mcd.se) /* storage error uncorrected */
  144. s390_handle_damage("received storage error uncorrected machine checkn");
  145. if (mcic.mcc.mcd.sc) /* storage error corrected */
  146. printk(KERN_WARNING "received storage error corrected machine checkn");
  147. if (mcic.mcc.mcd.ke) /* storage key-error uncorrected */
  148. s390_handle_damage("received storage key-error uncorrected machine checkn");
  149. if (mcic.mcc.mcd.ds && mcic.mcc.mcd.fa) /* storage degradation */
  150. s390_handle_damage("received storage degradation machine checkn");
  151. if ( mcic.mcc.mcd.cp ) // CRW pending ?
  152. {
  153. crw_count = s390_collect_crw_info();
  154. if ( crw_count )
  155. {
  156. up( &s_sem );
  157. } /* endif */
  158. } /* endif */
  159. #ifdef CONFIG_MACHCHK_WARNING
  160. /*
  161.  * The warning may remain for a prolonged period on the bare iron.
  162.  * (actually till the machine is powered off, or until the problem is gone)
  163.  * So we just stop listening for the WARNING MCH and prevent continuously
  164.  * being interrupted.  One caveat is however, that we must do this per 
  165.  * processor and cannot use the smp version of ctl_clear_bit().
  166.  * On VM we only get one interrupt per virtally presented machinecheck.
  167.  * Though one suffices, we may get one interrupt per (virtual) processor. 
  168.  */
  169. if ( mcic.mcc.mcd.w ) // WARNING pending ?
  170. {
  171. // Use single machine clear, as we cannot handle smp right now
  172. __ctl_clear_bit( 14, 24 ); // Disable WARNING MCH
  173. if ( ! mchchk_wng_posted )
  174. mchchk_wng_posted = s390_post_warning();
  175. if ( mchchk_wng_posted )
  176. {
  177. up( &s_sem );
  178. } /* endif */
  179. } /* endif */
  180. } /* endif */
  181. #endif
  182. #ifdef S390_MACHCHK_DEBUG
  183. printk( KERN_INFO "s390_do_machine_check : done n");
  184. #endif
  185. return;
  186. }
  187. /*
  188.  * s390_machine_check_handler
  189.  *
  190.  * machine check handler, dequeueing machine check entries
  191.  *  and processing them
  192.  */
  193. static int s390_machine_check_handler( void *parm)
  194. {
  195. struct semaphore *sem = parm;
  196. unsigned long     flags;
  197. mache_t          *pmache;
  198. int               found = 0;
  199.         /* set name to something sensible */
  200.         strcpy (current->comm, "kmcheck");
  201.         /* block all signals */
  202.         sigfillset(&current->blocked);
  203. #ifdef S390_MACHCHK_DEBUG
  204. printk( KERN_NOTICE "mach_handler : readyn");
  205. #endif
  206. do {
  207. #ifdef S390_MACHCHK_DEBUG
  208. printk( KERN_NOTICE "mach_handler : waiting for wakeupn");
  209. #endif
  210. down_interruptible( sem );
  211. #ifdef S390_MACHCHK_DEBUG
  212. printk( KERN_NOTICE "nmach_handler : wakeup ... n");
  213. #endif
  214. found = 0; /* init ... */
  215. __save_flags( flags );
  216. __cli();
  217. do {
  218. pmache = s390_dequeue_mchchk();
  219. if ( pmache )
  220. {
  221. found = 1;
  222. if ( pmache->mcic.mcc.mcd.cp )
  223. {
  224. crwe_t *pcrwe_n;
  225. crwe_t *pcrwe_h;
  226. s390_do_crw_pending( pmache->mc.crwe );
  227. pcrwe_h = pmache->mc.crwe;
  228. pcrwe_n = pmache->mc.crwe->crwe_next;
  229. pmache->mcic.mcc.mcd.cp = 0;
  230. pmache->mc.crwe         = NULL;
  231. spin_lock( &crw_queue_lock);
  232. while ( pcrwe_h )
  233. {
  234. pcrwe_h->crwe_next = crw_buffer_anchor;
  235. crw_buffer_anchor  = pcrwe_h;
  236. pcrwe_h            = pcrwe_n;
  237. if ( pcrwe_h != NULL )
  238. pcrwe_n = pcrwe_h->crwe_next;
  239. } /* endwhile */
  240. spin_unlock( &crw_queue_lock);
  241. } /* endif */
  242. #ifdef CONFIG_MACHCHK_WARNING
  243. if ( pmache->mcic.mcc.mcd.w )
  244. {
  245. ctrl_alt_del(); // shutdown NOW!
  246. #ifdef S390_MACHCHK_DEBUG
  247. printk( KERN_DEBUG "mach_handler : kill -SIGPWR initn");
  248. #endif
  249. } /* endif */
  250. #endif
  251. s390_enqueue_free_mchchk( pmache );
  252. }
  253. else
  254. {
  255. // unconditional surrender ...
  256. #ifdef S390_MACHCHK_DEBUG
  257. printk( KERN_DEBUG "mach_handler : nothing to do, sleepingn");
  258. #endif
  259. } /* endif */
  260. } while ( pmache );
  261. __restore_flags( flags );
  262. } while ( 1 );
  263. return( 0);
  264. }
  265. /*
  266.  * s390_dequeue_mchchk
  267.  *
  268.  * Dequeue an entry from the machine check queue
  269.  *
  270.  * Note : The queue elements provide for a double linked list.
  271.  *  We dequeue entries from the tail, and enqueue entries to
  272.  *  the head.
  273.  *
  274.  */
  275. static mache_t *s390_dequeue_mchchk( void )
  276. {
  277. mache_t *qe;
  278. spin_lock( &mchchk_queue_lock );
  279. qe = mchchk_queue_tail;
  280.    if ( qe != NULL )
  281.    {
  282.       mchchk_queue_tail = qe->prev;
  283.       if ( mchchk_queue_tail != NULL )
  284.       {
  285. mchchk_queue_tail->next = NULL;
  286. }
  287. else
  288.       {
  289. mchchk_queue_head = NULL;
  290.       } /* endif */
  291. } /* endif */
  292. spin_unlock( &mchchk_queue_lock );
  293. return qe;
  294. }
  295. /*
  296.  * s390_enqueue_mchchk
  297.  *
  298.  * Enqueue an entry to the machine check queue.
  299.  *
  300.  * Note : The queue elements provide for a double linked list.
  301.  *  We enqueue entries to the head, and dequeue entries from
  302.  *  the tail.
  303.  *
  304.  */
  305. static void s390_enqueue_mchchk( mache_t *pmache )
  306. {
  307. spin_lock( &mchchk_queue_lock );
  308. if ( pmache != NULL )
  309. {
  310. if ( mchchk_queue_head == NULL )  /* first element */
  311. {
  312.    pmache->next      = NULL;
  313.    pmache->prev      = NULL;
  314. mchchk_queue_head = pmache;
  315. mchchk_queue_tail = pmache;
  316. }
  317. else /* new head */
  318. {
  319.    pmache->prev            = NULL;
  320. pmache->next            = mchchk_queue_head;
  321. mchchk_queue_head->prev = pmache;
  322. mchchk_queue_head       = pmache;
  323. } /* endif */
  324. } /* endif */
  325. spin_unlock( &mchchk_queue_lock );
  326. return;
  327. }
  328. /*
  329.  * s390_enqueue_free_mchchk
  330.  *
  331.  * Enqueue a free entry to the free queue.
  332.  *
  333.  * Note : While the queue elements provide for a double linked list,
  334.  *  the free queue entries are only concatenated by means of a
  335.  *  single linked list (forward concatenation).
  336.  *
  337.  */
  338. static void s390_enqueue_free_mchchk( mache_t *pmache )
  339. {
  340. if ( pmache != NULL)
  341. {
  342. memset( pmache, '', sizeof( mache_t ));
  343. spin_lock( &mchchk_queue_lock );
  344. pmache->next = mchchk_queue_free;
  345. mchchk_queue_free = pmache;
  346. spin_unlock( &mchchk_queue_lock );
  347. } /* endif */
  348. return;
  349. }
  350. /*
  351.  * s390_dequeue_free_mchchk
  352.  *
  353.  * Dequeue an entry from the free queue.
  354.  *
  355.  * Note : While the queue elements provide for a double linked list,
  356.  *  the free queue entries are only concatenated by means of a
  357.  *  single linked list (forward concatenation).
  358.  *
  359.  */
  360. static mache_t *s390_dequeue_free_mchchk( void )
  361. {
  362. mache_t *qe;
  363. spin_lock( &mchchk_queue_lock );
  364. qe = mchchk_queue_free;
  365. if ( qe != NULL )
  366. {
  367. mchchk_queue_free = qe->next;
  368. } /* endif */
  369. spin_unlock( &mchchk_queue_lock );
  370. return qe;
  371. }
  372. /*
  373.  * s390_collect_crw_info
  374.  *
  375.  * Retrieve CRWs. If a CRW was found a machine check element
  376.  *  is dequeued from the free chain, filled and enqueued to
  377.  *  be processed.
  378.  *
  379.  * The function returns the number of CRWs found.
  380.  *
  381.  * Note : We must always be called disabled ...
  382.  */
  383. static int s390_collect_crw_info( void )
  384. {
  385. crw_t    tcrw;     /* temporarily holds a CRW */
  386. int      ccode;    /* condition code from stcrw() */
  387. crwe_t  *pcrwe;    /* pointer to CRW buffer entry */
  388. mache_t *pmache = NULL; /* ptr to mchchk entry */
  389. int      chain  = 0;    /* indicate chaining */
  390. crwe_t  *pccrw  = NULL; /* ptr to current CRW buffer entry */
  391. int      count  = 0;    /* CRW count */
  392. #ifdef S390_MACHCHK_DEBUG
  393. printk( KERN_DEBUG "crw_info : looking for CRWs ...n");
  394. #endif
  395. do
  396. {
  397. ccode = stcrw( (__u32 *)&tcrw);
  398. if ( ccode == 0 )
  399. {
  400. count++;
  401. #ifdef S390_MACHCHK_DEBUG
  402. printk( KERN_DEBUG "crw_info : CRW reports "
  403.         "slct=%d, oflw=%d, chn=%d, "
  404.         "rsc=%X, anc=%d, erc=%X, "
  405.         "rsid=%Xn",
  406.         tcrw.slct,
  407.         tcrw.oflw,
  408.         tcrw.chn,
  409.         tcrw.rsc,
  410.         tcrw.anc,
  411.         tcrw.erc,
  412.         tcrw.rsid );
  413. #endif
  414. /*
  415.  * Dequeue a CRW entry from the free chain
  416.  *  and process it ...
  417.  */
  418. spin_lock( &crw_queue_lock );
  419. pcrwe = crw_buffer_anchor;
  420. if ( pcrwe == NULL )
  421. {
  422. spin_unlock( &crw_queue_lock );
  423. printk( KERN_CRIT"crw_info : "
  424.         "no CRW buffer entries availablen");
  425. break;
  426. } /* endif */
  427. crw_buffer_anchor = pcrwe->crwe_next;
  428. pcrwe->crwe_next  = NULL;
  429. spin_unlock( &crw_queue_lock );
  430. memcpy( &(pcrwe->crw), &tcrw, sizeof(crw_t));
  431. /*
  432.  * If it is the first CRW, chain it to the mchchk
  433.  *  buffer entry, otherwise to the last CRW entry.
  434.  */
  435. if ( chain == 0 )
  436. {
  437. pmache = s390_dequeue_free_mchchk();
  438. if ( pmache != NULL )
  439. {
  440. memset( pmache, '', sizeof(mache_t));
  441. pmache->mcic.mcc.mcd.cp = 1;
  442. pmache->mc.crwe         = pcrwe;
  443. pccrw                   = pcrwe;
  444. }
  445. else
  446. {
  447. panic( "crw_info : "
  448.        "unable to dequeue "
  449.        "free mchchk buffer");
  450. } /* endif */
  451. }
  452. else
  453. {
  454. pccrw->crwe_next = pcrwe;
  455. pccrw            = pcrwe;
  456. } /* endif */
  457. if ( pccrw->crw.chn )
  458. {
  459. #ifdef S390_MACHCHK_DEBUG
  460. printk( KERN_DEBUG "crw_info : "
  461.         "chained CRWs pending ...nn");
  462. #endif
  463. chain = 1;
  464. }
  465. else
  466. {
  467. chain = 0;
  468. /*
  469.  * We can enqueue the mchchk buffer if
  470.  *  there aren't more CRWs chained.
  471.  */
  472. s390_enqueue_mchchk( pmache);
  473. } /* endif */
  474. } /* endif */
  475. } while ( ccode == 0 );
  476. return( count );
  477. }
  478. #ifdef CONFIG_MACHCHK_WARNING
  479. /*
  480.  * s390_post_warning
  481.  *
  482.  * Post a warning type machine check
  483.  *
  484.  * The function returns 1 when succesfull (panics otherwise)
  485.  */
  486. static int s390_post_warning( void )
  487. {
  488. mache_t  *pmache = NULL; /* ptr to mchchk entry */
  489. pmache = s390_dequeue_free_mchchk();
  490. if ( pmache != NULL )
  491. {
  492. memset( pmache, '', sizeof(mache_t) );
  493. pmache->mcic.mcc.mcd.w = 1;
  494. s390_enqueue_mchchk( pmache );
  495. }
  496. else
  497. {
  498. panic(  "post_warning : "
  499. "unable to dequeue "
  500. "free mchchk buffer" );
  501. } /* endif */
  502. #ifdef S390_MACHCHK_DEBUG
  503. printk( KERN_DEBUG "post_warning : 1 warning machine check postedn");
  504. #endif
  505. return ( 1 );
  506. }
  507. #endif