📄 st.c
字号:
STps->drv_block += blks; } (STp->buffer)->buffer_bytes = 0; STp->dirty = 0; } if (count != 0) { STp->dirty = 1; i = append_to_buffer(b_point, STp->buffer, count); if (i) { retval = i; goto out; } filp->f_pos += count; count = 0; } if (doing_write && (STp->buffer)->syscall_result != 0) { retval = (STp->buffer)->syscall_result; goto out; } if (STm->do_async_writes && (((STp->buffer)->buffer_bytes >= STp->write_threshold && (STp->buffer)->buffer_bytes >= STp->block_size) || STp->block_size == 0)) { /* Schedule an asynchronous write */ if (STp->block_size == 0) (STp->buffer)->writing = (STp->buffer)->buffer_bytes; else (STp->buffer)->writing = ((STp->buffer)->buffer_bytes / STp->block_size) * STp->block_size; STp->dirty = !((STp->buffer)->writing == (STp->buffer)->buffer_bytes); if (STp->block_size == 0) blks = (STp->buffer)->writing; else blks = (STp->buffer)->writing / STp->block_size; cmd[2] = blks >> 16; cmd[3] = blks >> 8; cmd[4] = blks; DEB( STp->write_pending = 1; ) SRpnt = st_do_scsi(SRpnt, STp, cmd, (STp->buffer)->writing, SCSI_DATA_WRITE, STp->timeout, MAX_WRITE_RETRIES, FALSE); if (SRpnt == NULL) { retval = (STp->buffer)->syscall_result; goto out; } SRpnt = NULL; /* Prevent releasing this request! */ } STps->at_sm &= (total == 0); if (total > 0) STps->eof = ST_NOEOF; retval = total; out: if (SRpnt != NULL) scsi_release_request(SRpnt); 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. */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; int dev = TAPE_NR(STp->devt); int retval = 0; if (count == 0) return 0; STm = &(STp->modes[STp->current_mode]); STps = &(STp->ps[STp->partition]); if (STps->eof == ST_FM_HIT) return 1; memset(cmd, 0, MAX_COMMAND_SIZE); cmd[0] = READ_6; cmd[1] = (STp->block_size != 0); if (STp->block_size == 0) blks = bytes = count; else { if (STm->do_read_ahead) { blks = (STp->buffer)->buffer_blocks; bytes = blks * STp->block_size; } else { bytes = count; if (bytes > (STp->buffer)->buffer_size) bytes = (STp->buffer)->buffer_size; blks = bytes / STp->block_size; bytes = blks * STp->block_size; } } 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->timeout, MAX_RETRIES, TRUE); *aSRpnt = SRpnt; if (!SRpnt) return (STp->buffer)->syscall_result; (STp->buffer)->read_pointer = 0; STps->at_sm = 0; /* Something to check */ if ((STp->buffer)->syscall_result) { retval = 1; DEBC(printk(ST_DEB_MSG "st%d: Sense: %2x %2x %2x %2x %2x %2x %2x %2x\n", dev, 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 (STps->drv_block >= 0) STps->drv_block += 1; return (-ENOMEM); } (STp->buffer)->buffer_bytes = bytes - transfer; } else { scsi_release_request(SRpnt); SRpnt = *aSRpnt = NULL; if (transfer == blks) { /* We did not get anything, error */ printk(KERN_NOTICE "st%d: Incorrect block size.\n", dev); 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 */ (STp->buffer)->buffer_bytes = (blks - transfer) * STp->block_size; DEBC(printk(ST_DEB_MSG "st%d: ILI but enough data received %ld %d.\n", dev, count, (STp->buffer)->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) (STp->buffer)->buffer_bytes = 0; else (STp->buffer)->buffer_bytes = bytes - transfer * STp->block_size; DEBC(printk(ST_DEB_MSG "st%d: EOF detected (%d bytes read).\n", dev, (STp->buffer)->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) (STp->buffer)->buffer_bytes = bytes - transfer; else (STp->buffer)->buffer_bytes = bytes - transfer * STp->block_size; DEBC(printk(ST_DEB_MSG "st%d: EOM detected (%d bytes read).\n", dev, (STp->buffer)->buffer_bytes)); } } /* end of EOF, EOM, ILI test */ else { /* nonzero sense key */ DEBC(printk(ST_DEB_MSG "st%d: Tape error while reading.\n", dev)); STps->drv_block = (-1); if (STps->eof == ST_FM && (SRpnt->sr_sense_buffer[2] & 0x0f) == BLANK_CHECK) { DEBC(printk(ST_DEB_MSG "st%d: Zero returned for first BLANK CHECK after EOF.\n", dev)); STps->eof = ST_EOD_2; /* First BLANK_CHECK after FM */ } else /* Some other extended sense code */ retval = (-EIO); } } /* End of extended sense test */ else { /* Non-extended sense */ retval = (STp->buffer)->syscall_result; } } /* End of error handling */ else /* Read successful */ (STp->buffer)->buffer_bytes = bytes; if (STps->drv_block >= 0) { if (STp->block_size == 0) STps->drv_block++; else STps->drv_block += (STp->buffer)->buffer_bytes / STp->block_size; } return retval;}/* Read command */static ssize_t st_read(struct file *filp, char *buf, size_t count, loff_t * ppos){ struct inode *inode = filp->f_dentry->d_inode; ssize_t total; ssize_t retval = 0; ssize_t i, transfer; int special; Scsi_Request *SRpnt = NULL; Scsi_Tape *STp; ST_mode *STm; ST_partstat *STps; int dev = TAPE_NR(inode->i_rdev); read_lock(&st_dev_arr_lock); STp = scsi_tapes[dev]; read_unlock(&st_dev_arr_lock); if (down_interruptible(&STp->lock)) return -ERESTARTSYS; /* * If we are in the middle of error recovery, don't let anyone * else try and use this device. Also, if error recovery fails, it * may try and take the device offline, in which case all further * access to the device is prohibited. */ if (!scsi_block_when_processing_errors(STp->device)) { retval = (-ENXIO); goto out; } if (ppos != &filp->f_pos) { /* "A request was outside the capabilities of the device." */ retval = (-ENXIO); goto out; } if (STp->ready != ST_READY) { if (STp->ready == ST_NO_TAPE) retval = (-ENOMEDIUM); else retval = (-EIO); goto out; } STm = &(STp->modes[STp->current_mode]); if (!STm->defined) { retval = (-ENXIO); goto out; } DEB( if (!STp->in_use) { printk(ST_DEB_MSG "st%d: Incorrect device.\n", dev); retval = (-EIO); goto out; } ) /* end DEB */ if (STp->can_partitions && (retval = update_partition(STp)) < 0) goto out; if (STp->block_size == 0) { if (STp->max_block > 0 && (count < STp->min_block || count > STp->max_block)) { retval = (-EINVAL); goto out; } if (count > (STp->buffer)->buffer_size && !enlarge_buffer(STp->buffer, count, STp->restr_dma)) { retval = (-EOVERFLOW); goto out; } } if ((STp->buffer)->buffer_blocks < 1) { /* Fixed block mode with too small buffer */ if (!enlarge_buffer(STp->buffer, STp->block_size, STp->restr_dma)) { retval = (-EOVERFLOW); goto out; } (STp->buffer)->buffer_blocks = 1; } if (!(STm->do_read_ahead) && STp->block_size != 0 && (count % STp->block_size) != 0) { retval = (-EINVAL); /* Read must be integral number of blocks */ goto out; } if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED && !st_int_ioctl(STp, MTLOCK, 0)) STp->door_locked = ST_LOCKED_AUTO; STps = &(STp->ps[STp->partition]); if (STps->rw == ST_WRITING) { retval = flush_buffer(STp, 0); if (retval) goto out; STps->rw = ST_READING; } DEB( if (debugging && STps->eof != ST_NOEOF) printk(ST_DEB_MSG "st%d: EOF/EOM flag up (%d). Bytes %d\n", dev, STps->eof, (STp->buffer)->buffer_bytes); ) /* end DEB */ if ((STp->buffer)->buffer_bytes == 0 && STps->eof >= ST_EOD_1) { if (STps->eof < ST_EOD) { STps->eof += 1; retval = 0; goto out; } retval = (-EIO); /* EOM or Blank Check */ goto out; } /* Check the buffer writability before any tape movement. Don't alter buffer data. */ if (copy_from_user(&i, buf, 1) != 0 || copy_to_user(buf, &i, 1) != 0 || copy_from_user(&i, buf + count - 1, 1) != 0 || copy_to_user(buf + count - 1, &i, 1) != 0) { retval = (-EFAULT); goto out; } STps->rw = ST_READING; /* Loop until enough data in buffer or a special condition found */ for (total = 0, special = 0; total < count && !special;) { /* Get new data if the buffer is empty */ if ((STp->buffer)->buffer_bytes == 0) { special = read_tape(STp, count - total, &SRpnt); if (special < 0) { /* No need to continue read */ retval = special; goto out; } } /* Move the data from driver buffer to user buffer */ if ((STp->buffer)->buffer_bytes > 0) { DEB( if (debugging && STps->eof != ST_NOEOF) printk(ST_DEB_MSG "st%d: EOF up (%d). Left %d, needed %d.\n", dev, STps->eof, (STp->buffer)->buffer_bytes, count - total); ) /* end DEB */ transfer = (STp->buffer)->buffer_bytes < count - total ? (STp->buffer)->buffer_bytes : count - total; i = from_buffer(STp->buffer, buf, transfer); if (i) { retval = i; goto out; } filp->f_pos += transfer; buf += transfer; total += transfer; } if (STp->block_size == 0) break; /* Read only one variable length block */ } /* for (total = 0, special = 0; total < count && !special; ) */ /* Change the eof state if no data from tape or buffer */ if (total == 0) { if (STps->eof == ST_FM_HIT) { STps->eof = ST_FM; STps->drv_block = 0; if (STps->drv_file >= 0) STps->drv_file++; } else if (STps->eof == ST_EOD_1) { STps->eof = ST_EOD_2; STps->drv_block = 0; if (STps->drv_file >= 0) STps->drv_file++; } else if (STps->eof == ST_EOD_2) STps->eof = ST_EOD; } else if (STps->eof == ST_FM) STps->eof = ST_NOEOF; retval = total; out: if (SRpnt != NULL) { scsi_release_request(SRpnt); SRpnt = NULL; } up(&STp->lock); return retval;}/* Set the driver options */static void st_log_options(Scsi_Tape * STp, ST_mode * STm, int dev){ printk(KERN_INFO "st%d: Mode %d options: buffer writes: %d, async writes: %d, read ahead: %d\n", dev, STp->current_mode, STm->do_buffer_writes, STm->do_async_writes, STm->do_read_ahead); printk(KERN_INFO "st%d: can bsr: %d, two FMs: %d, fast mteom: %d, auto lock: %d,\n", dev, STp->can_bsr, STp->two_fm, STp->fast_mteom, STp->do_auto_lock); printk(KERN_INFO "st%d: defs for wr: %d, no block limits: %d, partitions: %d, s2 log: %d\n", dev, STm->defaults_for_writes, STp->omit_blklims, STp->can_partitions, STp->scsi2_logical); printk(KERN_INFO "st%d: sysv: %d\n", dev, STm->sysv); DEB(printk(KERN_INFO "st%d: debugging: %d\n",
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -