Example #1
0
static int ftape_new_cartridge(void)
{
	ft_location.track = -1; /* force seek on first access */
	ftape_zap_read_buffers();
	ftape_zap_write_buffers();
	return 0;
}
Example #2
0
int ftape_new_cartridge(void)
{
	location.track = -1;	/* force seek on first access */
	first_data_segment = -1;	/* unknown */
	ftape_zap_read_buffers();
	ftape_zap_write_buffers();
	ftape_reset_position();
	return 0;
}
Example #3
0
/*      RELEASE routine called by kernel-interface code
 */
int _ftape_close(void)
{
	TRACE_FUN(8, "_ftape_close");
	int result = 0;
	int last_segment = 0;

	if (!ftape_offline) {
		result = ftape_flush_buffers();
		last_segment = ftape_seg_pos - 1;
		if (!(ftape_unit & FTAPE_NO_REWIND)) {
			if (result >= 0) {
				result = ftape_update_header_segments(NULL, 1);
				if (result < 0) {
					TRACE(1, "error: update of header segments failed");
				}
			} else {
				TRACE(1, "error: unable to update header segments");
			}
		}
		ftape_abort_operation();
		if (!(ftape_unit & FTAPE_NO_REWIND)) {
			if (!no_tape) {
				TRACE(5, "rewinding tape");
				result = ftape_seek_to_bot();
			}
			ftape_reset_position();
			ftape_zap_read_buffers();
			ftape_zap_write_buffers();
		}
	}
	ftape_detach_drive();
	fdc_uninit();
	if (history.used) {
		TRACE(3, "== Non-fatal errors this run: ==");
		TRACE(3, "fdc isr statistics:");
		TRACEi(3, " id_am_errors     :", history.id_am_errors);
		TRACEi(3, " id_crc_errors    :", history.id_crc_errors);
		TRACEi(3, " data_am_errors   :", history.data_am_errors);
		TRACEi(3, " data_crc_errors  :", history.data_crc_errors);
		TRACEi(3, " overrun_errors   :", history.overrun_errors);
		TRACEi(3, " no_data_errors   :", history.no_data_errors);
		TRACEi(3, " retries          :", history.retries);
		if (history.used & 1) {
			TRACE(3, "ecc statistics:");
			TRACEi(3, " crc_errors       :", history.crc_errors);
			TRACEi(3, " crc_failures     :", history.crc_failures);
			TRACEi(3, " ecc_failures     :", history.ecc_failures);
			TRACEi(3, " sectors corrected:", history.corrected);
		}
		TRACEx2(3, "media defects     : %d%s", history.defects,
			history.defects ? " !!!" : "");
		TRACEi(3, "repositions       :", history.rewinds);
		TRACEi(3, "last segment      :", last_segment);
	}
	if (going_offline) {
		going_offline = 0;
		ftape_offline = 1;
	}
	TRACE_EXIT;
	return result;
}
Example #4
0
int ftape_flush_buffers(void)
{
    TRACE_FUN(5, "ftape_flush_buffers");
    int result;
    int pad_count;
    int data_remaining;
    static int active = 0;

    if (active) {
        TRACE(5, "nested call, abort");
        TRACE_EXIT;
        return 0;
    }
    active = 1;
    TRACEi(5, "entered, ftape_state =", ftape_state);
    if (ftape_state != writing && !need_flush) {
        active = 0;
        TRACE(5, "no need for flush");
        TRACE_EXIT;
        return 0;
    }
    data_remaining = buf_pos_wr;
    buf_pos_wr = 0;		/* prevent further writes if this fails */
    TRACE(5, "flushing write buffers");
    if (last_write_failed) {
        ftape_zap_write_buffers();
        active = 0;
        TRACE_EXIT;
        return write_protected ? -EROFS : -EIO;
    }
    /*
     *    If there is any data not written to tape yet, append zero's
     *    up to the end of the sector. Then write the segment(s) to tape.
     */
    if (data_remaining > 0) {
        int written;

        do {
            TRACEi(4, "remaining in buffer:", data_remaining);
            pad_count = sizeof(deblock_buffer) - data_remaining;
            TRACEi(7, "flush, padding count:", pad_count);
            memset(deblock_buffer + data_remaining, 0, pad_count);	/* pad buffer */
            result = _write_segment(ftape_seg_pos, deblock_buffer, 1);
            if (result < 0) {
                if (result != -ENOSPC) {
                    last_write_failed = 1;
                }
                active = 0;
                TRACE_EXIT;
                return result;
            }
            written = result;
            clear_eof_mark_if_set(ftape_seg_pos, written);
            TRACEi(7, "flush, moved out buffer:", written);
            if (written > 0) {
                data_remaining -= written;
                if (data_remaining > 0) {
                    /*  Need another segment for remaining data, move the remainder
                     *  to the beginning of the buffer
                     */
                    memmove(deblock_buffer, deblock_buffer + written, data_remaining);
                }
            }
            ++ftape_seg_pos;
        } while (data_remaining > 0);
        /*  Data written to last segment == data_remaining + written
         *  value is in range [1..29K].
         */
        TRACEx2(4, "last write: %d, netto pad-count: %d",
                data_remaining + written, -data_remaining);
        if (-1024 < data_remaining && data_remaining <= 0) {
            /*  Last sector of segment was used for data, so put eof mark
             *  in next segment and position at second file mark.
             */
            if (ftape_weof(2, ftape_seg_pos, 1) >= 0) {
                ++ftape_seg_pos;	/* position between file marks */
            }
        } else {
            /*  Put eof mark in previous segment after data and position
             *  at second file mark.
             */
            ftape_weof(2, ftape_seg_pos - 1, 1 +
                       ((SECTOR_SIZE - 1 + result + data_remaining) / SECTOR_SIZE));
        }
    } else {
        TRACE(7, "deblock_buffer empty");
        if (ftape_weof(2, ftape_seg_pos, 1) >= 0) {
            ++ftape_seg_pos;	/* position between file marks */
        }
        start_writing(WRITE_MULTI);
    }
    TRACE(7, "waiting");
    result = loop_until_writes_done();
    if (result < 0) {
        TRACE(1, "flush buffers failed");
    }
    ftape_state = idle;
    last_write_failed = 0;
    need_flush = 0;
    active = 0;
    TRACE_EXIT;
    return result;
}
Example #5
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;
}