예제 #1
0
/*      Issue command and wait up to timeout milli seconds for drive ready
 */
int ftape_command_wait(qic117_cmd_t command, unsigned int timeout, int *status)
{
	int result;

	/* Drive should be ready, issue command
	 */
	result = ftape_command(command);
	if (result >= 0) {
		result = ftape_ready_wait(timeout, status);
	}
	return result;
}
예제 #2
0
int ftape_parameter_wait(unsigned int parm, unsigned int timeout, int *status)
{
	int result;

	/* Drive should be ready, issue command
	 */
	result = ftape_parameter(parm);
	if (result >= 0) {
		result = ftape_ready_wait(timeout, status);
	}
	return result;
}
예제 #3
0
int ftape_seek_to_bot(void)
{
	TRACE_FUN(8, "ftape_seek_to_bot");
	int result;
	int status;

	result = ftape_ready_wait(timeout.pause, &status);
	while ((status & QIC_STATUS_AT_BOT) == 0) {
		if (result < 0) {
			TRACE(1, "failed");
			TRACE_EXIT;
			return result;
		}
		if (ftape_not_operational(status)) {
			TRACE_EXIT;
			return -EIO;
		}
		result = ftape_command_wait(QIC_PHYSICAL_REVERSE,
					    timeout.rewind, &status);
	}
	TRACE_EXIT;
	return 0;
}
예제 #4
0
int ftape_fix(void)
{
    TRACE_FUN(5, "ftape_fix");
    int result = 0;
    int dummy;
    int status;

    if (write_protected) {
        result = -EROFS;
    } else {
        /*  This will copy header segment 2 to header segment 1
         *  Spares us a tape format operation if header 2 is still good.
         */
        header_segment_1 = 0;
        header_segment_2 = 1;
        first_data_segment = 2;
        result = read_segment(header_segment_2, scratch_buffer, &dummy, 0);
        result = ftape_ready_wait(timeout.pause, &status);
        result = ftape_write_header_segments(scratch_buffer);
    }
    TRACE_EXIT;
    return result;
}
예제 #5
0
int ftape_get_drive_status(void)
{
	int result;
	int status;
	TRACE_FUN(ft_t_flow);

	ft_no_tape = ft_write_protected = 0;
	/*    Tape drive is activated now.
	 *    First clear error status if present.
	 */
	do {
		result = ftape_ready_wait(ftape_timeout.reset, &status);
		if (result < 0) {
			if (result == -ETIME) {
				TRACE(ft_t_err, "ftape_ready_wait timeout");
			} else if (result == -EINTR) {
				TRACE(ft_t_err, "ftape_ready_wait aborted");
			} else {
				TRACE(ft_t_err, "ftape_ready_wait failed");
			}
			TRACE_EXIT -EIO;
		}
		/*  Clear error condition (drive is ready !)
		 */
		if (status & QIC_STATUS_ERROR) {
			unsigned int error;
			qic117_cmd_t command;

			TRACE(ft_t_err, "error status set");
			result = ftape_report_error(&error, &command, 1);
			if (result < 0) {
				TRACE(ft_t_err,
				      "report_error_code failed: %d", result);
				/* hope it's working next time */
				ftape_reset_drive();
				TRACE_EXIT -EIO;
			} else if (error != 0) {
				TRACE(ft_t_noise, "error code   : %d", error);
				TRACE(ft_t_noise, "error command: %d", command);
			}
		}
		if (status & QIC_STATUS_NEW_CARTRIDGE) {
			unsigned int error;
			qic117_cmd_t command;
			const ft_trace_t old_tracing = TRACE_LEVEL;
			SET_TRACE_LEVEL(ft_t_bug);

			/*  Undocumented feature: Must clear (not present!)
			 *  error here or we'll fail later.
			 */
			ftape_report_error(&error, &command, 1);

			SET_TRACE_LEVEL(old_tracing);
			TRACE(ft_t_info, "status: new cartridge");
			ft_new_tape = 1;
		} else {
			ft_new_tape = 0;
		}
		FT_SIGNAL_EXIT(_DONT_BLOCK);
	} while (status & QIC_STATUS_ERROR);
	
	ft_no_tape = !(status & QIC_STATUS_CARTRIDGE_PRESENT);
	ft_write_protected = (status & QIC_STATUS_WRITE_PROTECT) != 0;
	if (ft_no_tape) {
		TRACE(ft_t_warn, "no cartridge present");
	} else {
		if (ft_write_protected) {
			TRACE(ft_t_noise, "Write protected cartridge");
		}
	}
	TRACE_EXIT 0;
}
예제 #6
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;
}
예제 #7
0
int ftape_get_drive_status(int *new_tape, int *no_tape, int *wp_tape)
{
	TRACE_FUN(5, "ftape_get_drive_status");
	int result;
	int status;

	*no_tape =
	    *wp_tape = 0;
	/*    Tape drive is activated now.
	 *    First clear error status if present.
	 */
	do {
		result = ftape_ready_wait(timeout.reset, &status);
		if (result < 0) {
			if (result == -ETIME) {
				TRACE(1, "ftape_ready_wait timeout");
			} else if (result == -EINTR) {
				TRACE(1, "ftape_ready_wait aborted");
			} else {
				TRACE(1, "ftape_ready_wait failed");
			}
			result = -EIO;
			break;
		}
		/*  Clear error condition (drive is ready !)
		 */
		if (status & QIC_STATUS_ERROR) {
			int error;
			int command;

			TRACE(1, "error status set");
			result = ftape_report_error(&error, &command, 1);
			if (result < 0) {
				TRACEi(1, "report_error_code failed:", result);
				ftape_reset_drive();	/* hope it's working next time */
				init_drive_needed = 1;
				result = -EIO;
				break;
			} else if (error != 0) {
				TRACEi(4, "error code   :", error);
				TRACEi(4, "error command:", command);
			}
		}
		if (status & QIC_STATUS_NEW_CARTRIDGE) {
			int error;
			int command;
			int old_tracing = tracing;

			/*  Undocumented feature: Must clear (not present!) error 
			 *  here or we'll fail later.
			 */
			tracing = 0;
			ftape_report_error(&error, &command, 1);
			tracing = old_tracing;
			TRACE(3, "status: new cartridge");
			*new_tape = 1;
		}
	} while (status & QIC_STATUS_ERROR);

	*no_tape = !(status & QIC_STATUS_CARTRIDGE_PRESENT);
	*wp_tape = (status & QIC_STATUS_WRITE_PROTECT);
	if (*no_tape) {
		TRACE(1, "no cartridge present");
	} else {
		if (*wp_tape) {
			TRACE(2, "Write protected cartridge");
		}
	}
	TRACE_EXIT;
	return result;
}
예제 #8
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;
}