コード例 #1
0
ファイル: ftape-ctl.c プロジェクト: robacklin/uclinux-linux
void ftape_log_vendor_id(void)
{
	TRACE_FUN(5, "ftape_log_vendor_id");
	int vendor_index;

	ftape_report_vendor_id(&drive_type.vendor_id);
	vendor_index = lookup_vendor_id(drive_type.vendor_id);
	if (drive_type.vendor_id == UNKNOWN_VENDOR &&
	    drive_type.wake_up == wake_up_colorado) {
		vendor_index = 0;
		drive_type.vendor_id = 0;	/* hack to get rid of all this mail */
	}
	if (vendor_index < 0) {
		/* Unknown vendor id, first time opening device.
		 * The drive_type remains set to type found at wakeup time, this
		 * will probably keep the driver operating for this new vendor.
		 */
		TRACE(-1, "============ unknown vendor id ===========");
		TRACE(-1, "A new, yet unsupported tape drive is found");
		TRACE(-1, "Please report the following values:");
		TRACEx1(-1, "   Vendor id     : 0x%04x", drive_type.vendor_id);
		TRACEx1(-1, "   Wakeup method : %s", methods[drive_type.wake_up].name);
		TRACE(-1, "And a description of your tape drive to:");
		TRACE(-1, "Claus Heine <*****@*****.**>");
		TRACE(-1, "==========================================");
		drive_type.speed = 500;		/* deci-ips: very safe value */
	} else {
		drive_type.name = vendors[vendor_index].name;
		drive_type.speed = vendors[vendor_index].speed;
		TRACEx1(3, "tape drive type: %s", drive_type.name);
		/* scan all methods for this vendor_id in table */
		while (drive_type.wake_up != vendors[vendor_index].wake_up) {
			if (vendor_index < NR_ITEMS(vendors) - 1 &&
			    vendors[vendor_index + 1].vendor_id == drive_type.vendor_id) {
				++vendor_index;
			} else {
				break;
			}
		}
		if (drive_type.wake_up != vendors[vendor_index].wake_up) {
			TRACE(-1, "==========================================");
			TRACE(-1, "wakeup type mismatch:");
			TRACEx2(-1, "found: %s, expected: %s",
				methods[drive_type.wake_up].name,
			    methods[vendors[vendor_index].wake_up].name);
			TRACE(-1, "please report this to <*****@*****.**>");
			TRACE(-1, "==========================================");
		}
	}
	TRACE_EXIT;
}
コード例 #2
0
/*      Called by modules package when removing the driver
 */
void cleanup_module(void)
{
	int n;
	int order;
	TRACE_FUN(5, "cleanup_module");

	if (unregister_chrdev(QIC117_TAPE_MAJOR, "ft") != 0) {
		TRACE(3, "failed");
	} else {
		TRACE(3, "successful");
	}
	order = __get_order(BUFF_SIZE);
	for (n = 0; n < NR_BUFFERS; n++) {
		if (tape_buffer[n]) {
			dmafree(tape_buffer[n], order);
			tape_buffer[n] = NULL;
			TRACEx1(3, "removed dma-buffer #%d", n);
		} else {
			TRACEx1(1, "dma-buffer #%d == NULL (bug?)", n);
		}
	}
	TRACE_EXIT;
}
コード例 #3
0
/*  Write as much as fits from buffer to the given segment on tape
 *  and handle retries.
 *  Return the number of bytes written (>= 0), or:
 *      -EIO          write failed
 *      -EINTR        interrupted by signal
 *      -ENOSPC       device full
 */
int _write_segment(unsigned int segment_id, byte * buffer, int flush)
{
    TRACE_FUN(5, "_write_segment");
    int retry = 0;
    int result;

    history.used |= 2;
    for (;;) {
        if (segment_id > ftape_last_segment.id && !flush) {
            result = -ENOSPC;	/* tape full */
            break;
        }
        result = write_segment(segment_id, buffer, flush);
        if (result < 0) {
            if (result == -EAGAIN) {
                if (++retry > 100) {
                    TRACE(1, "write failed, >100 retries in segment");
                    result = -EIO;	/* give up */
                    break;
                } else {
                    TRACEx1(2, "write error, retry %d", retry);
                }
            } else {
                TRACEi(1, "write_segment failed, error:", -result);
                break;
            }
        } else {	/* success */
            if (result == 0) {	/* empty segment */
                TRACE(4, "empty segment, nothing written");
            }
            break;
        }
        /* 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;
        }
    }
    TRACE_EXIT;
    return result;
}
コード例 #4
0
int ftape_init(void)
{
	int n;
	int order;
	TRACE_FUN(5, "ftape_init");
#ifdef MODULE
	printk(KERN_INFO "ftape-2.08 960314\n"
	       KERN_INFO " (c) 1993-1995 Bas Laarhoven ([email protected])\n"
	       KERN_INFO " (c) 1995-1996 Kai Harrekilde-Petersen ([email protected])\n"
	KERN_INFO " QIC-117 driver for QIC-40/80/3010/3020 tape drives\n"
	       KERN_INFO " Compiled for kernel version %s"
#ifdef MODVERSIONS
	       " with versioned symbols"
#endif
	       "\n", kernel_version);
#else /* !MODULE */
	/* print a short no-nonsense boot message */
	printk("ftape-2.08 960314 for Linux 1.3.70\n");
#endif				/* MODULE */
	TRACE(3, "installing QIC-117 ftape driver...");
	if (register_chrdev(QIC117_TAPE_MAJOR, "ft", &ftape_cdev)) {
		TRACE(1, "register_chrdev failed");
		TRACE_EXIT;
		return -EIO;
	}
	TRACEx1(3, "ftape_init @ 0x%p", ftape_init);
	/*
	 * Allocate the DMA buffers. They are deallocated at cleanup() time.
	 */
	order = __get_order(BUFF_SIZE);
	for (n = 0; n < NR_BUFFERS; n++) {
		tape_buffer[n] = (byte *) dmaalloc(order);
		if (!tape_buffer[n]) {
			TRACE(1, "dmaalloc() failed");
			for (n = 0; n < NR_BUFFERS; n++) {
				if (tape_buffer[n]) {
					dmafree(tape_buffer[n], order);
					tape_buffer[n] = NULL;
				}
			}
			current->blocked = old_sigmask;		/* restore mask */
			if (unregister_chrdev(QIC117_TAPE_MAJOR, "ft") != 0) {
				TRACE(3, "unregister_chrdev failed");
			}
			TRACE_EXIT;
			return -ENOMEM;
		} else {
			TRACEx2(3, "dma-buffer #%d @ %p", n, tape_buffer[n]);
		}
	}
	busy_flag = 0;
	ftape_unit = -1;
	ftape_failure = 1;	/* inhibit any operation but open */
	udelay_calibrate();	/* must be before fdc_wait_calibrate ! */
	fdc_wait_calibrate();
	TRACE_EXIT;
#ifdef MODULE
	register_symtab(0);	/* remove global ftape symbols */
#endif
	return 0;
}
コード例 #5
0
void extract_bad_sector_map(byte * buffer)
{
	TRACE_FUN(8, "extract_bad_sector_map");

	/*  Fill the bad sector map with the contents of buffer.
	 */
	if (format_code == 4) {
		/* QIC-3010/3020 and wide QIC-80 tapes no longer have a failed
		 * sector log but use this area to extend the bad sector map.
		 */
		memcpy(bad_sector_map, buffer + 256, sizeof(bad_sector_map));
	} else {
		/* non-wide QIC-80 tapes have a failed sector log area that
		 * mustn't be included in the bad sector map.
		 */
		memcpy(bad_sector_map, buffer + 256 + FAILED_SECTOR_LOG_SIZE,
		       sizeof(bad_sector_map) - FAILED_SECTOR_LOG_SIZE);
	}
#if 0
	/* for testing of bad sector handling at end of tape
	 */
	((unsigned long *) bad_sector_map)[segments_per_track * tracks_per_tape - 3] = 0x000003e0;
	((unsigned long *) bad_sector_map)[segments_per_track * tracks_per_tape - 2] = 0xff3fffff;
	((unsigned long *) bad_sector_map)[segments_per_track * tracks_per_tape - 1] = 0xffffe000;
#endif
#if 0
	/*  Enable to test bad sector handling
	 */
	((unsigned long *) bad_sector_map)[30] = 0xfffffffe;
	((unsigned long *) bad_sector_map)[32] = 0x7fffffff;
	((unsigned long *) bad_sector_map)[34] = 0xfffeffff;
	((unsigned long *) bad_sector_map)[36] = 0x55555555;
	((unsigned long *) bad_sector_map)[38] = 0xffffffff;
	((unsigned long *) bad_sector_map)[50] = 0xffff0000;
	((unsigned long *) bad_sector_map)[51] = 0xffffffff;
	((unsigned long *) bad_sector_map)[52] = 0xffffffff;
	((unsigned long *) bad_sector_map)[53] = 0x0000ffff;
#endif
#if 0
	/*  Enable when testing multiple volume tar dumps.
	 */
	for (i = first_data_segment; i <= ftape_last_segment.id - 7; ++i) {
		((unsigned long *) bad_sector_map)[i] = EMPTY_SEGMENT;
	}
#endif
#if 0
	/*  Enable when testing bit positions in *_error_map
	 */
	for (i = first_data_segment; i <= ftape_last_segment.id; ++i) {
		((unsigned long *) bad_sector_map)[i] |= 0x00ff00ff;
	}
#endif
	if (tracing > 2) {
		unsigned int map;
		int good_sectors = 0;
		int bad_sectors;
		unsigned int total_bad = 0;
		int i;

		if (format_code == 4 || format_code == 3) {
			byte *ptr = bad_sector_map;
			unsigned sector;

			do {
				sector = get_sector(&ptr, forward);
				if (sector != 0) {
					if (format_code == 4 && sector & 0x800000) {
						total_bad += SECTORS_PER_SEGMENT - 3;
						TRACEx1(6, "bad segment at sector: %6d", sector & 0x7fffff);
					} else {
						++total_bad;
						TRACEx1(6, "bad sector: %6d", sector);
					}
				}
			} while (sector != 0);
			/*  Display end-of-file marks
			 */
			do {
				sector = *((unsigned short *) ptr)++;
				if (sector) {
					TRACEx2(4, "eof mark: %4d/%2d", sector,
					    *((unsigned short *) ptr)++);
				}
			} while (sector);
		} else {
			for (i = first_data_segment;
			 i < segments_per_track * tracks_per_tape; ++i) {
				map = ((unsigned long *) bad_sector_map)[i];
				bad_sectors = count_ones(map);
				if (bad_sectors > 0) {
					TRACEx2(6, "bsm for segment %4d: 0x%08x", i, map);
					if (bad_sectors > SECTORS_PER_SEGMENT - 3) {
						bad_sectors = SECTORS_PER_SEGMENT - 3;
					}
					total_bad += bad_sectors;
				}
			}
		}
		good_sectors = ((segments_per_track * tracks_per_tape - first_data_segment)
				* (SECTORS_PER_SEGMENT - 3)) - total_bad;
		TRACEx1(3, "%d Kb usable on this tape",
			good_sectors - ftape_last_segment.free);
		if (total_bad == 0) {
			TRACE(1, "WARNING: this tape has no bad blocks registered !");
		} else {
			TRACEx1(2, "%d bad sectors", total_bad);
		}
	}
	TRACE_EXIT;
}
コード例 #6
0
ファイル: ftape-ctl.c プロジェクト: robacklin/uclinux-linux
/*      IOCTL routine called by kernel-interface code
 */
int _ftape_ioctl(unsigned int command, void *arg)
{
	TRACE_FUN(8, "ftape_ioctl");
	int result = EINVAL;
	union {
		struct mtop mtop;
		struct mtget mtget;
	} krnl_arg;
	int arg_size = (command & IOCSIZE_MASK) >> IOCSIZE_SHIFT;

	/* This check will only catch arguments that are too large !
	 */
	if ((command & IOC_INOUT) && arg_size > sizeof(krnl_arg)) {
		TRACEi(1, "bad argument size:", arg_size);
		TRACE_EXIT;
		return -EINVAL;
	}
	if (command & IOC_IN) {
		int error = verify_area(VERIFY_READ, arg, arg_size);
		if (error) {
			TRACE_EXIT;
			return error;
		}
		memcpy_fromfs(&krnl_arg.mtop, arg, arg_size);
	}
	TRACEx1(5, "called with ioctl command: 0x%08x", command);
	switch (command) {
		/* cpio compatibility
		 * mtrasx and mtreset are mt extension by Hennus Bergman
		 * mtseek and mttell are mt extension by eddy olk
		 */
	case MTIOCTOP:
		TRACEx1(5, "calling MTIOCTOP command: 0x%08x", krnl_arg.mtop.mt_op);
		switch (krnl_arg.mtop.mt_op) {
		case MTNOP:
			/* gnu mt calls MTNOP before MTIOCGET to set status */
			result = 0;
			break;
		case MTRESET:
			result = ftape_reset_drive();
			init_drive_needed = 1;
			if (result < 0 || ftape_offline) {
				break;
			}
			result = ftape_seek_to_bot();
			ftape_reset_position();
			break;
		case MTREW:
		case MTOFFL:
			if (ftape_offline) {
				result = -EIO;
				break;
			}
			ftape_flush_buffers();
			ftape_update_header_segments(NULL, 1);
			result = ftape_seek_to_bot();
			ftape_reset_position();
			if (krnl_arg.mtop.mt_op == MTOFFL) {
				going_offline = 1;
				TRACE(4, "Putting tape drive offline");
			}
			result = 0;
			break;
		case MTRETEN:
			if (ftape_offline) {
				result = -EIO;
				break;
			}
			result = ftape_seek_to_eot();
			if (result >= 0) {
				result = ftape_seek_to_bot();
			}
			ftape_reset_position();
			break;
		case MTERASE:
			if (ftape_offline) {
				result = -EIO;
				break;
			}
			result = ftape_erase();
			break;
		case MTEOM:
			if (ftape_offline) {
				result = -EIO;
				break;
			}
			result = ftape_seek_eom();
			break;
		case MTFSFM:
			if (ftape_offline) {
				result = -EIO;
				break;
			}
			eof_mark = 1;	/* position ready to extend */
		case MTFSF:
			if (ftape_offline) {
				result = -EIO;
				break;
			}
			result = ftape_seek_eof(krnl_arg.mtop.mt_count);
			break;
		case MTBSFM:
			if (ftape_offline) {
				result = -EIO;
				break;
			}
			eof_mark = 1;	/* position ready to extend */
		case MTBSF:
			if (ftape_offline) {
				result = -EIO;
				break;
			}
			result = ftape_seek_eof(-krnl_arg.mtop.mt_count);
			break;
		case MTFSR:
			if (ftape_offline) {
				result = -EIO;
				break;
			}
			tracing = krnl_arg.mtop.mt_count;
			TRACEx1(2, "tracing set to %d", tracing);
			result = 0;
			break;
		case MTBSR:
			if (ftape_offline) {
				result = -EIO;
				break;
			}
#if 0
			result = ftape_fix();
#else
			result = 0;
#endif
			break;
		case MTWEOF:
			if (ftape_offline) {
				result = -EIO;
				break;
			}
			result = ftape_weof(krnl_arg.mtop.mt_count, ftape_seg_pos, 1);
			if (result >= 0) {
				ftape_seg_pos += krnl_arg.mtop.mt_count - 1;
			}
			break;
			/* MTRASx and MTRESET are mt extension by Hennus Bergman
			 */
		case MTRAS1:
		case MTRAS2:
		case MTRAS3:
		case MTSEEK:
		case MTTELL:
		default:
			TRACEi(1, "MTIOCTOP sub-command not implemented:", krnl_arg.mtop.mt_op);
			result = -EIO;
			break;
		}
		break;
	case MTIOCGET:
		krnl_arg.mtget.mt_type = drive_type.vendor_id + 0x800000;
		krnl_arg.mtget.mt_resid = 0;	/* not implemented */
		krnl_arg.mtget.mt_dsreg = 0;	/* status register */
		krnl_arg.mtget.mt_gstat =	/* device independent status */
		    ((ftape_offline) ? 0 : GMT_ONLINE(-1L)) |
		    ((write_protected) ? GMT_WR_PROT(-1L) : 0) |
		    ((no_tape) ? GMT_DR_OPEN(-1L) : 0);
		krnl_arg.mtget.mt_erreg = ftape_last_error;	/* error register */
		result = ftape_file_no(&krnl_arg.mtget.mt_fileno,
				       &krnl_arg.mtget.mt_blkno);
		break;
	case MTIOCPOS:
		TRACE(5, "Mag tape ioctl command: MTIOCPOS");
		TRACE(1, "MTIOCPOS command not implemented");
		break;
	default:
		result = -EINVAL;
		break;
	}
	if (command & IOC_OUT) {
		int error = verify_area(VERIFY_WRITE, arg, arg_size);
		if (error) {
			TRACE_EXIT;
			return error;
		}
		memcpy_tofs(arg, &krnl_arg, arg_size);
	}
	TRACE_EXIT;
	return result;
}
コード例 #7
0
ファイル: ftape-ctl.c プロジェクト: robacklin/uclinux-linux
void ftape_calc_timeouts(void)
{
	TRACE_FUN(8, "ftape_calc_timeouts");
	int speed;		/* deci-ips ! */
	int length;

	/*                           tape transport speed
	 *  data rate:        QIC-40   QIC-80   QIC-3010 QIC-3020
	 *
	 *    250 Kbps        25 ips     n/a      n/a      n/a
	 *    500 Kbps        50 ips   34 ips   22.6 ips   n/a
	 *      1 Mbps          n/a    68 ips   45.2 ips 22.6 ips
	 *      2 Mbps          n/a      n/a      n/a    45.2 ips
	 *
	 *  fast tape transport speed is at least 68 ips.
	 */
	switch (qic_std) {
	case QIC_TAPE_QIC40:
		speed = (ftape_data_rate == 3) ? 250 : 500;
		break;
	case QIC_TAPE_QIC80:
		speed = (ftape_data_rate == 2) ? 340 : 680;
		break;
	case QIC_TAPE_QIC3010:
		speed = (ftape_data_rate == 2) ? 226 : 452;
		break;
	case QIC_TAPE_QIC3020:
		speed = (ftape_data_rate == 1) ? 226 : 452;
		break;
	default:
		TRACE(-1, "Unknown qic_std (bug) ?");
		speed = 500;
		break;
	}
	if (tape_len <= 0) {
		/*  Handle unknown length tapes as 1100 ft ones (worst case)
		 */
		TRACE(1, "Unknown tape length, using worst case timing values!");
		length = 1100;
	} else {
		length = tape_len;
	}
	if (drive_type.speed == 0) {
		unsigned long t0;
		int dt;

		ftape_seek_to_bot();
		t0 = jiffies;
		ftape_seek_to_eot();
		ftape_seek_to_bot();
		dt = (int) ((jiffies - t0) * MSPT);
		drive_type.speed = (2 * 12 * length * 1000) / dt;
		TRACE(-1, "==========================================");
		TRACEx1(-1, "drive : %s", drive_type.name);
		TRACEx2(-1, "delta time = %d, length = %d", dt, length);
		TRACEx1(-1, "has max tape speed of %d ips", drive_type.speed);
		TRACE(-1, "please report this to <*****@*****.**>");
		TRACE(-1, "==========================================");
	}
	/*  time to go from bot to eot at normal speed (data rate):
	 *  time = (1+delta) * length (ft) * 12 (inch/ft) / speed (ips)
	 *  delta = 10 % for seek speed, 20 % for rewind speed.
	 */
	timeout.seek = (length * 132 * SECOND) / speed;
	timeout.rewind = (length * 144 * SECOND) / (10 * drive_type.speed);
	timeout.reset = 20 * SECOND + timeout.rewind;
	TRACEx2(4, "speed = %d, length = %d", speed, length);
	TRACEx1(4, "seek timeout: %d sec", (timeout.seek + 500) / 1000);
	TRACEx1(4, "rewind timeout: %d sec", (timeout.rewind + 500) / 1000);
	TRACE_EXIT;
}
コード例 #8
0
ファイル: ftape-ctl.c プロジェクト: robacklin/uclinux-linux
int ftape_activate_drive(vendor_struct * drive_type)
{
	TRACE_FUN(5, "ftape_activate_drive");
	int result = 0;

	/* If we already know the drive type, wake it up.
	 * Else try to find out what kind of drive is attached.
	 */
	if (drive_type->wake_up != unknown_wake_up) {
		TRACE(5, "enabling tape drive and fdc");
		result = ftape_wakeup_drive(drive_type->wake_up);
		if (result < 0) {
			TRACE(1, "known wakeup method failed");
		}
	} else {
		int old_tracing = tracing;
		wake_up_types method;

		/*  Try to awaken the drive using all known methods.
		 *  Lower tracing for a while.
		 */
		if (tracing <= 4) {
			tracing = 0;
		}
		for (method = no_wake_up; method < NR_ITEMS(methods); ++method) {
			drive_type->wake_up = method;
#if 0
			/*  Test setup for dual drive configuration in dodo.
			 *  /dev/rft2 uses mountain wakeup only -> Archive QIC-80
			 *  /dev/rft3 uses colorado wakeup only -> Jumbo QIC-40
			 *  Other systems will use the normal scheme.
			 */
			if ((FTAPE_UNIT < 2) ||
			(FTAPE_UNIT == 2 && method == wake_up_mountain) ||
			(FTAPE_UNIT == 3 && method == wake_up_colorado)) {
				result = ftape_wakeup_drive(drive_type->wake_up);
			} else {
				result = -EIO;
			}
#else
			result = ftape_wakeup_drive(drive_type->wake_up);
#endif
			if (result >= 0) {
				int tracing = old_tracing;	/* fool TRACE */
				TRACEx1(2, "drive wakeup method: %s",
				      methods[drive_type->wake_up].name);
				break;
			}
		}
		tracing = old_tracing;
		if (method >= NR_ITEMS(methods)) {
			/* no response at all, cannot open this drive */
			drive_type->wake_up = unknown_wake_up;
			TRACE(1, "no tape drive found !");
			tracing = old_tracing;
			result = -ENODEV;
		}
	}
	TRACE_EXIT;
	return result;
}
コード例 #9
0
/*      Write given segment from buffer at address onto tape.
 */
int write_segment(unsigned segment_id, byte * address, int flushing)
{
    TRACE_FUN(5, "write_segment");
    int result = 0;
    int bytes_written = 0;

    TRACEi(5, "segment_id =", segment_id);
    if (ftape_state != writing) {
        if (ftape_state == reading) {
            TRACE(5, "calling ftape_abort_operation");
            result = ftape_abort_operation();
            if (result < 0) {
                TRACE(1, "ftape_abort_operation failed");
            }
        }
        ftape_zap_read_buffers();
        ftape_zap_write_buffers();
        ftape_state = writing;
    }
    /*    if all buffers full we'll have to wait...
     */
    wait_segment(writing);
    if (buffer[tail].status == error) {
        /*  setup for a retry
         */
        buffer[tail].status = waiting;
        bytes_written = -EAGAIN;	/* force retry */
        if (buffer[tail].hard_error_map != 0) {
            TRACEx1(1, "warning: %d hard error(s) in written segment",
                    count_ones(buffer[tail].hard_error_map));
            TRACEx1(4, "hard_error_map = 0x%08lx", buffer[tail].hard_error_map);
            /*  Implement hard write error recovery here
             */
        }
    } else if (buffer[tail].status == done) {
        history.defects += count_ones(buffer[tail].hard_error_map);
    } else {
        TRACE(1, "wait for empty segment failed");
        result = -EIO;
    }
    /*    If just passed last segment on tape: wait for BOT or EOT mark.
     */
    if (result >= 0 && runner_status == logical_eot) {
        int status;

        result = ftape_ready_wait(timeout.seek, &status);
        if (result < 0 || (status & (QIC_STATUS_AT_BOT | QIC_STATUS_AT_EOT)) == 0) {
            TRACE(1, "eot/bot not reached");
        } else {
            runner_status = end_of_tape;
        }
    }
    /*    should runner stop ?
     */
    if (result >= 0 &&
            (runner_status == aborting || runner_status == buffer_underrun ||
             runner_status == end_of_tape)) {
        if (runner_status != end_of_tape) {
            result = ftape_dumb_stop();
        }
        if (result >= 0) {
            if (runner_status == aborting) {
                if (buffer[head].status == writing) {
                    buffer[head].status = done;	/* ????? */
                }
            }
            runner_status = idle;	/* aborted ? */
        }
    }
    /*  Don't start tape if runner idle and segment empty.
     */
    if (result >= 0 && !(runner_status == idle &&
                         get_bad_sector_entry(segment_id) == EMPTY_SEGMENT)) {
        if (buffer[tail].status == done) {
            /*    now at least one buffer is empty, fill it with our data.
             *    skip bad sectors and generate ecc.
             *    copy_and_gen_ecc return nr of bytes written,
             *    range 0..29 Kb inclusive !
             */
            result = copy_and_gen_ecc(buffer[tail].address, address,
                                      get_bad_sector_entry(segment_id));
            if (result >= 0) {
                bytes_written = result;
                buffer[tail].segment_id = segment_id;
                buffer[tail].status = waiting;
                next_buffer(&tail);
            }
        }
        /*    Start tape only if all buffers full or flush mode.
         *    This will give higher probability of streaming.
         */
        if (result >= 0 && runner_status != running &&
                ((head == tail && buffer[tail].status == waiting) || flushing)) {
            result = start_writing(WRITE_MULTI);
        }
    }
    TRACE_EXIT;
    return (result < 0) ? result : bytes_written;
}
コード例 #10
0
ファイル: fdc-isr.c プロジェクト: rohsaini/mkunity
static void print_error_cause(int cause)
{
	TRACE_FUN(8, "print_error_cause");

	switch (cause) {
	case no_data_error:
		TRACE(4, "no data error");
		break;
	case id_am_error:
		TRACE(4, "id am error");
		break;
	case id_crc_error:
		TRACE(4, "id crc error");
		break;
	case data_am_error:
		TRACE(4, "data am error");
		break;
	case data_crc_error:
		TRACE(4, "data crc error");
		break;
	case overrun_error:
		TRACE(4, "overrun error");
		break;
	default:
	}
	TRACE_EXIT;
}

static char *
get_fdc_mode_text(fdc_mode_enum fdc_mode)
{
	switch (fdc_mode) {
	case fdc_idle:
		return "fdc_idle";
	case fdc_reading_data:
		return "fdc_reading_data";
	case fdc_seeking:
		return "fdc_seeking";
	case fdc_writing_data:
		return "fdc_writing_data";
	case fdc_reading_id:
		return "fdc_reading_id";
	case fdc_recalibrating:
		return "fdc_recalibrating";
	default:
		return "unknown";
	}
}

static void
decode_irq_cause(fdc_mode_enum fdc_mode, byte st[],
		 char **fdc_mode_txt, error_cause * cause)
{
	TRACE_FUN(8, "decode_irq_cause");

	/*  Valid st[], decode cause of interrupt.
	 */
	*fdc_mode_txt = get_fdc_mode_text(fdc_mode);
	switch (st[0] & ST0_INT_MASK) {
	case FDC_INT_NORMAL:
		TRACEx1(fdc_mode == fdc_reading_id ? 6 : 5,
			"normal completion: %s", *fdc_mode_txt);
		*cause = no_error;
		break;
	case FDC_INT_ABNORMAL:
		TRACEx1(5, "abnormal completion %s", *fdc_mode_txt);
		TRACEx3(6, "ST0: 0x%02x, ST1: 0x%02x, ST2: 0x%02x",
			st[0], st[1], st[2]);
		TRACEx4(6, "C: 0x%02x, H: 0x%02x, R: 0x%02x, N: 0x%02x",
			st[3], st[4], st[5], st[6]);
		if (st[1] & 0x01) {
			if (st[2] & 0x01) {
				*cause = data_am_error;
			} else {
				*cause = id_am_error;
			}
		} else if (st[1] & 0x20) {
			if (st[2] & 0x20) {
				*cause = data_crc_error;
			} else {
				*cause = id_crc_error;
			}
		} else if (st[1] & 0x04) {
			*cause = no_data_error;
		} else if (st[1] & 0x10) {
			*cause = overrun_error;
		}
		print_error_cause(*cause);
		break;
	case FDC_INT_INVALID:
		TRACEx1(5, "invalid completion %s", *fdc_mode_txt);
		*cause = no_error;
		break;
	case FDC_INT_READYCH:
		TRACEx1(5, "ready change %s", *fdc_mode_txt);
		*cause = no_error;
		break;
	default:
	}
	TRACE_EXIT;
}

static void update_history(error_cause cause)
{
	switch (cause) {
	case id_am_error:
		history.id_am_errors++;
		break;
	case id_crc_error:
		history.id_crc_errors++;
		break;
	case data_am_error:
		history.data_am_errors++;
		break;
	case data_crc_error:
		history.data_crc_errors++;
		break;
	case overrun_error:
		history.overrun_errors++;
		break;
	case no_data_error:
		history.no_data_errors++;
		break;
	default:
	}
}

static void skip_bad_sector(buffer_struct * buff)
{
	TRACE_FUN(8, "skip_bad_sector");

	/* Mark sector as soft error and skip it
	 */
	if (buff->remaining > 0) {
		++buff->sector_offset;
		++buff->data_offset;
		--buff->remaining;
		buff->ptr += SECTOR_SIZE;
		buff->bad_sector_map >>= 1;
	} else {