int ftape_wakeup_drive(wake_up_types method) { int status; int motor_on = 0; TRACE_FUN(ft_t_any); switch (method) { case wake_up_colorado: TRACE_CATCH(ftape_command(QIC_PHANTOM_SELECT),); TRACE_CATCH(ftape_parameter(0 /* ft_drive_sel ?? */),); break; case wake_up_mountain: TRACE_CATCH(ftape_command(QIC_SOFT_SELECT),); ftape_sleep(FT_MILLISECOND); /* NEEDED */ TRACE_CATCH(ftape_parameter(18),); break; case wake_up_insight: ftape_sleep(100 * FT_MILLISECOND); motor_on = 1; fdc_motor(motor_on); /* enable is done by motor-on */ case no_wake_up: break; default: TRACE_EXIT -ENODEV; /* unknown wakeup method */ break; } /* If wakeup succeeded we shouldn't get an error here.. */ TRACE_CATCH(ftape_report_raw_drive_status(&status), if (motor_on) { fdc_motor(0); });
/* Wait for the drive to get ready. * timeout time in milli-seconds * Returned status is valid if result != -EIO * * Should we allow to be killed by SIGINT? (^C) * Would be nice at least for large timeouts. */ int ftape_ready_wait(unsigned int timeout, int *status) { unsigned long t0; unsigned int poll_delay; int signal_retries; TRACE_FUN(ft_t_any); /* the following ** REALLY ** reduces the system load when * e.g. one simply rewinds or retensions. The tape is slow * anyway. It is really not necessary to detect error * conditions with 1/10 seconds granularity * * On my AMD 133MHZ 486: 100 ms: 23% system load * 1 sec: 5% * 5 sec: 0.6%, yeah */ if (timeout <= FT_SECOND) { poll_delay = 100 * FT_MILLISECOND; signal_retries = 20; /* two seconds */ } else if (timeout < 20 * FT_SECOND) { TRACE(ft_t_flow, "setting poll delay to 1 second"); poll_delay = FT_SECOND; signal_retries = 2; /* two seconds */ } else { TRACE(ft_t_flow, "setting poll delay to 5 seconds"); poll_delay = 5 * FT_SECOND; signal_retries = 1; /* five seconds */ } for (;;) { t0 = jiffies; TRACE_CATCH(ftape_report_raw_drive_status(status),); if (*status & QIC_STATUS_READY) { TRACE_EXIT 0; } if (!signal_retries--) { FT_SIGNAL_EXIT(_NEVER_BLOCK); } if ((int)timeout >= 0) { /* this will fail when jiffies wraps around about * once every year :-) */ timeout -= ((jiffies - t0) * FT_SECOND) / HZ; if (timeout <= 0) { TRACE_ABORT(-ETIME, ft_t_err, "timeout"); } ftape_sleep(poll_delay); timeout -= poll_delay; } else { ftape_sleep(poll_delay); } } TRACE_EXIT -ETIME; }
/* Called by modules package when installing the driver * or by kernel during the initialization phase */ static int __init ftape_init(void) { TRACE_FUN(ft_t_flow); #ifdef MODULE #ifndef CONFIG_FT_NO_TRACE_AT_ALL if (ft_tracing != -1) { ftape_tracing = ft_tracing; } #endif printk(KERN_INFO FTAPE_VERSION "\n"); if (TRACE_LEVEL >= ft_t_info) { printk( KERN_INFO "(c) 1993-1996 Bas Laarhoven ([email protected])\n" KERN_INFO "(c) 1995-1996 Kai Harrekilde-Petersen ([email protected])\n" KERN_INFO "(c) 1996-1997 Claus-Justus Heine ([email protected])\n" KERN_INFO "QIC-117 driver for QIC-40/80/3010/3020 floppy tape drives\n" KERN_INFO "Compiled for Linux version %s\n", UTS_RELEASE); } #else /* !MODULE */ /* print a short no-nonsense boot message */ printk(KERN_INFO FTAPE_VERSION " for Linux " UTS_RELEASE "\n"); #endif /* MODULE */ TRACE(ft_t_info, "installing QIC-117 floppy tape hardware drive ... "); TRACE(ft_t_info, "ftape_init @ 0x%p", ftape_init); /* Allocate the DMA buffers. They are deallocated at cleanup() time. */ #if TESTING #ifdef MODULE while (ftape_set_nr_buffers(CONFIG_FT_NR_BUFFERS) < 0) { ftape_sleep(FT_SECOND/20); if (signal_pending(current)) { (void)ftape_set_nr_buffers(0); TRACE(ft_t_bug, "Killed by signal while allocating buffers."); TRACE_ABORT(-EINTR, ft_t_bug, "Free up memory and retry"); } } #else TRACE_CATCH(ftape_set_nr_buffers(CONFIG_FT_NR_BUFFERS), (void)ftape_set_nr_buffers(0)); #endif #else TRACE_CATCH(ftape_set_nr_buffers(CONFIG_FT_NR_BUFFERS), (void)ftape_set_nr_buffers(0)); #endif ft_drive_sel = -1; ft_failure = 1; /* inhibit any operation but open */ ftape_udelay_calibrate(); /* must be before fdc_wait_calibrate ! */ fdc_wait_calibrate(); #if defined(CONFIG_PROC_FS) && defined(CONFIG_FT_PROC_FS) (void)ftape_proc_init(); #endif #ifdef CONFIG_ZFTAPE (void)zft_init(); #endif TRACE_EXIT 0; }
/* send a command or parameter to the drive * Generates # of step pulses. */ static inline int ft_send_to_drive(int arg) { /* Always wait for a command_timeout period to separate * individuals commands and/or parameters. */ ftape_sleep(3 * FT_MILLISECOND); /* Keep cylinder nr within range, step towards home if possible. */ if (ftape_current_cylinder >= arg) { return fdc_seek(ftape_current_cylinder - arg); } else { return fdc_seek(ftape_current_cylinder + arg); } }
int ftape_report_operation(int *status, qic117_cmd_t command, int result_length) { int i, st3; unsigned int t0; unsigned int dt; TRACE_FUN(ft_t_any); TRACE_CATCH(ftape_command(command),); t0 = ftape_timestamp(); i = 0; do { ++i; ftape_sleep(3 * FT_MILLISECOND); /* see remark below */ TRACE_CATCH(fdc_sense_drive_status(&st3),); dt = ftape_timediff(t0, ftape_timestamp()); /* Ack should be asserted within Ttimout + Tack = 6 msec. * Looks like some drives fail to do this so extend this * period to 300 msec. */ } while (!(st3 & ST3_TRACK_0) && dt < 300000); if (!(st3 & ST3_TRACK_0)) { TRACE(ft_t_err, "No acknowledge after %u msec. (%i iter)", dt / 1000, i); TRACE_ABORT(-EIO, ft_t_err, "timeout on Acknowledge"); } /* dt may be larger than expected because of other tasks * scheduled while we were sleeping. */ if (i > 1 && dt > 6000) { TRACE(ft_t_err, "Acknowledge after %u msec. (%i iter)", dt / 1000, i); } *status = 0; for (i = 0; i < result_length + 1; i++) { TRACE_CATCH(ftape_command(QIC_REPORT_NEXT_BIT),); TRACE_CATCH(fdc_sense_drive_status(&st3),); if (i < result_length) { *status |= ((st3 & ST3_TRACK_0) ? 1 : 0) << i; } else if ((st3 & ST3_TRACK_0) == 0) { TRACE_ABORT(-EIO, ft_t_err, "missing status stop bit"); } } /* this command will put track zero and index back into normal state */ (void)ftape_command(QIC_REPORT_NEXT_BIT); TRACE_EXIT 0; }