예제 #1
0
/*      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(&current->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;
}
예제 #2
0
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;
}
예제 #3
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(&current->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;
}
예제 #4
0
/*  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;
}
예제 #5
0
/*  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;
}
예제 #6
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;
}
예제 #7
0
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;
}
예제 #8
0
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;
}