📄 st.c
字号:
size_t count, int is_read){ int i, bufsize, retval = 0; struct st_buffer *STbp = STp->buffer; if (is_read) i = STp->try_dio_now && try_rdio; else i = STp->try_dio_now && try_wdio; if (i && ((unsigned long)buf & queue_dma_alignment( STp->device->request_queue)) == 0) { i = sgl_map_user_pages(&(STbp->sg[0]), STbp->use_sg, (unsigned long)buf, count, (is_read ? READ : WRITE)); if (i > 0) { STbp->do_dio = i; STbp->buffer_bytes = 0; /* can be used as transfer counter */ } else STbp->do_dio = 0; /* fall back to buffering with any error */ STbp->sg_segs = STbp->do_dio; STbp->frp_sg_current = 0; DEB( if (STbp->do_dio) { STp->nbr_dio++; STp->nbr_pages += STbp->do_dio; for (i=1; i < STbp->do_dio; i++) if (page_to_pfn(STbp->sg[i].page) == page_to_pfn(STbp->sg[i-1].page) + 1) STp->nbr_combinable++; } ) } else STbp->do_dio = 0; DEB( STp->nbr_requests++; ) if (!STbp->do_dio) { if (STp->block_size) bufsize = STp->block_size > st_fixed_buffer_size ? STp->block_size : st_fixed_buffer_size; else bufsize = count; if (bufsize > STbp->buffer_size && !enlarge_buffer(STbp, bufsize, STp->restr_dma)) { printk(KERN_WARNING "%s: Can't allocate %d byte tape buffer.\n", tape_name(STp), bufsize); retval = (-EOVERFLOW); goto out; } if (STp->block_size) STbp->buffer_blocks = bufsize / STp->block_size; } out: return retval;}/* Can be called more than once after each setup_buffer() */static void release_buffering(struct scsi_tape *STp, int is_read){ struct st_buffer *STbp; STbp = STp->buffer; if (STbp->do_dio) { sgl_unmap_user_pages(&(STbp->sg[0]), STbp->do_dio, is_read); STbp->do_dio = 0; STbp->sg_segs = 0; }}/* Write command */static ssize_tst_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos){ ssize_t total; ssize_t i, do_count, blks, transfer; ssize_t retval; int undone, retry_eot = 0, scode; int async_write; unsigned char cmd[MAX_COMMAND_SIZE]; const char __user *b_point; struct st_request *SRpnt = NULL; struct scsi_tape *STp = filp->private_data; struct st_modedef *STm; struct st_partstat *STps; struct st_buffer *STbp; char *name = tape_name(STp); if (mutex_lock_interruptible(&STp->lock)) return -ERESTARTSYS; retval = rw_checks(STp, filp, count); if (retval || count == 0) goto out; /* Write must be integral number of blocks */ if (STp->block_size != 0 && (count % STp->block_size) != 0) { printk(KERN_WARNING "%s: Write not multiple of tape block size.\n", name); retval = (-EINVAL); goto out; } 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; i = write_behind_check(STp); if (i) { if (i == -ENOSPC) 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, 0); 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; 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_now && try_wdio) && STps->eof < ST_EOM_OK && STbp->buffer_bytes < STbp->buffer_size) { STp->dirty = 1; /* 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, DMA_TO_DEVICE, STp->device->timeout, MAX_WRITE_RETRIES, !async_write); if (!SRpnt) { retval = STbp->syscall_result; goto out; } if (async_write && !STbp->syscall_result) { 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) { struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat; DEBC(printk(ST_DEB_MSG "%s: Error on write:\n", name)); if (cmdstatp->have_sense && (cmdstatp->flags & SENSE_EOM)) { scode = cmdstatp->sense_hdr.sense_key; if (cmdstatp->remainder_valid) undone = (int)cmdstatp->uremainder64; else if (STp->block_size == 0 && scode == VOLUME_OVERFLOW) undone = transfer; else undone = 0; if (STp->block_size != 0) undone *= STp->block_size; 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, (int)count)); } else { /* EOT within data buffered earlier (possible only in fixed block mode without direct i/o) */ if (!retry_eot && !cmdstatp->deferred && (scode == NO_SENSE || scode == RECOVERED_ERROR)) { move_buffer_data(STp->buffer, transfer - undone); retry_eot = 1; 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 { count += do_count; STps->drv_block = (-1); /* Too cautious? */ retval = STbp->syscall_result; } } 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) st_release_request(SRpnt); release_buffering(STp, 0); mutex_unlock(&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(struct scsi_tape *STp, long count, struct st_request ** aSRpnt){ int transfer, blks, bytes; unsigned char cmd[MAX_COMMAND_SIZE]; struct st_request *SRpnt; struct st_modedef *STm; struct st_partstat *STps; struct 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_now && 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, DMA_FROM_DEVICE, STp->device->timeout, MAX_RETRIES, 1); release_buffering(STp, 1); *aSRpnt = SRpnt; if (!SRpnt) return STbp->syscall_result; STbp->read_pointer = 0; STps->at_sm = 0; /* Something to check */ if (STbp->syscall_result) { struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat; retval = 1; DEBC(printk(ST_DEB_MSG "%s: Sense: %2x %2x %2x %2x %2x %2x %2x %2x\n", name, SRpnt->sense[0], SRpnt->sense[1], SRpnt->sense[2], SRpnt->sense[3], SRpnt->sense[4], SRpnt->sense[5], SRpnt->sense[6], SRpnt->sense[7])); if (cmdstatp->have_sense) { if (cmdstatp->sense_hdr.sense_key == BLANK_CHECK) cmdstatp->flags &= 0xcf; /* No need for EOM in this case */ if (cmdstatp->flags != 0) { /* EOF, EOM, or ILI */ /* Compute the residual count */ if (cmdstatp->remainder_valid) transfer = (int)cmdstatp->uremainder64; else transfer = 0; if (STp->block_size == 0 && cmdstatp->sense_hdr.sense_key == MEDIUM_ERROR) transfer = bytes; if (cmdstatp->flags & SENSE_ILI) { /* 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 { st_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 (cmdstatp->flags & SENSE_FMK) { /* FM overrides EOM */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -