/* Input a res_len long result string from the FDC. * The FDC should be ready to send the result or an error * (EBUSY or ETIME) will occur. */ int fdc_result(__u8 * res_data, int res_len) { int result = 0; unsigned long flags; int count = res_len; int retry = 0; TRACE_FUN(ft_t_any); save_flags(flags); cli(); fdc_status = inb(fdc.msr); if ((fdc_status & FDC_DATA_READY_MASK) != FDC_DATA_OUT_READY) { TRACE(ft_t_err, "fdc not ready"); result = -EBUSY; } else while (count) { if (!(fdc_status & FDC_BUSY)) { restore_flags(flags); TRACE_ABORT(-EIO, ft_t_err, "premature end of result phase"); } result = fdc_read(res_data); if (result < 0) { TRACE(ft_t_fdc_dma, "fdc_mode = %02x, status = %02x at index %d", (int) fdc_mode, (int) fdc_status, res_len - count); if (++retry <= 3) { TRACE(ft_t_warn, "fdc_read timeout, retry"); } else { TRACE(ft_t_err, "fdc_read timeout, fatal"); /* recover ??? */ break; ++retry; } } else { --count; ++res_data; } } restore_flags(flags); fdc_usec_wait(FT_RQM_DELAY); /* allow FDC to negate BSY */ TRACE_EXIT result; }
/* Output a cmd_len long command string to the FDC. * The FDC should be ready to receive a new command or * an error (EBUSY or ETIME) will occur. */ int fdc_command(const __u8 * cmd_data, int cmd_len) { int result = 0; unsigned long flags; int count = cmd_len; int retry = 0; #ifdef TESTING static unsigned int last_time; unsigned int time; #endif TRACE_FUN(ft_t_any); fdc_usec_wait(FT_RQM_DELAY); /* wait for valid RQM status */ spin_lock_irqsave(&fdc_io_lock, flags); if (!in_interrupt()) /* Yes, I know, too much comments inside this function * ... * * Yet another bug in the original driver. All that * havoc is caused by the fact that the isr() sends * itself a command to the floppy tape driver (pause, * micro step pause). Now, the problem is that * commands are transmitted via the fdc_seek * command. But: the fdc performs seeks in the * background i.e. it doesn't signal busy while * sending the step pulses to the drive. Therefore the * non-interrupt level driver has no chance to tell * whether the isr() just has issued a seek. Therefore * we HAVE TO have a look at the ft_hide_interrupt * flag: it signals the non-interrupt level part of * the driver that it has to wait for the fdc until it * has completet seeking. * * THIS WAS PRESUMABLY THE REASON FOR ALL THAT * "fdc_read timeout" errors, I HOPE :-) */ if (ft_hide_interrupt) { restore_flags(flags); TRACE(ft_t_info, "Waiting for the isr() completing fdc_seek()"); if (fdc_interrupt_wait(2 * FT_SECOND) < 0) { TRACE(ft_t_warn, "Warning: timeout waiting for isr() seek to complete"); } if (ft_hide_interrupt || !ft_seek_completed) { /* There cannot be another * interrupt. The isr() only stops * the tape and the next interrupt * won't come until we have send our * command to the drive. */ TRACE_ABORT(-EIO, ft_t_bug, "BUG? isr() is still seeking?\n" KERN_INFO "hide: %d\n" KERN_INFO "seek: %d", ft_hide_interrupt, ft_seek_completed); } fdc_usec_wait(FT_RQM_DELAY); /* wait for valid RQM status */ spin_lock_irqsave(&fdc_io_lock, flags); } fdc_status = inb(fdc.msr); if ((fdc_status & FDC_DATA_READY_MASK) != FDC_DATA_IN_READY) { spin_unlock_irqrestore(&fdc_io_lock, flags); TRACE_ABORT(-EBUSY, ft_t_err, "fdc not ready"); } fdc_mode = *cmd_data; /* used by isr */ #ifdef TESTING if (fdc_mode == FDC_SEEK) { time = ftape_timediff(last_time, ftape_timestamp()); if (time < 6000) { TRACE(ft_t_bug,"Warning: short timeout between seek commands: %d", time); } } #endif if (!in_interrupt()) { /* shouldn't be cleared if called from isr */ ft_interrupt_seen = 0; } while (count) { result = fdc_write(*cmd_data); if (result < 0) { TRACE(ft_t_fdc_dma, "fdc_mode = %02x, status = %02x at index %d", (int) fdc_mode, (int) fdc_status, cmd_len - count); if (++retry <= 3) { TRACE(ft_t_warn, "fdc_write timeout, retry"); } else { TRACE(ft_t_err, "fdc_write timeout, fatal"); /* recover ??? */ break; } } else { --count; ++cmd_data; } } #ifdef TESTING if (fdc_mode == FDC_SEEK) { last_time = ftape_timestamp(); } #endif spin_unlock_irqrestore(&fdc_io_lock, flags); TRACE_EXIT result; }
static int fdc_ready_out_wait(unsigned int usecs) { fdc_usec_wait(FT_RQM_DELAY); /* wait for valid RQM status */ return fdc_wait(usecs, FDC_DATA_OUT_READY, FDC_DATA_OUT_READY); }