📄 ide-tape.c
字号:
}char *idetape_command_key_verbose (byte idetape_command_key){ switch (idetape_command_key) { case IDETAPE_TEST_UNIT_READY_CMD: return("TEST_UNIT_READY_CMD"); case IDETAPE_REWIND_CMD: return("REWIND_CMD"); case IDETAPE_REQUEST_SENSE_CMD: return("REQUEST_SENSE_CMD"); case IDETAPE_READ_CMD: return("READ_CMD"); case IDETAPE_WRITE_CMD: return("WRITE_CMD"); case IDETAPE_WRITE_FILEMARK_CMD: return("WRITE_FILEMARK_CMD"); case IDETAPE_SPACE_CMD: return("SPACE_CMD"); case IDETAPE_INQUIRY_CMD: return("INQUIRY_CMD"); case IDETAPE_ERASE_CMD: return("ERASE_CMD"); case IDETAPE_MODE_SENSE_CMD: return("MODE_SENSE_CMD"); case IDETAPE_MODE_SELECT_CMD: return("MODE_SELECT_CMD"); case IDETAPE_LOAD_UNLOAD_CMD: return("LOAD_UNLOAD_CMD"); case IDETAPE_PREVENT_CMD: return("PREVENT_CMD"); case IDETAPE_LOCATE_CMD: return("LOCATE_CMD"); case IDETAPE_READ_POSITION_CMD: return("READ_POSITION_CMD"); case IDETAPE_READ_BUFFER_CMD: return("READ_BUFFER_CMD"); case IDETAPE_SET_SPEED_CMD: return("SET_SPEED_CMD"); default: { char buf[20]; sprintf(buf, "CMD (0x%02x)", idetape_command_key); return(buf); } }}#endif /* IDETAPE_DEBUG_LOG_VERBOSE *//* * Function declarations * */static void idetape_onstream_mode_sense_tape_parameter_page(ide_drive_t *drive, int debug);static int idetape_chrdev_release (struct inode *inode, struct file *filp);static void idetape_write_release (struct inode *inode);/* * 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--) IN_BYTE (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 idetape_input_buffers\n"); idetape_discard_data (drive, bcount); return; }#endif /* IDETAPE_DEBUG_BUGS */ 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-
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -