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

📄 ide-tape.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	pc->buffer = pc->pc_buffer;	pc->buffer_size = IDETAPE_PC_BUFFER_SIZE;	pc->bh = NULL;	pc->b_data = NULL;}/* *	idetape_analyze_error is called on each failed packet command retry *	to analyze the request sense. We currently do not utilize this *	information. */static void idetape_analyze_error (ide_drive_t *drive, idetape_request_sense_result_t *result){	idetape_tape_t *tape = drive->driver_data;	idetape_pc_t *pc = tape->failed_pc;	tape->sense     = *result;	tape->sense_key = result->sense_key;	tape->asc       = result->asc;	tape->ascq      = result->ascq;#if IDETAPE_DEBUG_LOG	/*	 *	Without debugging, we only log an error if we decided to	 *	give up retrying.	 */	if (tape->debug_level >= 1)		printk(KERN_INFO "ide-tape: pc = %x, sense key = %x, "			"asc = %x, ascq = %x\n",			pc->c[0], result->sense_key,			result->asc, result->ascq);#endif /* IDETAPE_DEBUG_LOG */	/*	 *	Correct pc->actually_transferred by asking the tape.	 */	if (test_bit(PC_DMA_ERROR, &pc->flags)) {		pc->actually_transferred = pc->request_transfer - tape->tape_block_size * ntohl(get_unaligned(&result->information));		idetape_update_buffers(pc);	}	/*	 * If error was the result of a zero-length read or write command,	 * with sense key=5, asc=0x22, ascq=0, let it slide.  Some drives	 * (i.e. Seagate STT3401A Travan) don't support 0-length read/writes.	 */	if ((pc->c[0] == IDETAPE_READ_CMD || pc->c[0] == IDETAPE_WRITE_CMD)	    && pc->c[4] == 0 && pc->c[3] == 0 && pc->c[2] == 0) { /* length==0 */		if (result->sense_key == 5) {			/* don't report an error, everything's ok */			pc->error = 0;			/* don't retry read/write */			set_bit(PC_ABORT, &pc->flags);		}	}	if (pc->c[0] == IDETAPE_READ_CMD && result->filemark) {		pc->error = IDETAPE_ERROR_FILEMARK;		set_bit(PC_ABORT, &pc->flags);	}	if (pc->c[0] == IDETAPE_WRITE_CMD) {		if (result->eom ||		    (result->sense_key == 0xd && result->asc == 0x0 &&		     result->ascq == 0x2)) {			pc->error = IDETAPE_ERROR_EOD;			set_bit(PC_ABORT, &pc->flags);		}	}	if (pc->c[0] == IDETAPE_READ_CMD || pc->c[0] == IDETAPE_WRITE_CMD) {		if (result->sense_key == 8) {			pc->error = IDETAPE_ERROR_EOD;			set_bit(PC_ABORT, &pc->flags);		}		if (!test_bit(PC_ABORT, &pc->flags) &&		    pc->actually_transferred)			pc->retries = IDETAPE_MAX_PC_RETRIES + 1;	}}/* * idetape_active_next_stage will declare the next stage as "active". */static void idetape_active_next_stage (ide_drive_t *drive){	idetape_tape_t *tape = drive->driver_data;	idetape_stage_t *stage = tape->next_stage;	struct request *rq = &stage->rq;#if IDETAPE_DEBUG_LOG	if (tape->debug_level >= 4)		printk(KERN_INFO "ide-tape: Reached idetape_active_next_stage\n");#endif /* IDETAPE_DEBUG_LOG */#if IDETAPE_DEBUG_BUGS	if (stage == NULL) {		printk(KERN_ERR "ide-tape: bug: Trying to activate a non existing stage\n");		return;	}#endif /* IDETAPE_DEBUG_BUGS */		rq->rq_disk = tape->disk;	rq->buffer = NULL;	rq->special = (void *)stage->bh;	tape->active_data_request = rq;	tape->active_stage = stage;	tape->next_stage = stage->next;}/* *	idetape_increase_max_pipeline_stages is a part of the feedback *	loop which tries to find the optimum number of stages. In the *	feedback loop, we are starting from a minimum maximum number of *	stages, and if we sense that the pipeline is empty, we try to *	increase it, until we reach the user compile time memory limit. */static void idetape_increase_max_pipeline_stages (ide_drive_t *drive){	idetape_tape_t *tape = drive->driver_data;	int increase = (tape->max_pipeline - tape->min_pipeline) / 10;	#if IDETAPE_DEBUG_LOG	if (tape->debug_level >= 4)		printk (KERN_INFO "ide-tape: Reached idetape_increase_max_pipeline_stages\n");#endif /* IDETAPE_DEBUG_LOG */	tape->max_stages += max(increase, 1);	tape->max_stages = max(tape->max_stages, tape->min_pipeline);	tape->max_stages = min(tape->max_stages, tape->max_pipeline);}/* *	idetape_kfree_stage calls kfree to completely free a stage, along with *	its related buffers. */static void __idetape_kfree_stage (idetape_stage_t *stage){	struct idetape_bh *prev_bh, *bh = stage->bh;	int size;	while (bh != NULL) {		if (bh->b_data != NULL) {			size = (int) bh->b_size;			while (size > 0) {				free_page((unsigned long) bh->b_data);				size -= PAGE_SIZE;				bh->b_data += PAGE_SIZE;			}		}		prev_bh = bh;		bh = bh->b_reqnext;		kfree(prev_bh);	}	kfree(stage);}static void idetape_kfree_stage (idetape_tape_t *tape, idetape_stage_t *stage){	__idetape_kfree_stage(stage);}/* *	idetape_remove_stage_head removes tape->first_stage from the pipeline. *	The caller should avoid race conditions. */static void idetape_remove_stage_head (ide_drive_t *drive){	idetape_tape_t *tape = drive->driver_data;	idetape_stage_t *stage;	#if IDETAPE_DEBUG_LOG	if (tape->debug_level >= 4)		printk(KERN_INFO "ide-tape: Reached idetape_remove_stage_head\n");#endif /* IDETAPE_DEBUG_LOG */#if IDETAPE_DEBUG_BUGS	if (tape->first_stage == NULL) {		printk(KERN_ERR "ide-tape: bug: tape->first_stage is NULL\n");		return;			}	if (tape->active_stage == tape->first_stage) {		printk(KERN_ERR "ide-tape: bug: Trying to free our active pipeline stage\n");		return;	}#endif /* IDETAPE_DEBUG_BUGS */	stage = tape->first_stage;	tape->first_stage = stage->next;	idetape_kfree_stage(tape, stage);	tape->nr_stages--;	if (tape->first_stage == NULL) {		tape->last_stage = NULL;#if IDETAPE_DEBUG_BUGS		if (tape->next_stage != NULL)			printk(KERN_ERR "ide-tape: bug: tape->next_stage != NULL\n");		if (tape->nr_stages)			printk(KERN_ERR "ide-tape: bug: nr_stages should be 0 now\n");#endif /* IDETAPE_DEBUG_BUGS */	}}/* * This will free all the pipeline stages starting from new_last_stage->next * to the end of the list, and point tape->last_stage to new_last_stage. */static void idetape_abort_pipeline(ide_drive_t *drive,				   idetape_stage_t *new_last_stage){	idetape_tape_t *tape = drive->driver_data;	idetape_stage_t *stage = new_last_stage->next;	idetape_stage_t *nstage;#if IDETAPE_DEBUG_LOG	if (tape->debug_level >= 4)		printk(KERN_INFO "ide-tape: %s: idetape_abort_pipeline called\n", tape->name);#endif	while (stage) {		nstage = stage->next;		idetape_kfree_stage(tape, stage);		--tape->nr_stages;		--tape->nr_pending_stages;		stage = nstage;	}	if (new_last_stage)		new_last_stage->next = NULL;	tape->last_stage = new_last_stage;	tape->next_stage = NULL;}/* *	idetape_end_request is used to finish servicing a request, and to *	insert a pending pipeline request into the main device queue. */static int idetape_end_request(ide_drive_t *drive, int uptodate, int nr_sects){	struct request *rq = HWGROUP(drive)->rq;	idetape_tape_t *tape = drive->driver_data;	unsigned long flags;	int error;	int remove_stage = 0;	idetape_stage_t *active_stage;#if IDETAPE_DEBUG_LOG        if (tape->debug_level >= 4)	printk(KERN_INFO "ide-tape: Reached idetape_end_request\n");#endif /* IDETAPE_DEBUG_LOG */	switch (uptodate) {		case 0:	error = IDETAPE_ERROR_GENERAL; break;		case 1: error = 0; break;		default: error = uptodate;	}	rq->errors = error;	if (error)		tape->failed_pc = NULL;	spin_lock_irqsave(&tape->spinlock, flags);	/* The request was a pipelined data transfer request */	if (tape->active_data_request == rq) {		active_stage = tape->active_stage;		tape->active_stage = NULL;		tape->active_data_request = NULL;		tape->nr_pending_stages--;		if (rq->cmd[0] & REQ_IDETAPE_WRITE) {			remove_stage = 1;			if (error) {				set_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);				if (error == IDETAPE_ERROR_EOD)					idetape_abort_pipeline(drive, active_stage);			}		} else if (rq->cmd[0] & REQ_IDETAPE_READ) {			if (error == IDETAPE_ERROR_EOD) {				set_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);				idetape_abort_pipeline(drive, active_stage);			}		}		if (tape->next_stage != NULL) {			idetape_active_next_stage(drive);			/*			 * Insert the next request into the request queue.			 */			(void) ide_do_drive_cmd(drive, tape->active_data_request, ide_end);		} else if (!error) {				idetape_increase_max_pipeline_stages(drive);		}	}	ide_end_drive_cmd(drive, 0, 0);//	blkdev_dequeue_request(rq);//	drive->rq = NULL;//	end_that_request_last(rq);	if (remove_stage)		idetape_remove_stage_head(drive);	if (tape->active_data_request == NULL)		clear_bit(IDETAPE_PIPELINE_ACTIVE, &tape->flags);	spin_unlock_irqrestore(&tape->spinlock, flags);	return 0;}static ide_startstop_t idetape_request_sense_callback (ide_drive_t *drive){	idetape_tape_t *tape = drive->driver_data;#if IDETAPE_DEBUG_LOG	if (tape->debug_level >= 4)		printk(KERN_INFO "ide-tape: Reached idetape_request_sense_callback\n");#endif /* IDETAPE_DEBUG_LOG */	if (!tape->pc->error) {		idetape_analyze_error(drive, (idetape_request_sense_result_t *) tape->pc->buffer);		idetape_end_request(drive, 1, 0);	} else {		printk(KERN_ERR "ide-tape: Error in REQUEST SENSE itself - Aborting request!\n");		idetape_end_request(drive, 0, 0);	}	return ide_stopped;}static void idetape_create_request_sense_cmd (idetape_pc_t *pc){	idetape_init_pc(pc);		pc->c[0] = IDETAPE_REQUEST_SENSE_CMD;	pc->c[4] = 20;	pc->request_transfer = 20;	pc->callback = &idetape_request_sense_callback;}static void idetape_init_rq(struct request *rq, u8 cmd){	memset(rq, 0, sizeof(*rq));	rq->cmd_type = REQ_TYPE_SPECIAL;	rq->cmd[0] = cmd;}/* *	idetape_queue_pc_head generates a new packet command request in front *	of the request queue, before the current request, so that it will be *	processed immediately, on the next pass through the driver. * *	idetape_queue_pc_head is called from the request handling part of *	the driver (the "bottom" part). Safe storage for the request should *	be allocated with idetape_next_pc_storage and idetape_next_rq_storage *	before calling idetape_queue_pc_head. * *	Memory for those requests is pre-allocated at initialization time, and *	is limited to IDETAPE_PC_STACK requests. We assume that we have enough *	space for the maximum possible number of inter-dependent packet commands. * *	The higher level of the driver - The ioctl handler and the character *	device handling functions should queue request to the lower level part *	and wait for their completion using idetape_queue_pc_tail or *	idetape_queue_rw_tail. */static void idetape_queue_pc_head (ide_drive_t *drive, idetape_pc_t *pc,struct request *rq){	struct ide_tape_obj *tape = drive->driver_data;	idetape_init_rq(rq, REQ_IDETAPE_PC1);	rq->buffer = (char *) pc;	rq->rq_disk = tape->disk;	(void) ide_do_drive_cmd(drive, rq, ide_preempt);}/* *	idetape_retry_pc is called when a

⌨️ 快捷键说明

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