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

📄 st.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 5 页
字号:
			STp->drv_buffer = ((STp->buffer)->b_data[2] >> 4) & 7;			STp->density = (STp->buffer)->b_data[4];			STp->block_size = (STp->buffer)->b_data[9] * 65536 +			    (STp->buffer)->b_data[10] * 256 + (STp->buffer)->b_data[11];                        DEBC(printk(ST_DEB_MSG                                    "%s: Density %x, tape length: %x, drv buffer: %d\n",                                    name, STp->density, (STp->buffer)->b_data[5] * 65536 +                                    (STp->buffer)->b_data[6] * 256 + (STp->buffer)->b_data[7],                                    STp->drv_buffer));		}		STp->drv_write_prot = ((STp->buffer)->b_data[2] & 0x80) != 0;	}	scsi_release_request(SRpnt);	SRpnt = NULL;        STp->inited = TRUE;	if (STp->block_size > 0)		(STp->buffer)->buffer_blocks =                        (STp->buffer)->buffer_size / STp->block_size;	else		(STp->buffer)->buffer_blocks = 1;	(STp->buffer)->buffer_bytes = (STp->buffer)->read_pointer = 0;        DEBC(printk(ST_DEB_MSG                       "%s: Block size: %d, buffer size: %d (%d blocks).\n", name,		       STp->block_size, (STp->buffer)->buffer_size,		       (STp->buffer)->buffer_blocks));	if (STp->drv_write_prot) {		STp->write_prot = 1;                DEBC(printk(ST_DEB_MSG "%s: Write protected\n", name));		if (do_wait &&		    ((st_flags & O_ACCMODE) == O_WRONLY ||		     (st_flags & O_ACCMODE) == O_RDWR)) {			retval = (-EROFS);			goto err_out;		}	}	if (STp->can_partitions && STp->nbr_partitions < 1) {		/* This code is reached when the device is opened for the first time		   after the driver has been initialized with tape in the drive and the		   partition support has been enabled. */                DEBC(printk(ST_DEB_MSG                            "%s: Updating partition number in status.\n", name));		if ((STp->partition = find_partition(STp)) < 0) {			retval = STp->partition;			goto err_out;		}		STp->new_partition = STp->partition;		STp->nbr_partitions = 1; /* This guess will be updated when necessary */	}	if (new_session) {	/* Change the drive parameters for the new mode */		STp->density_changed = STp->blksize_changed = FALSE;		STp->compression_changed = FALSE;		if (!(STm->defaults_for_writes) &&		    (retval = set_mode_densblk(STp, STm)) < 0)		    goto err_out;		if (STp->default_drvbuffer != 0xff) {			if (st_int_ioctl(STp, MTSETDRVBUFFER, STp->default_drvbuffer))				printk(KERN_WARNING                                       "%s: Can't set default drive buffering to %d.\n",				       name, STp->default_drvbuffer);		}	}	return CHKRES_READY; err_out:	return retval;}/* Open the device. Needs to be called with BKL only because of incrementing the SCSI host   module count. */static int st_open(struct inode *inode, struct file *filp){	int i, retval = (-EIO);	Scsi_Tape *STp;	ST_partstat *STps;	int dev = TAPE_NR(inode);	char *name;	nonseekable_open(inode, filp);	write_lock(&st_dev_arr_lock);	if (dev >= st_dev_max || scsi_tapes == NULL ||	    ((STp = scsi_tapes[dev]) == NULL)) {		write_unlock(&st_dev_arr_lock);		return (-ENXIO);	}	filp->private_data = STp;	name = tape_name(STp);	if (STp->in_use) {		write_unlock(&st_dev_arr_lock);		DEB( printk(ST_DEB_MSG "%s: Device already in use.\n", name); )		return (-EBUSY);	}	if(scsi_device_get(STp->device)) {		write_unlock(&st_dev_arr_lock);		return (-ENXIO);	}	STp->in_use = 1;	write_unlock(&st_dev_arr_lock);	STp->rew_at_close = STp->autorew_dev = (iminor(inode) & 0x80) == 0;	if (!scsi_block_when_processing_errors(STp->device)) {		retval = (-ENXIO);		goto err_out;	}	/* See that we have at least a one page buffer available */	if (!enlarge_buffer(STp->buffer, PAGE_SIZE, STp->restr_dma)) {		printk(KERN_WARNING "%s: Can't allocate one page tape buffer.\n",		       name);		retval = (-EOVERFLOW);		goto err_out;	}	(STp->buffer)->writing = 0;	(STp->buffer)->syscall_result = 0;	STp->write_prot = ((filp->f_flags & O_ACCMODE) == O_RDONLY);	STp->dirty = 0;	for (i = 0; i < ST_NBR_PARTITIONS; i++) {		STps = &(STp->ps[i]);		STps->rw = ST_IDLE;	}	STp->recover_count = 0;	DEB( STp->nbr_waits = STp->nbr_finished = 0;	     STp->nbr_requests = STp->nbr_dio = STp->nbr_pages = STp->nbr_combinable = 0; )	retval = check_tape(STp, filp);	if (retval < 0)		goto err_out;	if ((filp->f_flags & O_NONBLOCK) == 0 &&	    retval != CHKRES_READY) {		retval = (-EIO);		goto err_out;	}	return 0; err_out:	normalize_buffer(STp->buffer);	STp->in_use = 0;	scsi_device_put(STp->device);	return retval;}/* Flush the tape buffer before close */static int st_flush(struct file *filp){	int result = 0, result2;	unsigned char cmd[MAX_COMMAND_SIZE];	Scsi_Request *SRpnt;	Scsi_Tape *STp = filp->private_data;	ST_mode *STm = &(STp->modes[STp->current_mode]);	ST_partstat *STps = &(STp->ps[STp->partition]);	char *name = tape_name(STp);	if (file_count(filp) > 1)		return 0;	if (STps->rw == ST_WRITING && !STp->pos_unknown) {		result = flush_write_buffer(STp);		if (result != 0 && result != (-ENOSPC))			goto out;	}	if (STp->can_partitions &&	    (result2 = switch_partition(STp)) < 0) {                DEBC(printk(ST_DEB_MSG                               "%s: switch_partition at close failed.\n", name));		if (result == 0)			result = result2;		goto out;	}	DEBC( if (STp->nbr_requests)		printk(KERN_WARNING "%s: Number of r/w requests %d, dio used in %d, pages %d (%d).\n",		       name, STp->nbr_requests, STp->nbr_dio, STp->nbr_pages, STp->nbr_combinable));	if (STps->rw == ST_WRITING && !STp->pos_unknown) {                DEBC(printk(ST_DEB_MSG "%s: File length %ld bytes.\n",                            name, (long) (filp->f_pos));                     printk(ST_DEB_MSG "%s: Async write waits %d, finished %d.\n",                            name, STp->nbr_waits, STp->nbr_finished);		)		memset(cmd, 0, MAX_COMMAND_SIZE);		cmd[0] = WRITE_FILEMARKS;		cmd[4] = 1 + STp->two_fm;		SRpnt = st_do_scsi(NULL, STp, cmd, 0, SCSI_DATA_NONE,				   STp->device->timeout, MAX_WRITE_RETRIES, TRUE);		if (!SRpnt) {			result = (STp->buffer)->syscall_result;			goto out;		}		if ((STp->buffer)->syscall_result != 0 &&		    ((SRpnt->sr_sense_buffer[0] & 0x70) != 0x70 ||		     (SRpnt->sr_sense_buffer[2] & 0x4f) != 0x40 ||		     ((SRpnt->sr_sense_buffer[0] & 0x80) != 0 &&		      (SRpnt->sr_sense_buffer[3] | SRpnt->sr_sense_buffer[4] |		       SRpnt->sr_sense_buffer[5] |		       SRpnt->sr_sense_buffer[6]) != 0))) {			/* Filter out successful write at EOM */			scsi_release_request(SRpnt);			SRpnt = NULL;			printk(KERN_ERR "%s: Error on write filemark.\n", name);			if (result == 0)				result = (-EIO);		} else {			scsi_release_request(SRpnt);			SRpnt = NULL;			if (STps->drv_file >= 0)				STps->drv_file++;			STps->drv_block = 0;			if (STp->two_fm)				cross_eof(STp, FALSE);			STps->eof = ST_FM;		}                DEBC(printk(ST_DEB_MSG "%s: Buffer flushed, %d EOF(s) written\n",                            name, cmd[4]));	} else if (!STp->rew_at_close) {		STps = &(STp->ps[STp->partition]);		if (!STm->sysv || STps->rw != ST_READING) {			if (STp->can_bsr)				result = flush_buffer(STp, 0);			else if (STps->eof == ST_FM_HIT) {				result = cross_eof(STp, FALSE);				if (result) {					if (STps->drv_file >= 0)						STps->drv_file++;					STps->drv_block = 0;					STps->eof = ST_FM;				} else					STps->eof = ST_NOEOF;			}		} else if ((STps->eof == ST_NOEOF &&			    !(result = cross_eof(STp, TRUE))) ||			   STps->eof == ST_FM_HIT) {			if (STps->drv_file >= 0)				STps->drv_file++;			STps->drv_block = 0;			STps->eof = ST_FM;		}	}      out:	if (STp->rew_at_close) {		result2 = st_int_ioctl(STp, MTREW, 1);		if (result == 0)			result = result2;	}	return result;}/* Close the device and release it. BKL is not needed: this is the only thread   accessing this tape. */static int st_release(struct inode *inode, struct file *filp){	int result = 0;	Scsi_Tape *STp = filp->private_data;	if (STp->door_locked == ST_LOCKED_AUTO)		do_door_lock(STp, 0);	normalize_buffer(STp->buffer);	write_lock(&st_dev_arr_lock);	STp->in_use = 0;	write_unlock(&st_dev_arr_lock);	scsi_device_put(STp->device);	return result;}/* The checks common to both reading and writing */static ssize_t rw_checks(Scsi_Tape *STp, struct file *filp, size_t count){	ssize_t retval = 0;	/*	 * 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 (STp->ready != ST_READY) {		if (STp->ready == ST_NO_TAPE)			retval = (-ENOMEDIUM);		else			retval = (-EIO);		goto out;	}	if (! STp->modes[STp->current_mode].defined) {		retval = (-ENXIO);		goto out;	}	/*	 * If there was a bus reset, block further access	 * to this device.	 */	if (STp->pos_unknown) {		retval = (-EIO);		goto out;	}	if (count == 0)		goto out;        DEB(	if (!STp->in_use) {		printk(ST_DEB_MSG "%s: Incorrect device.\n", tape_name(STp));		retval = (-EIO);		goto out;	} ) /* end DEB */	if (STp->can_partitions &&	    (retval = switch_partition(STp)) < 0)		goto out;	if (STp->block_size == 0 && STp->max_block > 0 &&	    (count < STp->min_block || count > STp->max_block)) {		retval = (-EINVAL);		goto out;	}	if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED &&	    !do_door_lock(STp, 1))		STp->door_locked = ST_LOCKED_AUTO; out:	return retval;}static int setup_buffering(Scsi_Tape *STp, const char __user *buf, size_t count, int is_read){	int i, bufsize, retval = 0;	ST_buffer *STbp = STp->buffer;	if (is_read)		i = STp->try_dio && try_rdio;	else		i = STp->try_dio && try_wdio;	if (i && ((unsigned long)buf & queue_dma_alignment(					STp->device->request_queue)) == 0) {		i = st_map_user_pages(&(STbp->sg[0]), STbp->use_sg,				      (unsigned long)buf, count, (is_read ? READ : WRITE),				      STp->max_pfn);		if (i > 0) {			STbp->do_dio = i;			STbp->buffer_bytes = 0;   /* can be used as transfer counter */		}		else			STbp->do_dio = FALSE;  /* 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 = FALSE;	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(Scsi_Tape *STp){	ST_buffer *STbp;	STbp = STp->buffer;	if (STbp->do_dio) {		sgl_unmap_user_pages(&(STbp->sg[0]), STbp->do_dio, FALSE);		STbp->do_dio = 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;	Scsi_Request *SRpnt = NULL;	Scsi_Tape *STp = filp->private_data;	ST_mode *STm;	ST_partstat *STps;	ST_buffer *STbp;	char *name = tape_name(STp);	if (down_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;

⌨️ 快捷键说明

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