/* * First write to nvram, if fatal error, that is the only * place we log the info. The error will be picked up * on the next reboot by rtasd. If not fatal, run the * method for the type of error. Currently, only RTAS * errors have methods implemented, but in the future * there might be a need to store data in nvram before a * call to panic(). * * XXX We write to nvram periodically, to indicate error has * been written and sync'd, but there is a possibility * that if we don't shutdown correctly, a duplicate error * record will be created on next reboot. */ void pSeries_log_error(char *buf, unsigned int err_type, int fatal) { unsigned long offset; unsigned long s; int len = 0; pr_debug("rtasd: logging event\n"); if (buf == NULL) return; spin_lock_irqsave(&rtasd_log_lock, s); /* get length and increase count */ switch (err_type & ERR_TYPE_MASK) { case ERR_TYPE_RTAS_LOG: len = log_rtas_len(buf); if (!(err_type & ERR_FLAG_BOOT)) error_log_cnt++; break; case ERR_TYPE_KERNEL_PANIC: default: WARN_ON_ONCE(!irqs_disabled()); /* @@@ DEBUG @@@ */ spin_unlock_irqrestore(&rtasd_log_lock, s); return; } #ifdef CONFIG_PPC64 /* Write error to NVRAM */ if (logging_enabled && !(err_type & ERR_FLAG_BOOT)) nvram_write_error_log(buf, len, err_type, error_log_cnt); #endif /* CONFIG_PPC64 */ /* * rtas errors can occur during boot, and we do want to capture * those somewhere, even if nvram isn't ready (why not?), and even * if rtasd isn't ready. Put them into the boot log, at least. */ if ((err_type & ERR_TYPE_MASK) == ERR_TYPE_RTAS_LOG) printk_log_rtas(buf, len); /* Check to see if we need to or have stopped logging */ if (fatal || !logging_enabled) { logging_enabled = 0; WARN_ON_ONCE(!irqs_disabled()); /* @@@ DEBUG @@@ */ spin_unlock_irqrestore(&rtasd_log_lock, s); return; } /* call type specific method for error */ switch (err_type & ERR_TYPE_MASK) { case ERR_TYPE_RTAS_LOG: offset = rtas_error_log_buffer_max * ((rtas_log_start+rtas_log_size) & LOG_NUMBER_MASK); /* First copy over sequence number */ memcpy(&rtas_log_buf[offset], (void *) &error_log_cnt, sizeof(int)); /* Second copy over error log data */ offset += sizeof(int); memcpy(&rtas_log_buf[offset], buf, len); if (rtas_log_size < LOG_NUMBER) rtas_log_size += 1; else rtas_log_start += 1; WARN_ON_ONCE(!irqs_disabled()); /* @@@ DEBUG @@@ */ spin_unlock_irqrestore(&rtasd_log_lock, s); wake_up_interruptible(&rtas_log_wait); break; case ERR_TYPE_KERNEL_PANIC: default: WARN_ON_ONCE(!irqs_disabled()); /* @@@ DEBUG @@@ */ spin_unlock_irqrestore(&rtasd_log_lock, s); return; } }
/* * First write to nvram, if fatal error, that is the only * place we log the info. The error will be picked up * on the next reboot by rtasd. If not fatal, run the * method for the type of error. Currently, only RTAS * errors have methods implemented, but in the future * there might be a need to store data in nvram before a * call to panic(). * * XXX We write to nvram periodically, to indicate error has * been written and sync'd, but there is a possibility * that if we don't shutdown correctly, a duplicate error * record will be created on next reboot. */ void pSeries_log_error(char *buf, unsigned int err_type, int fatal) { unsigned long offset; unsigned long s; int len = 0; DEBUG("logging event\n"); if (buf == NULL) return; spin_lock_irqsave(&log_lock, s); /* get length and increase count */ switch (err_type & ERR_TYPE_MASK) { case ERR_TYPE_RTAS_LOG: len = log_rtas_len(buf); if (!(err_type & ERR_FLAG_BOOT)) error_log_cnt++; break; case ERR_TYPE_KERNEL_PANIC: default: spin_unlock_irqrestore(&log_lock, s); return; } /* Write error to NVRAM */ if (!no_more_logging && !(err_type & ERR_FLAG_BOOT)) nvram_write_error_log(buf, len, err_type); /* Check to see if we need to or have stopped logging */ if (fatal || no_more_logging) { no_more_logging = 1; spin_unlock_irqrestore(&log_lock, s); return; } /* call type specific method for error */ switch (err_type & ERR_TYPE_MASK) { case ERR_TYPE_RTAS_LOG: /* put into syslog and error_log file */ printk_log_rtas(buf, len); offset = rtas_error_log_buffer_max * ((rtas_log_start+rtas_log_size) & LOG_NUMBER_MASK); /* First copy over sequence number */ memcpy(&rtas_log_buf[offset], (void *) &error_log_cnt, sizeof(int)); /* Second copy over error log data */ offset += sizeof(int); memcpy(&rtas_log_buf[offset], buf, len); if (rtas_log_size < LOG_NUMBER) rtas_log_size += 1; else rtas_log_start += 1; spin_unlock_irqrestore(&log_lock, s); wake_up_interruptible(&rtas_log_wait); break; case ERR_TYPE_KERNEL_PANIC: default: spin_unlock_irqrestore(&log_lock, s); return; } }