⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 st.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
{	struct completion *waiting;	/* if async, make sure there's no command outstanding */	if (!do_wait && ((STp->buffer)->last_SRpnt)) {		printk(KERN_ERR "%s: Async command already active.\n",		       tape_name(STp));		if (signal_pending(current))			(STp->buffer)->syscall_result = (-EINTR);		else			(STp->buffer)->syscall_result = (-EBUSY);		return NULL;	}	if (SRpnt == NULL) {		SRpnt = st_allocate_request();		if (SRpnt == NULL) {			DEBC( printk(KERN_ERR "%s: Can't get SCSI request.\n",				     tape_name(STp)); );			if (signal_pending(current))				(STp->buffer)->syscall_result = (-EINTR);			else				(STp->buffer)->syscall_result = (-EBUSY);			return NULL;		}		SRpnt->stp = STp;	}	/* If async IO, set last_SRpnt. This ptr tells write_behind_check	   which IO is outstanding. It's nulled out when the IO completes. */	if (!do_wait)		(STp->buffer)->last_SRpnt = SRpnt;	waiting = &STp->wait;	init_completion(waiting);	SRpnt->waiting = waiting;	if (!STp->buffer->do_dio)		buf_to_sg(STp->buffer, bytes);	memcpy(SRpnt->cmd, cmd, sizeof(SRpnt->cmd));	STp->buffer->cmdstat.have_sense = 0;	STp->buffer->syscall_result = 0;	if (scsi_execute_async(STp->device, cmd, COMMAND_SIZE(cmd[0]), direction,			&((STp->buffer)->sg[0]), bytes, (STp->buffer)->sg_segs,			       timeout, retries, SRpnt, st_sleep_done, GFP_KERNEL)) {		/* could not allocate the buffer or request was too large */		(STp->buffer)->syscall_result = (-EBUSY);		(STp->buffer)->last_SRpnt = NULL;	}	else if (do_wait) {		wait_for_completion(waiting);		SRpnt->waiting = NULL;		(STp->buffer)->syscall_result = st_chk_result(STp, SRpnt);	}	return SRpnt;}/* Handle the write-behind checking (waits for completion). Returns -ENOSPC if   write has been correct but EOM early warning reached, -EIO if write ended in   error or zero if write successful. Asynchronous writes are used only in   variable block mode. */static int write_behind_check(struct scsi_tape * STp){	int retval = 0;	struct st_buffer *STbuffer;	struct st_partstat *STps;	struct st_cmdstatus *cmdstatp;	struct st_request *SRpnt;	STbuffer = STp->buffer;	if (!STbuffer->writing)		return 0;        DEB(	if (STp->write_pending)		STp->nbr_waits++;	else		STp->nbr_finished++;        ) /* end DEB */	wait_for_completion(&(STp->wait));	SRpnt = STbuffer->last_SRpnt;	STbuffer->last_SRpnt = NULL;	SRpnt->waiting = NULL;	(STp->buffer)->syscall_result = st_chk_result(STp, SRpnt);	st_release_request(SRpnt);	STbuffer->buffer_bytes -= STbuffer->writing;	STps = &(STp->ps[STp->partition]);	if (STps->drv_block >= 0) {		if (STp->block_size == 0)			STps->drv_block++;		else			STps->drv_block += STbuffer->writing / STp->block_size;	}	cmdstatp = &STbuffer->cmdstat;	if (STbuffer->syscall_result) {		retval = -EIO;		if (cmdstatp->have_sense && !cmdstatp->deferred &&		    (cmdstatp->flags & SENSE_EOM) &&		    (cmdstatp->sense_hdr.sense_key == NO_SENSE ||		     cmdstatp->sense_hdr.sense_key == RECOVERED_ERROR)) {			/* EOM at write-behind, has all data been written? */			if (!cmdstatp->remainder_valid ||			    cmdstatp->uremainder64 == 0)				retval = -ENOSPC;		}		if (retval == -EIO)			STps->drv_block = -1;	}	STbuffer->writing = 0;	DEB(if (debugging && retval)	    printk(ST_DEB_MSG "%s: Async write error %x, return value %d.\n",		   tape_name(STp), STbuffer->cmdstat.midlevel_result, retval);) /* end DEB */	return retval;}/* Step over EOF if it has been inadvertently crossed (ioctl not used because   it messes up the block number). */static int cross_eof(struct scsi_tape * STp, int forward){	struct st_request *SRpnt;	unsigned char cmd[MAX_COMMAND_SIZE];	cmd[0] = SPACE;	cmd[1] = 0x01;		/* Space FileMarks */	if (forward) {		cmd[2] = cmd[3] = 0;		cmd[4] = 1;	} else		cmd[2] = cmd[3] = cmd[4] = 0xff;	/* -1 filemarks */	cmd[5] = 0;        DEBC(printk(ST_DEB_MSG "%s: Stepping over filemark %s.\n",		   tape_name(STp), forward ? "forward" : "backward"));	SRpnt = st_do_scsi(NULL, STp, cmd, 0, DMA_NONE,			   STp->device->timeout, MAX_RETRIES, 1);	if (!SRpnt)		return (STp->buffer)->syscall_result;	st_release_request(SRpnt);	SRpnt = NULL;	if ((STp->buffer)->cmdstat.midlevel_result != 0)		printk(KERN_ERR "%s: Stepping over filemark %s failed.\n",		   tape_name(STp), forward ? "forward" : "backward");	return (STp->buffer)->syscall_result;}/* Flush the write buffer (never need to write if variable blocksize). */static int flush_write_buffer(struct scsi_tape * STp){	int offset, transfer, blks;	int result;	unsigned char cmd[MAX_COMMAND_SIZE];	struct st_request *SRpnt;	struct st_partstat *STps;	result = write_behind_check(STp);	if (result)		return result;	result = 0;	if (STp->dirty == 1) {		offset = (STp->buffer)->buffer_bytes;		transfer = ((offset + STp->block_size - 1) /			    STp->block_size) * STp->block_size;                DEBC(printk(ST_DEB_MSG "%s: Flushing %d bytes.\n",                               tape_name(STp), transfer));		memset((STp->buffer)->b_data + offset, 0, transfer - offset);		memset(cmd, 0, MAX_COMMAND_SIZE);		cmd[0] = WRITE_6;		cmd[1] = 1;		blks = transfer / STp->block_size;		cmd[2] = blks >> 16;		cmd[3] = blks >> 8;		cmd[4] = blks;		SRpnt = st_do_scsi(NULL, STp, cmd, transfer, DMA_TO_DEVICE,				   STp->device->timeout, MAX_WRITE_RETRIES, 1);		if (!SRpnt)			return (STp->buffer)->syscall_result;		STps = &(STp->ps[STp->partition]);		if ((STp->buffer)->syscall_result != 0) {			struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat;			if (cmdstatp->have_sense && !cmdstatp->deferred &&			    (cmdstatp->flags & SENSE_EOM) &&			    (cmdstatp->sense_hdr.sense_key == NO_SENSE ||			     cmdstatp->sense_hdr.sense_key == RECOVERED_ERROR) &&			    (!cmdstatp->remainder_valid ||			     cmdstatp->uremainder64 == 0)) { /* All written at EOM early warning */				STp->dirty = 0;				(STp->buffer)->buffer_bytes = 0;				if (STps->drv_block >= 0)					STps->drv_block += blks;				result = (-ENOSPC);			} else {				printk(KERN_ERR "%s: Error on flush.\n",                                       tape_name(STp));				STps->drv_block = (-1);				result = (-EIO);			}		} else {			if (STps->drv_block >= 0)				STps->drv_block += blks;			STp->dirty = 0;			(STp->buffer)->buffer_bytes = 0;		}		st_release_request(SRpnt);		SRpnt = NULL;	}	return result;}/* Flush the tape buffer. The tape will be positioned correctly unless   seek_next is true. */static int flush_buffer(struct scsi_tape *STp, int seek_next){	int backspace, result;	struct st_buffer *STbuffer;	struct st_partstat *STps;	STbuffer = STp->buffer;	/*	 * If there was a bus reset, block further access	 * to this device.	 */	if (STp->pos_unknown)		return (-EIO);	if (STp->ready != ST_READY)		return 0;	STps = &(STp->ps[STp->partition]);	if (STps->rw == ST_WRITING)	/* Writing */		return flush_write_buffer(STp);	if (STp->block_size == 0)		return 0;	backspace = ((STp->buffer)->buffer_bytes +		     (STp->buffer)->read_pointer) / STp->block_size -	    ((STp->buffer)->read_pointer + STp->block_size - 1) /	    STp->block_size;	(STp->buffer)->buffer_bytes = 0;	(STp->buffer)->read_pointer = 0;	result = 0;	if (!seek_next) {		if (STps->eof == ST_FM_HIT) {			result = cross_eof(STp, 0);	/* Back over the EOF hit */			if (!result)				STps->eof = ST_NOEOF;			else {				if (STps->drv_file >= 0)					STps->drv_file++;				STps->drv_block = 0;			}		}		if (!result && backspace > 0)			result = st_int_ioctl(STp, MTBSR, backspace);	} else if (STps->eof == ST_FM_HIT) {		if (STps->drv_file >= 0)			STps->drv_file++;		STps->drv_block = 0;		STps->eof = ST_NOEOF;	}	return result;}/* Set the mode parameters */static int set_mode_densblk(struct scsi_tape * STp, struct st_modedef * STm){	int set_it = 0;	unsigned long arg;	char *name = tape_name(STp);	if (!STp->density_changed &&	    STm->default_density >= 0 &&	    STm->default_density != STp->density) {		arg = STm->default_density;		set_it = 1;	} else		arg = STp->density;	arg <<= MT_ST_DENSITY_SHIFT;	if (!STp->blksize_changed &&	    STm->default_blksize >= 0 &&	    STm->default_blksize != STp->block_size) {		arg |= STm->default_blksize;		set_it = 1;	} else		arg |= STp->block_size;	if (set_it &&	    st_int_ioctl(STp, SET_DENS_AND_BLK, arg)) {		printk(KERN_WARNING		       "%s: Can't set default block size to %d bytes and density %x.\n",		       name, STm->default_blksize, STm->default_density);		if (modes_defined)			return (-EINVAL);	}	return 0;}/* Lock or unlock the drive door. Don't use when st_request allocated. */static int do_door_lock(struct scsi_tape * STp, int do_lock){	int retval, cmd;	DEB(char *name = tape_name(STp);)	cmd = do_lock ? SCSI_IOCTL_DOORLOCK : SCSI_IOCTL_DOORUNLOCK;	DEBC(printk(ST_DEB_MSG "%s: %socking drive door.\n", name,		    do_lock ? "L" : "Unl"));	retval = scsi_ioctl(STp->device, cmd, NULL);	if (!retval) {		STp->door_locked = do_lock ? ST_LOCKED_EXPLICIT : ST_UNLOCKED;	}	else {		STp->door_locked = ST_LOCK_FAILS;	}	return retval;}/* Set the internal state after reset */static void reset_state(struct scsi_tape *STp){	int i;	struct st_partstat *STps;	STp->pos_unknown = 0;	for (i = 0; i < ST_NBR_PARTITIONS; i++) {		STps = &(STp->ps[i]);		STps->rw = ST_IDLE;		STps->eof = ST_NOEOF;		STps->at_sm = 0;		STps->last_block_valid = 0;		STps->drv_block = -1;		STps->drv_file = -1;	}	if (STp->can_partitions) {		STp->partition = find_partition(STp);		if (STp->partition < 0)			STp->partition = 0;		STp->new_partition = STp->partition;	}}/* Test if the drive is ready. Returns either one of the codes below or a negative system   error code. */#define CHKRES_READY       0#define CHKRES_NEW_SESSION 1#define CHKRES_NOT_READY   2#define CHKRES_NO_TAPE     3#define MAX_ATTENTIONS    10static int test_ready(struct scsi_tape *STp, int do_wait){	int attentions, waits, max_wait, scode;	int retval = CHKRES_READY, new_session = 0;	unsigned char cmd[MAX_COMMAND_SIZE];	struct st_request *SRpnt = NULL;	struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat;	max_wait = do_wait ? ST_BLOCK_SECONDS : 0;	for (attentions=waits=0; ; ) {		memset((void *) &cmd[0], 0, MAX_COMMAND_SIZE);		cmd[0] = TEST_UNIT_READY;		SRpnt = st_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE,				   STp->long_timeout, MAX_READY_RETRIES, 1);		if (!SRpnt) {			retval = (STp->buffer)->syscall_result;			break;		}		if (cmdstatp->have_sense) {			scode = cmdstatp->sense_hdr.sense_key;			if (scode == UNIT_ATTENTION) { /* New media? */				new_session = 1;				if (attentions < MAX_ATTENTIONS) {					attentions++;					continue;				}				else {					retval = (-EIO);					break;				}			}			if (scode == NOT_READY) {				if (waits < max_wait) {					if (msleep_interruptible(1000)) {						retval = (-EINTR);						break;					}					waits++;					continue;				}				else {					if ((STp->device)->scsi_level >= SCSI_2 &&					    cmdstatp->sense_hdr.asc == 0x3a)	/* Check ASC */						retval = CHKRES_NO_TAPE;					else						retval = CHKRES_NOT_READY;					break;				}			}		}		retval = (STp->buffer)->syscall_result;		if (!retval)			retval = new_session ? CHKRES_NEW_SESSION : CHKRES_READY;		break;	}	if (SRpnt != NULL)		st_release_request(SRpnt);	return retval;}/* See if the drive is ready and gather information about the tape. Return values:   < 0   negative error code from errno.h   0     drive ready   1     drive not ready (possibly no tape)*/static int check_tape(struct scsi_tape *STp, struct file *filp){	int i, retval, new_session = 0, do_wait;	unsigned char cmd[MAX_COMMAND_SIZE], saved_cleaning;	unsigned short st_flags = filp->f_flags;	struct st_request *SRpnt = NULL;	struct st_modedef *STm;	struct st_partstat *STps;	char *name = tape_name(STp);	struct inode *inode = filp->f_path.dentry->d_inode;	int mode = TAPE_MODE(inode);	STp->ready = ST_READY;	if (mode != STp->current_mode) {                DEBC(printk(ST_DEB_MSG "%s: Mode change from %d to %d.\n",

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -