static inline error_cause decode_irq_cause(fdc_mode_enum mode, __u8 st[]) { error_cause cause = no_error; TRACE_FUN(ft_t_any); /* Valid st[], decode cause of interrupt. */ switch (st[0] & ST0_INT_MASK) { case FDC_INT_NORMAL: TRACE(ft_t_fdc_dma,"normal completion: %s",fdc_mode_txt(mode)); break; case FDC_INT_ABNORMAL: TRACE(ft_t_flow, "abnormal completion %s", fdc_mode_txt(mode)); TRACE(ft_t_fdc_dma, "ST0: 0x%02x, ST1: 0x%02x, ST2: 0x%02x", st[0], st[1], st[2]); TRACE(ft_t_fdc_dma, "C: 0x%02x, H: 0x%02x, R: 0x%02x, N: 0x%02x", st[3], st[4], st[5], st[6]); if (st[1] & 0x01) { if (st[2] & 0x01) { cause = data_am_error; } else { cause = id_am_error; } } else if (st[1] & 0x20) { if (st[2] & 0x20) { cause = data_crc_error; } else { cause = id_crc_error; } } else if (st[1] & 0x04) { cause = no_data_error; } else if (st[1] & 0x10) { cause = overrun_error; } print_error_cause(cause); break; case FDC_INT_INVALID: TRACE(ft_t_flow, "invalid completion %s", fdc_mode_txt(mode)); break; case FDC_INT_READYCH: if (st[0] & ST0_SEEK_END) { TRACE(ft_t_flow, "drive poll completed"); } else { TRACE(ft_t_flow, "ready change %s",fdc_mode_txt(mode)); } break; default: break; } TRACE_EXIT cause; }
static void print_error_cause(int cause) { TRACE_FUN(ft_t_any); switch (cause) { case no_data_error: TRACE(ft_t_noise, "no data error"); break; case id_am_error: TRACE(ft_t_noise, "id am error"); break; case id_crc_error: TRACE(ft_t_noise, "id crc error"); break; case data_am_error: TRACE(ft_t_noise, "data am error"); break; case data_crc_error: TRACE(ft_t_noise, "data crc error"); break; case overrun_error: TRACE(ft_t_noise, "overrun error"); break; default: } TRACE_EXIT; } static char *fdc_mode_txt(fdc_mode_enum mode) { switch (mode) { case fdc_idle: return "fdc_idle"; case fdc_reading_data: return "fdc_reading_data"; case fdc_seeking: return "fdc_seeking"; case fdc_writing_data: return "fdc_writing_data"; case fdc_reading_id: return "fdc_reading_id"; case fdc_recalibrating: return "fdc_recalibrating"; case fdc_formatting: return "fdc_formatting"; case fdc_verifying: return "fdc_verifying"; default: return "unknown"; } } static inline error_cause decode_irq_cause(fdc_mode_enum mode, __u8 st[]) { error_cause cause = no_error; TRACE_FUN(ft_t_any); /* Valid st[], decode cause of interrupt. */ switch (st[0] & ST0_INT_MASK) { case FDC_INT_NORMAL: TRACE(ft_t_fdc_dma,"normal completion: %s",fdc_mode_txt(mode)); break; case FDC_INT_ABNORMAL: TRACE(ft_t_flow, "abnormal completion %s", fdc_mode_txt(mode)); TRACE(ft_t_fdc_dma, "ST0: 0x%02x, ST1: 0x%02x, ST2: 0x%02x", st[0], st[1], st[2]); TRACE(ft_t_fdc_dma, "C: 0x%02x, H: 0x%02x, R: 0x%02x, N: 0x%02x", st[3], st[4], st[5], st[6]); if (st[1] & 0x01) { if (st[2] & 0x01) { cause = data_am_error; } else { cause = id_am_error; } } else if (st[1] & 0x20) { if (st[2] & 0x20) { cause = data_crc_error; } else { cause = id_crc_error; } } else if (st[1] & 0x04) { cause = no_data_error; } else if (st[1] & 0x10) { cause = overrun_error; } print_error_cause(cause); break; case FDC_INT_INVALID: TRACE(ft_t_flow, "invalid completion %s", fdc_mode_txt(mode)); break; case FDC_INT_READYCH: if (st[0] & ST0_SEEK_END) { TRACE(ft_t_flow, "drive poll completed"); } else { TRACE(ft_t_flow, "ready change %s",fdc_mode_txt(mode)); } break; default: break; } TRACE_EXIT cause; }
static void print_error_cause(int cause) { TRACE_FUN(8, "print_error_cause"); switch (cause) { case no_data_error: TRACE(4, "no data error"); break; case id_am_error: TRACE(4, "id am error"); break; case id_crc_error: TRACE(4, "id crc error"); break; case data_am_error: TRACE(4, "data am error"); break; case data_crc_error: TRACE(4, "data crc error"); break; case overrun_error: TRACE(4, "overrun error"); break; default: } TRACE_EXIT; } static char * get_fdc_mode_text(fdc_mode_enum fdc_mode) { switch (fdc_mode) { case fdc_idle: return "fdc_idle"; case fdc_reading_data: return "fdc_reading_data"; case fdc_seeking: return "fdc_seeking"; case fdc_writing_data: return "fdc_writing_data"; case fdc_reading_id: return "fdc_reading_id"; case fdc_recalibrating: return "fdc_recalibrating"; default: return "unknown"; } } static void decode_irq_cause(fdc_mode_enum fdc_mode, byte st[], char **fdc_mode_txt, error_cause * cause) { TRACE_FUN(8, "decode_irq_cause"); /* Valid st[], decode cause of interrupt. */ *fdc_mode_txt = get_fdc_mode_text(fdc_mode); switch (st[0] & ST0_INT_MASK) { case FDC_INT_NORMAL: TRACEx1(fdc_mode == fdc_reading_id ? 6 : 5, "normal completion: %s", *fdc_mode_txt); *cause = no_error; break; case FDC_INT_ABNORMAL: TRACEx1(5, "abnormal completion %s", *fdc_mode_txt); TRACEx3(6, "ST0: 0x%02x, ST1: 0x%02x, ST2: 0x%02x", st[0], st[1], st[2]); TRACEx4(6, "C: 0x%02x, H: 0x%02x, R: 0x%02x, N: 0x%02x", st[3], st[4], st[5], st[6]); if (st[1] & 0x01) { if (st[2] & 0x01) { *cause = data_am_error; } else { *cause = id_am_error; } } else if (st[1] & 0x20) { if (st[2] & 0x20) { *cause = data_crc_error; } else { *cause = id_crc_error; } } else if (st[1] & 0x04) { *cause = no_data_error; } else if (st[1] & 0x10) { *cause = overrun_error; } print_error_cause(*cause); break; case FDC_INT_INVALID: TRACEx1(5, "invalid completion %s", *fdc_mode_txt); *cause = no_error; break; case FDC_INT_READYCH: TRACEx1(5, "ready change %s", *fdc_mode_txt); *cause = no_error; break; default: } TRACE_EXIT; } static void update_history(error_cause cause) { switch (cause) { case id_am_error: history.id_am_errors++; break; case id_crc_error: history.id_crc_errors++; break; case data_am_error: history.data_am_errors++; break; case data_crc_error: history.data_crc_errors++; break; case overrun_error: history.overrun_errors++; break; case no_data_error: history.no_data_errors++; break; default: } } static void skip_bad_sector(buffer_struct * buff) { TRACE_FUN(8, "skip_bad_sector"); /* Mark sector as soft error and skip it */ if (buff->remaining > 0) { ++buff->sector_offset; ++buff->data_offset; --buff->remaining; buff->ptr += SECTOR_SIZE; buff->bad_sector_map >>= 1; } else {