📄 st.c
字号:
goto out; STm = &(STp->modes[STp->current_mode]); 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; } 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 "%s: EOF/EOM flag up (%d). Bytes %d\n", name, STps->eof, STbp->buffer_bytes); ) /* end DEB */ retval = setup_buffering(STp, buf, count, TRUE); if (retval) goto out; do_dio = STbp->do_dio; if (STbp->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; } if (do_dio) { /* 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 (STbp->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 (STbp->buffer_bytes > 0) { DEB( if (debugging && STps->eof != ST_NOEOF) printk(ST_DEB_MSG "%s: EOF up (%d). Left %d, needed %d.\n", name, STps->eof, STbp->buffer_bytes, count - total); ) /* end DEB */ transfer = STbp->buffer_bytes < count - total ? STbp->buffer_bytes : count - total; if (!do_dio) { i = from_buffer(STbp, 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; } if (do_dio) { release_buffering(STp); STbp->buffer_bytes = 0; } up(&STp->lock); return retval;}DEB(/* Set the driver options */static void st_log_options(Scsi_Tape * STp, ST_mode * STm, char *name){ if (debugging) { printk(KERN_INFO "%s: Mode %d options: buffer writes: %d, async writes: %d, read ahead: %d\n", name, STp->current_mode, STm->do_buffer_writes, STm->do_async_writes, STm->do_read_ahead); printk(KERN_INFO "%s: can bsr: %d, two FMs: %d, fast mteom: %d, auto lock: %d,\n", name, STp->can_bsr, STp->two_fm, STp->fast_mteom, STp->do_auto_lock); printk(KERN_INFO "%s: defs for wr: %d, no block limits: %d, partitions: %d, s2 log: %d\n", name, STm->defaults_for_writes, STp->omit_blklims, STp->can_partitions, STp->scsi2_logical); printk(KERN_INFO "%s: sysv: %d nowait: %d\n", name, STm->sysv, STp->immediate); printk(KERN_INFO "%s: debugging: %d\n", name, debugging); }} )static int st_set_options(Scsi_Tape *STp, long options){ int value; long code; ST_mode *STm; char *name = tape_name(STp); struct cdev *cd0, *cd1; STm = &(STp->modes[STp->current_mode]); if (!STm->defined) { cd0 = STm->cdevs[0]; cd1 = STm->cdevs[1]; memcpy(STm, &(STp->modes[0]), sizeof(ST_mode)); STm->cdevs[0] = cd0; STm->cdevs[1] = cd1; modes_defined = TRUE; DEBC(printk(ST_DEB_MSG "%s: Initialized mode %d definition from mode 0\n", name, STp->current_mode)); } code = options & MT_ST_OPTIONS; if (code == MT_ST_BOOLEANS) { STm->do_buffer_writes = (options & MT_ST_BUFFER_WRITES) != 0; STm->do_async_writes = (options & MT_ST_ASYNC_WRITES) != 0; STm->defaults_for_writes = (options & MT_ST_DEF_WRITES) != 0; STm->do_read_ahead = (options & MT_ST_READ_AHEAD) != 0; STp->two_fm = (options & MT_ST_TWO_FM) != 0; STp->fast_mteom = (options & MT_ST_FAST_MTEOM) != 0; STp->do_auto_lock = (options & MT_ST_AUTO_LOCK) != 0; STp->can_bsr = (options & MT_ST_CAN_BSR) != 0; STp->omit_blklims = (options & MT_ST_NO_BLKLIMS) != 0; if ((STp->device)->scsi_level >= SCSI_2) STp->can_partitions = (options & MT_ST_CAN_PARTITIONS) != 0; STp->scsi2_logical = (options & MT_ST_SCSI2LOGICAL) != 0; STp->immediate = (options & MT_ST_NOWAIT) != 0; STm->sysv = (options & MT_ST_SYSV) != 0; DEB( debugging = (options & MT_ST_DEBUGGING) != 0; st_log_options(STp, STm, name); ) } else if (code == MT_ST_SETBOOLEANS || code == MT_ST_CLEARBOOLEANS) { value = (code == MT_ST_SETBOOLEANS); if ((options & MT_ST_BUFFER_WRITES) != 0) STm->do_buffer_writes = value; if ((options & MT_ST_ASYNC_WRITES) != 0) STm->do_async_writes = value; if ((options & MT_ST_DEF_WRITES) != 0) STm->defaults_for_writes = value; if ((options & MT_ST_READ_AHEAD) != 0) STm->do_read_ahead = value; if ((options & MT_ST_TWO_FM) != 0) STp->two_fm = value; if ((options & MT_ST_FAST_MTEOM) != 0) STp->fast_mteom = value; if ((options & MT_ST_AUTO_LOCK) != 0) STp->do_auto_lock = value; if ((options & MT_ST_CAN_BSR) != 0) STp->can_bsr = value; if ((options & MT_ST_NO_BLKLIMS) != 0) STp->omit_blklims = value; if ((STp->device)->scsi_level >= SCSI_2 && (options & MT_ST_CAN_PARTITIONS) != 0) STp->can_partitions = value; if ((options & MT_ST_SCSI2LOGICAL) != 0) STp->scsi2_logical = value; if ((options & MT_ST_NOWAIT) != 0) STp->immediate = value; if ((options & MT_ST_SYSV) != 0) STm->sysv = value; DEB( if ((options & MT_ST_DEBUGGING) != 0) debugging = value; st_log_options(STp, STm, name); ) } else if (code == MT_ST_WRITE_THRESHOLD) { /* Retained for compatibility */ } else if (code == MT_ST_DEF_BLKSIZE) { value = (options & ~MT_ST_OPTIONS); if (value == ~MT_ST_OPTIONS) { STm->default_blksize = (-1); DEBC( printk(KERN_INFO "%s: Default block size disabled.\n", name)); } else { STm->default_blksize = value; DEBC( printk(KERN_INFO "%s: Default block size set to %d bytes.\n", name, STm->default_blksize)); if (STp->ready == ST_READY) { STp->blksize_changed = FALSE; set_mode_densblk(STp, STm); } } } else if (code == MT_ST_TIMEOUTS) { value = (options & ~MT_ST_OPTIONS); if ((value & MT_ST_SET_LONG_TIMEOUT) != 0) { STp->long_timeout = (value & ~MT_ST_SET_LONG_TIMEOUT) * HZ; DEBC( printk(KERN_INFO "%s: Long timeout set to %d seconds.\n", name, (value & ~MT_ST_SET_LONG_TIMEOUT))); } else { STp->device->timeout = value * HZ; DEBC( printk(KERN_INFO "%s: Normal timeout set to %d seconds.\n", name, value) ); } } else if (code == MT_ST_SET_CLN) { value = (options & ~MT_ST_OPTIONS) & 0xff; if (value != 0 && value < EXTENDED_SENSE_START && value >= SCSI_SENSE_BUFFERSIZE) return (-EINVAL); STp->cln_mode = value; STp->cln_sense_mask = (options >> 8) & 0xff; STp->cln_sense_value = (options >> 16) & 0xff; printk(KERN_INFO "%s: Cleaning request mode %d, mask %02x, value %02x\n", name, value, STp->cln_sense_mask, STp->cln_sense_value); } else if (code == MT_ST_DEF_OPTIONS) { code = (options & ~MT_ST_CLEAR_DEFAULT); value = (options & MT_ST_CLEAR_DEFAULT); if (code == MT_ST_DEF_DENSITY) { if (value == MT_ST_CLEAR_DEFAULT) { STm->default_density = (-1); DEBC( printk(KERN_INFO "%s: Density default disabled.\n", name)); } else { STm->default_density = value & 0xff; DEBC( printk(KERN_INFO "%s: Density default set to %x\n", name, STm->default_density)); if (STp->ready == ST_READY) { STp->density_changed = FALSE; set_mode_densblk(STp, STm); } } } else if (code == MT_ST_DEF_DRVBUFFER) { if (value == MT_ST_CLEAR_DEFAULT) { STp->default_drvbuffer = 0xff; DEBC( printk(KERN_INFO "%s: Drive buffer default disabled.\n", name)); } else { STp->default_drvbuffer = value & 7; DEBC( printk(KERN_INFO "%s: Drive buffer default set to %x\n", name, STp->default_drvbuffer)); if (STp->ready == ST_READY) st_int_ioctl(STp, MTSETDRVBUFFER, STp->default_drvbuffer); } } else if (code == MT_ST_DEF_COMPRESSION) { if (value == MT_ST_CLEAR_DEFAULT) { STm->default_compression = ST_DONT_TOUCH; DEBC( printk(KERN_INFO "%s: Compression default disabled.\n", name)); } else { if ((value & 0xff00) != 0) { STp->c_algo = (value & 0xff00) >> 8; DEBC( printk(KERN_INFO "%s: Compression algorithm set to 0x%x.\n", name, STp->c_algo)); } if ((value & 0xff) != 0xff) { STm->default_compression = (value & 1 ? ST_YES : ST_NO); DEBC( printk(KERN_INFO "%s: Compression default set to %x\n", name, (value & 1))); if (STp->ready == ST_READY) { STp->compression_changed = FALSE; st_compression(STp, (STm->default_compression == ST_YES)); } } } } } else return (-EIO); return 0;}#define MODE_HEADER_LENGTH 4/* Mode header and page byte offsets */#define MH_OFF_DATA_LENGTH 0#define MH_OFF_MEDIUM_TYPE 1#define MH_OFF_DEV_SPECIFIC 2#define MH_OFF_BDESCS_LENGTH 3#define MP_OFF_PAGE_NBR 0#define MP_OFF_PAGE_LENGTH 1/* Mode header and page bit masks */#define MH_BIT_WP 0x80#define MP_MSK_PAGE_NBR 0x3f/* Don't return block descriptors */#define MODE_SENSE_OMIT_BDESCS 0x08#define MODE_SELECT_PAGE_FORMAT 0x10/* Read a mode page into the tape buffer. The block descriptors are included if incl_block_descs is true. The page control is ored to the page number parameter, if necessary. */static int read_mode_page(Scsi_Tape *STp, int page, int omit_block_descs){ unsigned char cmd[MAX_COMMAND_SIZE]; Scsi_Request *SRpnt = NULL; memset(cmd, 0, MAX_COMMAND_SIZE); cmd[0] = MODE_SENSE; if (omit_block_descs) cmd[1] = MODE_SENSE_OMIT_BDESCS; cmd[2] = page; cmd[4] = 255; SRpnt = st_do_scsi(SRpnt, STp, cmd, cmd[4], SCSI_DATA_READ, STp->device->timeout, 0, TRUE); if (SRpnt == NULL) return (STp->buffer)->syscall_result; scsi_release_request(SRpnt); return (STp->buffer)->syscall_result;}/* Send the mode page in the tape buffer to the drive. Assumes that the mode data in the buffer is correctly formatted. The long timeout is used if slow is non-zero. */static int write_mode_page(Scsi_Tape *STp, int page, int slow){ int pgo; unsigned char cmd[MAX_COMMAND_SIZE]; Scsi_Request *SRpnt = NULL; memset(cmd, 0, MAX_COMMAND_SIZE); cmd[0] = MODE_SELECT; cmd[1] = MODE_SELECT_PAGE_FORMAT; pgo = MODE_HEADER_LENGTH + (STp->buffer)->b_data[MH_OFF_BDESCS_LENGTH]; cmd[4] = pgo + (STp->buffer)->b_data[pgo + MP_OFF_PAGE_LENGTH] + 2; /* Clear reserved fields */ (STp->buffer)->b_data[MH_OFF_DATA_LENGTH] = 0; (STp->buffer)->b_data[MH_OFF_MEDIUM_TYPE] = 0; (STp->buffer)->b_data[MH_OFF_DEV_SPECIFIC] &= ~MH_BIT_WP; (STp->buffer)->b_data[pgo + MP_OFF_PAGE_NBR] &= MP_MSK_PAGE_NBR; SRpnt = st_do_scsi(SRpnt, STp, cmd, cmd[4], SCSI_DATA_WRITE, (slow ? STp->long_timeout : STp->device->timeout), 0, TRUE); if (SRpnt == NULL) return (STp->buffer)->syscall_result; scsi_release_request(SRpnt); return (STp->buffer)->syscall_result;}#define COMPRESSION_PAGE 0x0f#define COMPRESSION_PAGE_LENGTH 16#define CP_OFF_DCE_DCC 2#define CP_OFF_C_ALGO 7#define DCE_MASK 0x80#define DCC_MASK 0x40#define RED_MASK 0x60/* Control the compression with mode page 15. Algorithm not changed if zero. The block descriptors are read and written because Sony SDT-7000 does not work without this (suggestion from Michael Schaefer <Michael.Schaefer@dlr.de>). Including block descriptors should not cause any harm to other drives. */static int st_compression(Scsi_Tape * STp, int state){ int retval; int mpoffs; /* Offset to mode page start */ unsigned char *b_data = (STp->buffer)->b_data; DEB( char *name = tape_name(STp); ) if (STp->ready != ST_READY) return (-EIO); /* Read the current page contents */ retval = read_mode_page(STp, COMPRESSION_PAGE, FALSE); if (retval) { DEBC(printk(ST_DEB_MSG "%s: Compression mode page not supported.\n", name)); return (-EIO); } mpoffs = MODE_HEADER_LENGTH + b_data[MH_OFF_BDESCS_LENGTH]; DEBC(printk(ST_DEB_MSG "%s: Compression state is %d.\n", name, (b_data[mpoffs + CP_OFF_DCE_DCC] & DCE_MASK ? 1 : 0))); /* Check if compression can be changed */ if ((b_data[mpoffs + CP_OFF_DCE_DCC] & DCC_MASK) == 0) { DEBC(printk(ST_DEB_MSG "%s: Compression not supported.\n", name)); return (-EIO); } /* Do the change */ if (state) { b_data[mpoffs + CP_OFF_DCE_DCC] |= DCE_MASK; if (STp->c_algo != 0) b_data[mpoffs + CP_OFF_C_ALGO] = STp->c_algo; } else { b_data[mpoffs + CP_OFF_DCE_DCC] &= ~DCE_MASK; if (STp->c_algo != 0) b_data[mpoffs + CP_OFF_C_ALGO] = 0; /* no compression */ } retval = write_mode_page(STp, COMPRESSION_PAGE, FALSE); if (retval) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -