/* Read from floppy tape device */ static ssize_t zft_read(struct file *fp, char *buff, size_t req_len, loff_t *ppos) { int result = -EIO; sigset_t old_sigmask; struct inode *ino = fp->f_dentry->d_inode; TRACE_FUN(ft_t_flow); TRACE(ft_t_data_flow, "called with count: %ld", (unsigned long)req_len); if (!busy_flag || MINOR(ino->i_rdev) != zft_unit || ft_failure) { TRACE_ABORT(-EIO, ft_t_err, "failed: not busy, failure or wrong unit"); } old_sigmask = current->blocked; /* save mask */ sigfillset(¤t->blocked); result = _zft_read(buff, req_len); current->blocked = old_sigmask; /* restore mask */ TRACE(ft_t_data_flow, "return with count: %d", result); TRACE_EXIT result; }
int ftape_report_error(unsigned int *error, qic117_cmd_t *command, int report) { static const ftape_error ftape_errors[] = QIC117_ERRORS; int code; TRACE_FUN(ft_t_any); TRACE_CATCH(ftape_report_operation(&code, QIC_REPORT_ERROR_CODE, 16),); *error = (unsigned int)(code & 0xff); *command = (qic117_cmd_t)((code>>8)&0xff); /* remember hardware status, maybe useful for status ioctls */ ft_last_error.error.command = (__u8)*command; ft_last_error.error.error = (__u8)*error; if (!report) { TRACE_EXIT 0; } if (*error == 0) { TRACE_ABORT(0, ft_t_info, "No error"); } TRACE(ft_t_info, "errorcode: %d", *error); if (*error < NR_ITEMS(ftape_errors)) { TRACE(ft_t_noise, "%sFatal ERROR:", (ftape_errors[*error].fatal ? "" : "Non-")); TRACE(ft_t_noise, "%s ...", ftape_errors[*error].message); } else { TRACE(ft_t_noise, "Unknown ERROR !"); } if ((unsigned int)*command < NR_ITEMS(qic117_cmds) && qic117_cmds[*command].name != NULL) { TRACE(ft_t_noise, "... caused by command \'%s\'", qic117_cmds[*command].name); } else { TRACE(ft_t_noise, "... caused by unknown command %d", *command); } TRACE_EXIT 0; }
/* Ioctl for floppy tape device */ static int zft_mmap(struct file *filep, struct vm_area_struct *vma) { int result = -EIO; sigset_t old_sigmask; TRACE_FUN(ft_t_flow); if ( !test_bit(0,&busy_flag) || iminor(filep->f_dentry->d_inode) != zft_unit || ft_failure) { TRACE_ABORT(-EIO, ft_t_err, "failed: not busy, failure or wrong unit"); } old_sigmask = current->blocked; /* save mask */ sigfillset(¤t->blocked); if ((result = ftape_mmap(vma)) >= 0) { #ifndef MSYNC_BUG_WAS_FIXED static struct vm_operations_struct dummy = { NULL, }; vma->vm_ops = &dummy; #endif } current->blocked = old_sigmask; /* restore mask */ 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; }
/* Called by modules package when installing the driver * or by kernel during the initialization phase */ int __init ftape_init(void) { TRACE_FUN(ft_t_flow); #ifdef MODULE 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" #ifdef MODVERSIONS " with versioned symbols" #endif "\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 LINUX_VERSION_CODE < KERNEL_VER(2,1,18) register_symtab(&ftape_symbol_table); /* add global ftape symbols */ #endif #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; }
int fc10_enable(void) { int i; __u8 cardConfig = 0x00; __u8 x; TRACE_FUN(ft_t_flow); /* This code will only work if the FC-10 (or FC-20) is set to * use DMA channels 1, 2, or 3. DMA channels 5 and 7 seem to be * initialized by the same command as channels 1 and 3, respectively. */ if (ft_fdc_dma > 3) { TRACE_ABORT(0, ft_t_err, "Error: The FC-10/20 must be set to use DMA channels 1, 2, or 3!"); } /* Only allow the FC-10/20 to use IRQ 3-7, or 9. Note that CMS's program * only accepts IRQ's 2-7, but in linux, IRQ 2 is the same as IRQ 9. */ if (ft_fdc_irq < 3 || ft_fdc_irq == 8 || ft_fdc_irq > 9) { TRACE_ABORT(0, ft_t_err, "Error: The FC-10/20 must be set to use IRQ levels 3 - 7, or 9!\n" KERN_INFO "Note: IRQ 9 is the same as IRQ 2"); } /* Clear state machine ??? */ for (i = 0; i < NR_ITEMS(inbs_magic); i++) { inb(ft_fdc_base + inbs_magic[i]); } outb(0x0, ft_fdc_base); x = inb(ft_fdc_base); if (x == 0x13 || x == 0x93) { for (i = 1; i < 8; i++) { if (inb(ft_fdc_base + i) != x) { TRACE_EXIT 0; } } } else { TRACE_EXIT 0; } outb(0x8, ft_fdc_base); for (i = 0; i < 8; i++) { if (inb(ft_fdc_base + i) != 0x0) { TRACE_EXIT 0; } } outb(0x10, ft_fdc_base); for (i = 0; i < 8; i++) { if (inb(ft_fdc_base + i) != 0xff) { TRACE_EXIT 0; } } /* Okay, we found a FC-10 card ! ??? */ outb(0x0, fdc.ccr); /* Clear state machine again ??? */ for (i = 0; i < NR_ITEMS(inbs_magic); i++) { inb(ft_fdc_base + inbs_magic[i]); } /* Send io port */ for (i = 0; i < NR_ITEMS(fc10_ports); i++) if (ft_fdc_base == fc10_ports[i]) cardConfig = i + 1; if (cardConfig == 0) { TRACE_EXIT 0; /* Invalid I/O Port */ } /* and IRQ - If using IRQ 9, tell the FC card it is actually IRQ 2 */ if (ft_fdc_irq != 9) cardConfig |= ft_fdc_irq << 3; else cardConfig |= 2 << 3; /* and finally DMA Channel */ cardConfig |= ft_fdc_dma << 6; outb(cardConfig, ft_fdc_base); /* DMA [2 bits]/IRQ [3 bits]/BASE [3 bits] */ /* Enable FC-10 ??? */ outb(0, fdc.ccr); outb(0, fdc.dor2); outb(FDC_DMA_MODE /* 8 */, fdc.dor); outb(FDC_DMA_MODE /* 8 */, fdc.dor); outb(1, fdc.dor2); /************************************* * * cH: why the hell should this be necessary? This is done * by fdc_reset()!!! * *************************************/ /* Initialize fdc, select drive B: */ outb(FDC_DMA_MODE, fdc.dor); /* assert reset, dma & irq enabled */ /* 0x08 */ outb(FDC_DMA_MODE|FDC_RESET_NOT, fdc.dor); /* release reset */ /* 0x08 | 0x04 = 0x0c */ outb(FDC_DMA_MODE|FDC_RESET_NOT|FDC_MOTOR_1|FTAPE_SEL_B, fdc.dor); /* 0x08 | 0x04 | 0x20 | 0x01 = 0x2d */ /* select drive 1 */ /* why not drive 0 ???? */ TRACE_EXIT (x == 0x93) ? 2 : 1; }
int ftape_set_data_rate(unsigned int new_rate /* Kbps */, unsigned int qic_std) { int status; int result = 0; unsigned int data_rate = new_rate; static int supported; int rate_changed = 0; qic_model dummy_model; unsigned int dummy_qic_std, dummy_tape_len; TRACE_FUN(ft_t_any); if (ft_drive_max_rate == 0) { /* first time */ supported = ftape_set_rate_test(&ft_drive_max_rate); } if (supported) { ftape_command(QIC_SELECT_RATE); result = ftape_parameter_wait(qic_rate_code(new_rate), 1 * FT_SECOND, &status); if (result >= 0 && !(status & QIC_STATUS_ERROR)) { rate_changed = 1; } } TRACE_CATCH(result = ftape_report_configuration(&dummy_model, &data_rate, &dummy_qic_std, &dummy_tape_len),); if (data_rate != new_rate) { if (!supported) { TRACE(ft_t_warn, "Rate change not supported!"); } else if (rate_changed) { TRACE(ft_t_warn, "Requested: %d, got %d", new_rate, data_rate); } else { TRACE(ft_t_warn, "Rate change failed!"); } result = -EINVAL; } /* * Set data rate and write precompensation as specified: * * | QIC-40/80 | QIC-3010/3020 * rate | precomp | precomp * ----------+-------------+-------------- * 250 Kbps. | 250 ns. | 0 ns. * 500 Kbps. | 125 ns. | 0 ns. * 1 Mbps. | 42 ns. | 0 ns. * 2 Mbps | N/A | 0 ns. */ if ((qic_std == QIC_TAPE_QIC40 && data_rate > 500) || (qic_std == QIC_TAPE_QIC80 && data_rate > 1000)) { TRACE_ABORT(-EINVAL, ft_t_warn, "Datarate too high for QIC-mode"); } TRACE_CATCH(fdc_set_data_rate(data_rate),_res = -EINVAL); ft_data_rate = data_rate; if (qic_std == QIC_TAPE_QIC40 || qic_std == QIC_TAPE_QIC80) { switch (data_rate) { case 250: fdc_set_write_precomp(250); break; default: case 500: fdc_set_write_precomp(125); break; case 1000: fdc_set_write_precomp(42); break; } } else { fdc_set_write_precomp(0); } TRACE_EXIT result; }
static int ft_check_cmd_restrictions(qic117_cmd_t command) { int status = -1; TRACE_FUN(ft_t_any); TRACE(ft_t_flow, "%s", qic117_cmds[command].name); /* A new motion command during an uninterruptible (motion) * command requires a ready status before the new command can * be issued. Otherwise a new motion command needs to be * checked against required status. */ if (qic117_cmds[command].cmd_type == motion && qic117_cmds[ftape_current_command].non_intr) { ftape_report_raw_drive_status(&status); if ((status & QIC_STATUS_READY) == 0) { TRACE(ft_t_noise, "motion cmd (%d) during non-intr cmd (%d)", command, ftape_current_command); TRACE(ft_t_noise, "waiting until drive gets ready"); ftape_ready_wait(ftape_timeout.seek, &status); } } if (qic117_cmds[command].mask != 0) { __u8 difference; /* Some commands do require a certain status: */ if (status == -1) { /* not yet set */ ftape_report_raw_drive_status(&status); } difference = ((status ^ qic117_cmds[command].state) & qic117_cmds[command].mask); /* Wait until the drive gets * ready. This may last forever if * the drive never gets ready... */ while ((difference & QIC_STATUS_READY) != 0) { TRACE(ft_t_noise, "command %d issued while not ready", command); TRACE(ft_t_noise, "waiting until drive gets ready"); if (ftape_ready_wait(ftape_timeout.seek, &status) == -EINTR) { /* Bail out on signal ! */ TRACE_ABORT(-EINTR, ft_t_warn, "interrupted by non-blockable signal"); } difference = ((status ^ qic117_cmds[command].state) & qic117_cmds[command].mask); } while ((difference & QIC_STATUS_ERROR) != 0) { int err; qic117_cmd_t cmd; TRACE(ft_t_noise, "command %d issued while error pending", command); TRACE(ft_t_noise, "clearing error status"); ftape_report_error(&err, &cmd, 1); ftape_report_raw_drive_status(&status); difference = ((status ^ qic117_cmds[command].state) & qic117_cmds[command].mask); if ((difference & QIC_STATUS_ERROR) != 0) { /* Bail out on fatal signal ! */ FT_SIGNAL_EXIT(_NEVER_BLOCK); } } if (difference) { /* Any remaining difference can't be solved * here. */ if (difference & (QIC_STATUS_CARTRIDGE_PRESENT | QIC_STATUS_NEW_CARTRIDGE | QIC_STATUS_REFERENCED)) { TRACE(ft_t_warn, "Fatal: tape removed or reinserted !"); ft_failure = 1; } else { TRACE(ft_t_err, "wrong state: 0x%02x should be: 0x%02x", status & qic117_cmds[command].mask, qic117_cmds[command].state); } TRACE_EXIT -EIO; } if (~status & QIC_STATUS_READY & qic117_cmds[command].mask) { TRACE_ABORT(-EBUSY, ft_t_err, "Bad: still busy!"); } } TRACE_EXIT 0; }