📄 ide-tape.c
字号:
/* * Too bad. The drive wants to send us data which we are not ready to accept. * Just throw it away. */static void idetape_discard_data (ide_drive_t *drive, unsigned int bcount){ while (bcount--) (void) HWIF(drive)->INB(IDE_DATA_REG);}static void idetape_input_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 %s\n", __FUNCTION__); idetape_discard_data(drive, bcount); return; }#endif /* IDETAPE_DEBUG_BUGS */ count = IDE_MIN(bh->b_size - atomic_read(&bh->b_count), bcount); HWIF(drive)->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 %s\n", __FUNCTION__); return; }#endif /* IDETAPE_DEBUG_BUGS */ count = IDE_MIN(pc->b_count, bcount); HWIF(drive)->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 %s\n", __FUNCTION__); 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((u8) 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; }}/* * 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 %s\n", __FUNCTION__);#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 %s\n", __FUNCTION__);#endif /* IDETAPE_DEBUG_LOG */ tape->max_stages += IDE_MAX(increase, 1); 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 %s\n", __FUNCTION__);#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 */ }}static void idetape_abort_pipeline (ide_drive_t *drive, idetape_stage_t *last_stage){ idetape_tape_t *tape = drive->driver_data; idetape_stage_t *stage = tape->next_stage; idetape_stage_t *nstage;#if IDETAPE_DEBUG_LOG if (tape->debug_level >= 4) printk(KERN_INFO "ide-tape: %s: %s called\n", tape->name, __FUNCTION__);#endif while (stage) { nstage = stage->next; idetape_kfree_stage(tape, stage); --tape->nr_stages; --tape->nr_pending_stages; stage = nstage; } tape->last_stage = last_stage; if (last_stage) last_stage->next = NULL; tape->next_stage = NULL;}/* * idetape_end_request is used to finish servicing a request
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -