int loop_until_writes_done(void) { TRACE_FUN(5, "loop_until_writes_done"); int i; int result = 0; /* * Wait until all data is actually written to tape. */ while (ftape_state == writing && buffer[head].status != done) { TRACEx2(7, "tail: %d, head: %d", tail, head); for (i = 0; i < NR_BUFFERS; ++i) { TRACEx3(8, "buffer[ %d] segment_id: %d, status: %d", i, buffer[i].segment_id, buffer[i].status); } result = fdc_interrupt_wait(5 * SECOND); if (result < 0) { TRACE(1, "fdc_interrupt_wait failed"); last_write_failed = 1; break; } if (buffer[head].status == error) { /* Allow escape from loop when signaled ! */ if (current->signal & _DONT_BLOCK) { TRACE(2, "interrupted by signal"); TRACE_EXIT; result = -EINTR; /* is this the right return value ? */ break; } if (buffer[head].hard_error_map != 0) { /* Implement hard write error recovery here */ } buffer[head].status = waiting; /* retry this one */ if (runner_status == aborting) { ftape_dumb_stop(); runner_status = idle; } if (runner_status != idle) { TRACE(1, "unexpected state: runner_status != idle"); result = -EIO; break; } start_writing(WRITE_MULTI); } TRACE(5, "looping until writes done"); result = 0; /* normal exit status */ } TRACE_EXIT; return 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; }