📄 osst.c
字号:
#endif if (frame < 0 || frame >= STp->capacity) return (-ENXIO); if (frame <= STp->first_data_ppos) { STp->frame_seq_number = STp->logical_blk_num = STps->drv_file = STps->drv_block = 0; return (osst_set_frame_position(STp, aSRpnt, frame, 0)); } r = osst_set_frame_position(STp, aSRpnt, offset?frame:frame-1, 0); if (r < 0) return r; r = osst_get_logical_frame(STp, aSRpnt, -1, 1); if (r < 0) return r; if (osst_get_frame_position(STp, aSRpnt) != (offset?frame+1:frame)) return (-EIO); if (offset) { STp->logical_blk_num += offset / STp->block_size; STp->buffer->read_pointer = offset; STp->buffer->buffer_bytes -= offset; } else { STp->frame_seq_number++; STp->frame_in_buffer = 0; STp->logical_blk_num += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt); STp->buffer->buffer_bytes = STp->buffer->read_pointer = 0; } STps->drv_file = ntohl(STp->buffer->aux->filemark_cnt); if (STps->eof == ST_FM_HIT) { STps->drv_file++; STps->drv_block = 0; } else { STps->drv_block = ntohl(STp->buffer->aux->last_mark_lbn)? STp->logical_blk_num - (STps->drv_file ? ntohl(STp->buffer->aux->last_mark_lbn) + 1 : 0): -1; } STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD:ST_NOEOF;#if DEBUG printk(OSST_DEB_MSG "osst%d:D: Now positioned at ppos %d, frame %d, lbn %d, file %d, blk %d, rptr %d, eof %d\n", dev, STp->first_frame_position, STp->frame_seq_number, STp->logical_blk_num, STps->drv_file, STps->drv_block, STp->buffer->read_pointer, STps->eof);#endif return 0;}/* * Read back the drive's internal buffer contents, as a part * of the write error recovery mechanism for old OnStream * firmware revisions. * Precondition for this function to work: all frames in the * drive's buffer must be of one type (DATA, MARK or EOD)! */static int osst_read_back_buffer_and_rewrite(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, unsigned int frame, unsigned int skip, int pending){ Scsi_Request * SRpnt = * aSRpnt; unsigned char * buffer, * p; unsigned char cmd[MAX_COMMAND_SIZE]; int flag, new_frame, i; int nframes = STp->cur_frames; int blks_per_frame = ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt); int frame_seq_number = ntohl(STp->buffer->aux->frame_seq_num) - (nframes + pending - 1); int logical_blk_num = ntohl(STp->buffer->aux->logical_blk_num) - (nframes + pending - 1) * blks_per_frame; int dev = TAPE_NR(STp->devt); long startwait = jiffies;#if DEBUG int dbg = debugging;#endif if ((buffer = (unsigned char *)vmalloc((nframes + 1) * OS_DATA_SIZE)) == NULL) return (-EIO); printk(KERN_INFO "osst%d:I: Reading back %d frames from drive buffer%s\n", dev, nframes, pending?" and one that was pending":""); osst_copy_from_buffer(STp->buffer, (p = &buffer[nframes * OS_DATA_SIZE]));#if DEBUG if (pending && debugging) printk(OSST_DEB_MSG "osst%d:D: Pending frame %d (lblk %d), data %02x %02x %02x %02x\n", dev, frame_seq_number + nframes, logical_blk_num + nframes * blks_per_frame, p[0], p[1], p[2], p[3]);#endif for (i = 0, p = buffer; i < nframes; i++, p += OS_DATA_SIZE) { memset(cmd, 0, MAX_COMMAND_SIZE); cmd[0] = 0x3C; /* Buffer Read */ cmd[1] = 6; /* Retrieve Faulty Block */ cmd[7] = 32768 >> 8; cmd[8] = 32768 & 0xff; SRpnt = osst_do_scsi(SRpnt, STp, cmd, OS_FRAME_SIZE, SCSI_DATA_READ, STp->timeout, MAX_RETRIES, TRUE); if ((STp->buffer)->syscall_result || !SRpnt) { printk(KERN_ERR "osst%d:E: Failed to read frame back from OnStream buffer\n", dev); vfree((void *)buffer); *aSRpnt = SRpnt; return (-EIO); } osst_copy_from_buffer(STp->buffer, p);#if DEBUG if (debugging) printk(OSST_DEB_MSG "osst%d:D: Read back logical frame %d, data %02x %02x %02x %02x\n", dev, frame_seq_number + i, p[0], p[1], p[2], p[3]);#endif } *aSRpnt = SRpnt; osst_get_frame_position(STp, aSRpnt);#if DEBUG printk(OSST_DEB_MSG "osst%d:D: Frames left in buffer: %d\n", dev, STp->cur_frames);#endif /* Write synchronously so we can be sure we're OK again and don't have to recover recursively */ /* In the header we don't actually re-write the frames that fail, just the ones after them */ for (flag=1, new_frame=frame, p=buffer, i=0; i < nframes + pending; ) { if (flag) { if (STp->write_type == OS_WRITE_HEADER) { i += skip; p += skip * OS_DATA_SIZE; } else if (new_frame < 2990 && new_frame+skip+nframes+pending >= 2990) new_frame = 3000-i; else new_frame += skip;#if DEBUG printk(OSST_DEB_MSG "osst%d:D: Position to frame %d, write fseq %d\n", dev, new_frame+i, frame_seq_number+i);#endif osst_set_frame_position(STp, aSRpnt, new_frame + i, 0); osst_wait_ready(STp, aSRpnt, 60); osst_get_frame_position(STp, aSRpnt); SRpnt = * aSRpnt; if (new_frame > frame + 1000) { printk(KERN_ERR "osst%d:E: Failed to find writable tape media\n", dev); vfree((void *)buffer); return (-EIO); } flag = 0; if ( i >= nframes + pending ) break; } osst_copy_to_buffer(STp->buffer, p); /* * IMPORTANT: for error recovery to work, _never_ queue frames with mixed frame type! */ osst_init_aux(STp, STp->buffer->aux->frame_type, frame_seq_number+i, logical_blk_num + i*blks_per_frame, ntohl(STp->buffer->aux->dat.dat_list[0].blk_sz), blks_per_frame); memset(cmd, 0, MAX_COMMAND_SIZE); cmd[0] = WRITE_6; cmd[1] = 1; cmd[4] = 1;#if DEBUG if (debugging) printk(OSST_DEB_MSG "osst%d:D: About to write frame %d, seq %d, lbn %d, data %02x %02x %02x %02x\n", dev, new_frame+i, frame_seq_number+i, logical_blk_num + i*blks_per_frame, p[0], p[1], p[2], p[3]);#endif SRpnt = osst_do_scsi(SRpnt, STp, cmd, OS_FRAME_SIZE, SCSI_DATA_WRITE, STp->timeout, MAX_WRITE_RETRIES, TRUE); if (STp->buffer->syscall_result) flag = 1; else { p += OS_DATA_SIZE; i++; /* if we just sent the last frame, wait till all successfully written */ if ( i == nframes + pending ) {#if DEBUG printk(OSST_DEB_MSG "osst%d:D: Check re-write successful\n", dev);#endif memset(cmd, 0, MAX_COMMAND_SIZE); cmd[0] = WRITE_FILEMARKS; cmd[1] = 1; SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, SCSI_DATA_NONE, STp->timeout, MAX_WRITE_RETRIES, TRUE);#if DEBUG if (debugging) { printk(OSST_DEB_MSG "osst%d:D: Sleeping in re-write wait ready\n", dev); printk(OSST_DEB_MSG "osst%d:D: Turning off debugging for a while\n", dev); debugging = 0; }#endif flag = STp->buffer->syscall_result; while ( !flag && time_before(jiffies, startwait + 60*HZ) ) { memset(cmd, 0, MAX_COMMAND_SIZE); cmd[0] = TEST_UNIT_READY; SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, SCSI_DATA_NONE, STp->timeout, MAX_READY_RETRIES, TRUE); if (SRpnt->sr_sense_buffer[2] == 2 && SRpnt->sr_sense_buffer[12] == 4 && (SRpnt->sr_sense_buffer[13] == 1 || SRpnt->sr_sense_buffer[13] == 8)) { /* in the process of becoming ready */ schedule_timeout(HZ / 10); continue; } if (STp->buffer->syscall_result) flag = 1; break; }#if DEBUG debugging = dbg; printk(OSST_DEB_MSG "osst%d:D: Wait re-write finished\n", dev);#endif } } *aSRpnt = SRpnt; if (flag) { if ((SRpnt->sr_sense_buffer[ 2] & 0x0f) == 13 && SRpnt->sr_sense_buffer[12] == 0 && SRpnt->sr_sense_buffer[13] == 2) { printk(KERN_ERR "osst%d:E: Volume overflow in write error recovery\n", dev); vfree((void *)buffer); return (-EIO); /* hit end of tape = fail */ } i = ((SRpnt->sr_sense_buffer[3] << 24) | (SRpnt->sr_sense_buffer[4] << 16) | (SRpnt->sr_sense_buffer[5] << 8) | SRpnt->sr_sense_buffer[6] ) - new_frame; p = &buffer[i * OS_DATA_SIZE];#if DEBUG printk(OSST_DEB_MSG "osst%d:D: Additional write error at %d\n", dev, new_frame+i);#endif osst_get_frame_position(STp, aSRpnt);#if DEBUG printk(OSST_DEB_MSG "osst%d:D: reported frame positions: host = %d, tape = %d\n", dev, STp->first_frame_position, STp->last_frame_position);#endif } } if (!pending) osst_copy_to_buffer(STp->buffer, p); /* so buffer content == at entry in all cases */ vfree((void *)buffer); return 0;}static int osst_reposition_and_retry(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, unsigned int frame, unsigned int skip, int pending){ unsigned char cmd[MAX_COMMAND_SIZE]; Scsi_Request * SRpnt; int dev = TAPE_NR(STp->devt); int expected = 0; int attempts = 1000 / skip; int flag = 1; long startwait = jiffies;#if DEBUG int dbg = debugging;#endif while (attempts && time_before(jiffies, startwait + 60*HZ)) { if (flag) {#if DEBUG debugging = dbg;#endif if (frame < 2990 && frame+skip+STp->cur_frames+pending >= 2990) frame = 3000-skip; expected = frame+skip+STp->cur_frames+pending;#if DEBUG printk(OSST_DEB_MSG "osst%d:D: Position to fppos %d, re-write from fseq %d\n", dev, frame+skip, STp->frame_seq_number-STp->cur_frames-pending);#endif osst_set_frame_position(STp, aSRpnt, frame + skip, 1); flag = 0; attempts--; } if (osst_get_frame_position(STp, aSRpnt) < 0) { /* additional write error */#if DEBUG printk(OSST_DEB_MSG "osst%d:D: Addl error, host %d, tape %d, buffer %d\n", dev, STp->first_frame_position, STp->last_frame_position, STp->cur_frames);#endif frame = STp->last_frame_position; flag = 1; continue; } if (pending && STp->cur_frames < 50) { memset(cmd, 0, MAX_COMMAND_SIZE); cmd[0] = WRITE_6; cmd[1] = 1; cmd[4] = 1;#if DEBUG printk(OSST_DEB_MSG "osst%d:D: About to write pending fseq %d at fppos %d\n", dev, STp->frame_seq_number-1, STp->first_frame_position);#endif SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, OS_FRAME_SIZE, SCSI_DATA_WRITE, STp->timeout, MAX_WRITE_RETRIES, TRUE); *aSRpnt = SRpnt; if (STp->buffer->syscall_result) { /* additional write error */ if ((SRpnt->sr_sense_buffer[ 2] & 0x0f) == 13 && SRpnt->sr_sense_buffer[12] == 0 && SRpnt->sr_sense_buffer[13] == 2) { printk(KERN_ERR "osst%d:E: Volume overflow in write error recovery\n", dev); break; /* hit end of tape = fail */ } flag = 1; } else pending = 0; continue; } if (STp->cur_frames == 0) {#if DEBUG debugging = dbg; printk(OSST_DEB_MSG "osst%d:D: Wait re-write finished\n", dev);#endif if (STp->first_frame_position != expected) { printk(KERN_ERR "osst%d:A: Actual position %d - expected %d\n", dev, STp->first_frame_position, expected); return (-EIO); } return 0; }#if DEBUG if (debugging) { printk(OSST_DEB_MSG "osst%d:D: Sleeping in re-write wait ready\n", dev); printk(OSST_DEB_MSG "osst%d:D: Turning off debugging for a while\n", dev); debugging = 0; }#endif schedule_timeout(HZ / 10); } printk(KERN_ERR "osst%d:E: Failed to find valid tape media\n", dev);#if DEBUG debugging = dbg;#endif return (-EIO);}/* * Error recovery algorithm for the OnStream tape. */static int osst_write_error_recovery(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int pending){ Scsi_Request * SRpnt = * aSRpnt; ST_partstat * STps = & STp->ps[STp->partition]; int dev = TAPE_NR(STp->devt); int retval = 0; int rw_state; unsigned int frame, skip; rw_state = STps->rw; if ((SRpnt->sr_sense_buffer[ 2] & 0x0f) != 3 || SRpnt->sr_sense_buffer[12] != 12 || SRpnt->sr_sense_buffer[13] != 0) {#if DEBUG printk(OSST_DEB_MSG "osst%d:D: Write error recovery cannot handle %02x:%02x:%02x\n", dev, SRpnt->sr_sense_buffer[2], SRpnt->sr_sense_buffer[12], SRpnt->sr_sense_buffer[13]);#endif return (-EIO); } frame = (SRpnt->sr_sense_buffer[3] << 24) | (SRpnt->sr_sense_buffer[4] << 16) | (SRpnt->sr_sense_buffer[5] << 8) | SRpnt->sr_sense_buffer[6]; skip = SRpnt->sr_sense_buffer[9]; #if DEBUG printk(OSST_DEB_MSG "osst%d:D: Detected physical bad frame at %u, advised to skip %d\n", dev, frame, skip);#endif osst_get_frame_position(STp, aSRpnt);#if DEBUG printk(OSST_DEB_MSG "osst%d:D: reported frame positions: host = %d, tape = %d\n", dev, STp->first_frame_position, STp->last_frame_position);#endif switch (STp->write_type) { case OS_WRITE_DATA: case OS_WRITE_EOD: case OS_WRITE_NEW_MARK: printk(KERN_WARNING "osst%d:I: Relocating %d buffered logical frames from position %u to %u\n", dev, STp->cur_frames, frame, (frame + skip > 3000 && frame < 3000)?3000:frame + skip); if (STp->os_fw_rev >= 10600) retval = osst_reposition_and_retry(STp, aSRpnt, frame, skip, pending); else retval = osst_read_back_buffer_and_rewrite(STp, aSRpnt, frame, skip, pending); printk(KERN_WARNING "osst%d:%s: %sWrite error%srecovered\n", dev, retval?"E" :"I", retval?"" :"Don't worry, ", retval?" not ":" "); break; case OS_WRITE_LAST_MARK: printk(KERN_ERR "osst%d:E: Bad frame in update last marker, fatal\n", dev);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -