static void s390_reset_chpids_mcck_handler(void) { struct crw crw; union mci mci; /* Check for pending channel report word. */ mci.val = S390_lowcore.mcck_interruption_code; if (!mci.cp) return; /* Process channel report words. */ while (stcrw(&crw) == 0) { /* Check for responses to RCHP. */ if (crw.slct && crw.rsc == CRW_RSC_CPATH) atomic_dec(&chpid_reset_count); } }
/* * Retrieve CRWs and call function to handle event. */ static int crw_collect_info(void *unused) { struct crw crw[2]; int ccode; unsigned int chain; int ignore; repeat: ignore = down_interruptible(&crw_semaphore); chain = 0; while (1) { crw_handler_t handler; if (unlikely(chain > 1)) { struct crw tmp_crw; printk(KERN_WARNING"%s: Code does not support more " "than two chained crws; please report to " "[email protected]!\n", __func__); ccode = stcrw(&tmp_crw); printk(KERN_WARNING"%s: crw reports slct=%d, oflw=%d, " "chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n", __func__, tmp_crw.slct, tmp_crw.oflw, tmp_crw.chn, tmp_crw.rsc, tmp_crw.anc, tmp_crw.erc, tmp_crw.rsid); printk(KERN_WARNING"%s: This was crw number %x in the " "chain\n", __func__, chain); if (ccode != 0) break; chain = tmp_crw.chn ? chain + 1 : 0; continue; } ccode = stcrw(&crw[chain]); if (ccode != 0) break; printk(KERN_DEBUG "crw_info : CRW reports slct=%d, oflw=%d, " "chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n", crw[chain].slct, crw[chain].oflw, crw[chain].chn, crw[chain].rsc, crw[chain].anc, crw[chain].erc, crw[chain].rsid); /* Check for overflows. */ if (crw[chain].oflw) { int i; pr_debug("%s: crw overflow detected!\n", __func__); mutex_lock(&crw_handler_mutex); for (i = 0; i < NR_RSCS; i++) { if (crw_handlers[i]) crw_handlers[i](NULL, NULL, 1); } mutex_unlock(&crw_handler_mutex); chain = 0; continue; } if (crw[0].chn && !chain) { chain++; continue; } mutex_lock(&crw_handler_mutex); handler = crw_handlers[crw[chain].rsc]; if (handler) handler(&crw[0], chain ? &crw[1] : NULL, 0); mutex_unlock(&crw_handler_mutex); /* chain is always 0 or 1 here. */ chain = crw[chain].chn ? chain + 1 : 0; } goto repeat; return 0; }
/* * s390_collect_crw_info * * Retrieve CRWs. If a CRW was found a machine check element * is dequeued from the free chain, filled and enqueued to * be processed. * * The function returns the number of CRWs found. * * Note : We must always be called disabled ... */ static int s390_collect_crw_info( void ) { crw_t tcrw; /* temporarily holds a CRW */ int ccode; /* condition code from stcrw() */ crwe_t *pcrwe; /* pointer to CRW buffer entry */ mache_t *pmache = NULL; /* ptr to mchchk entry */ int chain = 0; /* indicate chaining */ crwe_t *pccrw = NULL; /* ptr to current CRW buffer entry */ int count = 0; /* CRW count */ #ifdef S390_MACHCHK_DEBUG printk( KERN_DEBUG "crw_info : looking for CRWs ...\n"); #endif do { ccode = stcrw( (__u32 *)&tcrw); if ( ccode == 0 ) { count++; #ifdef S390_MACHCHK_DEBUG printk( KERN_DEBUG "crw_info : CRW reports " "slct=%d, oflw=%d, chn=%d, " "rsc=%X, anc=%d, erc=%X, " "rsid=%X\n", tcrw.slct, tcrw.oflw, tcrw.chn, tcrw.rsc, tcrw.anc, tcrw.erc, tcrw.rsid ); #endif /* * Dequeue a CRW entry from the free chain * and process it ... */ spin_lock( &crw_queue_lock ); pcrwe = crw_buffer_anchor; if ( pcrwe == NULL ) { spin_unlock( &crw_queue_lock ); printk( KERN_CRIT"crw_info : " "no CRW buffer entries available\n"); break; } /* endif */ crw_buffer_anchor = pcrwe->crwe_next; pcrwe->crwe_next = NULL; spin_unlock( &crw_queue_lock ); memcpy( &(pcrwe->crw), &tcrw, sizeof(crw_t)); /* * If it is the first CRW, chain it to the mchchk * buffer entry, otherwise to the last CRW entry. */ if ( chain == 0 ) { pmache = s390_dequeue_free_mchchk(); if ( pmache != NULL ) { memset( pmache, '\0', sizeof(mache_t)); pmache->mcic.mcc.mcd.cp = 1; pmache->mc.crwe = pcrwe; pccrw = pcrwe; } else { panic( "crw_info : " "unable to dequeue " "free mchchk buffer"); } /* endif */ } else { pccrw->crwe_next = pcrwe; pccrw = pcrwe; } /* endif */ if ( pccrw->crw.chn ) { #ifdef S390_MACHCHK_DEBUG printk( KERN_DEBUG "crw_info : " "chained CRWs pending ...\n\n"); #endif chain = 1; } else { chain = 0; /* * We can enqueue the mchchk buffer if * there aren't more CRWs chained. */ s390_enqueue_mchchk( pmache); } /* endif */ } /* endif */ } while ( ccode == 0 ); return( count ); }
/* * Retrieve CRWs and call function to handle event. * * Note : we currently process CRWs for io and chsc subchannels only */ static int s390_collect_crw_info(void *param) { struct crw crw; int ccode, ret, slow; struct semaphore *sem; sem = (struct semaphore *)param; /* Set a nice name. */ daemonize("kmcheck"); repeat: down_interruptible(sem); slow = 0; while (1) { ccode = stcrw(&crw); if (ccode != 0) break; DBG(KERN_DEBUG "crw_info : CRW reports slct=%d, oflw=%d, " "chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n", crw.slct, crw.oflw, crw.chn, crw.rsc, crw.anc, crw.erc, crw.rsid); /* Check for overflows. */ if (crw.oflw) { pr_debug("%s: crw overflow detected!\n", __FUNCTION__); css_reiterate_subchannels(); slow = 1; continue; } switch (crw.rsc) { case CRW_RSC_SCH: pr_debug("source is subchannel %04X\n", crw.rsid); ret = css_process_crw (crw.rsid); if (ret == -EAGAIN) slow = 1; break; case CRW_RSC_MONITOR: pr_debug("source is monitoring facility\n"); break; case CRW_RSC_CPATH: pr_debug("source is channel path %02X\n", crw.rsid); switch (crw.erc) { case CRW_ERC_IPARM: /* Path has come. */ ret = chp_process_crw(crw.rsid, 1); break; case CRW_ERC_PERRI: /* Path has gone. */ case CRW_ERC_PERRN: ret = chp_process_crw(crw.rsid, 0); break; default: pr_debug("Don't know how to handle erc=%x\n", crw.erc); ret = 0; } if (ret == -EAGAIN) slow = 1; break; case CRW_RSC_CONFIG: pr_debug("source is configuration-alert facility\n"); break; case CRW_RSC_CSS: pr_debug("source is channel subsystem\n"); ret = chsc_process_crw(); if (ret == -EAGAIN) slow = 1; break; default: pr_debug("unknown source\n"); break; } } if (slow) queue_work(slow_path_wq, &slow_path_work); goto repeat; return 0; }
/* * Retrieve CRWs and call function to handle event. */ static int crw_collect_info(void *unused) { struct crw crw[2]; int ccode, signal; unsigned int chain; repeat: signal = wait_event_interruptible(crw_handler_wait_q, atomic_read(&crw_nr_req) > 0); if (unlikely(signal)) atomic_inc(&crw_nr_req); chain = 0; while (1) { crw_handler_t handler; if (unlikely(chain > 1)) { struct crw tmp_crw; #ifdef CONFIG_DEBUG_PRINTK printk(KERN_WARNING"%s: Code does not support more " "than two chained crws; please report to " #else ; #endif "[email protected]!\n", __func__); ccode = stcrw(&tmp_crw); #ifdef CONFIG_DEBUG_PRINTK printk(KERN_WARNING"%s: crw reports slct=%d, oflw=%d, " "chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n", __func__, tmp_crw.slct, tmp_crw.oflw, tmp_crw.chn, tmp_crw.rsc, tmp_crw.anc, tmp_crw.erc, tmp_crw.rsid); #else ; #endif #ifdef CONFIG_DEBUG_PRINTK printk(KERN_WARNING"%s: This was crw number %x in the " "chain\n", __func__, chain); #else ; #endif if (ccode != 0) break; chain = tmp_crw.chn ? chain + 1 : 0; continue; } ccode = stcrw(&crw[chain]); if (ccode != 0) break; #ifdef CONFIG_DEBUG_PRINTK printk(KERN_DEBUG "crw_info : CRW reports slct=%d, oflw=%d, " "chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n", crw[chain].slct, crw[chain].oflw, crw[chain].chn, crw[chain].rsc, crw[chain].anc, crw[chain].erc, crw[chain].rsid); #else ; #endif /* Check for overflows. */ if (crw[chain].oflw) { int i; pr_debug("%s: crw overflow detected!\n", __func__); mutex_lock(&crw_handler_mutex); for (i = 0; i < NR_RSCS; i++) { if (crw_handlers[i]) crw_handlers[i](NULL, NULL, 1); } mutex_unlock(&crw_handler_mutex); chain = 0; continue; } if (crw[0].chn && !chain) { chain++; continue; } mutex_lock(&crw_handler_mutex); handler = crw_handlers[crw[chain].rsc]; if (handler) handler(&crw[0], chain ? &crw[1] : NULL, 0); mutex_unlock(&crw_handler_mutex); /* chain is always 0 or 1 here. */ chain = crw[chain].chn ? chain + 1 : 0; } if (atomic_dec_and_test(&crw_nr_req)) wake_up(&crw_handler_wait_q); goto repeat; return 0; }