ide-tape.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,801 行 · 第 1/5 页

C
1,801
字号
#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->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->flags = REQ_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){	idetape_init_rq(rq, REQ_IDETAPE_PC1);	rq->buffer = (char *) pc;	(void) ide_do_drive_cmd(drive, rq, ide_preempt);}/* *	idetape_retry_pc is called when an error was detected during the *	last packet command. We queue a request sense packet command in *	the head of the request list. */static ide_startstop_t idetape_retry_pc (ide_drive_t *drive){	idetape_tape_t *tape = drive->driver_data;	idetape_pc_t *pc;	struct request *rq;	atapi_error_t error;	error.all = HWIF(drive)->INB(IDE_ERROR_REG);	pc = idetape_next_pc_storage(drive);	rq = idetape_next_rq_storage(drive);	idetape_create_request_sense_cmd(pc);	set_bit(IDETAPE_IGNORE_DSC, &tape->flags);	idetape_queue_pc_head(drive, pc, rq);	return ide_stopped;}/* *	idetape_postpone_request postpones the current request so that *	ide.c will be able to service requests from another device on *	the same hwgroup while we are polling for DSC. */static void idetape_postpone_request (ide_drive_t *drive){	idetape_tape_t *tape = drive->driver_data;#if IDETAPE_DEBUG_LOG	if (tape->debug_level >= 4)		printk(KE

⌨️ 快捷键说明

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