📄 ide-tape.c
字号:
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 + -