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

📄 st.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
			   size_t count, int is_read){	int i, bufsize, retval = 0;	struct st_buffer *STbp = STp->buffer;	if (is_read)		i = STp->try_dio_now && try_rdio;	else		i = STp->try_dio_now && try_wdio;	if (i && ((unsigned long)buf & queue_dma_alignment(					STp->device->request_queue)) == 0) {		i = sgl_map_user_pages(&(STbp->sg[0]), STbp->use_sg,				      (unsigned long)buf, count, (is_read ? READ : WRITE));		if (i > 0) {			STbp->do_dio = i;			STbp->buffer_bytes = 0;   /* can be used as transfer counter */		}		else			STbp->do_dio = 0;  /* 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 = 0;	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(struct scsi_tape *STp, int is_read){	struct st_buffer *STbp;	STbp = STp->buffer;	if (STbp->do_dio) {		sgl_unmap_user_pages(&(STbp->sg[0]), STbp->do_dio, is_read);		STbp->do_dio = 0;		STbp->sg_segs = 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;	struct st_request *SRpnt = NULL;	struct scsi_tape *STp = filp->private_data;	struct st_modedef *STm;	struct st_partstat *STps;	struct st_buffer *STbp;	char *name = tape_name(STp);	if (mutex_lock_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;	}	STm = &(STp->modes[STp->current_mode]);	STps = &(STp->ps[STp->partition]);	if (STp->write_prot) {		retval = (-EACCES);		goto out;	}	if (STps->rw == ST_READING) {		retval = flush_buffer(STp, 0);		if (retval)			goto out;		STps->rw = ST_WRITING;	} else if (STps->rw != ST_WRITING &&		   STps->drv_file == 0 && STps->drv_block == 0) {		if ((retval = set_mode_densblk(STp, STm)) < 0)			goto out;		if (STm->default_compression != ST_DONT_TOUCH &&		    !(STp->compression_changed)) {			if (st_compression(STp, (STm->default_compression == ST_YES))) {				printk(KERN_WARNING "%s: Can't set default compression.\n",				       name);				if (modes_defined) {					retval = (-EINVAL);					goto out;				}			}		}	}	STbp = STp->buffer;	i = write_behind_check(STp);	if (i) {		if (i == -ENOSPC)			STps->eof = ST_EOM_OK;		else			STps->eof = ST_EOM_ERROR;	}	if (STps->eof == ST_EOM_OK) {		STps->eof = ST_EOD_1;  /* allow next write */		retval = (-ENOSPC);		goto out;	}	else if (STps->eof == ST_EOM_ERROR) {		retval = (-EIO);		goto out;	}	/* Check the buffer readability in cases where copy_user might catch	   the problems after some tape movement. */	if (STp->block_size != 0 &&	    !STbp->do_dio &&	    (copy_from_user(&i, buf, 1) != 0 ||	     copy_from_user(&i, buf + count - 1, 1) != 0)) {		retval = (-EFAULT);		goto out;	}	retval = setup_buffering(STp, buf, count, 0);	if (retval)		goto out;	total = count;	memset(cmd, 0, MAX_COMMAND_SIZE);	cmd[0] = WRITE_6;	cmd[1] = (STp->block_size != 0);	STps->rw = ST_WRITING;	b_point = buf;	while (count > 0 && !retry_eot) {		if (STbp->do_dio) {			do_count = count;		}		else {			if (STp->block_size == 0)				do_count = count;			else {				do_count = STbp->buffer_blocks * STp->block_size -					STbp->buffer_bytes;				if (do_count > count)					do_count = count;			}			i = append_to_buffer(b_point, STbp, do_count);			if (i) {				retval = i;				goto out;			}		}		count -= do_count;		b_point += do_count;		async_write = STp->block_size == 0 && !STbp->do_dio &&			STm->do_async_writes && STps->eof < ST_EOM_OK;		if (STp->block_size != 0 && STm->do_buffer_writes &&		    !(STp->try_dio_now && try_wdio) && STps->eof < ST_EOM_OK &&		    STbp->buffer_bytes < STbp->buffer_size) {			STp->dirty = 1;			/* Don't write a buffer that is not full enough. */			if (!async_write && count == 0)				break;		}	retry_write:		if (STp->block_size == 0)			blks = transfer = do_count;		else {			if (!STbp->do_dio)				blks = STbp->buffer_bytes;			else				blks = do_count;			blks /= STp->block_size;			transfer = blks * STp->block_size;		}		cmd[2] = blks >> 16;		cmd[3] = blks >> 8;		cmd[4] = blks;		SRpnt = st_do_scsi(SRpnt, STp, cmd, transfer, DMA_TO_DEVICE,				   STp->device->timeout, MAX_WRITE_RETRIES, !async_write);		if (!SRpnt) {			retval = STbp->syscall_result;			goto out;		}		if (async_write && !STbp->syscall_result) {			STbp->writing = transfer;			STp->dirty = !(STbp->writing ==				       STbp->buffer_bytes);			SRpnt = NULL;  /* Prevent releasing this request! */			DEB( STp->write_pending = 1; )			break;		}		if (STbp->syscall_result != 0) {			struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat;                        DEBC(printk(ST_DEB_MSG "%s: Error on write:\n", name));			if (cmdstatp->have_sense && (cmdstatp->flags & SENSE_EOM)) {				scode = cmdstatp->sense_hdr.sense_key;				if (cmdstatp->remainder_valid)					undone = (int)cmdstatp->uremainder64;				else if (STp->block_size == 0 &&					 scode == VOLUME_OVERFLOW)					undone = transfer;				else					undone = 0;				if (STp->block_size != 0)					undone *= STp->block_size;				if (undone <= do_count) {					/* Only data from this write is not written */					count += undone;					do_count -= undone;					if (STp->block_size)						blks = (transfer - undone) / STp->block_size;					STps->eof = ST_EOM_OK;					/* Continue in fixed block mode if all written					   in this request but still something left to write					   (retval left to zero)					*/					if (STp->block_size == 0 ||					    undone > 0 || count == 0)						retval = (-ENOSPC); /* EOM within current request */                                        DEBC(printk(ST_DEB_MSG                                                       "%s: EOM with %d bytes unwritten.\n",						       name, (int)count));				} else {					/* EOT within data buffered earlier (possible only					   in fixed block mode without direct i/o) */					if (!retry_eot && !cmdstatp->deferred &&					    (scode == NO_SENSE || scode == RECOVERED_ERROR)) {						move_buffer_data(STp->buffer, transfer - undone);						retry_eot = 1;						if (STps->drv_block >= 0) {							STps->drv_block += (transfer - undone) /								STp->block_size;						}						STps->eof = ST_EOM_OK;						DEBC(printk(ST_DEB_MSG							    "%s: Retry write of %d bytes at EOM.\n",							    name, STp->buffer->buffer_bytes));						goto retry_write;					}					else {						/* Either error within data buffered by driver or						   failed retry */						count -= do_count;						blks = do_count = 0;						STps->eof = ST_EOM_ERROR;						STps->drv_block = (-1); /* Too cautious? */						retval = (-EIO);	/* EOM for old data */						DEBC(printk(ST_DEB_MSG							    "%s: EOM with lost data.\n",							    name));					}				}			} else {				count += do_count;				STps->drv_block = (-1);		/* Too cautious? */				retval = STbp->syscall_result;			}		}		if (STps->drv_block >= 0) {			if (STp->block_size == 0)				STps->drv_block += (do_count > 0);			else				STps->drv_block += blks;		}		STbp->buffer_bytes = 0;		STp->dirty = 0;		if (retval || retry_eot) {			if (count < total)				retval = total - count;			goto out;		}	}	if (STps->eof == ST_EOD_1)		STps->eof = ST_EOM_OK;	else if (STps->eof != ST_EOM_OK)		STps->eof = ST_NOEOF;	retval = total - count; out:	if (SRpnt != NULL)		st_release_request(SRpnt);	release_buffering(STp, 0);	mutex_unlock(&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.   Does release user buffer mapping if it is set.*/static long read_tape(struct scsi_tape *STp, long count,		      struct st_request ** aSRpnt){	int transfer, blks, bytes;	unsigned char cmd[MAX_COMMAND_SIZE];	struct st_request *SRpnt;	struct st_modedef *STm;	struct st_partstat *STps;	struct st_buffer *STbp;	int retval = 0;	char *name = tape_name(STp);	if (count == 0)		return 0;	STm = &(STp->modes[STp->current_mode]);	STps = &(STp->ps[STp->partition]);	if (STps->eof == ST_FM_HIT)		return 1;	STbp = STp->buffer;	if (STp->block_size == 0)		blks = bytes = count;	else {		if (!(STp->try_dio_now && try_rdio) && STm->do_read_ahead) {			blks = (STp->buffer)->buffer_blocks;			bytes = blks * STp->block_size;		} else {			bytes = count;			if (!STbp->do_dio && bytes > (STp->buffer)->buffer_size)				bytes = (STp->buffer)->buffer_size;			blks = bytes / STp->block_size;			bytes = blks * STp->block_size;		}	}	memset(cmd, 0, MAX_COMMAND_SIZE);	cmd[0] = READ_6;	cmd[1] = (STp->block_size != 0);	cmd[2] = blks >> 16;	cmd[3] = blks >> 8;	cmd[4] = blks;	SRpnt = *aSRpnt;	SRpnt = st_do_scsi(SRpnt, STp, cmd, bytes, DMA_FROM_DEVICE,			   STp->device->timeout, MAX_RETRIES, 1);	release_buffering(STp, 1);	*aSRpnt = SRpnt;	if (!SRpnt)		return STbp->syscall_result;	STbp->read_pointer = 0;	STps->at_sm = 0;	/* Something to check */	if (STbp->syscall_result) {		struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat;		retval = 1;		DEBC(printk(ST_DEB_MSG "%s: Sense: %2x %2x %2x %2x %2x %2x %2x %2x\n",                            name,                            SRpnt->sense[0], SRpnt->sense[1],                            SRpnt->sense[2], SRpnt->sense[3],                            SRpnt->sense[4], SRpnt->sense[5],                            SRpnt->sense[6], SRpnt->sense[7]));		if (cmdstatp->have_sense) {			if (cmdstatp->sense_hdr.sense_key == BLANK_CHECK)				cmdstatp->flags &= 0xcf;	/* No need for EOM in this case */			if (cmdstatp->flags != 0) { /* EOF, EOM, or ILI */				/* Compute the residual count */				if (cmdstatp->remainder_valid)					transfer = (int)cmdstatp->uremainder64;				else					transfer = 0;				if (STp->block_size == 0 &&				    cmdstatp->sense_hdr.sense_key == MEDIUM_ERROR)					transfer = bytes;				if (cmdstatp->flags & SENSE_ILI) {	/* ILI */					if (STp->block_size == 0) {						if (transfer <= 0) {							if (transfer < 0)								printk(KERN_NOTICE								       "%s: Failed to read %d byte block with %d byte transfer.\n",								       name, bytes - transfer, bytes);							if (STps->drv_block >= 0)								STps->drv_block += 1;							STbp->buffer_bytes = 0;							return (-ENOMEM);						}						STbp->buffer_bytes = bytes - transfer;					} else {						st_release_request(SRpnt);						SRpnt = *aSRpnt = NULL;						if (transfer == blks) {	/* We did not get anything, error */							printk(KERN_NOTICE "%s: Incorrect block size.\n", name);							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 */						STbp->buffer_bytes = (blks - transfer) *						    STp->block_size;                                                DEBC(printk(ST_DEB_MSG                                                            "%s: ILI but enough data received %ld %d.\n",                                                            name, count, STbp->buffer_bytes));						if (STps->drv_block >= 0)							STps->drv_block += 1;						if (st_int_ioctl(STp, MTBSR, 1))							return (-EIO);					}				} else if (cmdstatp->flags & SENSE_FMK) {	/* FM overrides EOM */

⌨️ 快捷键说明

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