📄 ide-tape.c
字号:
count = IDE_MIN (bh->b_size - atomic_read(&bh->b_count), bcount); atapi_input_bytes (drive, bh->b_data + atomic_read(&bh->b_count), count); bcount -= count; atomic_add(count, &bh->b_count); if (atomic_read(&bh->b_count) == bh->b_size) { bh = bh->b_reqnext; if (bh) atomic_set(&bh->b_count, 0); } } pc->bh = bh;}static void idetape_output_buffers (ide_drive_t *drive, idetape_pc_t *pc, unsigned int bcount){ struct buffer_head *bh = pc->bh; int count; while (bcount) {#if IDETAPE_DEBUG_BUGS if (bh == NULL) { printk (KERN_ERR "ide-tape: bh == NULL in idetape_output_buffers\n"); return; }#endif /* IDETAPE_DEBUG_BUGS */ count = IDE_MIN (pc->b_count, bcount); atapi_output_bytes (drive, pc->b_data, count); bcount -= count; pc->b_data += count; pc->b_count -= count; if (!pc->b_count) { pc->bh = bh = bh->b_reqnext; if (bh) { pc->b_data = bh->b_data; pc->b_count = atomic_read(&bh->b_count); } } }}#ifdef CONFIG_BLK_DEV_IDEDMAstatic void idetape_update_buffers (idetape_pc_t *pc){ struct buffer_head *bh = pc->bh; int count, bcount = pc->actually_transferred; if (test_bit (PC_WRITING, &pc->flags)) return; while (bcount) {#if IDETAPE_DEBUG_BUGS if (bh == NULL) { printk (KERN_ERR "ide-tape: bh == NULL in idetape_update_buffers\n"); return; }#endif /* IDETAPE_DEBUG_BUGS */ count = IDE_MIN (bh->b_size, bcount); atomic_set(&bh->b_count, count); if (atomic_read(&bh->b_count) == bh->b_size) bh = bh->b_reqnext; bcount -= count; } pc->bh = bh;}#endif /* CONFIG_BLK_DEV_IDEDMA *//* * idetape_next_pc_storage returns a pointer to a place in which we can * safely store a packet command, even though we intend to leave the * driver. A storage space for a maximum of IDETAPE_PC_STACK packet * commands is allocated at initialization time. */static idetape_pc_t *idetape_next_pc_storage (ide_drive_t *drive){ idetape_tape_t *tape = drive->driver_data;#if IDETAPE_DEBUG_LOG if (tape->debug_level >= 5) printk (KERN_INFO "ide-tape: pc_stack_index=%d\n",tape->pc_stack_index);#endif /* IDETAPE_DEBUG_LOG */ if (tape->pc_stack_index==IDETAPE_PC_STACK) tape->pc_stack_index=0; return (&tape->pc_stack[tape->pc_stack_index++]);}/* * idetape_next_rq_storage is used along with idetape_next_pc_storage. * Since we queue packet commands in the request queue, we need to * allocate a request, along with the allocation of a packet command. */ /************************************************************** * * * This should get fixed to use kmalloc(.., GFP_ATOMIC) * * followed later on by kfree(). -ml * * * **************************************************************/ static struct request *idetape_next_rq_storage (ide_drive_t *drive){ idetape_tape_t *tape = drive->driver_data;#if IDETAPE_DEBUG_LOG if (tape->debug_level >= 5) printk (KERN_INFO "ide-tape: rq_stack_index=%d\n",tape->rq_stack_index);#endif /* IDETAPE_DEBUG_LOG */ if (tape->rq_stack_index==IDETAPE_PC_STACK) tape->rq_stack_index=0; return (&tape->rq_stack[tape->rq_stack_index++]);}/* * idetape_init_pc initializes a packet command. */static void idetape_init_pc (idetape_pc_t *pc){ memset (pc->c, 0, 12); pc->retries = 0; pc->flags = 0; pc->request_transfer = 0; 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);#if IDETAPE_DEBUG_LOG_VERBOSE if (tape->debug_level >= 1) printk (KERN_INFO "ide-tape: pc = %s, sense key = %x, asc = %x, ascq = %x\n", idetape_command_key_verbose((byte) pc->c[0]), result->sense_key, result->asc, result->ascq);#endif /* IDETAPE_DEBUG_LOG_VERBOSE */#endif /* IDETAPE_DEBUG_LOG */ if (tape->onstream && result->sense_key == 2 && result->asc == 0x53 && result->ascq == 2) { clear_bit(PC_DMA_ERROR, &pc->flags); ide_stall_queue(drive, HZ / 2); return; }#ifdef CONFIG_BLK_DEV_IDEDMA /* * 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); }#endif /* CONFIG_BLK_DEV_IDEDMA */ 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) && (tape->onstream || pc->actually_transferred)) pc->retries = IDETAPE_MAX_PC_RETRIES + 1; }}static void idetape_abort_pipeline (ide_drive_t *drive){ idetape_tape_t *tape = drive->driver_data; idetape_stage_t *stage = tape->next_stage;#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) { if (stage->rq.cmd == IDETAPE_WRITE_RQ) stage->rq.cmd = IDETAPE_ABORTED_WRITE_RQ; else if (stage->rq.cmd == IDETAPE_READ_RQ) stage->rq.cmd = IDETAPE_ABORTED_READ_RQ; stage = stage->next; }}/* * 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->bh = 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 += increase; tape->max_stages = IDE_MAX(tape->max_stages, tape->min_pipeline); tape->max_stages = IDE_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 buffer_head *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 */ }}/* * idetape_end_request is used to finish servicing a request, and to * insert a pending pipeline request into the main device queue. */static void idetape_end_request (byte uptodate, ide_hwgroup_t *hwgroup){ ide_drive_t *drive = hwgroup->drive; struct request *rq = hwgroup->rq; idetape_tape_t *tape = drive->driver_data; unsigned long flags; int error; int remove_stage = 0;#if ONSTREAM_DEBUG idetape_stage_t *stage; os_aux_t *aux; unsigned char *p;#endif#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); if (tape->active_data_request == rq) { /* The request was a pipelined data transfer request */ tape->active_stage = NULL; tape->active_data_request = NULL; tape->nr_pending_stages--; if (rq->cmd == IDETAPE_WRITE_RQ) {#if ONSTREAM_DEBUG if (tape->de
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -