/* --- Main FDC dispatcher --- */ static void fdc_execute(FDC_765 *self) { /* This code to dump out FDC commands as they are received is very useful * in debugging * * */ int NC; fdc_dprintf(5, "FDC: "); for (NC = 0; NC < bytes_in_cmd[self->fdc_cmd_buf[0] & 0x1F]; NC++) fdc_dprintf(5, "%02x ", self->fdc_cmd_buf[NC]); fdc_dprintf(5, "\n"); /* */ /* Check if the DOR (ugh!) is being used to force us to a different drive. */ fdc_dorcheck(self); /* Reset "seek finished" flag */ self->fdc_st0 &= 0xBF; switch(self->fdc_cmd_buf[0] & 0x1F) { case 2: fdc_read_track(self); break; /* 2: READ TRACK */ case 3: fdc_specify(self); break; /* 3: SPECIFY */ case 4: fdc_sense_drive(self); break; /* 4: SENSE DRV STATUS*/ case 5: fdc_write(self, 0); break; /* 5: WRITE */ case 6: fdc_read(self, 0); break; /* 6: READ */ case 7: fdc_recalibrate(self); break; /* 7: RECALIBRATE */ case 8: fdc_sense_int(self); break; /* 8: SENSE INT STATUS*/ case 9: fdc_write(self, 1); break; /* 9: WRITE DELETED */ case 10:fdc_read_id(self); break; /*10: READ ID */ case 12:fdc_read(self, 1); break; /*12: READ DELETED */ case 13:fdc_format(self); break; /*13: FORMAT TRACK */ case 15:fdc_seek(self); break; /*15: SEEK */ case 17: /*17: SCAN EQUAL */ case 25: /*25: SCAN LOW/EQUAL */ case 30:fdc_scan(self); break; /*30: SCAN HIGH/EQUAL*/ default: fdc_dprintf(2, "Unknown FDC command %d\n", self->fdc_cmd_buf[0] & 0x1F); fdc_error(self); break; } }
/* 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; }