diff options
Diffstat (limited to 'drivers/ide/ide-tape.c')
-rw-r--r-- | drivers/ide/ide-tape.c | 1191 |
1 files changed, 207 insertions, 984 deletions
diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c index d3d8b8d5157..29870c41511 100644 --- a/drivers/ide/ide-tape.c +++ b/drivers/ide/ide-tape.c @@ -72,26 +72,6 @@ enum { #endif /**************************** Tunable parameters *****************************/ - - -/* - * Pipelined mode parameters. - * - * We try to use the minimum number of stages which is enough to keep the tape - * constantly streaming. To accomplish that, we implement a feedback loop around - * the maximum number of stages: - * - * We start from MIN maximum stages (we will not even use MIN stages if we don't - * need them), increment it by RATE*(MAX-MIN) whenever we sense that the - * pipeline is empty, until we reach the optimum value or until we reach MAX. - * - * Setting the following parameter to 0 is illegal: the pipelined mode cannot be - * disabled (idetape_calculate_speeds() divides by tape->max_stages.) - */ -#define IDETAPE_MIN_PIPELINE_STAGES 1 -#define IDETAPE_MAX_PIPELINE_STAGES 400 -#define IDETAPE_INCREASE_STAGES_RATE 20 - /* * After each failed packet command we issue a request sense command and retry * the packet command IDETAPE_MAX_PC_RETRIES times. @@ -224,28 +204,17 @@ enum { /* 0 When the tape position is unknown */ IDETAPE_FLAG_ADDRESS_VALID = (1 << 1), /* Device already opened */ - IDETAPE_FLAG_BUSY = (1 << 2), - /* Error detected in a pipeline stage */ - IDETAPE_FLAG_PIPELINE_ERR = (1 << 3), + IDETAPE_FLAG_BUSY = (1 << 2), /* Attempt to auto-detect the current user block size */ - IDETAPE_FLAG_DETECT_BS = (1 << 4), + IDETAPE_FLAG_DETECT_BS = (1 << 3), /* Currently on a filemark */ - IDETAPE_FLAG_FILEMARK = (1 << 5), + IDETAPE_FLAG_FILEMARK = (1 << 4), /* DRQ interrupt device */ - IDETAPE_FLAG_DRQ_INTERRUPT = (1 << 6), - /* pipeline active */ - IDETAPE_FLAG_PIPELINE_ACTIVE = (1 << 7), + IDETAPE_FLAG_DRQ_INTERRUPT = (1 << 5), /* 0 = no tape is loaded, so we don't rewind after ejecting */ - IDETAPE_FLAG_MEDIUM_PRESENT = (1 << 8), + IDETAPE_FLAG_MEDIUM_PRESENT = (1 << 6), }; -/* A pipeline stage. */ -typedef struct idetape_stage_s { - struct request rq; /* The corresponding request */ - struct idetape_bh *bh; /* The data buffers */ - struct idetape_stage_s *next; /* Pointer to the next stage */ -} idetape_stage_t; - /* * Most of our global data which we need to save even as we leave the driver due * to an interrupt or a timer event is stored in the struct defined below. @@ -289,9 +258,7 @@ typedef struct ide_tape_obj { * While polling for DSC we use postponed_rq to postpone the current * request so that ide.c will be able to service pending requests on the * other device. Note that at most we will have only one DSC (usually - * data transfer) request in the device request queue. Additional - * requests can be queued in our internal pipeline, but they will be - * visible to ide.c only one at a time. + * data transfer) request in the device request queue. */ struct request *postponed_rq; /* The time in which we started polling for DSC */ @@ -331,43 +298,20 @@ typedef struct ide_tape_obj { * At most, there is only one ide-tape originated data transfer request * in the device request queue. This allows ide.c to easily service * requests from the other device when we postpone our active request. - * In the pipelined operation mode, we use our internal pipeline - * structure to hold more data requests. The data buffer size is chosen - * based on the tape's recommendation. */ - /* ptr to the request which is waiting in the device request queue */ - struct request *active_data_rq; + /* Data buffer size chosen based on the tape's recommendation */ - int stage_size; - idetape_stage_t *merge_stage; - int merge_stage_size; + int buffer_size; + /* merge buffer */ + struct idetape_bh *merge_bh; + /* size of the merge buffer */ + int merge_bh_size; + /* pointer to current buffer head within the merge buffer */ struct idetape_bh *bh; char *b_data; int b_count; - /* - * Pipeline parameters. - * - * To accomplish non-pipelined mode, we simply set the following - * variables to zero (or NULL, where appropriate). - */ - /* Number of currently used stages */ - int nr_stages; - /* Number of pending stages */ - int nr_pending_stages; - /* We will not allocate more than this number of stages */ - int max_stages, min_pipeline, max_pipeline; - /* The first stage which will be removed from the pipeline */ - idetape_stage_t *first_stage; - /* The currently active stage */ - idetape_stage_t *active_stage; - /* Will be serviced after the currently active request */ - idetape_stage_t *next_stage; - /* New requests will be added to the pipeline here */ - idetape_stage_t *last_stage; - /* Optional free stage which we can use */ - idetape_stage_t *cache_stage; - int pages_per_stage; + int pages_per_buffer; /* Wasted space in each stage */ int excess_bh_size; @@ -388,45 +332,6 @@ typedef struct ide_tape_obj { /* the tape is write protected (hardware or opened as read-only) */ char write_prot; - /* - * Limit the number of times a request can be postponed, to avoid an - * infinite postpone deadlock. - */ - int postpone_cnt; - - /* - * Measures number of frames: - * - * 1. written/read to/from the driver pipeline (pipeline_head). - * 2. written/read to/from the tape buffers (idetape_bh). - * 3. written/read by the tape to/from the media (tape_head). - */ - int pipeline_head; - int buffer_head; - int tape_head; - int last_tape_head; - - /* Speed control at the tape buffers input/output */ - unsigned long insert_time; - int insert_size; - int insert_speed; - int max_insert_speed; - int measure_insert_time; - - /* Speed regulation negative feedback loop */ - int speed_control; - int pipeline_head_speed; - int controlled_pipeline_head_speed; - int uncontrolled_pipeline_head_speed; - int controlled_last_pipeline_head; - unsigned long uncontrolled_pipeline_head_time; - unsigned long controlled_pipeline_head_time; - int controlled_previous_pipeline_head; - int uncontrolled_previous_pipeline_head; - unsigned long controlled_previous_head_time; - unsigned long uncontrolled_previous_head_time; - int restart_speed_control_req; - u32 debug_mask; } idetape_tape_t; @@ -674,128 +579,36 @@ static void idetape_analyze_error(ide_drive_t *drive, u8 *sense) } } -static void idetape_activate_next_stage(ide_drive_t *drive) +/* Free data buffers completely. */ +static void ide_tape_kfree_buffer(idetape_tape_t *tape) { - idetape_tape_t *tape = drive->driver_data; - idetape_stage_t *stage = tape->next_stage; - struct request *rq = &stage->rq; + struct idetape_bh *prev_bh, *bh = tape->merge_bh; - debug_log(DBG_PROCS, "Enter %s\n", __func__); + while (bh) { + u32 size = bh->b_size; - if (stage == NULL) { - printk(KERN_ERR "ide-tape: bug: Trying to activate a non" - " existing stage\n"); - return; - } + while (size) { + unsigned int order = fls(size >> PAGE_SHIFT)-1; - rq->rq_disk = tape->disk; - rq->buffer = NULL; - rq->special = (void *)stage->bh; - tape->active_data_rq = rq; - tape->active_stage = stage; - tape->next_stage = stage->next; -} - -/* Free a stage along with its related buffers completely. */ -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; - } + if (bh->b_data) + free_pages((unsigned long)bh->b_data, order); + + size &= (order-1); + bh->b_data += (1 << order) * 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); -} - -/* - * Remove 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; - - debug_log(DBG_PROCS, "Enter %s\n", __func__); - - 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; - } - 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 (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"); - } + kfree(tape->merge_bh); } -/* - * 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; - - debug_log(DBG_PROCS, "%s: Enter %s\n", tape->name, __func__); - - 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; -} - -/* - * Finish servicing a request and 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; debug_log(DBG_PROCS, "Enter %s\n", __func__); @@ -815,58 +628,8 @@ static int idetape_end_request(ide_drive_t *drive, int uptodate, int nr_sects) spin_lock_irqsave(&tape->lock, flags); - /* The request was a pipelined data transfer request */ - if (tape->active_data_rq == rq) { - active_stage = tape->active_stage; - tape->active_stage = NULL; - tape->active_data_rq = NULL; - tape->nr_pending_stages--; - if (rq->cmd[0] & REQ_IDETAPE_WRITE) { - remove_stage = 1; - if (error) { - set_bit(IDETAPE_FLAG_PIPELINE_ERR, - &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_FLAG_PIPELINE_ERR, - &tape->flags); - idetape_abort_pipeline(drive, active_stage); - } - } - if (tape->next_stage != NULL) { - idetape_activate_next_stage(drive); - - /* Insert the next request into the request queue. */ - (void)ide_do_drive_cmd(drive, tape->active_data_rq, - ide_end); - } else if (!error) { - /* - * This is a part of the feedback loop which tries to - * find the optimum number of stages. 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. - */ - int i = (tape->max_pipeline - tape->min_pipeline) / 10; - - tape->max_stages += max(i, 1); - tape->max_stages = max(tape->max_stages, - tape->min_pipeline); - tape->max_stages = min(tape->max_stages, - tape->max_pipeline); - } - } ide_end_drive_cmd(drive, 0, 0); - if (remove_stage) - idetape_remove_stage_head(drive); - if (tape->active_data_rq == NULL) - clear_bit(IDETAPE_FLAG_PIPELINE_ACTIVE, &tape->flags); spin_unlock_irqrestore(&tape->lock, flags); return 0; } @@ -1083,10 +846,10 @@ static ide_startstop_t idetape_pc_intr(ide_drive_t *drive) return ide_do_reset(drive); } /* Get the number of bytes to transfer on this interrupt. */ - bcount = (hwif->INB(hwif->io_ports[IDE_BCOUNTH_OFFSET]) << 8) | - hwif->INB(hwif->io_ports[IDE_BCOUNTL_OFFSET]); + bcount = (hwif->INB(hwif->io_ports.lbah_addr) << 8) | + hwif->INB(hwif->io_ports.lbam_addr); - ireason = hwif->INB(hwif->io_ports[IDE_IREASON_OFFSET]); + ireason = hwif->INB(hwif->io_ports.nsect_addr); if (ireason & CD) { printk(KERN_ERR "ide-tape: CoD != 0 in %s\n", __func__); @@ -1190,12 +953,12 @@ static ide_startstop_t idetape_transfer_pc(ide_drive_t *drive) "yet DRQ isn't asserted\n"); return startstop; } - ireason = hwif->INB(hwif->io_ports[IDE_IREASON_OFFSET]); + ireason = hwif->INB(hwif->io_ports.nsect_addr); while (retries-- && ((ireason & CD) == 0 || (ireason & IO))) { printk(KERN_ERR "ide-tape: (IO,CoD != (0,1) while issuing " "a packet command, retrying\n"); udelay(100); - ireason = hwif->INB(hwif->io_ports[IDE_IREASON_OFFSET]); + ireason = hwif->INB(hwif->io_ports.nsect_addr); if (retries == 0) { printk(KERN_ERR "ide-tape: (IO,CoD != (0,1) while " "issuing a packet command, ignoring\n"); @@ -1292,7 +1055,7 @@ static ide_startstop_t idetape_issue_pc(ide_drive_t *drive, IDETAPE_WAIT_CMD, NULL); return ide_started; } else { - hwif->OUTB(WIN_PACKETCMD, hwif->io_ports[IDE_COMMAND_OFFSET]); + hwif->OUTB(WIN_PACKETCMD, hwif->io_ports.command_addr); return idetape_transfer_pc(drive); } } @@ -1335,69 +1098,6 @@ static void idetape_create_mode_sense_cmd(struct ide_atapi_pc *pc, u8 page_code) pc->idetape_callback = &idetape_pc_callback; } -static void idetape_calculate_speeds(ide_drive_t *drive) -{ - idetape_tape_t *tape = drive->driver_data; - - if (time_after(jiffies, - tape->controlled_pipeline_head_time + 120 * HZ)) { - tape->controlled_previous_pipeline_head = - tape->controlled_last_pipeline_head; - tape->controlled_previous_head_time = - tape->controlled_pipeline_head_time; - tape->controlled_last_pipeline_head = tape->pipeline_head; - tape->controlled_pipeline_head_time = jiffies; - } - if (time_after(jiffies, tape->controlled_pipeline_head_time + 60 * HZ)) - tape->controlled_pipeline_head_speed = (tape->pipeline_head - - tape->controlled_last_pipeline_head) * 32 * HZ / - (jiffies - tape->controlled_pipeline_head_time); - else if (time_after(jiffies, tape->controlled_previous_head_time)) - tape->controlled_pipeline_head_speed = (tape->pipeline_head - - tape->controlled_previous_pipeline_head) * 32 * - HZ / (jiffies - tape->controlled_previous_head_time); - - if (tape->nr_pending_stages < tape->max_stages/*- 1 */) { - /* -1 for read mode error recovery */ - if (time_after(jiffies, tape->uncontrolled_previous_head_time + - 10 * HZ)) { - tape->uncontrolled_pipeline_head_time = jiffies; - tape->uncontrolled_pipeline_head_speed = - (tape->pipeline_head - - tape->uncontrolled_previous_pipeline_head) * - 32 * HZ / (jiffies - - tape->uncontrolled_previous_head_time); - } - } else { - tape->uncontrolled_previous_head_time = jiffies; - tape->uncontrolled_previous_pipeline_head = tape->pipeline_head; - if (time_after(jiffies, tape->uncontrolled_pipeline_head_time + - 30 * HZ)) - tape->uncontrolled_pipeline_head_time = jiffies; - - } - tape->pipeline_head_speed = max(tape->uncontrolled_pipeline_head_speed, - tape->controlled_pipeline_head_speed); - - if (tape->speed_control == 1) { - if (tape->nr_pending_stages >= tape->max_stages / 2) - tape->max_insert_speed = tape->pipeline_head_speed + - (1100 - tape->pipeline_head_speed) * 2 * - (tape->nr_pending_stages - tape->max_stages / 2) - / tape->max_stages; - else - tape->max_insert_speed = 500 + - (tape->pipeline_head_speed - 500) * 2 * - tape->nr_pending_stages / tape->max_stages; - - if (tape->nr_pending_stages >= tape->max_stages * 99 / 100) - tape->max_insert_speed = 5000; - } else - tape->max_insert_speed = tape->speed_control; - - tape->max_insert_speed = max(tape->max_insert_speed, 500); -} - static ide_startstop_t idetape_media_access_finished(ide_drive_t *drive) { idetape_tape_t *tape = drive->driver_data; @@ -1432,17 +1132,7 @@ static ide_startstop_t idetape_rw_callback(ide_drive_t *drive) int blocks = tape->pc->xferred / tape->blk_size; tape->avg_size += blocks * tape->blk_size; - tape->insert_size += blocks * tape->blk_size; - if (tape->insert_size > 1024 * 1024) - tape->measure_insert_time = 1; - if (tape->measure_insert_time) { - tape->measure_insert_time = 0; - tape->insert_time = jiffies; - tape->insert_size = 0; - } - if (time_after(jiffies, tape->insert_time)) - tape->insert_speed = tape->insert_size / 1024 * HZ / - (jiffies - tape->insert_time); + if (time_after_eq(jiffies, tape->avg_time + HZ)) { tape->avg_speed = tape->avg_size * HZ / (jiffies - tape->avg_time) / 1024; @@ -1475,7 +1165,7 @@ static void idetape_create_read_cmd(idetape_tape_t *tape, pc->buf = NULL; pc->buf_size = length * tape->blk_size; pc->req_xfer = pc->buf_size; - if (pc->req_xfer == tape->stage_size) + if (pc->req_xfer == tape->buffer_size) pc->flags |= PC_FLAG_DMA_RECOMMENDED; } @@ -1495,7 +1185,7 @@ static void idetape_create_write_cmd(idetape_tape_t *tape, pc->buf = NULL; pc->buf_size = length * tape->blk_size; pc->req_xfer = pc->buf_size; - if (pc->req_xfer == tape->stage_size) + if (pc->req_xfer == tape->buffer_size) pc->flags |= PC_FLAG_DMA_RECOMMENDED; } @@ -1547,10 +1237,6 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive, drive->post_reset = 0; } - if (time_after(jiffies, tape->insert_time)) - tape->insert_speed = tape->insert_size / 1024 * HZ / - (jiffies - tape->insert_time); - idetape_calculate_speeds(drive); if (!test_and_clear_bit(IDETAPE_FLAG_IGNORE_DSC, &tape->flags) && (stat & SEEK_STAT) == 0) { if (postponed_rq == NULL) { @@ -1574,16 +1260,12 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive, return ide_stopped; } if (rq->cmd[0] & REQ_IDETAPE_READ) { - tape->buffer_head++; - tape->postpone_cnt = 0; pc = idetape_next_pc_storage(drive); idetape_create_read_cmd(tape, pc, rq->current_nr_sectors, (struct idetape_bh *)rq->special); goto out; } if (rq->cmd[0] & REQ_IDETAPE_WRITE) { - tape->buffer_head++; - tape->postpone_cnt = 0; pc = idetape_next_pc_storage(drive); idetape_create_write_cmd(tape, pc, rq->current_nr_sectors, (struct idetape_bh *)rq->special); @@ -1604,103 +1286,91 @@ out: return idetape_issue_pc(drive, pc); } -/* Pipeline related functions */ - /* - * The function below uses __get_free_page to allocate a pipeline stage, along - * with all the necessary small buffers which together make a buffer of size - * tape->stage_size (or a bit more). We attempt to combine sequential pages as + * The function below uses __get_free_pages to allocate a data buffer of size + * tape->buffer_size (or a bit more). We attempt to combine sequential pages as * much as possible. * - * It returns a pointer to the new allocated stage, or NULL if we can't (or - * don't want to) allocate a stage. - * - * Pipeline stages are optional and are used to increase performance. If we - * can't allocate them, we'll manage without them. + * It returns a pointer to the newly allocated buffer, or NULL in case of + * failure. */ -static idetape_stage_t *__idetape_kmalloc_stage(idetape_tape_t *tape, int full, - int clear) +static struct idetape_bh *ide_tape_kmalloc_buffer(idetape_tape_t *tape, + int full, int clear) { - idetape_stage_t *stage; - struct idetape_bh *prev_bh, *bh; - int pages = tape->pages_per_stage; + struct idetape_bh *prev_bh, *bh, *merge_bh; + int pages = tape->pages_per_buffer; + unsigned int order, b_allocd; char *b_data = NULL; - stage = kmalloc(sizeof(idetape_stage_t), GFP_KERNEL); - if (!stage) - return NULL; - stage->next = NULL; - - stage->bh = kmalloc(sizeof(struct idetape_bh), GFP_KERNEL); - bh = stage->bh; + merge_bh = kmalloc(sizeof(struct idetape_bh), GFP_KERNEL); + bh = merge_bh; if (bh == NULL) goto abort; - bh->b_reqnext = NULL; - bh->b_data = (char *) __get_free_page(GFP_KERNEL); + + order = fls(pages) - 1; + bh->b_data = (char *) __get_free_pages(GFP_KERNEL, order); if (!bh->b_data) goto abort; + b_allocd = (1 << order) * PAGE_SIZE; + pages &= (order-1); + if (clear) - memset(bh->b_data, 0, PAGE_SIZE); - bh->b_size = PAGE_SIZE; + memset(bh->b_data, 0, b_allocd); + bh->b_reqnext = NULL; + bh->b_size = b_allocd; atomic_set(&bh->b_count, full ? bh->b_size : 0); - while (--pages) { - b_data = (char *) __get_free_page(GFP_KERNEL); + while (pages) { + order = fls(pages) - 1; + b_data = (char *) __get_free_pages(GFP_KERNEL, order); if (!b_data) goto abort; + b_allocd = (1 << order) * PAGE_SIZE; + if (clear) - memset(b_data, 0, PAGE_SIZE); - if (bh->b_data == b_data + PAGE_SIZE) { - bh->b_size += PAGE_SIZE; - bh->b_data -= PAGE_SIZE; + memset(b_data, 0, b_allocd); + + /* newly allocated page frames below buffer header or ...*/ + if (bh->b_data == b_data + b_allocd) { + bh->b_size += b_allocd; + bh->b_data -= b_allocd; if (full) - atomic_add(PAGE_SIZE, &bh->b_count); + atomic_add(b_allocd, &bh->b_count); continue; } + /* they are above the header */ if (b_data == bh->b_data + bh->b_size) { - bh->b_size += PAGE_SIZE; + bh->b_size += b_allocd; if (full) - atomic_add(PAGE_SIZE, &bh->b_count); + atomic_add(b_allocd, &bh->b_count); continue; } prev_bh = bh; bh = kmalloc(sizeof(struct idetape_bh), GFP_KERNEL); if (!bh) { - free_page((unsigned long) b_data); + free_pages((unsigned long) b_data, order); goto abort; } bh->b_reqnext = NULL; bh->b_data = b_data; - bh->b_size = PAGE_SIZE; + bh->b_size = b_allocd; atomic_set(&bh->b_count, full ? bh->b_size : 0); prev_bh->b_reqnext = bh; + + pages &= (order-1); } + bh->b_size -= tape->excess_bh_size; if (full) atomic_sub(tape->excess_bh_size, &bh->b_count); - return stage; + return merge_bh; abort: - __idetape_kfree_stage(stage); + ide_tape_kfree_buffer(tape); return NULL; } -static idetape_stage_t *idetape_kmalloc_stage(idetape_tape_t *tape) -{ - idetape_stage_t *cache_stage = tape->cache_stage; - - debug_log(DBG_PROCS, "Enter %s\n", __func__); - - if (tape->nr_stages >= tape->max_stages) - return NULL; - if (cache_stage != NULL) { - tape->cache_stage = NULL; - return cache_stage; - } - return __idetape_kmalloc_stage(tape, 0, 0); -} - static int idetape_copy_stage_from_user(idetape_tape_t *tape, - idetape_stage_t *stage, const char __user *buf, int n) + const char __user *buf, int n) { struct idetape_bh *bh = tape->bh; int count; @@ -1732,7 +1402,7 @@ static int idetape_copy_stage_from_user(idetape_tape_t *tape, } static int idetape_copy_stage_to_user(idetape_tape_t *tape, char __user *buf, - idetape_stage_t *stage, int n) + int n) { struct idetape_bh *bh = tape->bh; int count; @@ -1763,11 +1433,11 @@ static int idetape_copy_stage_to_user(idetape_tape_t *tape, char __user *buf, return ret; } -static void idetape_init_merge_stage(idetape_tape_t *tape) +static void idetape_init_merge_buffer(idetape_tape_t *tape) { - struct idetape_bh *bh = tape->merge_stage->bh; + struct idetape_bh *bh = tape->merge_bh; + tape->bh = tape->merge_bh; - tape->bh = bh; if (tape->chrdev_dir == IDETAPE_DIR_WRITE) atomic_set(&bh->b_count, 0); else { @@ -1776,61 +1446,6 @@ static void idetape_init_merge_stage(idetape_tape_t *tape) } } -static void idetape_switch_buffers(idetape_tape_t *tape, idetape_stage_t *stage) -{ - struct idetape_bh *tmp; - - tmp = stage->bh; - stage->bh = tape->merge_stage->bh; - tape->merge_stage->bh = tmp; - idetape_init_merge_stage(tape); -} - -/* Add a new stage at the end of the pipeline. */ -static void idetape_add_stage_tail(ide_drive_t *drive, idetape_stage_t *stage) -{ - idetape_tape_t *tape = drive->driver_data; - unsigned long flags; - - debug_log(DBG_PROCS, "Enter %s\n", __func__); - - spin_lock_irqsave(&tape->lock, flags); - stage->next = NULL; - if (tape->last_stage != NULL) - tape->last_stage->next = stage; - else - tape->first_stage = stage; - tape->next_stage = stage; - tape->last_stage = stage; - if (tape->next_stage == NULL) - tape->next_stage = tape->last_stage; - tape->nr_stages++; - tape->nr_pending_stages++; - spin_unlock_irqrestore(&tape->lock, flags); -} - -/* Install a completion in a pending request and sleep until it is serviced. The - * caller should ensure that the request will not be serviced before we install - * the completion (usually by disabling interrupts). - */ -static void idetape_wait_for_request(ide_drive_t *drive, struct request *rq) -{ - DECLARE_COMPLETION_ONSTACK(wait); - idetape_tape_t *tape = drive->driver_data; - - if (rq == NULL || !blk_special_request(rq)) { - printk(KERN_ERR "ide-tape: bug: Trying to sleep on non-valid" - " request\n"); - return; - } - rq->end_io_data = &wait; - rq->end_io = blk_end_sync_rq; - spin_unlock_irq(&tape->lock); - wait_for_completion(&wait); - /* The stage and its struct request have been deallocated */ - spin_lock_irq(&tape->lock); -} - static ide_startstop_t idetape_read_position_callback(ide_drive_t *drive) { idetape_tape_t *tape = drive->driver_data; @@ -1899,7 +1514,7 @@ static void idetape_create_test_unit_ready_cmd(struct ide_atapi_pc *pc) * to the request list without waiting for it to be serviced! In that case, we * usually use idetape_queue_pc_head(). */ -static int __idetape_queue_pc_tail(ide_drive_t *drive, struct ide_atapi_pc *pc) +static int idetape_queue_pc_tail(ide_drive_t *drive, struct ide_atapi_pc *pc) { struct ide_tape_obj *tape = drive->driver_data; struct request rq; @@ -1931,7 +1546,7 @@ static int idetape_wait_ready(ide_drive_t *drive, unsigned long timeout) timeout += jiffies; while (time_before(jiffies, timeout)) { idetape_create_test_unit_ready_cmd(&pc); - if (!__idetape_queue_pc_tail(drive, &pc)) + if (!idetape_queue_pc_tail(drive, &pc)) return 0; if ((tape->sense_key == 2 && tape->asc == 4 && tape->ascq == 2) || (tape->asc == 0x3A)) { @@ -1940,7 +1555,7 @@ static int idetape_wait_ready(ide_drive_t *drive, unsigned long timeout) return -ENOMEDIUM; idetape_create_load_unload_cmd(drive, &pc, IDETAPE_LU_LOAD_MASK); - __idetape_queue_pc_tail(drive, &pc); + idetape_queue_pc_tail(drive, &pc); load_attempted = 1; /* not about to be ready */ } else if (!(tape->sense_key == 2 && tape->asc == 4 && @@ -1951,11 +1566,6 @@ static int idetape_wait_ready(ide_drive_t *drive, unsigned long timeout) return -EIO; } -static int idetape_queue_pc_tail(ide_drive_t *drive, struct ide_atapi_pc *pc) -{ - return __idetape_queue_pc_tail(drive, pc); -} - static int idetape_flush_tape_buffers(ide_drive_t *drive) { struct ide_atapi_pc pc; @@ -2021,50 +1631,21 @@ static int idetape_create_prevent_cmd(ide_drive_t *drive, return 1; } -static int __idetape_discard_read_pipeline(ide_drive_t *drive) +static void __ide_tape_discard_merge_buffer(ide_drive_t *drive) { idetape_tape_t *tape = drive->driver_data; - unsigned long flags; - int cnt; if (tape->chrdev_dir != IDETAPE_DIR_READ) - return 0; + return; - /* Remove merge stage. */ - cnt = tape->merge_stage_size / tape->blk_size; - if (test_and_clear_bit(IDETAPE_FLAG_FILEMARK, &tape->flags)) - ++cnt; /* Filemarks count as 1 sector */ - tape->merge_stage_size = 0; - if (tape->merge_stage != NULL) { - __idetape_kfree_stage(tape->merge_stage); - tape->merge_stage = NULL; + clear_bit(IDETAPE_FLAG_FILEMARK, &tape->flags); + tape->merge_bh_size = 0; + if (tape->merge_bh != NULL) { + ide_tape_kfree_buffer(tape); + tape->merge_bh = NULL; } - /* Clear pipeline flags. */ - clear_bit(IDETAPE_FLAG_PIPELINE_ERR, &tape->flags); tape->chrdev_dir = IDETAPE_DIR_NONE; - - /* Remove pipeline stages. */ - if (tape->first_stage == NULL) - return 0; - - spin_lock_irqsave(&tape->lock, flags); - tape->next_stage = NULL; - if (test_bit(IDETAPE_FLAG_PIPELINE_ACTIVE, &tape->flags)) - idetape_wait_for_request(drive, tape->active_data_rq); - spin_unlock_irqrestore(&tape->lock, flags); - - while (tape->first_stage != NULL) { - struct request *rq_ptr = &tape->first_stage->rq; - - cnt += rq_ptr->nr_sectors - rq_ptr->current_nr_sectors; - if (rq_ptr->errors == IDETAPE_ERROR_FILEMARK) - ++cnt; - idetape_remove_stage_head(drive); - } - tape->nr_pending_stages = 0; - tape->max_stages = tape->min_pipeline; - return cnt; } /* @@ -2081,7 +1662,7 @@ static int idetape_position_tape(ide_drive_t *drive, unsigned int block, struct ide_atapi_pc pc; if (tape->chrdev_dir == IDETAPE_DIR_READ) - __idetape_discard_read_pipeline(drive); + __ide_tape_discard_merge_buffer(drive); idetape_wait_ready(drive, 60 * 5 * HZ); idetape_create_locate_cmd(drive, &pc, block, partition, skip); retval = idetape_queue_pc_tail(drive, &pc); @@ -2092,20 +1673,19 @@ static int idetape_position_tape(ide_drive_t *drive, unsigned int block, return (idetape_queue_pc_tail(drive, &pc)); } -static void idetape_discard_read_pipeline(ide_drive_t *drive, +static void ide_tape_discard_merge_buffer(ide_drive_t *drive, int restore_position) { idetape_tape_t *tape = drive->driver_data; - int cnt; int seek, position; - cnt = __idetape_discard_read_pipeline(drive); + __ide_tape_discard_merge_buffer(drive); if (restore_position) { position = idetape_read_position(drive); - seek = position > cnt ? position - cnt : 0; + seek = position > 0 ? position : 0; if (idetape_position_tape(drive, seek, 0, 0)) { printk(KERN_INFO "ide-tape: %s: position_tape failed in" - " discard_pipeline()\n", tape->name); + " %s\n", tape->name, __func__); return; } } @@ -2123,12 +1703,6 @@ static int idetape_queue_rw_tail(ide_drive_t *drive, int cmd, int blocks, debug_log(DBG_SENSE, "%s: cmd=%d\n", __func__, cmd); - if (test_bit(IDETAPE_FLAG_PIPELINE_ACTIVE, &tape->flags)) { - printk(KERN_ERR "ide-tape: bug: the pipeline is active in %s\n", - __func__); - return (0); - } - idetape_init_rq(&rq, cmd); rq.rq_disk = tape->disk; rq.special = (void *)bh; @@ -2140,26 +1714,13 @@ static int idetape_queue_rw_tail(ide_drive_t *drive, int cmd, int blocks, if ((cmd & (REQ_IDETAPE_READ | REQ_IDETAPE_WRITE)) == 0) return 0; - if (tape->merge_stage) - idetape_init_merge_stage(tape); + if (tape->merge_bh) + idetape_init_merge_buffer(tape); if (rq.errors == IDETAPE_ERROR_GENERAL) return -EIO; return (tape->blk_size * (blocks-rq.current_nr_sectors)); } -/* start servicing the pipeline stages, starting from tape->next_stage. */ -static void idetape_plug_pipeline(ide_drive_t *drive) -{ - idetape_tape_t *tape = drive->driver_data; - - if (tape->next_stage == NULL) - return; - if (!test_and_set_bit(IDETAPE_FLAG_PIPELINE_ACTIVE, &tape->flags)) { - idetape_activate_next_stage(drive); - (void) ide_do_drive_cmd(drive, tape->active_data_rq, ide_end); - } -} - static void idetape_create_inquiry_cmd(struct ide_atapi_pc *pc) { idetape_init_pc(pc); @@ -2197,137 +1758,39 @@ static void idetape_create_space_cmd(struct ide_atapi_pc *pc, int count, u8 cmd) pc->idetape_callback = &idetape_pc_callback; } -static void idetape_wait_first_stage(ide_drive_t *drive) -{ - idetape_tape_t *tape = drive->driver_data; - unsigned long flags; - - if (tape->first_stage == NULL) - return; - spin_lock_irqsave(&tape->lock, flags); - if (tape->active_stage == tape->first_stage) - idetape_wait_for_request(drive, tape->active_data_rq); - spin_unlock_irqrestore(&tape->lock, flags); -} - -/* - * Try to add a character device originated write request to our pipeline. In - * case we don't succeed, we revert to non-pipelined operation mode for this - * request. In order to accomplish that, we - * - * 1. Try to allocate a new pipeline stage. - * 2. If we can't, wait for more and more requests to be serviced and try again - * each time. - * 3. If we still can't allocate a stage, fallback to non-pipelined operation - * mode for this request. - */ +/* Queue up a character device originated write request. */ static int idetape_add_chrdev_write_request(ide_drive_t *drive, int blocks) { idetape_tape_t *tape = drive->driver_data; - idetape_stage_t *new_stage; - unsigned long flags; - struct request *rq; debug_log(DBG_CHRDEV, "Enter %s\n", __func__); - /* Attempt to allocate a new stage. Beware possible race conditions. */ - while ((new_stage = idetape_kmalloc_stage(tape)) == NULL) { - spin_lock_irqsave(&tape->lock, flags); - if (test_bit(IDETAPE_FLAG_PIPELINE_ACTIVE, &tape->flags)) { - idetape_wait_for_request(drive, tape->active_data_rq); - spin_unlock_irqrestore(&tape->lock, flags); - } else { - spin_unlock_irqrestore(&tape->lock, flags); - idetape_plug_pipeline(drive); - if (test_bit(IDETAPE_FLAG_PIPELINE_ACTIVE, - &tape->flags)) - continue; - /* - * The machine is short on memory. Fallback to non- - * pipelined operation mode for this request. - */ - return idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, - blocks, tape->merge_stage->bh); - } - } - rq = &new_stage->rq; - idetape_init_rq(rq, REQ_IDETAPE_WRITE); - /* Doesn't actually matter - We always assume sequential access */ - rq->sector = tape->first_frame; - rq->current_nr_sectors = blocks; - rq->nr_sectors = blocks; - - idetape_switch_buffers(tape, new_stage); - idetape_add_stage_tail(drive, new_stage); - tape->pipeline_head++; - idetape_calculate_speeds(drive); - - /* - * Estimate whether the tape has stopped writing by checking if our - * write pipeline is currently empty. If we are not writing anymore, - * wait for the pipeline to be almost completely full (90%) before - * starting to service requests, so that we will be able to keep up with - * the higher speeds of the tape. - */ - if (!test_bit(IDETAPE_FLAG_PIPELINE_ACTIVE, &tape->flags)) { - if (tape->nr_stages >= tape->max_stages * 9 / 10 || - tape->nr_stages >= tape->max_stages - - tape->uncontrolled_pipeline_head_speed * 3 * 1024 / - tape->blk_size) { - tape->measure_insert_time = 1; - tape->insert_time = jiffies; - tape->insert_size = 0; - tape->insert_speed = 0; - idetape_plug_pipeline(drive); - } - } - if (test_and_clear_bit(IDETAPE_FLAG_PIPELINE_ERR, &tape->flags)) - /* Return a deferred error */ - return -EIO; - return blocks; + return idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, + blocks, tape->merge_bh); } -/* - * Wait until all pending pipeline requests are serviced. Typically called on - * device close. - */ -static void idetape_wait_for_pipeline(ide_drive_t *drive) -{ - idetape_tape_t *tape = drive->driver_data; - unsigned long flags; - - while (tape->next_stage || test_bit(IDETAPE_FLAG_PIPELINE_ACTIVE, - &tape->flags)) { - idetape_plug_pipeline(drive); - spin_lock_irqsave(&tape->lock, flags); - if (test_bit(IDETAPE_FLAG_PIPELINE_ACTIVE, &tape->flags)) - idetape_wait_for_request(drive, tape->active_data_rq); - spin_unlock_irqrestore(&tape->lock, flags); - } -} - -static void idetape_empty_write_pipeline(ide_drive_t *drive) +static void ide_tape_flush_merge_buffer(ide_drive_t *drive) { idetape_tape_t *tape = drive->driver_data; int blocks, min; struct idetape_bh *bh; if (tape->chrdev_dir != IDETAPE_DIR_WRITE) { - printk(KERN_ERR "ide-tape: bug: Trying to empty write pipeline," + printk(KERN_ERR "ide-tape: bug: Trying to empty merge buffer" " but we are not writing.\n"); return; } - if (tape->merge_stage_size > tape->stage_size) { + if (tape->merge_bh_size > tape->buffer_size) { printk(KERN_ERR "ide-tape: bug: merge_buffer too big\n"); - tape->merge_stage_size = tape->stage_size; + tape->merge_bh_size = tape->buffer_size; } - if (tape->merge_stage_size) { - blocks = tape->merge_stage_size / tape->blk_size; - if (tape->merge_stage_size % tape->blk_size) { + if (tape->merge_bh_size) { + blocks = tape->merge_bh_size / tape->blk_size; + if (tape->merge_bh_size % tape->blk_size) { unsigned int i; blocks++; - i = tape->blk_size - tape->merge_stage_size % + i = tape->blk_size - tape->merge_bh_size % tape->blk_size; bh = tape->bh->b_reqnext; while (bh) { @@ -2351,74 +1814,33 @@ static void idetape_empty_write_pipeline(ide_drive_t *drive) } } (void) idetape_add_chrdev_write_request(drive, blocks); - tape->merge_stage_size = 0; + tape->merge_bh_size = 0; } - idetape_wait_for_pipeline(drive); - if (tape->merge_stage != NULL) { - __idetape_kfree_stage(tape->merge_stage); - tape->merge_stage = NULL; + if (tape->merge_bh != NULL) { + ide_tape_kfree_buffer(tape); + tape->merge_bh = NULL; } - clear_bit(IDETAPE_FLAG_PIPELINE_ERR, &tape->flags); tape->chrdev_dir = IDETAPE_DIR_NONE; - - /* - * On the next backup, perform the feedback loop again. (I don't want to - * keep sense information between backups, as some systems are - * constantly on, and the system load can be totally different on the - * next backup). - */ - tape->max_stages = tape->min_pipeline; - if (tape->first_stage != NULL || - tape->next_stage != NULL || - tape->last_stage != NULL || - tape->nr_stages != 0) { - printk(KERN_ERR "ide-tape: ide-tape pipeline bug, " - "first_stage %p, next_stage %p, " - "last_stage %p, nr_stages %d\n", - tape->first_stage, tape->next_stage, - tape->last_stage, tape->nr_stages); - } } -static void idetape_restart_speed_control(ide_drive_t *drive) +static int idetape_init_read(ide_drive_t *drive) { idetape_tape_t *tape = drive->driver_data; - - tape->restart_speed_control_req = 0; - tape->pipeline_head = 0; - tape->controlled_last_pipeline_head = 0; - tape->controlled_previous_pipeline_head = 0; - tape->uncontrolled_previous_pipeline_head = 0; - tape->controlled_pipeline_head_speed = 5000; - tape->pipeline_head_speed = 5000; - tape->uncontrolled_pipeline_head_speed = 0; - tape->controlled_pipeline_head_time = - tape->uncontrolled_pipeline_head_time = jiffies; - tape->controlled_previous_head_time = - tape->uncontrolled_previous_head_time = jiffies; -} - -static int idetape_init_read(ide_drive_t *drive, int max_stages) -{ - idetape_tape_t *tape = drive->driver_data; - idetape_stage_t *new_stage; - struct request rq; int bytes_read; - u16 blocks = *(u16 *)&tape->caps[12]; /* Initialize read operation */ if (tape->chrdev_dir != IDETAPE_DIR_READ) { if (tape->chrdev_dir == IDETAPE_DIR_WRITE) { - idetape_empty_write_pipeline(drive); + ide_tape_flush_merge_buffer(drive); idetape_flush_tape_buffers(drive); } - if (tape->merge_stage || tape->merge_stage_size) { - printk(KERN_ERR "ide-tape: merge_stage_size should be" + if (tape->merge_bh || tape->merge_bh_size) { + printk(KERN_ERR "ide-tape: merge_bh_size should be" " 0 now\n"); - tape->merge_stage_size = 0; + tape->merge_bh_size = 0; } - tape->merge_stage = __idetape_kmalloc_stage(tape, 0, 0); - if (!tape->merge_stage) + tape->merge_bh = ide_tape_kmalloc_buffer(tape, 0, 0); + if (!tape->merge_bh) return -ENOMEM; tape->chrdev_dir = IDETAPE_DIR_READ; @@ -2431,54 +1853,23 @@ static int idetape_init_read(ide_drive_t *drive, int max_stages) if (drive->dsc_overlap) { bytes_read = idetape_queue_rw_tail(drive, REQ_IDETAPE_READ, 0, - tape->merge_stage->bh); + tape->merge_bh); if (bytes_read < 0) { - __idetape_kfree_stage(tape->merge_stage); - tape->merge_stage = NULL; + ide_tape_kfree_buffer(tape); + tape->merge_bh = NULL; tape->chrdev_dir = IDETAPE_DIR_NONE; return bytes_read; } } } - if (tape->restart_speed_control_req) - idetape_restart_speed_control(drive); - idetape_init_rq(&rq, REQ_IDETAPE_READ); - rq.sector = tape->first_frame; - rq.nr_sectors = blocks; - rq.current_nr_sectors = blocks; - if (!test_bit(IDETAPE_FLAG_PIPELINE_ERR, &tape->flags) && - tape->nr_stages < max_stages) { - new_stage = idetape_kmalloc_stage(tape); - while (new_stage != NULL) { - new_stage->rq = rq; - idetape_add_stage_tail(drive, new_stage); - if (tape->nr_stages >= max_stages) - break; - new_stage = idetape_kmalloc_stage(tape); - } - } - if (!test_bit(IDETAPE_FLAG_PIPELINE_ACTIVE, &tape->flags)) { - if (tape->nr_pending_stages >= 3 * max_stages / 4) { - tape->measure_insert_time = 1; - tape->insert_time = jiffies; - tape->insert_size = 0; - tape->insert_speed = 0; - idetape_plug_pipeline(drive); - } - } + return 0; } -/* - * Called from idetape_chrdev_read() to service a character device read request - * and add read-ahead requests to our pipeline. - */ +/* called from idetape_chrdev_read() to service a chrdev read request. */ static int idetape_add_chrdev_read_request(ide_drive_t *drive, int blocks) { idetape_tape_t *tape = drive->driver_data; - unsigned long flags; - struct request *rq_ptr; - int bytes_read; debug_log(DBG_PROCS, "Enter %s, %d blocks\n", __func__, blocks); @@ -2486,39 +1877,10 @@ static int idetape_add_chrdev_read_request(ide_drive_t *drive, int blocks) if (test_bit(IDETAPE_FLAG_FILEMARK, &tape->flags)) return 0; - /* Wait for the next block to reach the head of the pipeline. */ - idetape_init_read(drive, tape->max_stages); - if (tape->first_stage == NULL) { - if (test_bit(IDETAPE_FLAG_PIPELINE_ERR, &tape->flags)) - return 0; - return idetape_queue_rw_tail(drive, REQ_IDETAPE_READ, blocks, - tape->merge_stage->bh); - } - idetape_wait_first_stage(drive); - rq_ptr = &tape->first_stage->rq; - bytes_read = tape->blk_size * (rq_ptr->nr_sectors - - rq_ptr->current_nr_sectors); - rq_ptr->nr_sectors = 0; - rq_ptr->current_nr_sectors = 0; + idetape_init_read(drive); - if (rq_ptr->errors == IDETAPE_ERROR_EOD) - return 0; - else { - idetape_switch_buffers(tape, tape->first_stage); - if (rq_ptr->errors == IDETAPE_ERROR_FILEMARK) - set_bit(IDETAPE_FLAG_FILEMARK, &tape->flags); - spin_lock_irqsave(&tape->lock, flags); - idetape_remove_stage_head(drive); - spin_unlock_irqrestore(&tape->lock, flags); - tape->pipeline_head++; - idetape_calculate_speeds(drive); - } - if (bytes_read > blocks * tape->blk_size) { - printk(KERN_ERR "ide-tape: bug: trying to return more bytes" - " than requested\n"); - bytes_read = blocks * tape->blk_size; - } - return (bytes_read); + return idetape_queue_rw_tail(drive, REQ_IDETAPE_READ, blocks, + tape->merge_bh); } static void idetape_pad_zeros(ide_drive_t *drive, int bcount) @@ -2530,8 +1892,8 @@ static void idetape_pad_zeros(ide_drive_t *drive, int bcount) while (bcount) { unsigned int count; - bh = tape->merge_stage->bh; - count = min(tape->stage_size, bcount); + bh = tape->merge_bh; + count = min(tape->buffer_size, bcount); bcount -= count; blocks = count / tape->blk_size; while (count) { @@ -2542,29 +1904,8 @@ static void idetape_pad_zeros(ide_drive_t *drive, int bcount) bh = bh->b_reqnext; } idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, blocks, - tape->merge_stage->bh); - } -} - -static int idetape_pipeline_size(ide_drive_t *drive) -{ - idetape_tape_t *tape = drive->driver_data; - idetape_stage_t *stage; - struct request *rq; - int size = 0; - - idetape_wait_for_pipeline(drive); - stage = tape->first_stage; - while (stage != NULL) { - rq = &stage->rq; - size += tape->blk_size * (rq->nr_sectors - - rq->current_nr_sectors); - if (rq->errors == IDETAPE_ERROR_FILEMARK) - size += tape->blk_size; - stage = stage->next; + tape->merge_bh); } - size += tape->merge_stage_size; - return size; } /* @@ -2612,11 +1953,10 @@ static int idetape_blkdev_ioctl(ide_drive_t *drive, unsigned int cmd, if (copy_from_user(&config, argp, sizeof(config))) return -EFAULT; tape->best_dsc_rw_freq = config.dsc_rw_frequency; - tape->max_stages = config.nr_stages; break; case 0x0350: config.dsc_rw_frequency = (int) tape->best_dsc_rw_freq; - config.nr_stages = tape->max_stages; + config.nr_stages = 1; if (copy_to_user(argp, &config, sizeof(config))) return -EFAULT; break; @@ -2626,19 +1966,11 @@ static int idetape_blkdev_ioctl(ide_drive_t *drive, unsigned int cmd, return 0; } -/* - * The function below is now a bit more complicated than just passing the - * command to the tape since we may have crossed some filemarks during our - * pipelined read-ahead mode. As a minor side effect, the pipeline enables us to - * support MTFSFM when the filemark is in our internal pipeline even if the tape - * doesn't support spacing over filemarks in the reverse direction. - */ static int idetape_space_over_filemarks(ide_drive_t *drive, short mt_op, int mt_count) { idetape_tape_t *tape = drive->driver_data; struct ide_atapi_pc pc; - unsigned long flags; int retval, count = 0; int sprev = !!(tape->caps[4] & 0x20); @@ -2651,48 +1983,12 @@ static int idetape_space_over_filemarks(ide_drive_t *drive, short mt_op, } if (tape->chrdev_dir == IDETAPE_DIR_READ) { - /* its a read-ahead buffer, scan it for crossed filemarks. */ - tape->merge_stage_size = 0; + tape->merge_bh_size = 0; if (test_and_clear_bit(IDETAPE_FLAG_FILEMARK, &tape->flags)) ++count; - while (tape->first_stage != NULL) { - if (count == mt_count) { - if (mt_op == MTFSFM) - set_bit(IDETAPE_FLAG_FILEMARK, - &tape->flags); - return 0; - } - spin_lock_irqsave(&tape->lock, flags); - if (tape->first_stage == tape->active_stage) { - /* - * We have reached the active stage in the read - * pipeline. There is no point in allowing the - * drive to continue reading any farther, so we - * stop the pipeline. - * - * This section should be moved to a separate - * subroutine because similar operations are - * done in __idetape_discard_read_pipeline(), - * for example. - */ - tape->next_stage = NULL; - spin_unlock_irqrestore(&tape->lock, flags); - idetape_wait_first_stage(drive); - tape->next_stage = tape->first_stage->next; - } else - spin_unlock_irqrestore(&tape->lock, flags); - if (tape->first_stage->rq.errors == - IDETAPE_ERROR_FILEMARK) - ++count; - idetape_remove_stage_head(drive); - } - idetape_discard_read_pipeline(drive, 0); + ide_tape_discard_merge_buffer(drive, 0); } - /* - * The filemark was not found in our internal pipeline; now we can issue - * the space command. - */ switch (mt_op) { case MTFSF: case MTBSF: @@ -2748,27 +2044,25 @@ static ssize_t idetape_chrdev_read(struct file *file, char __user *buf, (count % tape->blk_size) == 0) tape->user_bs_factor = count / tape->blk_size; } - rc = idetape_init_read(drive, tape->max_stages); + rc = idetape_init_read(drive); if (rc < 0) return rc; if (count == 0) return (0); - if (tape->merge_stage_size) { - actually_read = min((unsigned int)(tape->merge_stage_size), + if (tape->merge_bh_size) { + actually_read = min((unsigned int)(tape->merge_bh_size), (unsigned int)count); - if (idetape_copy_stage_to_user(tape, buf, tape->merge_stage, - actually_read)) + if (idetape_copy_stage_to_user(tape, buf, actually_read)) ret = -EFAULT; buf += actually_read; - tape->merge_stage_size -= actually_read; + tape->merge_bh_size -= actually_read; count -= actually_read; } - while (count >= tape->stage_size) { + while (count >= tape->buffer_size) { bytes_read = idetape_add_chrdev_read_request(drive, ctl); if (bytes_read <= 0) goto finish; - if (idetape_copy_stage_to_user(tape, buf, tape->merge_stage, - bytes_read)) + if (idetape_copy_stage_to_user(tape, buf, bytes_read)) ret = -EFAULT; buf += bytes_read; count -= bytes_read; @@ -2779,11 +2073,10 @@ static ssize_t idetape_chrdev_read(struct file *file, char __user *buf, if (bytes_read <= 0) goto finish; temp = min((unsigned long)count, (unsigned long)bytes_read); - if (idetape_copy_stage_to_user(tape, buf, tape->merge_stage, - temp)) + if (idetape_copy_stage_to_user(tape, buf, temp)) ret = -EFAULT; actually_read += temp; - tape->merge_stage_size = bytes_read-temp; + tape->merge_bh_size = bytes_read-temp; } finish: if (!actually_read && test_bit(IDETAPE_FLAG_FILEMARK, &tape->flags)) { @@ -2814,17 +2107,17 @@ static ssize_t idetape_chrdev_write(struct file *file, const char __user *buf, /* Initialize write operation */ if (tape->chrdev_dir != IDETAPE_DIR_WRITE) { if (tape->chrdev_dir == IDETAPE_DIR_READ) - idetape_discard_read_pipeline(drive, 1); - if (tape->merge_stage || tape->merge_stage_size) { - printk(KERN_ERR "ide-tape: merge_stage_size " + ide_tape_discard_merge_buffer(drive, 1); + if (tape->merge_bh || tape->merge_bh_size) { + printk(KERN_ERR "ide-tape: merge_bh_size " "should be 0 now\n"); - tape->merge_stage_size = 0; + tape->merge_bh_size = 0; } - tape->merge_stage = __idetape_kmalloc_stage(tape, 0, 0); - if (!tape->merge_stage) + tape->merge_bh = ide_tape_kmalloc_buffer(tape, 0, 0); + if (!tape->merge_bh) return -ENOMEM; tape->chrdev_dir = IDETAPE_DIR_WRITE; - idetape_init_merge_stage(tape); + idetape_init_merge_buffer(tape); /* * Issue a write 0 command to ensure that DSC handshake is @@ -2835,10 +2128,10 @@ static ssize_t idetape_chrdev_write(struct file *file, const char __user *buf, if (drive->dsc_overlap) { ssize_t retval = idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, 0, - tape->merge_stage->bh); + tape->merge_bh); if (retval < 0) { - __idetape_kfree_stage(tape->merge_stage); - tape->merge_stage = NULL; + ide_tape_kfree_buffer(tape); + tape->merge_bh = NULL; tape->chrdev_dir = IDETAPE_DIR_NONE; return retval; } @@ -2846,49 +2139,44 @@ static ssize_t idetape_chrdev_write(struct file *file, const char __user *buf, } if (count == 0) return (0); - if (tape->restart_speed_control_req) - idetape_restart_speed_control(drive); - if (tape->merge_stage_size) { - if (tape->merge_stage_size >= tape->stage_size) { + if (tape->merge_bh_size) { + if (tape->merge_bh_size >= tape->buffer_size) { printk(KERN_ERR "ide-tape: bug: merge buf too big\n"); - tape->merge_stage_size = 0; + tape->merge_bh_size = 0; } actually_written = min((unsigned int) - (tape->stage_size - tape->merge_stage_size), + (tape->buffer_size - tape->merge_bh_size), (unsigned int)count); - if (idetape_copy_stage_from_user(tape, tape->merge_stage, buf, - actually_written)) + if (idetape_copy_stage_from_user(tape, buf, actually_written)) ret = -EFAULT; buf += actually_written; - tape->merge_stage_size += actually_written; + tape->merge_bh_size += actually_written; count -= actually_written; - if (tape->merge_stage_size == tape->stage_size) { + if (tape->merge_bh_size == tape->buffer_size) { ssize_t retval; - tape->merge_stage_size = 0; + tape->merge_bh_size = 0; retval = idetape_add_chrdev_write_request(drive, ctl); if (retval <= 0) return (retval); } } - while (count >= tape->stage_size) { + while (count >= tape->buffer_size) { ssize_t retval; - if (idetape_copy_stage_from_user(tape, tape->merge_stage, buf, - tape->stage_size)) + if (idetape_copy_stage_from_user(tape, buf, tape->buffer_size)) ret = -EFAULT; - buf += tape->stage_size; - count -= tape->stage_size; + buf += tape->buffer_size; + count -= tape->buffer_size; retval = idetape_add_chrdev_write_request(drive, ctl); - actually_written += tape->stage_size; + actually_written += tape->buffer_size; if (retval <= 0) return (retval); } if (count) { actually_written += count; - if (idetape_copy_stage_from_user(tape, tape->merge_stage, buf, - count)) + if (idetape_copy_stage_from_user(tape, buf, count)) ret = -EFAULT; - tape->merge_stage_size += count; + tape->merge_bh_size += count; } return ret ? ret : actually_written; } @@ -2912,8 +2200,7 @@ static int idetape_write_filemark(ide_drive_t *drive) * * Note: MTBSF and MTBSFM are not supported when the tape doesn't support * spacing over filemarks in the reverse direction. In this case, MTFSFM is also - * usually not supported (it is supported in the rare case in which we crossed - * the filemark during our read-ahead pipelined operation mode). + * usually not supported. * * The following commands are currently not supported: * @@ -2929,7 +2216,6 @@ static int idetape_mtioctop(ide_drive_t *drive, short mt_op, int mt_count) debug_log(DBG_ERR, "Handling MTIOCTOP ioctl: mt_op=%d, mt_count=%d\n", mt_op, mt_count); - /* Commands which need our pipelined read-ahead stages. */ switch (mt_op) { case MTFSF: case MTFSFM: @@ -2946,7 +2232,7 @@ static int idetape_mtioctop(ide_drive_t *drive, short mt_op, int mt_count) case MTWEOF: if (tape->write_prot) return -EACCES; - idetape_discard_read_pipeline(drive, 1); + ide_tape_discard_merge_buffer(drive, 1); for (i = 0; i < mt_count; i++) { retval = idetape_write_filemark(drive); if (retval) @@ -2954,12 +2240,12 @@ static int idetape_mtioctop(ide_drive_t *drive, short mt_op, int mt_count) } return 0; case MTREW: - idetape_discard_read_pipeline(drive, 0); + ide_tape_discard_merge_buffer(drive, 0); if (idetape_rewind_tape(drive)) return -EIO; return 0; case MTLOAD: - idetape_discard_read_pipeline(drive, 0); + ide_tape_discard_merge_buffer(drive, 0); idetape_create_load_unload_cmd(drive, &pc, IDETAPE_LU_LOAD_MASK); return idetape_queue_pc_tail(drive, &pc); @@ -2974,7 +2260,7 @@ static int idetape_mtioctop(ide_drive_t *drive, short mt_op, int mt_count) if (!idetape_queue_pc_tail(drive, &pc)) tape->door_locked = DOOR_UNLOCKED; } - idetape_discard_read_pipeline(drive, 0); + ide_tape_discard_merge_buffer(drive, 0); idetape_create_load_unload_cmd(drive, &pc, !IDETAPE_LU_LOAD_MASK); retval = idetape_queue_pc_tail(drive, &pc); @@ -2982,10 +2268,10 @@ static int idetape_mtioctop(ide_drive_t *drive, short mt_op, int mt_count) clear_bit(IDETAPE_FLAG_MEDIUM_PRESENT, &tape->flags); return retval; case MTNOP: - idetape_discard_read_pipeline(drive, 0); + ide_tape_discard_merge_buffer(drive, 0); return idetape_flush_tape_buffers(drive); case MTRETEN: - idetape_discard_read_pipeline(drive, 0); + ide_tape_discard_merge_buffer(drive, 0); idetape_create_load_unload_cmd(drive, &pc, IDETAPE_LU_RETENSION_MASK | IDETAPE_LU_LOAD_MASK); return idetape_queue_pc_tail(drive, &pc); @@ -3007,11 +2293,11 @@ static int idetape_mtioctop(ide_drive_t *drive, short mt_op, int mt_count) set_bit(IDETAPE_FLAG_DETECT_BS, &tape->flags); return 0; case MTSEEK: - idetape_discard_read_pipeline(drive, 0); + ide_tape_discard_merge_buffer(drive, 0); return idetape_position_tape(drive, mt_count * tape->user_bs_factor, tape->partition, 0); case MTSETPART: - idetape_discard_read_pipeline(drive, 0); + ide_tape_discard_merge_buffer(drive, 0); return idetape_position_tape(drive, 0, mt_count, 0); case MTFSR: case MTBSR: @@ -3056,13 +2342,12 @@ static int idetape_chrdev_ioctl(struct inode *inode, struct file *file, debug_log(DBG_CHRDEV, "Enter %s, cmd=%u\n", __func__, cmd); - tape->restart_speed_control_req = 1; if (tape->chrdev_dir == IDETAPE_DIR_WRITE) { - idetape_empty_write_pipeline(drive); + ide_tape_flush_merge_buffer(drive); idetape_flush_tape_buffers(drive); } if (cmd == MTIOCGET || cmd == MTIOCPOS) { - block_offset = idetape_pipeline_size(drive) / + block_offset = tape->merge_bh_size / (tape->blk_size * tape->user_bs_factor); position = idetape_read_position(drive); if (position < 0) @@ -3094,7 +2379,7 @@ static int idetape_chrdev_ioctl(struct inode *inode, struct file *file, return 0; default: if (tape->chrdev_dir == IDETAPE_DIR_READ) - idetape_discard_read_pipeline(drive, 1); + ide_tape_discard_merge_buffer(drive, 1); return idetape_blkdev_ioctl(drive, cmd, arg); } } @@ -3168,9 +2453,6 @@ static int idetape_chrdev_open(struct inode *inode, struct file *filp) if (!test_bit(IDETAPE_FLAG_ADDRESS_VALID, &tape->flags)) (void)idetape_rewind_tape(drive); - if (tape->chrdev_dir != IDETAPE_DIR_READ) - clear_bit(IDETAPE_FLAG_PIPELINE_ERR, &tape->flags); - /* Read block size and write protect status from drive. */ ide_tape_get_bsize_from_bdesc(drive); @@ -3199,8 +2481,6 @@ static int idetape_chrdev_open(struct inode *inode, struct file *filp) } } } - idetape_restart_speed_control(drive); - tape->restart_speed_control_req = 0; return 0; out_put_tape: @@ -3212,13 +2492,13 @@ static void idetape_write_release(ide_drive_t *drive, unsigned int minor) { idetape_tape_t *tape = drive->driver_data; - idetape_empty_write_pipeline(drive); - tape->merge_stage = __idetape_kmalloc_stage(tape, 1, 0); - if (tape->merge_stage != NULL) { + ide_tape_flush_merge_buffer(drive); + tape->merge_bh = ide_tape_kmalloc_buffer(tape, 1, 0); + if (tape->merge_bh != NULL) { idetape_pad_zeros(drive, tape->blk_size * (tape->user_bs_factor - 1)); - __idetape_kfree_stage(tape->merge_stage); - tape->merge_stage = NULL; + ide_tape_kfree_buffer(tape); + tape->merge_bh = NULL; } idetape_write_filemark(drive); idetape_flush_tape_buffers(drive); @@ -3241,14 +2521,9 @@ static int idetape_chrdev_release(struct inode *inode, struct file *filp) idetape_write_release(drive, minor); if (tape->chrdev_dir == IDETAPE_DIR_READ) { if (minor < 128) - idetape_discard_read_pipeline(drive, 1); - else - idetape_wait_for_pipeline(drive); - } - if (tape->cache_stage != NULL) { - __idetape_kfree_stage(tape->cache_stage); - tape->cache_stage = NULL; + ide_tape_discard_merge_buffer(drive, 1); } + if (minor < 128 && test_bit(IDETAPE_FLAG_MEDIUM_PRESENT, &tape->flags)) (void) idetape_rewind_tape(drive); if (tape->chrdev_dir == IDETAPE_DIR_NONE) { @@ -3385,33 +2660,15 @@ static void idetape_add_settings(ide_drive_t *drive) ide_add_setting(drive, "buffer", SETTING_READ, TYPE_SHORT, 0, 0xffff, 1, 2, (u16 *)&tape->caps[16], NULL); - ide_add_setting(drive, "pipeline_min", SETTING_RW, TYPE_INT, 1, 0xffff, - tape->stage_size / 1024, 1, &tape->min_pipeline, NULL); - ide_add_setting(drive, "pipeline", SETTING_RW, TYPE_INT, 1, 0xffff, - tape->stage_size / 1024, 1, &tape->max_stages, NULL); - ide_add_setting(drive, "pipeline_max", SETTING_RW, TYPE_INT, 1, 0xffff, - tape->stage_size / 1024, 1, &tape->max_pipeline, NULL); - ide_add_setting(drive, "pipeline_used", SETTING_READ, TYPE_INT, 0, - 0xffff, tape->stage_size / 1024, 1, &tape->nr_stages, - NULL); - ide_add_setting(drive, "pipeline_pending", SETTING_READ, TYPE_INT, 0, - 0xffff, tape->stage_size / 1024, 1, - &tape->nr_pending_stages, NULL); ide_add_setting(drive, "speed", SETTING_READ, TYPE_SHORT, 0, 0xffff, 1, 1, (u16 *)&tape->caps[14], NULL); - ide_add_setting(drive, "stage", SETTING_READ, TYPE_INT, 0, 0xffff, 1, - 1024, &tape->stage_size, NULL); + ide_add_setting(drive, "buffer_size", SETTING_READ, TYPE_INT, 0, 0xffff, + 1, 1024, &tape->buffer_size, NULL); ide_add_setting(drive, "tdsc", SETTING_RW, TYPE_INT, IDETAPE_DSC_RW_MIN, IDETAPE_DSC_RW_MAX, 1000, HZ, &tape->best_dsc_rw_freq, NULL); ide_add_setting(drive, "dsc_overlap", SETTING_RW, TYPE_BYTE, 0, 1, 1, 1, &drive->dsc_overlap, NULL); - ide_add_setting(drive, "pipeline_head_speed_c", SETTING_READ, TYPE_INT, - 0, 0xffff, 1, 1, &tape->controlled_pipeline_head_speed, - NULL); - ide_add_setting(drive, "pipeline_head_speed_u", SETTING_READ, TYPE_INT, - 0, 0xffff, 1, 1, - &tape->uncontrolled_pipeline_head_speed, NULL); ide_add_setting(drive, "avg_speed", SETTING_READ, TYPE_INT, 0, 0xffff, 1, 1, &tape->avg_speed, NULL); ide_add_setting(drive, "debug_mask", SETTING_RW, TYPE_INT, 0, 0xffff, 1, @@ -3434,11 +2691,10 @@ static inline void idetape_add_settings(ide_drive_t *drive) { ; } */ static void idetape_setup(ide_drive_t *drive, idetape_tape_t *tape, int minor) { - unsigned long t1, tmid, tn, t; + unsigned long t; int speed; - int stage_size; + int buffer_size; u8 gcw[2]; - struct sysinfo si; u16 *ctl = (u16 *)&tape->caps[12]; spin_lock_init(&tape->lock); @@ -3457,65 +2713,33 @@ static void idetape_setup(ide_drive_t *drive, idetape_tape_t *tape, int minor) tape->name[2] = '0' + minor; tape->chrdev_dir = IDETAPE_DIR_NONE; tape->pc = tape->pc_stack; - tape->max_insert_speed = 10000; - tape->speed_control = 1; *((unsigned short *) &gcw) = drive->id->config; /* Command packet DRQ type */ if (((gcw[0] & 0x60) >> 5) == 1) set_bit(IDETAPE_FLAG_DRQ_INTERRUPT, &tape->flags); - tape->min_pipeline = 10; - tape->max_pipeline = 10; - tape->max_stages = 10; - idetape_get_inquiry_results(drive); idetape_get_mode_sense_results(drive); ide_tape_get_bsize_from_bdesc(drive); tape->user_bs_factor = 1; - tape->stage_size = *ctl * tape->blk_size; - while (tape->stage_size > 0xffff) { + tape->buffer_size = *ctl * tape->blk_size; + while (tape->buffer_size > 0xffff) { printk(KERN_NOTICE "ide-tape: decreasing stage size\n"); *ctl /= 2; - tape->stage_size = *ctl * tape->blk_size; + tape->buffer_size = *ctl * tape->blk_size; } - stage_size = tape->stage_size; - tape->pages_per_stage = stage_size / PAGE_SIZE; - if (stage_size % PAGE_SIZE) { - tape->pages_per_stage++; - tape->excess_bh_size = PAGE_SIZE - stage_size % PAGE_SIZE; + buffer_size = tape->buffer_size; + tape->pages_per_buffer = buffer_size / PAGE_SIZE; + if (buffer_size % PAGE_SIZE) { + tape->pages_per_buffer++; + tape->excess_bh_size = PAGE_SIZE - buffer_size % PAGE_SIZE; } - /* Select the "best" DSC read/write polling freq and pipeline size. */ + /* select the "best" DSC read/write polling freq */ speed = max(*(u16 *)&tape->caps[14], *(u16 *)&tape->caps[8]); - tape->max_stages = speed * 1000 * 10 / tape->stage_size; - - /* Limit memory use for pipeline to 10% of physical memory */ - si_meminfo(&si); - if (tape->max_stages * tape->stage_size > - si.totalram * si.mem_unit / 10) - tape->max_stages = - si.totalram * si.mem_unit / (10 * tape->stage_size); - - tape->max_stages = min(tape->max_stages, IDETAPE_MAX_PIPELINE_STAGES); - tape->min_pipeline = min(tape->max_stages, IDETAPE_MIN_PIPELINE_STAGES); - tape->max_pipeline = - min(tape->max_stages * 2, IDETAPE_MAX_PIPELINE_STAGES); - if (tape->max_stages == 0) { - tape->max_stages = 1; - tape->min_pipeline = 1; - tape->max_pipeline = 1; - } - - t1 = (tape->stage_size * HZ) / (speed * 1000); - tmid = (*(u16 *)&tape->caps[16] * 32 * HZ) / (speed * 125); - tn = (IDETAPE_FIFO_THRESHOLD * tape->stage_size * HZ) / (speed * 1000); - - if (tape->max_stages) - t = tn; - else - t = t1; + t = (IDETAPE_FIFO_THRESHOLD * tape->buffer_size * HZ) / (speed * 1000); /* * Ensure that the number we got makes sense; limit it within @@ -3525,11 +2749,10 @@ static void idetape_setup(ide_drive_t *drive, idetape_tape_t *tape, int minor) min_t(unsigned long, t, IDETAPE_DSC_RW_MAX), IDETAPE_DSC_RW_MIN); printk(KERN_INFO "ide-tape: %s <-> %s: %dKBps, %d*%dkB buffer, " - "%dkB pipeline, %lums tDSC%s\n", + "%lums tDSC%s\n", drive->name, tape->name, *(u16 *)&tape->caps[14], - (*(u16 *)&tape->caps[16] * 512) / tape->stage_size, - tape->stage_size / 1024, - tape->max_stages * tape->stage_size / 1024, + (*(u16 *)&tape->caps[16] * 512) / tape->buffer_size, + tape->buffer_size / 1024, tape->best_dsc_rw_freq * 1000 / HZ, drive->using_dma ? ", DMA":""); @@ -3553,7 +2776,7 @@ static void ide_tape_release(struct kref *kref) ide_drive_t *drive = tape->drive; struct gendisk *g = tape->disk; - BUG_ON(tape->first_stage != NULL || tape->merge_stage_size); + BUG_ON(tape->merge_bh_size); drive->dsc_overlap = 0; drive->driver_data = NULL; |