📄 st.c
字号:
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 nowait: %d\n", dev, STm->sysv, STp->immediate); DEB(printk(KERN_INFO "st%d: debugging: %d\n", dev, debugging);)}static int st_set_options(Scsi_Tape *STp, long options){ int value; long code; ST_mode *STm; int dev = TAPE_NR(STp->devt); STm = &(STp->modes[STp->current_mode]); if (!STm->defined) { memcpy(STm, &(STp->modes[0]), sizeof(ST_mode)); modes_defined = TRUE; DEBC(printk(ST_DEB_MSG "st%d: Initialized mode %d definition from mode 0\n", dev, 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, dev); } 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, dev); } else if (code == MT_ST_WRITE_THRESHOLD) { value = (options & ~MT_ST_OPTIONS) * ST_KILOBYTE; if (value < 1 || value > st_buffer_size) { printk(KERN_WARNING "st%d: Write threshold %d too small or too large.\n", dev, value); return (-EIO); } STp->write_threshold = value; printk(KERN_INFO "st%d: Write threshold set to %d bytes.\n", dev, value); } else if (code == MT_ST_DEF_BLKSIZE) { value = (options & ~MT_ST_OPTIONS); if (value == ~MT_ST_OPTIONS) { STm->default_blksize = (-1); printk(KERN_INFO "st%d: Default block size disabled.\n", dev); } else { STm->default_blksize = value; printk(KERN_INFO "st%d: Default block size set to %d bytes.\n", dev, 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; printk(KERN_INFO "st%d: Long timeout set to %d seconds.\n", dev, (value & ~MT_ST_SET_LONG_TIMEOUT)); } else { STp->timeout = value * HZ; printk(KERN_INFO "st%d: Normal timeout set to %d seconds.\n", dev, 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 "st%d: Cleaning request mode %d, mask %02x, value %02x\n", dev, 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); printk(KERN_INFO "st%d: Density default disabled.\n", dev); } else { STm->default_density = value & 0xff; printk(KERN_INFO "st%d: Density default set to %x\n", dev, 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; printk(KERN_INFO "st%d: Drive buffer default disabled.\n", dev); } else { STp->default_drvbuffer = value & 7; printk(KERN_INFO "st%d: Drive buffer default set to %x\n", dev, 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; printk(KERN_INFO "st%d: Compression default disabled.\n", dev); } else { if ((value & 0xff00) != 0) { STp->c_algo = (value & 0xff00) >> 8; printk(KERN_INFO "st%d: Compression algorithm set to 0x%x.\n", dev, STp->c_algo); } if ((value & 0xff) != 0xff) { STm->default_compression = (value & 1 ? ST_YES : ST_NO); printk(KERN_INFO "st%d: Compression default set to %x\n", dev, (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->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. */static int write_mode_page(Scsi_Tape *STp, int page){ 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, STp->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( int dev = TAPE_NR(STp->devt); ) 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 "st%d: Compression mode page not supported.\n", dev)); return (-EIO); } mpoffs = MODE_HEADER_LENGTH + b_data[MH_OFF_BDESCS_LENGTH]; DEBC(printk(ST_DEB_MSG "st%d: Compression state is %d.\n", dev, (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 "st%d: Compression not supported.\n", dev)); 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); if (retval) { DEBC(printk(ST_DEB_MSG "st%d: Compression change failed.\n", dev)); return (-EIO); } DEBC(printk(ST_DEB_MSG "st%d: Compression state changed to %d.\n", dev, state)); STp->compression_changed = TRUE; return 0;}/* Process the load and unload commands (does unload if the load code is zero) */static int do_load_unload(Scsi_Tape *STp, struct file *filp, int load_code){ int retval = (-EIO), timeout; DEB(int dev = TAPE_NR(STp->devt);) unsigned char cmd[MAX_COMMAND_SIZE]; ST_partstat *STps; Scsi_Request *SRpnt; if (STp->ready != ST_READY && !load_code) { if (STp->ready == ST_NO_TAPE) return (-ENOMEDIUM); else return (-EIO); } memset(cmd, 0, MAX_COMMAND_SIZE); cmd[0] = START_STOP; if (load_code) cmd[4] |= 1; /* * If arg >= 1 && arg <= 6 Enhanced load/unload in HP C1553A */ if (load_code >= 1 + MT_ST_HPLOADER_OFFSET && load_code <= 6 + MT_ST_HPLOADER_OFFSET) { DEBC(printk(ST_DEB_MSG "st%d: Enhanced %sload slot %2d.\n", dev, (cmd[4]) ? "" : "un", load_code - MT_ST_HPLOADER_OFFSET)); cmd[3] = load_code - MT_ST_HPLOADER_OFFSET; /* MediaID field of C1553A */ } if (STp->immediate) { cmd[1] = 1; /* Don't wait for completion */ timeout = STp->timeout; } else timeout = STp->long_timeout; DEBC( if (!load_code) printk(ST_DEB_MSG "st%d: Unloading tape.\n", dev); else printk(ST_DEB_MSG "st%d: Loading tape.\n", dev); ); SRpnt = st_do_scsi(NULL, STp, cmd, 0, SCSI_DATA_NONE, timeout, MAX_RETRIES, TRUE); if (!SRpnt) return (STp->buffer)->syscall_result; retval = (STp->buffer)->syscall_result; scsi_release_request(SRpnt); if (!retval) { /* SCSI command successful */ if (!load_code) STp->rew_at_close = 0; else STp->rew_at_close = STp->autorew_dev; retval = check_tape(STp, filp); if (retval > 0) retval = 0; } else { STps = &(STp->ps[STp->partition]); STps->drv_file = STps->drv_block = (-1); } return retval;}/* Internal ioctl function */static int st_int_ioctl(Scsi_Tape *STp, unsigned int cmd_in, unsigned long arg){ int timeout; long ltmp; int ioctl_result; int chg_eof = TRUE; unsigned char cmd[MAX_COMMAND_SIZE]; Scsi_Request *SRpnt; ST_partstat *STps; int fileno, blkno, at_sm, undone; int datalen = 0, direction = SCSI_DATA_NONE; int dev = TAPE_NR(STp->devt); if (STp->ready != ST_READY) { if (STp->ready == ST_NO_TAPE) return (-ENOMEDIUM)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -