📄 st.c
字号:
} STm = &(STp->modes[STp->current_mode]); STps = &(STp->ps[STp->partition]); if (STp->write_prot) { retval = (-EACCES); goto out; } if (STps->rw == ST_READING) { retval = flush_buffer(STp, 0); if (retval) goto out; STps->rw = ST_WRITING; } else if (STps->rw != ST_WRITING && STps->drv_file == 0 && STps->drv_block == 0) { if ((retval = set_mode_densblk(STp, STm)) < 0) goto out; if (STm->default_compression != ST_DONT_TOUCH && !(STp->compression_changed)) { if (st_compression(STp, (STm->default_compression == ST_YES))) { printk(KERN_WARNING "%s: Can't set default compression.\n", name); if (modes_defined) { retval = (-EINVAL); goto out; } } } } STbp = STp->buffer; if (STbp->writing) { write_behind_check(STp); if (STbp->syscall_result) { DEBC(printk(ST_DEB_MSG "%s: Async write error (write) %x.\n", name, STbp->midlevel_result)); if (STbp->midlevel_result == INT_MAX) STps->eof = ST_EOM_OK; else STps->eof = ST_EOM_ERROR; } } if (STps->eof == ST_EOM_OK) { STps->eof = ST_EOD_1; /* allow next write */ retval = (-ENOSPC); goto out; } else if (STps->eof == ST_EOM_ERROR) { retval = (-EIO); goto out; } /* Check the buffer readability in cases where copy_user might catch the problems after some tape movement. */ if (STp->block_size != 0 && !STbp->do_dio && (copy_from_user(&i, buf, 1) != 0 || copy_from_user(&i, buf + count - 1, 1) != 0)) { retval = (-EFAULT); goto out; } retval = setup_buffering(STp, buf, count, FALSE); if (retval) goto out; total = count; memset(cmd, 0, MAX_COMMAND_SIZE); cmd[0] = WRITE_6; cmd[1] = (STp->block_size != 0); STps->rw = ST_WRITING; b_point = buf; while (count > 0 && !retry_eot) { if (STbp->do_dio) { do_count = count; } else { if (STp->block_size == 0) do_count = count; else { do_count = STbp->buffer_blocks * STp->block_size - STbp->buffer_bytes; if (do_count > count) do_count = count; } i = append_to_buffer(b_point, STbp, do_count); if (i) { retval = i; goto out; } } count -= do_count; filp->f_pos += do_count; b_point += do_count; async_write = STp->block_size == 0 && !STbp->do_dio && STm->do_async_writes && STps->eof < ST_EOM_OK; if (STp->block_size != 0 && STm->do_buffer_writes && !(STp->try_dio && try_wdio) && STps->eof < ST_EOM_OK && STbp->buffer_bytes < STbp->buffer_size) { STp->dirty = TRUE; /* Don't write a buffer that is not full enough. */ if (!async_write && count == 0) break; } retry_write: if (STp->block_size == 0) blks = transfer = do_count; else { if (!STbp->do_dio) blks = STbp->buffer_bytes; else blks = do_count; blks /= STp->block_size; transfer = blks * STp->block_size; } cmd[2] = blks >> 16; cmd[3] = blks >> 8; cmd[4] = blks; SRpnt = st_do_scsi(SRpnt, STp, cmd, transfer, SCSI_DATA_WRITE, STp->device->timeout, MAX_WRITE_RETRIES, !async_write); if (!SRpnt) { retval = STbp->syscall_result; goto out; } if (async_write) { STbp->writing = transfer; STp->dirty = !(STbp->writing == STbp->buffer_bytes); SRpnt = NULL; /* Prevent releasing this request! */ DEB( STp->write_pending = 1; ) break; } if (STbp->syscall_result != 0) { DEBC(printk(ST_DEB_MSG "%s: Error on write:\n", name)); if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 && (SRpnt->sr_sense_buffer[2] & 0x40)) { scode = SRpnt->sr_sense_buffer[2] & 0x0f; if ((SRpnt->sr_sense_buffer[0] & 0x80) != 0) undone = (SRpnt->sr_sense_buffer[3] << 24) | (SRpnt->sr_sense_buffer[4] << 16) | (SRpnt->sr_sense_buffer[5] << 8) | SRpnt->sr_sense_buffer[6]; else if (STp->block_size == 0 && scode == VOLUME_OVERFLOW) undone = transfer; else undone = 0; if (STp->block_size != 0) undone *= STp->block_size; filp->f_pos -= undone; if (undone <= do_count) { /* Only data from this write is not written */ count += undone; do_count -= undone; if (STp->block_size) blks = (transfer - undone) / STp->block_size; STps->eof = ST_EOM_OK; /* Continue in fixed block mode if all written in this request but still something left to write (retval left to zero) */ if (STp->block_size == 0 || undone > 0 || count == 0) retval = (-ENOSPC); /* EOM within current request */ DEBC(printk(ST_DEB_MSG "%s: EOM with %d bytes unwritten.\n", name, count)); } else { /* EOT within data buffered earlier (possible only in fixed block mode without direct i/o) */ if (!retry_eot && (SRpnt->sr_sense_buffer[0] & 1) == 0 && (scode == NO_SENSE || scode == RECOVERED_ERROR)) { move_buffer_data(STp->buffer, transfer - undone); retry_eot = TRUE; if (STps->drv_block >= 0) { STps->drv_block += (transfer - undone) / STp->block_size; } STps->eof = ST_EOM_OK; DEBC(printk(ST_DEB_MSG "%s: Retry write of %d bytes at EOM.\n", name, STp->buffer->buffer_bytes)); goto retry_write; } else { /* Either error within data buffered by driver or failed retry */ count -= do_count; blks = do_count = 0; STps->eof = ST_EOM_ERROR; STps->drv_block = (-1); /* Too cautious? */ retval = (-EIO); /* EOM for old data */ DEBC(printk(ST_DEB_MSG "%s: EOM with lost data.\n", name)); } } } else { filp->f_pos -= do_count; count += do_count; STps->drv_block = (-1); /* Too cautious? */ retval = (-EIO); } } if (STps->drv_block >= 0) { if (STp->block_size == 0) STps->drv_block += (do_count > 0); else STps->drv_block += blks; } STbp->buffer_bytes = 0; STp->dirty = 0; if (retval || retry_eot) { if (count < total) retval = total - count; goto out; } } if (STps->eof == ST_EOD_1) STps->eof = ST_EOM_OK; else if (STps->eof != ST_EOM_OK) STps->eof = ST_NOEOF; retval = total - count; out: if (SRpnt != NULL) scsi_release_request(SRpnt); release_buffering(STp); up(&STp->lock); return retval;}/* Read data from the tape. Returns zero in the normal case, one if the eof status has changed, and the negative error code in case of a fatal error. Otherwise updates the buffer and the eof state. Does release user buffer mapping if it is set.*/static long read_tape(Scsi_Tape *STp, long count, Scsi_Request ** aSRpnt){ int transfer, blks, bytes; unsigned char cmd[MAX_COMMAND_SIZE]; Scsi_Request *SRpnt; ST_mode *STm; ST_partstat *STps; ST_buffer *STbp; int retval = 0; char *name = tape_name(STp); if (count == 0) return 0; STm = &(STp->modes[STp->current_mode]); STps = &(STp->ps[STp->partition]); if (STps->eof == ST_FM_HIT) return 1; STbp = STp->buffer; if (STp->block_size == 0) blks = bytes = count; else { if (!(STp->try_dio && try_rdio) && STm->do_read_ahead) { blks = (STp->buffer)->buffer_blocks; bytes = blks * STp->block_size; } else { bytes = count; if (!STbp->do_dio && bytes > (STp->buffer)->buffer_size) bytes = (STp->buffer)->buffer_size; blks = bytes / STp->block_size; bytes = blks * STp->block_size; } } memset(cmd, 0, MAX_COMMAND_SIZE); cmd[0] = READ_6; cmd[1] = (STp->block_size != 0); cmd[2] = blks >> 16; cmd[3] = blks >> 8; cmd[4] = blks; SRpnt = *aSRpnt; SRpnt = st_do_scsi(SRpnt, STp, cmd, bytes, SCSI_DATA_READ, STp->device->timeout, MAX_RETRIES, TRUE); release_buffering(STp); *aSRpnt = SRpnt; if (!SRpnt) return STbp->syscall_result; STbp->read_pointer = 0; STps->at_sm = 0; /* Something to check */ if (STbp->syscall_result) { retval = 1; DEBC(printk(ST_DEB_MSG "%s: Sense: %2x %2x %2x %2x %2x %2x %2x %2x\n", name, SRpnt->sr_sense_buffer[0], SRpnt->sr_sense_buffer[1], SRpnt->sr_sense_buffer[2], SRpnt->sr_sense_buffer[3], SRpnt->sr_sense_buffer[4], SRpnt->sr_sense_buffer[5], SRpnt->sr_sense_buffer[6], SRpnt->sr_sense_buffer[7])); if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70) { /* extended sense */ if ((SRpnt->sr_sense_buffer[2] & 0x0f) == BLANK_CHECK) SRpnt->sr_sense_buffer[2] &= 0xcf; /* No need for EOM in this case */ if ((SRpnt->sr_sense_buffer[2] & 0xe0) != 0) { /* EOF, EOM, or ILI */ /* Compute the residual count */ if ((SRpnt->sr_sense_buffer[0] & 0x80) != 0) transfer = (SRpnt->sr_sense_buffer[3] << 24) | (SRpnt->sr_sense_buffer[4] << 16) | (SRpnt->sr_sense_buffer[5] << 8) | SRpnt->sr_sense_buffer[6]; else transfer = 0; if (STp->block_size == 0 && (SRpnt->sr_sense_buffer[2] & 0x0f) == MEDIUM_ERROR) transfer = bytes; if (SRpnt->sr_sense_buffer[2] & 0x20) { /* ILI */ if (STp->block_size == 0) { if (transfer <= 0) { if (transfer < 0) printk(KERN_NOTICE "%s: Failed to read %d byte block with %d byte transfer.\n", name, bytes - transfer, bytes); if (STps->drv_block >= 0) STps->drv_block += 1; STbp->buffer_bytes = 0; return (-ENOMEM); } STbp->buffer_bytes = bytes - transfer; } else { scsi_release_request(SRpnt); SRpnt = *aSRpnt = NULL; if (transfer == blks) { /* We did not get anything, error */ printk(KERN_NOTICE "%s: Incorrect block size.\n", name); if (STps->drv_block >= 0) STps->drv_block += blks - transfer + 1; st_int_ioctl(STp, MTBSR, 1); return (-EIO); } /* We have some data, deliver it */ STbp->buffer_bytes = (blks - transfer) * STp->block_size; DEBC(printk(ST_DEB_MSG "%s: ILI but enough data received %ld %d.\n", name, count, STbp->buffer_bytes)); if (STps->drv_block >= 0) STps->drv_block += 1; if (st_int_ioctl(STp, MTBSR, 1)) return (-EIO); } } else if (SRpnt->sr_sense_buffer[2] & 0x80) { /* FM overrides EOM */ if (STps->eof != ST_FM_HIT) STps->eof = ST_FM_HIT; else STps->eof = ST_EOD_2; if (STp->block_size == 0) STbp->buffer_bytes = 0; else STbp->buffer_bytes = bytes - transfer * STp->block_size; DEBC(printk(ST_DEB_MSG "%s: EOF detected (%d bytes read).\n", name, STbp->buffer_bytes)); } else if (SRpnt->sr_sense_buffer[2] & 0x40) { if (STps->eof == ST_FM) STps->eof = ST_EOD_1; else STps->eof = ST_EOM_OK; if (STp->block_size == 0) STbp->buffer_bytes = bytes - transfer; else STbp->buffer_bytes = bytes - transfer * STp->block_size; DEBC(printk(ST_DEB_MSG "%s: EOM detected (%d bytes read).\n", name, STbp->buffer_bytes)); } } /* end of EOF, EOM, ILI test */ else { /* nonzero sense key */ DEBC(printk(ST_DEB_MSG "%s: Tape error while reading.\n", name)); STps->drv_block = (-1); if (STps->eof == ST_FM && (SRpnt->sr_sense_buffer[2] & 0x0f) == BLANK_CHECK) { DEBC(printk(ST_DEB_MSG "%s: Zero returned for first BLANK CHECK after EOF.\n", name)); STps->eof = ST_EOD_2; /* First BLANK_CHECK after FM */ } else /* Some other extended sense code */ retval = (-EIO); } if (STbp->buffer_bytes < 0) /* Caused by bogus sense data */ STbp->buffer_bytes = 0; } /* End of extended sense test */ else { /* Non-extended sense */ retval = STbp->syscall_result; } } /* End of error handling */ else /* Read successful */ STbp->buffer_bytes = bytes; if (STps->drv_block >= 0) { if (STp->block_size == 0) STps->drv_block++; else STps->drv_block += STbp->buffer_bytes / STp->block_size; } return retval;}/* Read command */static ssize_tst_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos){ ssize_t total; ssize_t retval = 0; ssize_t i, transfer; int special, do_dio = 0; Scsi_Request *SRpnt = NULL; Scsi_Tape *STp = filp->private_data; ST_mode *STm; ST_partstat *STps; ST_buffer *STbp = STp->buffer; DEB( char *name = tape_name(STp); ) if (down_interruptible(&STp->lock)) return -ERESTARTSYS; retval = rw_checks(STp, filp, count); if (retval || count == 0)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -