ide-tape.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:217k
- rq.cmd = IDETAPE_PC_RQ1;
- return ide_do_drive_cmd (drive, &rq, ide_wait);
- }
- static void idetape_create_load_unload_cmd (ide_drive_t *drive, idetape_pc_t *pc,int cmd)
- {
- idetape_tape_t *tape = drive->driver_data;
- idetape_init_pc (pc);
- pc->c[0] = IDETAPE_LOAD_UNLOAD_CMD;
- pc->c[4] = cmd;
- if (tape->onstream) {
- pc->c[1] = 1;
- if (cmd == !IDETAPE_LU_LOAD_MASK)
- pc->c[4] = 4;
- }
- set_bit (PC_WAIT_FOR_DSC, &pc->flags);
- pc->callback = &idetape_pc_callback;
- }
- static int idetape_wait_ready (ide_drive_t *drive, unsigned long long timeout)
- {
- idetape_tape_t *tape = drive->driver_data;
- idetape_pc_t pc;
- /*
- * Wait for the tape to become ready
- */
- timeout += jiffies;
- while (time_before(jiffies, timeout)) {
- idetape_create_test_unit_ready_cmd(&pc);
- if (!__idetape_queue_pc_tail(drive, &pc))
- return 0;
- if (tape->sense_key == 2 && tape->asc == 4 && tape->ascq == 2) {
- idetape_create_load_unload_cmd (drive, &pc, IDETAPE_LU_LOAD_MASK);
- __idetape_queue_pc_tail(drive, &pc);
- idetape_create_test_unit_ready_cmd(&pc);
- if (!__idetape_queue_pc_tail(drive, &pc))
- return 0;
- }
- if (!(tape->sense_key == 2 && tape->asc == 4 && (tape->ascq == 1 || tape->ascq == 8)))
- break;
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(HZ / 10);
- }
- return -EIO;
- }
- static int idetape_queue_pc_tail (ide_drive_t *drive,idetape_pc_t *pc)
- {
- idetape_tape_t *tape = drive->driver_data;
- int rc;
- rc = __idetape_queue_pc_tail(drive, pc);
- if (rc)
- return rc;
- if (tape->onstream && test_bit(PC_WAIT_FOR_DSC, &pc->flags))
- rc = idetape_wait_ready(drive, 60 * 10 * HZ); /* AJN-4: Changed from 5 to 10 minutes;
- because retension takes approx. 8:20 with Onstream 30GB tape */
- return rc;
- }
- static int idetape_flush_tape_buffers (ide_drive_t *drive)
- {
- idetape_pc_t pc;
- int rc;
- idetape_create_write_filemark_cmd(drive, &pc, 0);
- if ((rc = idetape_queue_pc_tail (drive, &pc)))
- return rc;
- idetape_wait_ready(drive, 60 * 5 * HZ);
- return 0;
- }
- static void idetape_create_read_position_cmd (idetape_pc_t *pc)
- {
- idetape_init_pc (pc);
- pc->c[0] = IDETAPE_READ_POSITION_CMD;
- pc->request_transfer = 20;
- pc->callback = &idetape_read_position_callback;
- }
- static int idetape_read_position (ide_drive_t *drive)
- {
- idetape_tape_t *tape = drive->driver_data;
- idetape_pc_t pc;
- int position;
- #if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 4)
- printk (KERN_INFO "ide-tape: Reached idetape_read_positionn");
- #endif /* IDETAPE_DEBUG_LOG */
- #ifdef NO_LONGER_REQUIRED
- idetape_flush_tape_buffers(drive);
- #endif
- idetape_create_read_position_cmd(&pc);
- if (idetape_queue_pc_tail (drive, &pc))
- return -1;
- position = tape->first_frame_position;
- #ifdef NO_LONGER_REQUIRED
- if (tape->onstream) {
- if ((position != tape->last_frame_position - tape->blocks_in_buffer) &&
- (position != tape->last_frame_position + tape->blocks_in_buffer)) {
- if (tape->blocks_in_buffer == 0) {
- printk("ide-tape: %s: correcting read position %d, %d, %dn", tape->name, position, tape->last_frame_position, tape->blocks_in_buffer);
- position = tape->last_frame_position;
- tape->first_frame_position = position;
- }
- }
- }
- #endif
- return position;
- }
- static void idetape_create_locate_cmd (ide_drive_t *drive, idetape_pc_t *pc, unsigned int block, byte partition, int skip)
- {
- idetape_tape_t *tape = drive->driver_data;
- idetape_init_pc (pc);
- pc->c[0] = IDETAPE_LOCATE_CMD;
- if (tape->onstream)
- pc->c[1] = 1; /* Immediate bit */
- else
- pc->c[1] = 2;
- put_unaligned (htonl (block), (unsigned int *) &pc->c[3]);
- pc->c[8] = partition;
- if (tape->onstream)
- /*
- * Set SKIP bit.
- * In case of write error this will write buffered
- * data in the drive to this new position!
- */
- pc->c[9] = skip << 7;
- set_bit (PC_WAIT_FOR_DSC, &pc->flags);
- pc->callback = &idetape_pc_callback;
- }
- static int idetape_create_prevent_cmd (ide_drive_t *drive, idetape_pc_t *pc, int prevent)
- {
- idetape_tape_t *tape = drive->driver_data;
- if (!tape->capabilities.lock)
- return 0;
- idetape_init_pc(pc);
- pc->c[0] = IDETAPE_PREVENT_CMD;
- pc->c[4] = prevent;
- pc->callback = &idetape_pc_callback;
- return 1;
- }
- static int __idetape_discard_read_pipeline (ide_drive_t *drive)
- {
- idetape_tape_t *tape = drive->driver_data;
- unsigned long flags;
- int cnt;
- if (tape->chrdev_direction != idetape_direction_read)
- return 0;
- tape->merge_stage_size = 0;
- if (tape->merge_stage != NULL) {
- __idetape_kfree_stage (tape->merge_stage);
- tape->merge_stage = NULL;
- }
- tape->chrdev_direction = idetape_direction_none;
-
- if (tape->first_stage == NULL)
- return 0;
- spin_lock_irqsave(&tape->spinlock, flags);
- tape->next_stage = NULL;
- if (idetape_pipeline_active (tape))
- idetape_wait_for_request(drive, tape->active_data_request);
- spin_unlock_irqrestore(&tape->spinlock, flags);
- cnt = tape->nr_stages - tape->nr_pending_stages;
- while (tape->first_stage != NULL)
- idetape_remove_stage_head (drive);
- tape->nr_pending_stages = 0;
- tape->max_stages = tape->min_pipeline;
- return cnt;
- }
- /*
- * idetape_position_tape positions the tape to the requested block
- * using the LOCATE packet command. A READ POSITION command is then
- * issued to check where we are positioned.
- *
- * Like all higher level operations, we queue the commands at the tail
- * of the request queue and wait for their completion.
- *
- */
- static int idetape_position_tape (ide_drive_t *drive, unsigned int block, byte partition, int skip)
- {
- idetape_tape_t *tape = drive->driver_data;
- int retval;
- idetape_pc_t pc;
- if (tape->chrdev_direction == idetape_direction_read)
- __idetape_discard_read_pipeline(drive);
- idetape_wait_ready(drive, 60 * 5 * HZ);
- idetape_create_locate_cmd (drive, &pc, block, partition, skip);
- retval = idetape_queue_pc_tail (drive, &pc);
- if (retval)
- return (retval);
- idetape_create_read_position_cmd (&pc);
- return (idetape_queue_pc_tail (drive, &pc));
- }
- static void idetape_discard_read_pipeline (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);
- if (restore_position) {
- position = idetape_read_position(drive);
- #if ONSTREAM_DEBUG
- if (tape->debug_level >= 2)
- printk(KERN_INFO "ide-tape: address %u, nr_stages %dn", position, cnt);
- #endif
- seek = position > cnt ? position - cnt : 0;
- if (idetape_position_tape(drive, seek, 0, 0)) {
- printk(KERN_INFO "ide-tape: %s: position_tape failed in discard_pipeline()n", tape->name);
- return;
- }
- }
- }
- static void idetape_update_stats (ide_drive_t *drive)
- {
- idetape_pc_t pc;
- idetape_create_mode_sense_cmd (&pc, IDETAPE_BUFFER_FILLING_PAGE);
- pc.callback = idetape_onstream_buffer_fill_callback;
- (void) idetape_queue_pc_tail(drive, &pc);
- }
- /*
- * idetape_queue_rw_tail generates a read/write request for the block
- * device interface and wait for it to be serviced.
- */
- static int idetape_queue_rw_tail (ide_drive_t *drive, int cmd, int blocks, struct buffer_head *bh)
- {
- idetape_tape_t *tape = drive->driver_data;
- struct request rq;
- #if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 2)
- printk (KERN_INFO "ide-tape: idetape_queue_rw_tail: cmd=%dn",cmd);
- #endif /* IDETAPE_DEBUG_LOG */
- #if IDETAPE_DEBUG_BUGS
- if (idetape_pipeline_active (tape)) {
- printk (KERN_ERR "ide-tape: bug: the pipeline is active in idetape_queue_rw_tailn");
- return (0);
- }
- #endif /* IDETAPE_DEBUG_BUGS */
- ide_init_drive_cmd (&rq);
- rq.bh = bh;
- rq.cmd = cmd;
- rq.sector = tape->first_frame_position;
- rq.nr_sectors = rq.current_nr_sectors = blocks;
- if (tape->onstream)
- tape->postpone_cnt = 600;
- (void) ide_do_drive_cmd (drive, &rq, ide_wait);
- if (cmd != IDETAPE_READ_RQ && cmd != IDETAPE_WRITE_RQ)
- return 0;
- if (tape->merge_stage)
- idetape_init_merge_stage (tape);
- if (rq.errors == IDETAPE_ERROR_GENERAL)
- return -EIO;
- return (tape->tape_block_size * (blocks-rq.current_nr_sectors));
- }
- /*
- * Read back the drive's internal buffer contents, as a part
- * of the write error recovery mechanism for old OnStream
- * firmware revisions.
- */
- static void idetape_onstream_read_back_buffer (ide_drive_t *drive)
- {
- idetape_tape_t *tape = drive->driver_data;
- int frames, i, logical_blk_num;
- idetape_stage_t *stage, *first = NULL, *last = NULL;
- os_aux_t *aux;
- struct request *rq;
- unsigned char *p;
- unsigned long flags;
- idetape_update_stats(drive);
- frames = tape->cur_frames;
- logical_blk_num = ntohl(tape->first_stage->aux->logical_blk_num) - frames;
- printk(KERN_INFO "ide-tape: %s: reading back %d frames from the drive's internal buffern", tape->name, frames);
- for (i = 0; i < frames; i++) {
- stage = __idetape_kmalloc_stage(tape, 0, 0);
- if (!first)
- first = stage;
- aux = stage->aux;
- p = stage->bh->b_data;
- idetape_queue_rw_tail(drive, IDETAPE_READ_BUFFER_RQ, tape->capabilities.ctl, stage->bh);
- #if ONSTREAM_DEBUG
- if (tape->debug_level >= 2)
- printk(KERN_INFO "ide-tape: %s: read back logical block %d, data %x %x %x %xn", tape->name, logical_blk_num, *p++, *p++, *p++, *p++);
- #endif
- rq = &stage->rq;
- ide_init_drive_cmd (rq);
- rq->cmd = IDETAPE_WRITE_RQ;
- rq->sector = tape->first_frame_position;
- rq->nr_sectors = rq->current_nr_sectors = tape->capabilities.ctl;
- idetape_init_stage(drive, stage, OS_FRAME_TYPE_DATA, logical_blk_num++);
- stage->next = NULL;
- if (last)
- last->next = stage;
- last = stage;
- }
- if (frames) {
- spin_lock_irqsave(&tape->spinlock, flags);
- last->next = tape->first_stage;
- tape->next_stage = tape->first_stage = first;
- tape->nr_stages += frames;
- tape->nr_pending_stages += frames;
- spin_unlock_irqrestore(&tape->spinlock, flags);
- }
- idetape_update_stats(drive);
- #if ONSTREAM_DEBUG
- if (tape->debug_level >= 2)
- printk(KERN_INFO "ide-tape: %s: frames left in buffer: %dn", tape->name, tape->cur_frames);
- #endif
- }
- /*
- * Error recovery algorithm for the OnStream tape.
- */
- static void idetape_onstream_write_error_recovery (ide_drive_t *drive)
- {
- idetape_tape_t *tape = drive->driver_data;
- unsigned int block;
- if (tape->onstream_write_error == OS_WRITE_ERROR) {
- printk(KERN_ERR "ide-tape: %s: onstream_write_error_recovery: detected physical bad block at %u, logical %u first frame %u last_frame %u bufblocks %u stages %u skipping %u framesn",
- tape->name, ntohl(tape->sense.information), tape->logical_blk_num,
- tape->first_frame_position, tape->last_frame_position,
- tape->blocks_in_buffer, tape->nr_stages,
- (ntohl(tape->sense.command_specific) >> 16) & 0xff );
- block = ntohl(tape->sense.information) + ((ntohl(tape->sense.command_specific) >> 16) & 0xff);
- idetape_update_stats(drive);
- printk(KERN_ERR "ide-tape: %s: relocating %d buffered logical blocks to physical block %un", tape->name, tape->cur_frames, block);
- #if 0 /* isn't once enough ??? MM */
- idetape_update_stats(drive);
- #endif
- if (tape->firmware_revision_num >= 106)
- idetape_position_tape(drive, block, 0, 1);
- else {
- idetape_onstream_read_back_buffer(drive);
- idetape_position_tape(drive, block, 0, 0);
- }
- #if 0 /* already done in idetape_position_tape MM */
- idetape_read_position(drive);
- #endif
- #if ONSTREAM_DEBUG
- if (tape->debug_level >= 1)
- printk(KERN_ERR "ide-tape: %s: positioning complete, cur_frames %d, pos %d, tape pos %dn", tape->name, tape->cur_frames, tape->first_frame_position, tape->last_frame_position);
- #endif
- } else if (tape->onstream_write_error == OS_PART_ERROR) {
- #if ONSTREAM_DEBUG
- if (tape->debug_level >= 1)
- printk(KERN_INFO "ide-tape: %s: skipping over config partitionn", tape->name);
- #endif
- idetape_flush_tape_buffers(drive);
- block = idetape_read_position(drive);
- if (block != OS_DATA_ENDFRAME1)
- printk(KERN_ERR "ide-tape: warning, current position %d, expected %dn", block, OS_DATA_ENDFRAME1);
- idetape_position_tape(drive, 0xbb8, 0, 0); /* 3000 */
- }
- tape->onstream_write_error = 0;
- }
- /*
- * idetape_insert_pipeline_into_queue is used to start servicing the
- * pipeline stages, starting from tape->next_stage.
- */
- static void idetape_insert_pipeline_into_queue (ide_drive_t *drive)
- {
- idetape_tape_t *tape = drive->driver_data;
- if (tape->next_stage == NULL)
- return;
- if (!idetape_pipeline_active (tape)) {
- if (tape->onstream_write_error)
- idetape_onstream_write_error_recovery(drive);
- set_bit(IDETAPE_PIPELINE_ACTIVE, &tape->flags);
- idetape_active_next_stage (drive);
- (void) ide_do_drive_cmd (drive, tape->active_data_request, ide_end);
- }
- }
- static void idetape_create_inquiry_cmd (idetape_pc_t *pc)
- {
- idetape_init_pc(pc);
- pc->c[0] = IDETAPE_INQUIRY_CMD;
- pc->c[4] = pc->request_transfer = 254;
- pc->callback = &idetape_pc_callback;
- }
- static void idetape_create_rewind_cmd (ide_drive_t *drive, idetape_pc_t *pc)
- {
- idetape_tape_t *tape = drive->driver_data;
- idetape_init_pc (pc);
- pc->c[0] = IDETAPE_REWIND_CMD;
- if (tape->onstream)
- pc->c[1] = 1;
- set_bit (PC_WAIT_FOR_DSC, &pc->flags);
- pc->callback = &idetape_pc_callback;
- }
- static void idetape_create_mode_select_cmd (idetape_pc_t *pc, int length)
- {
- idetape_init_pc (pc);
- set_bit (PC_WRITING, &pc->flags);
- pc->c[0] = IDETAPE_MODE_SELECT_CMD;
- pc->c[1] = 0x10;
- put_unaligned (htons(length), (unsigned short *) &pc->c[3]);
- pc->request_transfer = 255;
- pc->callback = &idetape_pc_callback;
- }
- static void idetape_create_erase_cmd (idetape_pc_t *pc)
- {
- idetape_init_pc (pc);
- pc->c[0] = IDETAPE_ERASE_CMD;
- pc->c[1] = 1;
- set_bit (PC_WAIT_FOR_DSC, &pc->flags);
- pc->callback = &idetape_pc_callback;
- }
- static void idetape_create_space_cmd (idetape_pc_t *pc,int count,byte cmd)
- {
- idetape_init_pc (pc);
- pc->c[0] = IDETAPE_SPACE_CMD;
- put_unaligned (htonl (count), (unsigned int *) &pc->c[1]);
- pc->c[1] = cmd;
- set_bit (PC_WAIT_FOR_DSC, &pc->flags);
- pc->callback = &idetape_pc_callback;
- }
- /*
- * Verify that we have the correct tape frame
- */
- static int idetape_verify_stage (ide_drive_t *drive, idetape_stage_t *stage, int logical_blk_num, int quiet)
- {
- idetape_tape_t *tape = drive->driver_data;
- os_aux_t *aux = stage->aux;
- os_partition_t *par = &aux->partition;
- struct request *rq = &stage->rq;
- struct buffer_head *bh;
- if (!tape->onstream)
- return 1;
- if (tape->raw) {
- if (rq->errors) {
- bh = stage->bh;
- while (bh) {
- memset(bh->b_data, 0, bh->b_size);
- bh = bh->b_reqnext;
- }
- strcpy(stage->bh->b_data, "READ ERROR ON FRAME");
- }
- return 1;
- }
- if (rq->errors == IDETAPE_ERROR_GENERAL) {
- printk(KERN_INFO "ide-tape: %s: skipping frame %d, read errorn", tape->name, tape->first_frame_position);
- return 0;
- }
- if (rq->errors == IDETAPE_ERROR_EOD) {
- printk(KERN_INFO "ide-tape: %s: skipping frame %d, eodn", tape->name, tape->first_frame_position);
- return 0;
- }
- if (ntohl(aux->format_id) != 0) {
- printk(KERN_INFO "ide-tape: %s: skipping frame %d, format_id %un", tape->name, tape->first_frame_position, ntohl(aux->format_id));
- return 0;
- }
- if (memcmp(aux->application_sig, tape->application_sig, 4) != 0) {
- printk(KERN_INFO "ide-tape: %s: skipping frame %d, incorrect application signaturen", tape->name, tape->first_frame_position);
- return 0;
- }
- if (aux->frame_type != OS_FRAME_TYPE_DATA &&
- aux->frame_type != OS_FRAME_TYPE_EOD &&
- aux->frame_type != OS_FRAME_TYPE_MARKER) {
- printk(KERN_INFO "ide-tape: %s: skipping frame %d, frame type %xn", tape->name, tape->first_frame_position, aux->frame_type);
- return 0;
- }
- if (par->partition_num != OS_DATA_PARTITION) {
- if (!tape->linux_media || tape->linux_media_version != 2) {
- printk(KERN_INFO "ide-tape: %s: skipping frame %d, partition num %dn", tape->name, tape->first_frame_position, par->partition_num);
- return 0;
- }
- }
- if (par->par_desc_ver != OS_PARTITION_VERSION) {
- printk(KERN_INFO "ide-tape: %s: skipping frame %d, partition version %dn", tape->name, tape->first_frame_position, par->par_desc_ver);
- return 0;
- }
- if (ntohs(par->wrt_pass_cntr) != tape->wrt_pass_cntr) {
- printk(KERN_INFO "ide-tape: %s: skipping frame %d, wrt_pass_cntr %d (expected %d)(logical_blk_num %u)n", tape->name, tape->first_frame_position, ntohs(par->wrt_pass_cntr), tape->wrt_pass_cntr, ntohl(aux->logical_blk_num));
- return 0;
- }
- if (aux->frame_seq_num != aux->logical_blk_num) {
- printk(KERN_INFO "ide-tape: %s: skipping frame %d, seq != logicaln", tape->name, tape->first_frame_position);
- return 0;
- }
- if (logical_blk_num != -1 && ntohl(aux->logical_blk_num) != logical_blk_num) {
- if (!quiet)
- printk(KERN_INFO "ide-tape: %s: skipping frame %d, logical_blk_num %u (expected %d)n", tape->name, tape->first_frame_position, ntohl(aux->logical_blk_num), logical_blk_num);
- return 0;
- }
- if (aux->frame_type == OS_FRAME_TYPE_MARKER) {
- rq->errors = IDETAPE_ERROR_FILEMARK;
- rq->current_nr_sectors = rq->nr_sectors;
- }
- return 1;
- }
- 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->spinlock, flags);
- if (tape->active_stage == tape->first_stage)
- idetape_wait_for_request(drive, tape->active_data_request);
- spin_unlock_irqrestore(&tape->spinlock, flags);
- }
- /*
- * idetape_add_chrdev_write_request tries 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.
- *
- * 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.
- */
- 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;
- #if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 3)
- printk (KERN_INFO "ide-tape: Reached idetape_add_chrdev_write_requestn");
- #endif /* IDETAPE_DEBUG_LOG */
- /*
- * Attempt to allocate a new stage.
- * Pay special attention to possible race conditions.
- */
- while ((new_stage = idetape_kmalloc_stage (tape)) == NULL) {
- spin_lock_irqsave(&tape->spinlock, flags);
- if (idetape_pipeline_active (tape)) {
- idetape_wait_for_request(drive, tape->active_data_request);
- spin_unlock_irqrestore(&tape->spinlock, flags);
- } else {
- spin_unlock_irqrestore(&tape->spinlock, flags);
- idetape_insert_pipeline_into_queue (drive);
- if (idetape_pipeline_active (tape))
- continue;
- /*
- * Linux is short on memory. Fallback to
- * non-pipelined operation mode for this request.
- */
- return idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, blocks, tape->merge_stage->bh);
- }
- }
- rq = &new_stage->rq;
- ide_init_drive_cmd (rq);
- rq->cmd = IDETAPE_WRITE_RQ;
- rq->sector = tape->first_frame_position; /* Doesn't actually matter - We always assume sequential access */
- rq->nr_sectors = rq->current_nr_sectors = blocks;
- idetape_switch_buffers (tape, new_stage);
- idetape_init_stage(drive, new_stage, OS_FRAME_TYPE_DATA, tape->logical_blk_num);
- tape->logical_blk_num++;
- idetape_add_stage_tail (drive, new_stage);
- tape->pipeline_head++;
- #if USE_IOTRACE
- IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor);
- #endif
- 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 full enough
- * (90%) before starting to service requests, so that we will
- * be able to keep up with the higher speeds of the tape.
- *
- * For the OnStream drive, we can query the number of pending
- * frames in the drive's internal buffer. As long as the tape
- * is still writing, it is better to write frames immediately
- * rather than gather them in the pipeline. This will give the
- * tape's firmware the ability to sense the current incoming
- * data rate more accurately, and since the OnStream tape
- * supports variable speeds, it can try to adjust itself to the
- * incoming data rate.
- */
- if (!idetape_pipeline_active(tape)) {
- if (tape->nr_stages >= tape->max_stages * 9 / 10 ||
- tape->nr_stages >= tape->max_stages - tape->uncontrolled_pipeline_head_speed * 3 * 1024 / tape->tape_block_size) {
- tape->measure_insert_time = 1;
- tape->insert_time = jiffies;
- tape->insert_size = 0;
- tape->insert_speed = 0;
- idetape_insert_pipeline_into_queue (drive);
- } else if (tape->onstream) {
- idetape_update_stats(drive);
- if (tape->cur_frames > 5)
- idetape_insert_pipeline_into_queue (drive);
- }
- }
- if (test_and_clear_bit (IDETAPE_PIPELINE_ERROR, &tape->flags)) /* Return a deferred error */
- return -EIO;
- return blocks;
- }
- /*
- * idetape_wait_for_pipeline will 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 || idetape_pipeline_active(tape)) {
- idetape_insert_pipeline_into_queue (drive);
- spin_lock_irqsave(&tape->spinlock, flags);
- if (idetape_pipeline_active(tape))
- idetape_wait_for_request(drive, tape->active_data_request);
- spin_unlock_irqrestore(&tape->spinlock, flags);
- }
- }
- static void idetape_empty_write_pipeline (ide_drive_t *drive)
- {
- idetape_tape_t *tape = drive->driver_data;
- int blocks, i, min;
- struct buffer_head *bh;
-
- #if IDETAPE_DEBUG_BUGS
- if (tape->chrdev_direction != idetape_direction_write) {
- printk (KERN_ERR "ide-tape: bug: Trying to empty write pipeline, but we are not writing.n");
- return;
- }
- if (tape->merge_stage_size > tape->stage_size) {
- printk (KERN_ERR "ide-tape: bug: merge_buffer too bign");
- tape->merge_stage_size = tape->stage_size;
- }
- #endif /* IDETAPE_DEBUG_BUGS */
- if (tape->merge_stage_size) {
- blocks = tape->merge_stage_size / tape->tape_block_size;
- if (tape->merge_stage_size % tape->tape_block_size) {
- blocks++;
- i = tape->tape_block_size - tape->merge_stage_size % tape->tape_block_size;
- bh = tape->bh->b_reqnext;
- while (bh) {
- atomic_set(&bh->b_count, 0);
- bh = bh->b_reqnext;
- }
- bh = tape->bh;
- while (i) {
- if (bh == NULL) {
- printk(KERN_INFO "ide-tape: bug, bh NULLn");
- break;
- }
- min = IDE_MIN(i, bh->b_size - atomic_read(&bh->b_count));
- memset(bh->b_data + atomic_read(&bh->b_count), 0, min);
- atomic_add(min, &bh->b_count);
- i -= min;
- bh = bh->b_reqnext;
- }
- }
- (void) idetape_add_chrdev_write_request (drive, blocks);
- tape->merge_stage_size = 0;
- }
- idetape_wait_for_pipeline (drive);
- if (tape->merge_stage != NULL) {
- __idetape_kfree_stage (tape->merge_stage);
- tape->merge_stage = NULL;
- }
- clear_bit (IDETAPE_PIPELINE_ERROR, &tape->flags);
- tape->chrdev_direction = idetape_direction_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 IDETAPE_DEBUG_BUGS
- 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 %dn",
- tape->first_stage, tape->next_stage, tape->last_stage, tape->nr_stages);
- }
- #endif /* IDETAPE_DEBUG_BUGS */
- }
- static void idetape_restart_speed_control (ide_drive_t *drive)
- {
- idetape_tape_t *tape = drive->driver_data;
- tape->restart_speed_control_req = 0;
- tape->pipeline_head = 0;
- tape->buffer_head = tape->tape_head = tape->cur_frames;
- tape->controlled_last_pipeline_head = tape->uncontrolled_last_pipeline_head = 0;
- tape->controlled_previous_pipeline_head = tape->uncontrolled_previous_pipeline_head = 0;
- tape->pipeline_head_speed = tape->controlled_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_initiate_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;
- int blocks = tape->capabilities.ctl;
- if (tape->chrdev_direction != idetape_direction_read) { /* Initialize read operation */
- if (tape->chrdev_direction == idetape_direction_write) {
- idetape_empty_write_pipeline (drive);
- idetape_flush_tape_buffers (drive);
- }
- #if IDETAPE_DEBUG_BUGS
- if (tape->merge_stage || tape->merge_stage_size) {
- printk (KERN_ERR "ide-tape: merge_stage_size should be 0 nown");
- tape->merge_stage_size = 0;
- }
- #endif /* IDETAPE_DEBUG_BUGS */
- if ((tape->merge_stage = __idetape_kmalloc_stage (tape, 0, 0)) == NULL)
- return -ENOMEM;
- tape->chrdev_direction = idetape_direction_read;
- tape->logical_blk_num = 0;
- /*
- * Issue a read 0 command to ensure that DSC handshake
- * is switched from completion mode to buffer available
- * mode.
- */
- bytes_read = idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, 0, tape->merge_stage->bh);
- if (bytes_read < 0) {
- kfree (tape->merge_stage);
- tape->merge_stage = NULL;
- tape->chrdev_direction = idetape_direction_none;
- return bytes_read;
- }
- }
- if (tape->restart_speed_control_req)
- idetape_restart_speed_control(drive);
- ide_init_drive_cmd (&rq);
- rq.cmd = IDETAPE_READ_RQ;
- rq.sector = tape->first_frame_position;
- rq.nr_sectors = rq.current_nr_sectors = blocks;
- if (!test_bit(IDETAPE_PIPELINE_ERROR, &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 (!idetape_pipeline_active(tape)) {
- 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_insert_pipeline_into_queue (drive);
- } else if (tape->onstream) {
- idetape_update_stats(drive);
- if (tape->cur_frames < tape->max_frames - 5)
- idetape_insert_pipeline_into_queue (drive);
- }
- }
- return 0;
- }
- static int idetape_get_logical_blk (ide_drive_t *drive, int logical_blk_num, int max_stages, int quiet)
- {
- idetape_tape_t *tape = drive->driver_data;
- unsigned long flags;
- int cnt = 0, x, position;
- /*
- * Search and wait for the next logical tape block
- */
- while (1) {
- if (cnt++ > 1000) { /* AJN: was 100 */
- printk(KERN_INFO "ide-tape: %s: couldn't find logical block %d, abortingn", tape->name, logical_blk_num);
- return 0;
- }
- idetape_initiate_read(drive, max_stages);
- if (tape->first_stage == NULL) {
- if (tape->onstream) {
- #if ONSTREAM_DEBUG
- if (tape->debug_level >= 1)
- printk(KERN_INFO "ide-tape: %s: first_stage == NULL, pipeline error %ldn", tape->name, (long)test_bit(IDETAPE_PIPELINE_ERROR, &tape->flags));
- #endif
- clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
- position = idetape_read_position(drive);
- printk(KERN_INFO "ide-tape: %s: blank block detected at %dn", tape->name, position);
- if (position >= 3000 && position < 3080)
- position += 32; /* Why is this check and number ??? MM */
- if (position >= OS_DATA_ENDFRAME1 && position < 3000)
- position = 3000;
- else
- /*
- * compensate for write errors that generally skip 80 frames,
- * expect around 20 read errors in a row...
- */
- position += 60;
- if (position >= OS_DATA_ENDFRAME1 && position < 3000)
- position = 3000;
- printk(KERN_INFO "ide-tape: %s: positioning tape to block %dn", tape->name, position);
- if (position == 3000) /* seems to be needed to correctly position at block 3000 MM */
- idetape_position_tape(drive, 0, 0, 0);
- idetape_position_tape(drive, position, 0, 0);
- cnt += 40;
- continue;
- } else
- return 0;
- }
- idetape_wait_first_stage(drive);
- if (idetape_verify_stage(drive, tape->first_stage, logical_blk_num, quiet))
- break;
- if (tape->first_stage->rq.errors == IDETAPE_ERROR_EOD)
- cnt--;
- if (idetape_verify_stage(drive, tape->first_stage, -1, quiet)) {
- x = ntohl(tape->first_stage->aux->logical_blk_num);
- if (x > logical_blk_num) {
- printk(KERN_ERR "ide-tape: %s: couldn't find logical block %d, aborting (block %d found)n", tape->name, logical_blk_num, x);
- return 0;
- }
- }
- spin_lock_irqsave(&tape->spinlock, flags);
- idetape_remove_stage_head(drive);
- spin_unlock_irqrestore(&tape->spinlock, flags);
- }
- if (tape->onstream)
- tape->logical_blk_num = ntohl(tape->first_stage->aux->logical_blk_num);
- return 1;
- }
- /*
- * idetape_add_chrdev_read_request is called from idetape_chrdev_read
- * to service a character device read request and add read-ahead
- * requests to our pipeline.
- */
- 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;
- #if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 4)
- printk (KERN_INFO "ide-tape: Reached idetape_add_chrdev_read_request, %d blocksn", blocks);
- #endif /* IDETAPE_DEBUG_LOG */
- /*
- * Wait for the next logical block to be available at the head
- * of the pipeline
- */
- if (!idetape_get_logical_blk(drive, tape->logical_blk_num, tape->max_stages, 0)) {
- if (tape->onstream) {
- set_bit(IDETAPE_READ_ERROR, &tape->flags);
- return 0;
- }
- if (test_bit(IDETAPE_PIPELINE_ERROR, &tape->flags))
- return 0;
- return idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, blocks, tape->merge_stage->bh);
- }
- rq_ptr = &tape->first_stage->rq;
- bytes_read = tape->tape_block_size * (rq_ptr->nr_sectors - rq_ptr->current_nr_sectors);
- rq_ptr->nr_sectors = rq_ptr->current_nr_sectors = 0;
- if (tape->onstream && !tape->raw && tape->first_stage->aux->frame_type == OS_FRAME_TYPE_EOD) {
- #if ONSTREAM_DEBUG
- if (tape->debug_level >= 2)
- printk(KERN_INFO "ide-tape: %s: EOD reachedn", tape->name);
- #endif
- return 0;
- }
- if (rq_ptr->errors == IDETAPE_ERROR_EOD)
- return 0;
- if (rq_ptr->errors == IDETAPE_ERROR_FILEMARK) {
- idetape_switch_buffers (tape, tape->first_stage);
- set_bit (IDETAPE_FILEMARK, &tape->flags);
- #if USE_IOTRACE
- IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor);
- #endif
- calculate_speeds(drive);
- } else {
- idetape_switch_buffers (tape, tape->first_stage);
- if (rq_ptr->errors == IDETAPE_ERROR_GENERAL) {
- #if ONSTREAM_DEBUG
- if (tape->debug_level >= 1)
- printk(KERN_INFO "ide-tape: error detected, bytes_read %dn", bytes_read);
- #endif
- }
- clear_bit (IDETAPE_FILEMARK, &tape->flags);
- spin_lock_irqsave(&tape->spinlock, flags);
- idetape_remove_stage_head (drive);
- spin_unlock_irqrestore(&tape->spinlock, flags);
- tape->logical_blk_num++;
- tape->pipeline_head++;
- #if USE_IOTRACE
- IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor);
- #endif
- calculate_speeds(drive);
- }
- #if IDETAPE_DEBUG_BUGS
- if (bytes_read > blocks*tape->tape_block_size) {
- printk (KERN_ERR "ide-tape: bug: trying to return more bytes than requestedn");
- bytes_read=blocks*tape->tape_block_size;
- }
- #endif /* IDETAPE_DEBUG_BUGS */
- return (bytes_read);
- }
- static void idetape_pad_zeros (ide_drive_t *drive, int bcount)
- {
- idetape_tape_t *tape = drive->driver_data;
- struct buffer_head *bh;
- int count, blocks;
-
- while (bcount) {
- bh = tape->merge_stage->bh;
- count = IDE_MIN (tape->stage_size, bcount);
- bcount -= count;
- blocks = count / tape->tape_block_size;
- while (count) {
- atomic_set(&bh->b_count, IDE_MIN (count, bh->b_size));
- memset (bh->b_data, 0, atomic_read(&bh->b_count));
- count -= atomic_read(&bh->b_count);
- bh = bh->b_reqnext;
- }
- idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 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->tape_block_size * (rq->nr_sectors-rq->current_nr_sectors);
- if (rq->errors == IDETAPE_ERROR_FILEMARK)
- size += tape->tape_block_size;
- stage = stage->next;
- }
- size += tape->merge_stage_size;
- return size;
- }
- /*
- * Rewinds the tape to the Beginning Of the current Partition (BOP).
- *
- * We currently support only one partition.
- */
- static int idetape_rewind_tape (ide_drive_t *drive)
- {
- int retval;
- idetape_pc_t pc;
- idetape_tape_t *tape = drive->driver_data;
- #if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 2)
- printk (KERN_INFO "ide-tape: Reached idetape_rewind_tapen");
- #endif /* IDETAPE_DEBUG_LOG */
-
- idetape_create_rewind_cmd (drive, &pc);
- retval = idetape_queue_pc_tail (drive, &pc);
- if (retval)
- return retval;
- idetape_create_read_position_cmd (&pc);
- retval = idetape_queue_pc_tail (drive, &pc);
- if (retval)
- return retval;
- tape->logical_blk_num = 0;
- return 0;
- }
- /*
- * Our special ide-tape ioctl's.
- *
- * Currently there aren't any ioctl's.
- * mtio.h compatible commands should be issued to the character device
- * interface.
- */
- static int idetape_blkdev_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
- {
- idetape_tape_t *tape = drive->driver_data;
- idetape_config_t config;
- #if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 4)
- printk (KERN_INFO "ide-tape: Reached idetape_blkdev_ioctln");
- #endif /* IDETAPE_DEBUG_LOG */
- switch (cmd) {
- case 0x0340:
- if (copy_from_user ((char *) &config, (char *) arg, sizeof (idetape_config_t)))
- return -EFAULT;
- tape->best_dsc_rw_frequency = config.dsc_rw_frequency;
- tape->max_stages = config.nr_stages;
- break;
- case 0x0350:
- config.dsc_rw_frequency = (int) tape->best_dsc_rw_frequency;
- config.nr_stages = tape->max_stages;
- if (copy_to_user ((char *) arg, (char *) &config, sizeof (idetape_config_t)))
- return -EFAULT;
- break;
- default:
- return -EIO;
- }
- return 0;
- }
- /*
- * The block device interface should not be used for data transfers.
- * However, we still allow opening it so that we can issue general
- * ide driver configuration ioctl's, such as the interrupt unmask feature.
- */
- static int idetape_blkdev_open (struct inode *inode, struct file *filp, ide_drive_t *drive)
- {
- MOD_INC_USE_COUNT;
- #if ONSTREAM_DEBUG
- printk(KERN_INFO "ide-tape: MOD_INC_USE_COUNT in idetape_blkdev_openn");
- #endif
- return 0;
- }
- static void idetape_blkdev_release (struct inode *inode, struct file *filp, ide_drive_t *drive)
- {
- MOD_DEC_USE_COUNT;
- #if ONSTREAM_DEBUG
- printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_blkdev_releasen");
- #endif
- }
- /*
- * idetape_pre_reset is called before an ATAPI/ATA software reset.
- */
- static void idetape_pre_reset (ide_drive_t *drive)
- {
- idetape_tape_t *tape = drive->driver_data;
- if (tape != NULL)
- set_bit (IDETAPE_IGNORE_DSC, &tape->flags);
- }
- /*
- * Character device interface functions
- */
- static ide_drive_t *get_drive_ptr (kdev_t i_rdev)
- {
- unsigned int i = MINOR(i_rdev) & ~0xc0;
- if (i >= MAX_HWIFS * MAX_DRIVES)
- return NULL;
- return (idetape_chrdevs[i].drive);
- }
- static int idetape_onstream_space_over_filemarks_backward (ide_drive_t *drive,short mt_op,int mt_count)
- {
- idetape_tape_t *tape = drive->driver_data;
- int cnt = 0;
- int last_mark_addr;
- unsigned long flags;
- if (!idetape_get_logical_blk(drive, -1, 10, 0)) {
- printk(KERN_INFO "ide-tape: %s: couldn't get logical blk num in space_filemarks_bwdn", tape->name);
- return -EIO;
- }
- while (cnt != mt_count) {
- last_mark_addr = ntohl(tape->first_stage->aux->last_mark_addr);
- if (last_mark_addr == -1)
- return -EIO;
- #if ONSTREAM_DEBUG
- if (tape->debug_level >= 2)
- printk(KERN_INFO "ide-tape: positioning to last mark at %dn", last_mark_addr);
- #endif
- idetape_position_tape(drive, last_mark_addr, 0, 0);
- cnt++;
- if (!idetape_get_logical_blk(drive, -1, 10, 0)) {
- printk(KERN_INFO "ide-tape: %s: couldn't get logical blk num in space_filemarksn", tape->name);
- return -EIO;
- }
- if (tape->first_stage->aux->frame_type != OS_FRAME_TYPE_MARKER) {
- printk(KERN_INFO "ide-tape: %s: expected to find marker at block %d, not foundn", tape->name, last_mark_addr);
- return -EIO;
- }
- }
- if (mt_op == MTBSFM) {
- spin_lock_irqsave(&tape->spinlock, flags);
- idetape_remove_stage_head (drive);
- tape->logical_blk_num++;
- spin_unlock_irqrestore(&tape->spinlock, flags);
- }
- return 0;
- }
- /*
- * ADRL 1.1 compatible "slow" space filemarks fwd version
- *
- * Just scans for the filemark sequentially.
- */
- static int idetape_onstream_space_over_filemarks_forward_slow (ide_drive_t *drive,short mt_op,int mt_count)
- {
- idetape_tape_t *tape = drive->driver_data;
- int cnt = 0;
- unsigned long flags;
- if (!idetape_get_logical_blk(drive, -1, 10, 0)) {
- printk(KERN_INFO "ide-tape: %s: couldn't get logical blk num in space_filemarks_fwdn", tape->name);
- return -EIO;
- }
- while (1) {
- if (!idetape_get_logical_blk(drive, -1, 10, 0)) {
- printk(KERN_INFO "ide-tape: %s: couldn't get logical blk num in space_filemarksn", tape->name);
- return -EIO;
- }
- if (tape->first_stage->aux->frame_type == OS_FRAME_TYPE_MARKER)
- cnt++;
- if (tape->first_stage->aux->frame_type == OS_FRAME_TYPE_EOD) {
- #if ONSTREAM_DEBUG
- if (tape->debug_level >= 2)
- printk(KERN_INFO "ide-tape: %s: space_fwd: EOD reachedn", tape->name);
- #endif
- return -EIO;
- }
- if (cnt == mt_count)
- break;
- spin_lock_irqsave(&tape->spinlock, flags);
- idetape_remove_stage_head (drive);
- spin_unlock_irqrestore(&tape->spinlock, flags);
- }
- if (mt_op == MTFSF) {
- spin_lock_irqsave(&tape->spinlock, flags);
- idetape_remove_stage_head (drive);
- tape->logical_blk_num++;
- spin_unlock_irqrestore(&tape->spinlock, flags);
- }
- return 0;
- }
- /*
- * Fast linux specific version of OnStream FSF
- */
- static int idetape_onstream_space_over_filemarks_forward_fast (ide_drive_t *drive,short mt_op,int mt_count)
- {
- idetape_tape_t *tape = drive->driver_data;
- int cnt = 0, next_mark_addr;
- unsigned long flags;
- if (!idetape_get_logical_blk(drive, -1, 10, 0)) {
- printk(KERN_INFO "ide-tape: %s: couldn't get logical blk num in space_filemarks_fwdn", tape->name);
- return -EIO;
- }
- /*
- * Find nearest (usually previous) marker
- */
- while (1) {
- if (tape->first_stage->aux->frame_type == OS_FRAME_TYPE_MARKER)
- break;
- if (tape->first_stage->aux->frame_type == OS_FRAME_TYPE_EOD) {
- #if ONSTREAM_DEBUG
- if (tape->debug_level >= 2)
- printk(KERN_INFO "ide-tape: %s: space_fwd: EOD reachedn", tape->name);
- #endif
- return -EIO;
- }
- if (ntohl(tape->first_stage->aux->filemark_cnt) == 0) {
- if (tape->first_mark_addr == -1) {
- printk(KERN_INFO "ide-tape: %s: reverting to slow filemark spacen", tape->name);
- return idetape_onstream_space_over_filemarks_forward_slow(drive, mt_op, mt_count);
- }
- idetape_position_tape(drive, tape->first_mark_addr, 0, 0);
- if (!idetape_get_logical_blk(drive, -1, 10, 0)) {
- printk(KERN_INFO "ide-tape: %s: couldn't get logical blk num in space_filemarks_fwd_fastn", tape->name);
- return -EIO;
- }
- if (tape->first_stage->aux->frame_type != OS_FRAME_TYPE_MARKER) {
- printk(KERN_INFO "ide-tape: %s: expected to find filemark at %dn", tape->name, tape->first_mark_addr);
- return -EIO;
- }
- } else {
- if (idetape_onstream_space_over_filemarks_backward(drive, MTBSF, 1) < 0)
- return -EIO;
- mt_count++;
- }
- }
- cnt++;
- while (cnt != mt_count) {
- next_mark_addr = ntohl(tape->first_stage->aux->next_mark_addr);
- if (!next_mark_addr || next_mark_addr > tape->eod_frame_addr) {
- printk(KERN_INFO "ide-tape: %s: reverting to slow filemark spacen", tape->name);
- return idetape_onstream_space_over_filemarks_forward_slow(drive, mt_op, mt_count - cnt);
- #if ONSTREAM_DEBUG
- } else if (tape->debug_level >= 2) {
- printk(KERN_INFO "ide-tape: positioning to next mark at %dn", next_mark_addr);
- #endif
- }
- idetape_position_tape(drive, next_mark_addr, 0, 0);
- cnt++;
- if (!idetape_get_logical_blk(drive, -1, 10, 0)) {
- printk(KERN_INFO "ide-tape: %s: couldn't get logical blk num in space_filemarksn", tape->name);
- return -EIO;
- }
- if (tape->first_stage->aux->frame_type != OS_FRAME_TYPE_MARKER) {
- printk(KERN_INFO "ide-tape: %s: expected to find marker at block %d, not foundn", tape->name, next_mark_addr);
- return -EIO;
- }
- }
- if (mt_op == MTFSF) {
- spin_lock_irqsave(&tape->spinlock, flags);
- idetape_remove_stage_head (drive);
- tape->logical_blk_num++;
- spin_unlock_irqrestore(&tape->spinlock, flags);
- }
- return 0;
- }
- /*
- * idetape_space_over_filemarks 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;
- idetape_pc_t pc;
- unsigned long flags;
- int retval,count=0;
- int speed_control;
- if (tape->onstream) {
- if (tape->raw)
- return -EIO;
- speed_control = tape->speed_control;
- tape->speed_control = 0;
- if (mt_op == MTFSF || mt_op == MTFSFM) {
- if (tape->linux_media)
- retval = idetape_onstream_space_over_filemarks_forward_fast(drive, mt_op, mt_count);
- else
- retval = idetape_onstream_space_over_filemarks_forward_slow(drive, mt_op, mt_count);
- } else
- retval = idetape_onstream_space_over_filemarks_backward(drive, mt_op, mt_count);
- tape->speed_control = speed_control;
- tape->restart_speed_control_req = 1;
- return retval;
- }
- if (tape->chrdev_direction == idetape_direction_read) {
- /*
- * We have a read-ahead buffer. Scan it for crossed
- * filemarks.
- */
- tape->merge_stage_size = 0;
- clear_bit (IDETAPE_FILEMARK, &tape->flags);
- while (tape->first_stage != NULL) {
- idetape_wait_first_stage(drive);
- if (tape->first_stage->rq.errors == IDETAPE_ERROR_FILEMARK)
- count++;
- if (count == mt_count) {
- switch (mt_op) {
- case MTFSF:
- spin_lock_irqsave(&tape->spinlock, flags);
- idetape_remove_stage_head (drive);
- spin_unlock_irqrestore(&tape->spinlock, flags);
- case MTFSFM:
- return (0);
- default:
- break;
- }
- }
- spin_lock_irqsave(&tape->spinlock, flags);
- idetape_remove_stage_head (drive);
- spin_unlock_irqrestore(&tape->spinlock, flags);
- }
- idetape_discard_read_pipeline (drive, 1);
- }
- /*
- * The filemark was not found in our internal pipeline.
- * Now we can issue the space command.
- */
- switch (mt_op) {
- case MTFSF:
- idetape_create_space_cmd (&pc,mt_count-count,IDETAPE_SPACE_OVER_FILEMARK);
- return (idetape_queue_pc_tail (drive, &pc));
- case MTFSFM:
- if (!tape->capabilities.sprev)
- return (-EIO);
- retval = idetape_space_over_filemarks (drive, MTFSF, mt_count-count);
- if (retval) return (retval);
- return (idetape_space_over_filemarks (drive, MTBSF, 1));
- case MTBSF:
- if (!tape->capabilities.sprev)
- return (-EIO);
- idetape_create_space_cmd (&pc,-(mt_count+count),IDETAPE_SPACE_OVER_FILEMARK);
- return (idetape_queue_pc_tail (drive, &pc));
- case MTBSFM:
- if (!tape->capabilities.sprev)
- return (-EIO);
- retval = idetape_space_over_filemarks (drive, MTBSF, mt_count+count);
- if (retval) return (retval);
- return (idetape_space_over_filemarks (drive, MTFSF, 1));
- default:
- printk (KERN_ERR "ide-tape: MTIO operation %d not supportedn",mt_op);
- return (-EIO);
- }
- }
- /*
- * Our character device read / write functions.
- *
- * The tape is optimized to maximize throughput when it is transferring
- * an integral number of the "continuous transfer limit", which is
- * a parameter of the specific tape (26 KB on my particular tape).
- * (32 kB for Onstream)
- *
- * As of version 1.3 of the driver, the character device provides an
- * abstract continuous view of the media - any mix of block sizes (even 1
- * byte) on the same backup/restore procedure is supported. The driver
- * will internally convert the requests to the recommended transfer unit,
- * so that an unmatch between the user's block size to the recommended
- * size will only result in a (slightly) increased driver overhead, but
- * will no longer hit performance.
- * This is not applicable to Onstream.
- */
- static ssize_t idetape_chrdev_read (struct file *file, char *buf,
- size_t count, loff_t *ppos)
- {
- struct inode *inode = file->f_dentry->d_inode;
- ide_drive_t *drive = get_drive_ptr (inode->i_rdev);
- idetape_tape_t *tape = drive->driver_data;
- ssize_t bytes_read,temp, actually_read = 0, rc;
- if (ppos != &file->f_pos) {
- /* "A request was outside the capabilities of the device." */
- return -ENXIO;
- }
- if (tape->onstream && (count != tape->tape_block_size)) {
- printk(KERN_ERR "ide-tape: %s: use %d bytes as block size (%Zd used)n", tape->name, tape->tape_block_size, count);
- return -EINVAL;
- }
- #if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 3)
- printk (KERN_INFO "ide-tape: Reached idetape_chrdev_read, count %Zdn", count);
- #endif /* IDETAPE_DEBUG_LOG */
- if (tape->chrdev_direction != idetape_direction_read) {
- if (test_bit (IDETAPE_DETECT_BS, &tape->flags))
- if (count > tape->tape_block_size && (count % tape->tape_block_size) == 0)
- tape->user_bs_factor = count / tape->tape_block_size;
- }
- if ((rc = idetape_initiate_read(drive, tape->max_stages)) < 0)
- return rc;
- if (count == 0)
- return (0);
- if (tape->merge_stage_size) {
- actually_read = IDE_MIN (tape->merge_stage_size, count);
- idetape_copy_stage_to_user (tape, buf, tape->merge_stage, actually_read);
- buf += actually_read;
- tape->merge_stage_size -= actually_read;
- count -= actually_read;
- }
- while (count >= tape->stage_size) {
- bytes_read = idetape_add_chrdev_read_request (drive, tape->capabilities.ctl);
- if (bytes_read <= 0)
- goto finish;
- idetape_copy_stage_to_user (tape, buf, tape->merge_stage, bytes_read);
- buf += bytes_read;
- count -= bytes_read;
- actually_read += bytes_read;
- }
- if (count) {
- bytes_read=idetape_add_chrdev_read_request (drive, tape->capabilities.ctl);
- if (bytes_read <= 0)
- goto finish;
- temp = IDE_MIN (count, bytes_read);
- idetape_copy_stage_to_user (tape, buf, tape->merge_stage, temp);
- actually_read += temp;
- tape->merge_stage_size = bytes_read-temp;
- }
- finish:
- if (!actually_read && test_bit (IDETAPE_FILEMARK, &tape->flags)) {
- #if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 2)
- printk(KERN_INFO "ide-tape: %s: spacing over filemarkn", tape->name);
- #endif
- idetape_space_over_filemarks (drive, MTFSF, 1);
- return 0;
- }
- if (tape->onstream && !actually_read && test_and_clear_bit(IDETAPE_READ_ERROR, &tape->flags)) {
- printk(KERN_ERR "ide-tape: %s: unrecovered read error on logical block number %d, skippingn",
- tape->name, tape->logical_blk_num);
- tape->logical_blk_num++;
- return -EIO;
- }
- return actually_read;
- }
- static void idetape_update_last_marker (ide_drive_t *drive, int last_mark_addr, int next_mark_addr)
- {
- idetape_tape_t *tape = drive->driver_data;
- idetape_stage_t *stage;
- os_aux_t *aux;
- int position;
- if (!tape->onstream || tape->raw)
- return;
- if (last_mark_addr == -1)
- return;
- stage = __idetape_kmalloc_stage(tape, 0, 0);
- if (stage == NULL)
- return;
- idetape_flush_tape_buffers(drive);
- position = idetape_read_position(drive);
- #if ONSTREAM_DEBUG
- if (tape->debug_level >= 2)
- printk(KERN_INFO "ide-tape: current position (2) %d, lblk %dn", position, tape->logical_blk_num);
- if (tape->debug_level >= 2)
- printk(KERN_INFO "ide-tape: current position (2) tape block %dn", tape->last_frame_position);
- #endif
- idetape_position_tape(drive, last_mark_addr, 0, 0);
- if (!idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, 1, stage->bh)) {
- printk(KERN_INFO "ide-tape: %s: couldn't read last markern", tape->name);
- __idetape_kfree_stage (stage);
- idetape_position_tape(drive, position, 0, 0);
- return;
- }
- aux = stage->aux;
- if (aux->frame_type != OS_FRAME_TYPE_MARKER) {
- printk(KERN_INFO "ide-tape: %s: expected to find marker at addr %dn", tape->name, last_mark_addr);
- __idetape_kfree_stage (stage);
- idetape_position_tape(drive, position, 0, 0);
- return;
- }
- #if ONSTREAM_DEBUG
- if (tape->debug_level >= 2)
- printk(KERN_INFO "ide-tape: writing back markern");
- #endif
- aux->next_mark_addr = htonl(next_mark_addr);
- idetape_position_tape(drive, last_mark_addr, 0, 0);
- if (!idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 1, stage->bh)) {
- printk(KERN_INFO "ide-tape: %s: couldn't write back marker frame at %dn", tape->name, last_mark_addr);
- __idetape_kfree_stage (stage);
- idetape_position_tape(drive, position, 0, 0);
- return;
- }
- __idetape_kfree_stage (stage);
- idetape_flush_tape_buffers (drive);
- idetape_position_tape(drive, position, 0, 0);
- return;
- }
- static void idetape_write_filler (ide_drive_t *drive, int block, int cnt)
- {
- idetape_tape_t *tape = drive->driver_data;
- idetape_stage_t *stage;
- int rc;
- if (!tape->onstream || tape->raw)
- return;
- stage = __idetape_kmalloc_stage(tape, 1, 1);
- if (stage == NULL)
- return;
- idetape_init_stage(drive, stage, OS_FRAME_TYPE_FILL, 0);
- idetape_wait_ready(drive, 60 * 5 * HZ);
- rc = idetape_position_tape(drive, block, 0, 0);
- #if ONSTREAM_DEBUG
- printk(KERN_INFO "write_filler: positioning failed it returned %dn", rc);
- #endif
- if (rc != 0)
- return; /* don't write fillers if we cannot position the tape. */
- strcpy(stage->bh->b_data, "Filler");
- while (cnt--) {
- if (!idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 1, stage->bh)) {
- printk(KERN_INFO "ide-tape: %s: write_filler: couldn't write header framen", tape->name);
- __idetape_kfree_stage (stage);
- return;
- }
- }
- __idetape_kfree_stage (stage);
- }
- static void __idetape_write_header (ide_drive_t *drive, int block, int cnt)
- {
- idetape_tape_t *tape = drive->driver_data;
- idetape_stage_t *stage;
- os_header_t header;
- stage = __idetape_kmalloc_stage(tape, 1, 1);
- if (stage == NULL)
- return;
- idetape_init_stage(drive, stage, OS_FRAME_TYPE_HEADER, tape->logical_blk_num);
- idetape_wait_ready(drive, 60 * 5 * HZ);
- idetape_position_tape(drive, block, 0, 0);
- memset(&header, 0, sizeof(header));
- strcpy(header.ident_str, "ADR_SEQ");
- header.major_rev = 1;
- header.minor_rev = OS_ADR_MINREV;
- header.par_num = 1;
- header.partition.partition_num = OS_DATA_PARTITION;
- header.partition.par_desc_ver = OS_PARTITION_VERSION;
- header.partition.first_frame_addr = htonl(OS_DATA_STARTFRAME1);
- header.partition.last_frame_addr = htonl(tape->capacity);
- header.partition.wrt_pass_cntr = htons(tape->wrt_pass_cntr);
- header.partition.eod_frame_addr = htonl(tape->eod_frame_addr);
- memcpy(stage->bh->b_data, &header, sizeof(header));
- while (cnt--) {
- if (!idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 1, stage->bh)) {
- printk(KERN_INFO "ide-tape: %s: couldn't write header framen", tape->name);
- __idetape_kfree_stage (stage);
- return;
- }
- }
- __idetape_kfree_stage (stage);
- idetape_flush_tape_buffers (drive);
- }
- static void idetape_write_header (ide_drive_t *drive, int locate_eod)
- {
- idetape_tape_t *tape = drive->driver_data;
- #if ONSTREAM_DEBUG
- if (tape->debug_level >= 2)
- printk(KERN_INFO "ide-tape: %s: writing tape headern", tape->name);
- #endif
- if (!tape->onstream || tape->raw)
- return;
- tape->update_frame_cntr++;
- __idetape_write_header(drive, 5, 5);
- __idetape_write_header(drive, 0xbae, 5); /* 2990 */
- if (locate_eod) {
- #if ONSTREAM_DEBUG
- if (tape->debug_level >= 2)
- printk(KERN_INFO "ide-tape: %s: locating back to eod frame addr %dn", tape->name, tape->eod_frame_addr);
- #endif
- idetape_position_tape(drive, tape->eod_frame_addr, 0, 0);
- }
- }
- static ssize_t idetape_chrdev_write (struct file *file, const char *buf,
- size_t count, loff_t *ppos)
- {
- struct inode *inode = file->f_dentry->d_inode;
- ide_drive_t *drive = get_drive_ptr (inode->i_rdev);
- idetape_tape_t *tape = drive->driver_data;
- ssize_t retval, actually_written = 0;
- int position;
- if (ppos != &file->f_pos) {
- /* "A request was outside the capabilities of the device." */
- return -ENXIO;
- }
- #if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 3)
- printk (KERN_INFO "ide-tape: Reached idetape_chrdev_write, count %Zdn", count);
- #endif /* IDETAPE_DEBUG_LOG */
- if (tape->onstream) {
- if (count != tape->tape_block_size) {
- printk(KERN_ERR "ide-tape: %s: chrdev_write: use %d bytes as block size (%Zd used)n",
- tape->name, tape->tape_block_size, count);
- return -EINVAL;
- }
- /*
- * Check if we reach the end of the tape. Just assume the whole pipeline
- * is filled with write requests!
- */
- if (tape->first_frame_position + tape->nr_stages >= tape->capacity - OS_EW) {
- #if ONSTREAM_DEBUG
- printk(KERN_INFO, "chrdev_write: Write truncated at EOM early warning");
- #endif
- if (tape->chrdev_direction == idetape_direction_write)
- idetape_write_release(inode);
- return -ENOSPC;
- }
- }
- if (tape->chrdev_direction != idetape_direction_write) { /* Initialize write operation */
- if (tape->chrdev_direction == idetape_direction_read)
- idetape_discard_read_pipeline (drive, 1);
- #if IDETAPE_DEBUG_BUGS
- if (tape->merge_stage || tape->merge_stage_size) {
- printk (KERN_ERR "ide-tape: merge_stage_size should be 0 nown");
- tape->merge_stage_size = 0;
- }
- #endif /* IDETAPE_DEBUG_BUGS */
- if ((tape->merge_stage = __idetape_kmalloc_stage (tape, 0, 0)) == NULL)
- return -ENOMEM;
- tape->chrdev_direction = idetape_direction_write;
- idetape_init_merge_stage (tape);
- if (tape->onstream) {
- position = idetape_read_position(drive);
- if (position <= OS_DATA_STARTFRAME1) {
- tape->logical_blk_num = 0;
- tape->wrt_pass_cntr++;
- #if ONSTREAM_DEBUG
- if (tape->debug_level >= 2)
- printk(KERN_INFO "ide-tape: %s: logical block num 0, setting eod to %dn", tape->name, OS_DATA_STARTFRAME1);
- if (tape->debug_level >= 2)
- printk(KERN_INFO "ide-tape: %s: allocating new write pass counter %dn", tape->name, tape->wrt_pass_cntr);
- #endif
- tape->filemark_cnt = 0;
- tape->eod_frame_addr = OS_DATA_STARTFRAME1;
- tape->first_mark_addr = tape->last_mark_addr = -1;
- idetape_write_header(drive, 1);
- }
- #if ONSTREAM_DEBUG
- if (tape->debug_level >= 2)
- printk(KERN_INFO "ide-tape: %s: positioning tape to eod at %dn", tape->name, tape->eod_frame_addr);
- #endif
- position = idetape_read_position(drive);
- if (position != tape->eod_frame_addr)
- idetape_position_tape(drive, tape->eod_frame_addr, 0, 0);
- #if ONSTREAM_DEBUG
- if (tape->debug_level >= 2)
- printk(KERN_INFO "ide-tape: %s: first_frame_position %dn", tape->name, tape->first_frame_position);
- #endif
- }
- /*
- * Issue a write 0 command to ensure that DSC handshake
- * is switched from completion mode to buffer available
- * mode.
- */
- retval = idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 0, tape->merge_stage->bh);
- if (retval < 0) {
- kfree (tape->merge_stage);
- tape->merge_stage = NULL;
- tape->chrdev_direction = idetape_direction_none;
- return retval;
- }
- #if ONSTREAM_DEBUG
- if (tape->debug_level >= 2)
- printk("ide-tape: first_frame_position %dn", tape->first_frame_position);
- #endif
- }
- if (count == 0)
- return (0);
- if (tape->restart_speed_control_req)
- idetape_restart_speed_control(drive);
- if (tape->merge_stage_size) {
- #if IDETAPE_DEBUG_BUGS
- if (tape->merge_stage_size >= tape->stage_size) {
- printk (KERN_ERR "ide-tape: bug: merge buffer too bign");
- tape->merge_stage_size = 0;
- }
- #endif /* IDETAPE_DEBUG_BUGS */
- actually_written = IDE_MIN (tape->stage_size - tape->merge_stage_size, count);
- idetape_copy_stage_from_user (tape, tape->merge_stage, buf, actually_written);
- buf += actually_written;
- tape->merge_stage_size += actually_written;
- count -= actually_written;
- if (tape->merge_stage_size == tape->stage_size) {
- tape->merge_stage_size = 0;
- retval = idetape_add_chrdev_write_request (drive, tape->capabilities.ctl);
- if (retval <= 0)
- return (retval);
- }
- }
- while (count >= tape->stage_size) {
- idetape_copy_stage_from_user (tape, tape->merge_stage, buf, tape->stage_size);
- buf += tape->stage_size;
- count -= tape->stage_size;
- retval = idetape_add_chrdev_write_request (drive, tape->capabilities.ctl);
- actually_written += tape->stage_size;
- if (retval <= 0)
- return (retval);
- }
- if (count) {
- actually_written+=count;
- idetape_copy_stage_from_user (tape, tape->merge_stage, buf, count);
- tape->merge_stage_size += count;
- }
- return (actually_written);
- }
- static int idetape_write_filemark (ide_drive_t *drive)
- {
- idetape_tape_t *tape = drive->driver_data;
- int last_mark_addr;
- idetape_pc_t pc;
- if (!tape->onstream) {
- idetape_create_write_filemark_cmd(drive, &pc, 1); /* Write a filemark */
- if (idetape_queue_pc_tail (drive, &pc)) {
- printk (KERN_ERR "ide-tape: Couldn't write a filemarkn");
- return -EIO;
- }
- } else if (!tape->raw) {
- last_mark_addr = idetape_read_position(drive);
- tape->merge_stage = __idetape_kmalloc_stage (tape, 1, 0);
- if (tape->merge_stage != NULL) {
- idetape_init_stage(drive, tape->merge_stage, OS_FRAME_TYPE_MARKER, tape->logical_blk_num);
- idetape_pad_zeros (drive, tape->stage_size);
- tape->logical_blk_num++;
- __idetape_kfree_stage (tape->merge_stage);
- tape->merge_stage = NULL;
- }
- if (tape->filemark_cnt)
- idetape_update_last_marker(drive, tape->last_mark_addr, last_mark_addr);
- tape->last_mark_addr = last_mark_addr;
- if (tape->filemark_cnt++ == 0)
- tape->first_mark_addr = last_mark_addr;
- }
- return 0;
- }
- static void idetape_write_eod (ide_drive_t *drive)
- {
- idetape_tape_t *tape = drive->driver_data;
- if (!tape->onstream || tape->raw)
- return;
- tape->merge_stage = __idetape_kmalloc_stage (tape, 1, 0);
- if (tape->merge_stage != NULL) {
- tape->eod_frame_addr = idetape_read_position(drive);
- idetape_init_stage(drive, tape->merge_stage, OS_FRAME_TYPE_EOD, tape->logical_blk_num);
- idetape_pad_zeros (drive, tape->stage_size);
- __idetape_kfree_stage (tape->merge_stage);
- tape->merge_stage = NULL;
- }
- return;
- }
- int idetape_seek_logical_blk (ide_drive_t *drive, int logical_blk_num)
- {
- idetape_tape_t *tape = drive->driver_data;
- int estimated_address = logical_blk_num + 20;
- int retries = 0;
- int speed_control;
- speed_control = tape->speed_control;
- tape->speed_control = 0;
- if (logical_blk_num < 0)
- logical_blk_num = 0;
- if (idetape_get_logical_blk(drive, logical_blk_num, 10, 1))
- goto ok;
- while (++retries < 10) {
- idetape_discard_read_pipeline(drive, 0);
- idetape_position_tape(drive, estimated_address, 0, 0);
- if (idetape_get_logical_blk(drive, logical_blk_num, 10, 1))
- goto ok;
- if (!idetape_get_logical_blk(drive, -1, 10, 1))
- goto error;
- if (tape->logical_blk_num < logical_blk_num)
- estimated_address += logical_blk_num - tape->logical_blk_num;
- else
- break;
- }
- error:
- tape->speed_control = speed_control;
- tape->restart_speed_control_req = 1;
- printk(KERN_INFO "ide-tape: %s: couldn't seek to logical block %d (at %d), %d retriesn", tape->name, logical_blk_num, tape->logical_blk_num, retries);
- return -EIO;
- ok:
- tape->speed_control = speed_control;
- tape->restart_speed_control_req = 1;
- return 0;
- }
- /*
- * idetape_mtioctop is called from idetape_chrdev_ioctl when
- * the general mtio MTIOCTOP ioctl is requested.
- *
- * We currently support the following mtio.h operations:
- *
- * MTFSF - Space over mt_count filemarks in the positive direction.
- * The tape is positioned after the last spaced filemark.
- *
- * MTFSFM - Same as MTFSF, but the tape is positioned before the
- * last filemark.
- *
- * MTBSF - Steps background over mt_count filemarks, tape is
- * positioned before the last filemark.
- *
- * MTBSFM - Like MTBSF, only tape is positioned after the last filemark.
- *
- * Note:
- *
- * MTBSF and MTBSFM are not supported when the tape doesn't
- * supports 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).
- *
- * MTWEOF - Writes mt_count filemarks. Tape is positioned after
- * the last written filemark.
- *
- * MTREW - Rewinds tape.
- *
- * MTLOAD - Loads the tape.
- *
- * MTOFFL - Puts the tape drive "Offline": Rewinds the tape and
- * MTUNLOAD prevents further access until the media is replaced.
- *
- * MTNOP - Flushes tape buffers.
- *
- * MTRETEN - Retension media. This typically consists of one end
- * to end pass on the media.
- *
- * MTEOM - Moves to the end of recorded data.
- *
- * MTERASE - Erases tape.
- *
- * MTSETBLK - Sets the user block size to mt_count bytes. If
- * mt_count is 0, we will attempt to autodetect
- * the block size.
- *
- * MTSEEK - Positions the tape in a specific block number, where
- * each block is assumed to contain which user_block_size
- * bytes.
- *
- * MTSETPART - Switches to another tape partition.
- *
- * MTLOCK - Locks the tape door.
- *
- * MTUNLOCK - Unlocks the tape door.
- *
- * The following commands are currently not supported:
- *
- * MTFSS, MTBSS, MTWSM, MTSETDENSITY,
- * MTSETDRVBUFFER, MT_ST_BOOLEANS, MT_ST_WRITE_THRESHOLD.
- */
- static int idetape_mtioctop (ide_drive_t *drive,short mt_op,int mt_count)
- {
- idetape_tape_t *tape = drive->driver_data;
- idetape_pc_t pc;
- int i,retval;
- #if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 1)
- printk (KERN_INFO "ide-tape: Handling MTIOCTOP ioctl: mt_op=%d, mt_count=%dn",mt_op,mt_count);
- #endif /* IDETAPE_DEBUG_LOG */
- /*
- * Commands which need our pipelined read-ahead stages.
- */
- switch (mt_op) {
- case MTFSF:
- case MTFSFM:
- case MTBSF:
- case MTBSFM:
- if (!mt_count)
- return (0);
- return (idetape_space_over_filemarks (drive,mt_op,mt_count));
- default:
- break;
- }
- switch (mt_op) {
- case MTWEOF:
- idetape_discard_read_pipeline (drive, 1);
- for (i = 0; i < mt_count; i++) {
- retval = idetape_write_filemark(drive);
- if (retval) return retval;
- }
- return (0);
- case MTREW:
- idetape_discard_read_pipeline (drive, 0);
- if (idetape_rewind_tape(drive))
- return -EIO;
- if (tape->onstream && !tape->raw)
- return idetape_position_tape(drive, OS_DATA_STARTFRAME1, 0, 0);
- return 0;
- case MTLOAD:
- idetape_discard_read_pipeline (drive, 0);
- idetape_create_load_unload_cmd (drive, &pc, IDETAPE_LU_LOAD_MASK);
- return (idetape_queue_pc_tail (drive, &pc));
- case MTUNLOAD:
- case MTOFFL:
- idetape_discard_read_pipeline (drive, 0);
- idetape_create_load_unload_cmd (drive, &pc,!IDETAPE_LU_LOAD_MASK);
- return (idetape_queue_pc_tail (drive, &pc));
- case MTNOP:
- idetape_discard_read_pipeline (drive, 0);
- return (idetape_flush_tape_buffers (drive));
- case MTRETEN:
- idetape_discard_read_pipeline (drive, 0);
- idetape_create_load_unload_cmd (drive, &pc,IDETAPE_LU_RETENSION_MASK | IDETAPE_LU_LOAD_MASK);
- return (idetape_queue_pc_tail (drive, &pc));
- case MTEOM:
- if (tape->onstream) {
- #if ONSTREAM_DEBUG
- if (tape->debug_level >= 2)
- printk(KERN_INFO "ide-tape: %s: positioning tape to eod at %dn", tape->name, tape->eod_frame_addr);
- #endif
- idetape_position_tape(drive, tape->eod_frame_addr, 0, 0);
- if (!idetape_get_logical_blk(drive, -1, 10, 0))
- return -EIO;
- if (tape->first_stage->aux->frame_type != OS_FRAME_TYPE_EOD)
- return -EIO;
- return 0;
- }
- idetape_create_space_cmd (&pc, 0, IDETAPE_SPACE_TO_EOD);
- return (idetape_queue_pc_tail (drive, &pc));
- case MTERASE:
- if (tape->onstream) {
- tape->eod_frame_addr = OS_DATA_STARTFRAME1;
- tape->logical_blk_num = 0;
- tape->first_mark_addr = tape->last_mark_addr = -1;
- idetape_position_tape(drive, tape->eod_frame_addr, 0, 0);
- idetape_write_eod(drive);
- idetape_flush_tape_buffers (drive);
- idetape_write_header(drive, 0);
- /*
- * write filler frames to the unused frames...
- * REMOVE WHEN going to LIN4 application type...
- */
- idetape_write_filler(drive, OS_DATA_STARTFRAME1 - 10, 10);
- idetape_write_filler(drive, OS_DATA_ENDFRAME1, 10);
- idetape_flush_tape_buffers (drive);
- (void) idetape_rewind_tape (drive);
- return 0;
- }
- (void) idetape_rewind_tape (drive);
- idetape_create_erase_cmd (&pc);
- return (idetape_queue_pc_tail (drive, &pc));
- case MTSETBLK:
- if (tape->onstream) {
- if (mt_count != tape->tape_block_size) {
- printk(KERN_INFO "ide-tape: %s: MTSETBLK %d -- only %d bytes block size supportedn", tape->name, mt_count, tape->tape_block_size);
- return -EINVAL;
- }
- return 0;
- }
- if (mt_count) {
- if (mt_count < tape->tape_block_size || mt_count % tape->tape_block_size)
- return -EIO;
- tape->user_bs_factor = mt_count / tape->tape_block_size;
- clear_bit (IDETAPE_DETECT_BS, &tape->flags);
- } else
- set_bit (IDETAPE_DETECT_BS, &tape->flags);
- return 0;
- case MTSEEK:
- if (!tape->onstream || tape->raw) {
- idetape_discard_read_pipeline (drive, 0);
- return idetape_position_tape (drive, mt_count * tape->user_bs_factor, tape->partition, 0);
- }
- return idetape_seek_logical_blk(drive, mt_count);
- case MTSETPART:
- idetape_discard_read_pipeline (drive, 0);
- if (tape->onstream)
- return -EIO;
- return (idetape_position_tape (drive, 0, mt_count, 0));
- case MTFSR:
- case MTBSR:
- if (tape->onstream) {
- if (!idetape_get_logical_blk(drive, -1, 10, 0))
- return -EIO;
- if (mt_op == MTFSR)
- return idetape_seek_logical_blk(drive, tape->logical_blk_num + mt_count);
- else {
- idetape_discard_read_pipeline (drive, 0);
- return idetape_seek_logical_blk(drive, tape->logical_blk_num - mt_count);
- }
- }
- case MTLOCK:
- if (!idetape_create_prevent_cmd(drive, &pc, 1))
- return 0;
- retval = idetape_queue_pc_tail (drive, &pc);
- if (retval) return retval;
- tape->door_locked = DOOR_EXPLICITLY_LOCKED;
- return 0;
- case MTUNLOCK:
- if (!idetape_create_prevent_cmd(drive, &pc, 0))
- return 0;
- retval = idetape_queue_pc_tail (drive, &pc);
- if (retval) return retval;
- tape->door_locked = DOOR_UNLOCKED;
- return 0;
- default:
- printk (KERN_ERR "ide-tape: MTIO operation %d not supportedn",mt_op);
- return (-EIO);
- }
- }
- /*
- * Our character device ioctls.
- *
- * General mtio.h magnetic io commands are supported here, and not in
- * the corresponding block interface.
- *
- * The following ioctls are supported:
- *
- * MTIOCTOP - Refer to idetape_mtioctop for detailed description.
- *
- * MTIOCGET - The mt_dsreg field in the returned mtget structure
- * will be set to (user block size in bytes <<
- * MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK.
- *
- * The mt_blkno is set to the current user block number.
- * The other mtget fields are not supported.
- *
- * MTIOCPOS - The current tape "block position" is returned. We
- * assume that each block contains user_block_size
- * bytes.
- *
- * Our own ide-tape ioctls are supported on both interfaces.
- */
- static int idetape_chrdev_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
- {
- ide_drive_t *drive = get_drive_ptr (inode->i_rdev);
- idetape_tape_t *tape = drive->driver_data;
- struct mtop mtop;
- struct mtget mtget;
- struct mtpos mtpos;
- int block_offset = 0, position = tape->first_frame_position;
- #if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 3)
- printk (KERN_INFO "ide-tape: Reached idetape_chrdev_ioctl, cmd=%un",cmd);
- #endif /* IDETAPE_DEBUG_LOG */
- tape->restart_speed_control_req = 1;
- if (tape->chrdev_direction == idetape_direction_write) {
- idetape_empty_write_pipeline (drive);
- idetape_flush_tape_buffers (drive);
- }
- if (cmd == MTIOCGET || cmd == MTIOCPOS) {
- block_offset = idetape_pipeline_size (drive) / (tape->tape_block_size * tape->user_bs_factor);
- if ((position = idetape_read_position(drive)) < 0)
- return -EIO;
- }
- switch (cmd) {
- case MTIOCTOP:
- if (copy_from_user ((char *) &mtop, (char *) arg, sizeof (struct mtop)))
- return -EFAULT;
- return (idetape_mtioctop (drive,mtop.mt_op,mtop.mt_count));
- case MTIOCGET:
- memset (&mtget, 0, sizeof (struct mtget));
- mtget.mt_type = MT_ISSCSI2;
- if (!tape->onstream || tape->raw)
- mtget.mt_blkno = position / tape->user_bs_factor - block_offset;
- else {
- if (!idetape_get_logical_blk(drive, -1, 10, 0))
- mtget.mt_blkno = -1;
- else
- mtget.mt_blkno = tape->logical_blk_num;
- }
- mtget.mt_dsreg = ((tape->tape_block_size * tape->user_bs_factor) << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK;
- if (tape->onstream) {
- mtget.mt_gstat |= GMT_ONLINE(0xffffffff);
- if (tape->first_stage && tape->first_stage->aux->frame_type == OS_FRAME_TYPE_EOD)
- mtget.mt_gstat |= GMT_EOD(0xffffffff);
- if (position <= OS_DATA_STARTFRAME1)
- mtget.mt_gstat |= GMT_BOT(0xffffffff);
- }
- if (copy_to_user ((char *) arg,(char *) &mtget, sizeof (struct mtget)))
- return -EFAULT;
- return 0;
- case MTIOCPOS:
- if (tape->onstream && !tape->raw) {
- if (!idetape_get_logical_blk(drive, -1, 10, 0))
- return -EIO;
- mtpos.mt_blkno = tape->logical_blk_num;
- } else
- mtpos.mt_blkno = position / tape->user_bs_factor - block_offset;
- if (copy_to_user ((char *) arg,(char *) &mtpos, sizeof (struct mtpos)))
- return -EFAULT;
- return 0;
- default:
- if (tape->chrdev_direction == idetape_direction_read)
- idetape_discard_read_pipeline (drive, 1);
- return (idetape_blkdev_ioctl (drive,inode,file,cmd,arg));
- }
- }
- static int __idetape_analyze_headers (ide_drive_t *drive, int block)
- {
- idetape_tape_t *tape = drive->driver_data;
- idetape_stage_t *stage;
- os_header_t *header;
- os_aux_t *aux;
- if (!tape->onstream || tape->raw) {
- tape->header_ok = tape->linux_media = 1;
- return 1;
- }
- tape->header_ok = tape->linux_media = 0;
- tape->update_frame_cntr = 0;
- tape->wrt_pass_cntr = 0;
- tape->eod_frame_addr = OS_DATA_STARTFRAME1;
- tape->first_mark_addr = tape->last_mark_addr = -1;
- stage = __idetape_kmalloc_stage (tape, 0, 0);
- if (stage == NULL)
- return 0;
- #if ONSTREAM_DEBUG
- if (tape->debug_level >= 2)
- printk(KERN_INFO "ide-tape: %s: reading headern", tape->name);
- #endif
- idetape_position_tape(drive, block, 0, 0);
- if (!idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, 1, stage->bh)) {
- printk(KERN_INFO "ide-tape: %s: couldn't read header framen", tape->name);
- __idetape_kfree_stage (stage);
- return 0;
- }
- header = (os_header_t *) stage->bh->b_data;
- aux = stage->aux;
- if (strncmp(header->ident_str, "ADR_SEQ", 7) != 0) {
- printk(KERN_INFO "ide-tape: %s: invalid header identification stringn", tape->name);
- __idetape_kfree_stage (stage);
- return 0;
- }
- if (header->major_rev != 1 || (header->minor_rev > OS_ADR_MINREV))
- printk(KERN_INFO "ide-tape: warning: revision %d.%d detected (up to 1.%d supported)n", header->major_rev, header->minor_rev, OS_ADR_MINREV);
- if (header->par_num != 1)
- printk(KERN_INFO "ide-tape: warning: %d partitions defined, only one supportedn", header->par_num);
- tape->wrt_pass_cntr = ntohs(header->partition.wrt_pass_cntr);
- tape->eod_frame_addr = ntohl(header->partition.eod_frame_addr);
- tape->filemark_cnt = ntohl(aux->filemark_cnt);
- tape->first_mark_addr = ntohl(aux->next_mark_addr);
- tape->last_mark_addr = ntohl(aux->last_mark_addr);
- tape->update_frame_cntr = ntohl(aux->update_frame_cntr);
- memcpy(tape->application_sig, aux->application_sig, 4);
- tape->application_sig[4] = 0;
- if (memcmp(tape->application_sig, "LIN", 3) == 0) {
- tape->linux_media = 1;
- tape->linux_media_version = tape->application_sig[3] - '0';
- if (tape->linux_media_version != 3)
- printk(KERN_INFO "ide-tape: %s: Linux media version %d detected (current 3)n",
- tape->name, tape->linux_media_version);
- } else {
- printk(KERN_INFO "ide-tape: %s: non Linux media detected (%s)n", tape->name, tape->application_sig);
- tape->linux_media = 0;
- }
- #if ONSTREAM_DEBUG
- if (tape->debug_level >= 2)
- printk(KERN_INFO "ide-tape: %s: detected write pass counter %d, eod frame addr %dn", tape->name, tape->wrt_pass_cntr, tape->eod_frame_addr);
- #endif
- __idetape_kfree_stage (stage);
- return 1;
- }
- static int idetape_analyze_headers (ide_drive_t *drive)
- {
- idetape_tape_t *tape = drive->driver_data;
- int position, block;
- if (!tape->onstream || tape->raw) {
- tape->header_ok = tape->linux_media = 1;
- return 1;
- }
- tape->header_ok = tape->linux_media = 0;
- position = idetape_read_position(drive);
- for (block = 5; block < 10; block++)
- if (__idetape_analyze_headers(drive, block))
- goto ok;
- for (block = 0xbae; block < 0xbb3; block++) /* 2990 - 2994 */
- if (__idetape_analyze_headers(drive, block))
- goto ok;
- printk(KERN_ERR "ide-tape: %s: failed to find valid ADRL headern", tape->name);
- return 0;
- ok:
- if (position < OS_DATA_STARTFRAME1)
- position = OS_DATA_STARTFRAME1;
- idetape_position_tape(drive, position, 0, 0);
- tape->header_ok = 1;
- return 1;
- }
- /*
- * Our character device open function.
- */
- static int idetape_chrdev_open (struct inode *inode, struct file *filp)
- {
- ide_drive_t *drive;
- idetape_tape_t *tape;
- idetape_pc_t pc;
- unsigned int minor=MINOR (inode->i_rdev);
-
- #if IDETAPE_DEBUG_LOG
- printk (KERN_INFO "ide-tape: Reached idetape_chrdev_openn");
- #endif /* IDETAPE_DEBUG_LOG */
-
- if ((drive = get_drive_ptr (inode->i_rdev)) == NULL)
- return -ENXIO;
- tape = drive->driver_data;
- if (test_and_set_bit (IDETAPE_BUSY, &tape->flags))
- return -EBUSY;
- MOD_INC_USE_COUNT;
- if (!tape->onstream) {
- idetape_read_position(drive);
- if (!test_bit (IDETAPE_ADDRESS_VALID, &tape->flags))
- (void) idetape_rewind_tape (drive);
- } else {
- if (minor & 64) {
- tape->tape_block_size = tape->stage_size = 32768 + 512;
- tape->raw = 1;
- } else {
- tape->tape_block_size = tape->stage_size = 32768;
- tape->raw = 0;
- }
- idetape_onstream_mode_sense_tape_parameter_page(drive, tape->debug_level);
- }
- if (idetape_wait_ready(drive, 60 * HZ)) {
- clear_bit(IDETAPE_BUSY, &tape->flags);
- printk(KERN_ERR "ide-tape: %s: drive not readyn", tape->name);
- MOD_DEC_USE_COUNT;
- return -EBUSY;
- }
- idetape_read_position(drive);
- MOD_DEC_USE_COUNT;
- clear_bit (IDETAPE_PIPELINE_ERROR, &tape->flags);
- if (tape->chrdev_direction == idetape_direction_none) {
- MOD_INC_USE_COUNT;
- if (idetape_create_prevent_cmd(drive, &pc, 1)) {
- if (!idetape_queue_pc_tail (drive, &pc)) {
- if (tape->door_locked != DOOR_EXPLICITLY_LOCKED)
- tape->door_locked = DOOR_LOCKED;
- }
- }
- idetape_analyze_headers(drive);
- }
- tape->max_frames = tape->cur_frames = tape->req_buffer_fill = 0;
- idetape_restart_speed_control(drive);
- tape->restart_speed_control_req = 0;
- return 0;
- }
- static void idetape_write_release (struct inode *inode)
- {
- ide_drive_t *drive = get_drive_ptr (inode->i_rdev);
- idetape_tape_t *tape = drive->driver_data;
- unsigned int minor=MINOR (inode->i_rdev);
- idetape_empty_write_pipeline (drive);
- tape->merge_stage = __idetape_kmalloc_stage (tape, 1, 0);
- if (tape->merge_stage != NULL) {
- idetape_pad_zeros (drive, tape->tape_block_size * (tape->user_bs_factor - 1));
- __idetape_kfree_stage (tape->merge_stage);
- tape->merge_stage = NULL;
- }
- idetape_write_filemark(drive);
- idetape_write_eod(drive);
- idetape_flush_tape_buffers (drive);
- idetape_write_header(drive, minor >= 128);
- idetape_flush_tape_buffers (drive);
- return;
- }
- /*
- * Our character device release function.
- */
- static int idetape_chrdev_release (struct inode *inode, struct file *filp)
- {
- ide_drive_t *drive = get_drive_ptr (inode->i_rdev);
- idetape_tape_t *tape;
- idetape_pc_t pc;
- unsigned int minor=MINOR (inode->i_rdev);
- lock_kernel();
- tape = drive->driver_data;
- #if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 3)
- printk (KERN_INFO "ide-tape: Reached idetape_chrdev_releasen");
- #endif /* IDETAPE_DEBUG_LOG */
- if (tape->chrdev_direction == idetape_direction_write) {
- idetape_write_release(inode);
- }
- if (tape->chrdev_direction == idetape_direction_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;
- }
- if (minor < 128)
- (void) idetape_rewind_tape (drive);
- if (tape->chrdev_direction == idetape_direction_none) {
- if (tape->door_locked != DOOR_EXPLICITLY_LOCKED) {
- if (idetape_create_prevent_cmd(drive, &pc, 0))
- if (!idetape_queue_pc_tail (drive, &pc))
- tape->door_locked = DOOR_UNLOCKED;
- }
- MOD_DEC_USE_COUNT;
- }
- clear_bit (IDETAPE_BUSY, &tape->flags);
- unlock_kernel();
- return 0;
- }
- /*
- * idetape_identify_device is called to check the contents of the
- * ATAPI IDENTIFY command results. We return:
- *
- * 1 If the tape can be supported by us, based on the information
- * we have so far.
- *
- * 0 If this tape driver is not currently supported by us.
- */
- static int idetape_identify_device (ide_drive_t *drive,struct hd_driveid *id)
- {
- struct idetape_id_gcw gcw;
- #if IDETAPE_DEBUG_INFO
- unsigned short mask,i;
- #endif /* IDETAPE_DEBUG_INFO */
- if (!id)
- return 0;
- *((unsigned short *) &gcw) = id->config;
- #if IDETAPE_DEBUG_INFO
- printk (KERN_INFO "ide-tape: Dumping ATAPI Identify Device tape parametersn");
- printk (KERN_INFO "ide-tape: Protocol Type: ");
- switch (gcw.protocol) {
- case 0: case 1: printk (KERN_INFO "ATAn");break;
- case 2: printk (KERN_INFO "ATAPIn");break;
- case 3: printk (KERN_INFO "Reserved (Unknown to ide-tape)n");break;
- }
- printk (KERN_INFO "ide-tape: Device Type: %x - ",gcw.device_type);
- switch (gcw.device_type) {
- case 0: printk (KERN_INFO "Direct-access Devicen");break;
- case 1: printk (KERN_INFO "Streaming Tape Devicen");break;
- case 2: case 3: case 4: printk (KERN_INFO "Reservedn");break;
- case 5: printk (KERN_INFO "CD-ROM Devicen");break;
- case 6: printk (KERN_INFO "Reservedn");
- case 7: printk (KERN_INFO "Optical memory Devicen");break;
- case 0x1f: printk (KERN_INFO "Unknown or no Device typen");break;
- default: printk (KERN_INFO "Reservedn");
- }
- printk (KERN_INFO "ide-tape: Removable: %s",gcw.removable ? "Yesn":"Non");
- printk (KERN_INFO "ide-tape: Command Packet DRQ Type: ");
- switch (gcw.drq_type) {
- case 0: printk (KERN_INFO "Microprocessor DRQn");break;
- case 1: printk (KERN_INFO "Interrupt DRQn");break;
- case 2: printk (KERN_INFO "Accelerated DRQn");break;
- case 3: printk (KERN_INFO "Reservedn");break;
- }
- printk (KERN_INFO "ide-tape: Command Packet Size: ");
- switch (gcw.packet_size) {
- case 0: printk (KERN_INFO "12 bytesn");break;
- case 1: printk (KERN_INFO "16 bytesn");break;
- default: printk (KERN_INFO "Reservedn");break;
- }
- printk (KERN_INFO "ide-tape: Model: %.40sn",id->model);
- printk (KERN_INFO "ide-tape: Firmware Revision: %.8sn",id->fw_rev);
- printk (KERN_INFO "ide-tape: Serial Number: %.20sn",id->serial_no);
- printk (KERN_INFO "ide-tape: Write buffer size: %d bytesn",id->buf_size*512);
- printk (KERN_INFO "ide-tape: DMA: %s",id->capability & 0x01 ? "Yesn":"Non");
- printk (KERN_INFO "ide-tape: LBA: %s",id->capability & 0x02 ? "Yesn":"Non");
- printk (KERN_INFO "ide-tape: IORDY can be disabled: %s",id->capability & 0x04 ? "Yesn":"Non");
- printk (KERN_INFO "ide-tape: IORDY supported: %s",id->capability & 0x08 ? "Yesn":"Unknownn");
- printk (KERN_INFO "ide-tape: ATAPI overlap supported: %s",id->capability & 0x20 ? "Yesn":"Non");
- printk (KERN_INFO "ide-tape: PIO Cycle Timing Category: %dn",id->tPIO);
- printk (KERN_INFO "ide-tape: DMA Cycle Timing Category: %dn",id->tDMA);
- printk (KERN_INFO "ide-tape: Single Word DMA supported modes: ");
- for (i=0,mask=1;i<8;i++,mask=mask << 1) {
- if (id->dma_1word & mask)
- printk (KERN_INFO "%d ",i);
- if (id->dma_1word & (mask << 8))
- printk (KERN_INFO "(active) ");
- }
- printk (KERN_INFO "n");
- printk (KERN_INFO "ide-tape: Multi Word DMA supported modes: ");
- for (i=0,mask=1;i<8;i++,mask=mask << 1) {
- if (id->dma_mword & mask)
- printk (KERN_INFO "%d ",i);
- if (id->dma_mword & (mask << 8))
- printk (KERN_INFO "(active) ");
- }
- printk (KERN_INFO "n");
- if (id->field_valid & 0x0002) {
- printk (KERN_INFO "ide-tape: Enhanced PIO Modes: %sn",id->eide_pio_modes & 1 ? "Mode 3":"None");
- printk (KERN_INFO "ide-tape: Minimum Multi-word DMA cycle per word: ");
- if (id->eide_dma_min == 0)
- printk (KERN_INFO "Not supportedn");
- else
- printk (KERN_INFO "%d nsn",id->eide_dma_min);
- printk (KERN_INFO "ide-tape: Manufacturer's Recommended Multi-word cycle: ");
- if (id->eide_dma_time == 0)
- printk (KERN_INFO "Not supportedn");
- else
- printk (KERN_INFO "%d nsn",id->eide_dma_time);
- printk (KERN_INFO "ide-tape: Minimum PIO cycle without IORDY: ");
- if (id->eide_pio == 0)
- printk (KERN_INFO "Not supportedn");
- else
- printk (KERN_INFO "%d nsn",id->eide_pio);
- printk (KERN_INFO "ide-tape: Minimum PIO cycle with IORDY: ");
- if (id->eide_pio_iordy == 0)
- printk (KERN_INFO "Not supportedn");
- else
- printk (KERN_INFO "%d nsn",id->eide_pio_iordy);
-
- } else
- printk (KERN_INFO "ide-tape: According to the device, fields 64-70 are not valid.n");
- #endif /* IDETAPE_DEBUG_INFO */
- /* Check that we can support this device */
- if (gcw.protocol !=2 )
- printk (KERN_ERR "ide-tape: Protocol is not ATAPIn");
- else if (gcw.device_type != 1)
- printk (KERN_ERR "ide-tape: Device type is not set to tapen");
- else if (!gcw.removable)
- printk (KERN_ERR "ide-tape: The removable flag is not setn");
- else if (gcw.packet_size != 0) {
- printk (KERN_ERR "ide-tape: Packet size is not 12 bytes longn");
- if (gcw.packet_size == 1)
- printk (KERN_ERR "ide-tape: Sorry, padding to 16 bytes is still not supportedn");
- } else
- return 1;
- return 0;
- }
- /*
- * Notify vendor ID to the OnStream tape drive
- */
- static void idetape_onstream_set_vendor (ide_drive_t *drive, char *vendor)
- {
- idetape_pc_t pc;
- idetape_mode_parameter_header_t *header;
- idetape_create_mode_select_cmd(&pc, sizeof(*header) + 8);
- pc.buffer[0] = 3 + 8; /* Mode Data Length */
- pc.buffer[1] = 0; /* Medium Type - ignoring */
- pc.buffer[2] = 0; /* Reserved */
- pc.buffer[3] = 0; /* Block Descriptor Length */
- pc.buffer[4 + 0] = 0x36 | (1 << 7);
- pc.buffer[4 + 1] = 6;
- pc.buffer[4 + 2] = vendor[0];
- pc.buffer[4 + 3] = vendor[1];
- pc.buffer[4 + 4] = vendor[2];
- pc.buffer[4 + 5] = vendor[3];
- pc.buffer[4 + 6] = 0;
- pc.buffer[4 + 7] = 0;
- if (idetape_queue_pc_tail (drive, &pc))
- printk (KERN_ERR "ide-tape: Couldn't set vendor name to %sn", vendor);
- }
- /*
- * Various unused OnStream commands
- */
- #if ONSTREAM_DEBUG
- static void idetape_onstream_set_retries (ide_drive_t *drive, int retries)
- {
- idetape_pc_t pc;
- idetape_create_mode_select_cmd(&pc, sizeof(idetape_mode_parameter_header_t) + 4);
- pc.buffer[0] = 3 + 4;
- pc.buffer[1] = 0; /* Medium Type - ignoring */
- pc.buffer[2] = 0; /* Reserved */
- pc.buffer[3] = 0; /* Block Descriptor Length */
- pc.buffer[4 + 0] = 0x2f | (1 << 7);
- pc.buffer[4 + 1] = 2;
- pc.buffer[4 + 2] = 4;
- pc.buffer[4 + 3] = retries;
- if (idetape_queue_pc_tail (drive, &pc))
- printk (KERN_ERR "ide-tape: Couldn't set retries to %dn", retries);
- }
- #endif
- /*
- * Configure 32.5KB block size.
- */
- static void idetape_onstream_configure_block_size (ide_drive_t *drive)
- {
- idetape_pc_t pc;
- idetape_mode_parameter_header_t *header;
- idetape_block_size_page_t *bs;
- /*
- * Get the current block size from the block size mode page
- */
- idetape_create_mode_sense_cmd (&pc, IDETAPE_BLOCK_SIZE_PAGE);
- if (idetape_queue_pc_tail (drive, &pc))
- printk (KERN_ERR "ide-tape: can't get tape block size mode pagen");
- header = (idetape_mode_parameter_header_t *) pc.buffer;
- bs = (idetape_block_size_page_t *) (pc.buffer + sizeof(idetape_mode_parameter_header_t) + header->bdl);
- #if IDETAPE_DEBUG_INFO
- printk(KERN_INFO "ide-tape: 32KB play back: %sn", bs->play32 ? "Yes" : "No");
- printk(KERN_INFO "ide-tape: 32.5KB play back: %sn", bs->play32_5 ? "Yes" : "No");
- printk(KERN_INFO "ide-tape: 32KB record: %sn", bs->record32 ? "Yes" : "No");
- printk(KERN_INFO "ide-tape: 32.5KB record: %sn", bs->record32_5 ? "Yes" : "No");
- #endif /* IDETAPE_DEBUG_INFO */
- /*
- * Configure default auto columns mode, 32.5KB block size
- */
- bs->one = 1;
- bs->play32 = 0;
- bs->play32_5 = 1;
- bs->record32 = 0;
- bs->record32_5 = 1;
- idetape_create_mode_select_cmd(&pc, sizeof(*header) + sizeof(*bs));
- if (idetape_queue_pc_tail (drive, &pc))
- printk (KERN_ERR "ide-tape: Couldn't set tape block size mode pagen");
- #if ONSTREAM_DEBUG
- /*
- * In debug mode, we want to see as many errors as possible
- * to test the error recovery mechanism.
- */
- idetape_onstream_set_retries(drive, 0);
- #endif
- }
- /*
- * Use INQUIRY to get the firmware revision
- */
- static void idetape_get_inquiry_results (ide_drive_t *drive)
- {
- char *r;
- idetape_tape_t *tape = drive->driver_data;
- idetape_pc_t pc;
- idetape_inquiry_result_t *inquiry;
-
- idetape_create_inquiry_cmd(&pc);
- if (idetape_queue_pc_tail (drive, &pc)) {
- printk (KERN_ERR "ide-tape: %s: can't get INQUIRY resultsn", tape->name);
- return;
- }
- inquiry = (idetape_inquiry_result_t *) pc.buffer;
- memcpy(tape->vendor_id, inquiry->vendor_id, 8);
- memcpy(tape->product_id, inquiry->product_id, 16);
- memcpy(tape->firmware_revision, inquiry->revision_level, 4);
- ide_fixstring(tape->vendor_id, 10, 0);
- ide_fixstring(tape->product_id, 18, 0);
- ide_fixstring(tape->firmware_revision, 6, 0);
- r = tape->firmware_revision;
- if (*(r + 1) == '.')
- tape->firmware_revision_num = (*r - '0') * 100 + (*(r + 2) - '0') * 10 + *(r + 3) - '0';
- else if (tape->onstream)
- tape->firmware_revision_num = (*r - '0') * 100 + (*(r + 1) - '0') * 10 + *(r + 2) - '0';
- printk(KERN_INFO "ide-tape: %s <-> %s: %s %s rev %sn", drive->name, tape->name, tape->vendor_id, tape->product_id, tape->firmware_revision);
- }
- /*
- * Configure the OnStream ATAPI tape drive for default operation
- */
- static void idetape_configure_onstream (ide_drive_t *drive)
- {
- idetape_tape_t *tape = drive->driver_data;
- if (tape->firmware_revision_num < 105) {
- printk(KERN_INFO "ide-tape: %s: Old OnStream firmware revision detected (%s)n", tape->name, tape->firmware_revision);
- printk(KERN_INFO "ide-tape: %s: An upgrade to version 1.05 or above is recommendedn", tape->name);
- }
- /*
- * Configure 32.5KB (data+aux) block size.
- */
- idetape_onstream_configure_block_size(drive);
- /*
- * Set vendor name to 'LIN3' for "Linux support version 3".
- */
- idetape_onstream_set_vendor(drive, "LIN3");
- }
- /*
- * idetape_get_mode_sense_parameters asks the tape about its various
- * parameters. This may work for other drives to???
- */
- static void idetape_onstream_mode_sense_tape_parameter_page(ide_drive_t *drive, int debug)
- {
- idetape_tape_t *tape = drive->driver_data;
- idetape_pc_t pc;
- idetape_mode_parameter_header_t *header;
- onstream_tape_paramtr_page_t *prm;
-
- idetape_create_mode_sense_cmd (&pc, IDETAPE_PARAMTR_PAGE);
- if (idetape_queue_pc_tail (drive, &pc)) {
- printk (KERN_ERR "ide-tape: Can't get tape parameters page - probably no tape inserted in onstream driven");
- return;
- }
- header = (idetape_mode_parameter_header_t *) pc.buffer;
- prm = (onstream_tape_paramtr_page_t *) (pc.buffer + sizeof(idetape_mode_parameter_header_t) + header->bdl);
- tape->capacity = ntohs(prm->segtrk) * ntohs(prm->trks);
- if (debug) {
- printk (KERN_INFO "ide-tape: %s <-> %s: Tape length %dMB (%d frames/track, %d tracks = %d blocks, density: %dKbpi)n",
- drive->name, tape->name, tape->capacity/32, ntohs(prm->segtrk), ntohs(prm->trks), tape->capacity, prm->density);
- }
- return;
- }
- /*
- * idetape_get_mode_sense_results asks the tape about its various
- * parameters. In particular, we will adjust our data transfer buffer
- * size to the recommended value as returned by the tape.
- */
- static void idetape_get_mode_sense_results (ide_drive_t *drive)
- {
- idetape_tape_t *tape = drive->driver_data;
- idetape_pc_t pc;
- idetape_mode_parameter_header_t *header;
- idetape_capabilities_page_t *capabilities;
-
- idetape_create_mode_sense_cmd (&pc, IDETAPE_CAPABILITIES_PAGE);
- if (idetape_queue_pc_tail (drive, &pc)) {
- printk (KERN_ERR "ide-tape: Can't get tape parameters - assuming some default valuesn");
- tape->tape_block_size = 512; tape->capabilities.ctl = 52;
- tape->capabilities.speed = 450; tape->capabilities.buffer_size = 6 * 52;
- return;
- }
- header = (idetape_mode_parameter_header_t *) pc.buffer;
- capabilities = (idetape_capabilities_page_t *) (pc.buffer + sizeof(idetape_mode_parameter_header_t) + header->bdl);
- capabilities->max_speed = ntohs (capabilities->max_speed);
- capabilities->ctl = ntohs (capabilities->ctl);
- capabilities->speed = ntohs (capabilities->speed);
- capabilities->buffer_size = ntohs (capabilities->buffer_size);
- if (!capabilities->speed) {
- printk(KERN_INFO "ide-tape: %s: overriding capabilities->speed (assuming 650KB/sec)n", drive->name);
- capabilities->speed = 650;
- }
- if (!capabilities->max_speed) {
- printk(KERN_INFO "ide-tape: %s: overriding capabilities->max_speed (assuming 650KB/sec)n", drive->name);
- capabilities->max_speed = 650;
- }
- tape->capabilities = *capabilities; /* Save us a copy */
- if (capabilities->blk512)
- tape->tape_block_size = 512;
- else if (capabilities->blk1024)
- tape->tape_block_size = 1024;
- else if (tape->onstream && capabilities->blk32768)
- tape->tape_block_size = 32768;
- #if IDETAPE_DEBUG_INFO
- printk (KERN_INFO "ide-tape: Dumping the results of the MODE SENSE packet commandn");
- printk (KERN_INFO "ide-tape: Mode Parameter Header:n");
- printk (KERN_INFO "ide-tape: Mode Data Length - %dn",header->mode_data_length);
- printk (KERN_INFO "ide-tape: Medium Type - %dn",header->medium_type);
- printk (KERN_INFO "ide-tape: Device Specific Parameter - %dn",header->dsp);
- printk (KERN_INFO "ide-tape: Block Descriptor Length - %dn",header->bdl);
-
- printk (KERN_INFO "ide-tape: Capabilities and Mechanical Status Page:n");
- printk (KERN_INFO "ide-tape: Page code - %dn",capabilities->page_code);
- printk (KERN_INFO "ide-tape: Page length - %dn",capabilities->page_length);
- printk (KERN_INFO "ide-tape: Read only - %sn",capabilities->ro ? "Yes":"No");
- printk (KERN_INFO "ide-tape: Supports reverse space - %sn",capabilities->sprev ? "Yes":"No");
- printk (KERN_INFO "ide-tape: Supports erase initiated formatting - %sn",capabilities->efmt ? "Yes":"No");
- printk (KERN_INFO "ide-tape: Supports QFA two Partition format - %sn",capabilities->qfa ? "Yes":"No");
- printk (KERN_INFO "ide-tape: Supports locking the medium - %sn",capabilities->lock ? "Yes":"No");
- printk (KERN_INFO "ide-tape: The volume is currently locked - %sn",capabilities->locked ? "Yes":"No");
- printk (KERN_INFO "ide-tape: The device defaults in the prevent state - %sn",capabilities->prevent ? "Yes":"No");
- printk (KERN_INFO "ide-tape: Supports ejecting the medium - %sn",capabilities->eject ? "Yes":"No");
- printk (KERN_INFO "ide-tape: Supports error correction - %sn",capabilities->ecc ? "Yes":"No");
- printk (KERN_INFO "ide-tape: Supports data compression - %sn",capabilities->cmprs ? "Yes":"No");
- printk (KERN_INFO "ide-tape: Supports 512 bytes block size - %sn",capabilities->blk512 ? "Yes":"No");
- printk (KERN_INFO "ide-tape: Supports 1024 bytes block size - %sn",capabilities->blk1024 ? "Yes":"No");
- printk (KERN_INFO "ide-tape: Supports 32768 bytes block size / Restricted byte count for PIO transfers - %sn",capabilities->blk32768 ? "Yes":"No");
- printk (KERN_INFO "ide-tape: Maximum supported speed in KBps - %dn",capabilities->max_speed);
- printk (KERN_INFO "ide-tape: Continuous transfer limits in blocks - %dn",capabilities->ctl);
- printk (KERN_INFO "ide-tape: Current speed in KBps - %dn",capabilities->speed);
- printk (KERN_INFO "ide-tape: Buffer size - %dn",capabilities->buffer_size*512);
- #endif /* IDETAPE_DEBUG_INFO */
- }
- /*
- * ide_get_blocksize_from_block_descriptor does a mode sense page 0 with block descriptor
- * and if it succeeds sets the tape block size with the reported value
- */
- static void idetape_get_blocksize_from_block_descriptor(ide_drive_t *drive)
- {
- idetape_tape_t *tape = drive->driver_data;
- idetape_pc_t pc;
- idetape_mode_parameter_header_t *header;
- idetape_parameter_block_descriptor_t *block_descrp;
-
- idetape_create_mode_sense_cmd (&pc, IDETAPE_BLOCK_DESCRIPTOR);
- if (idetape_queue_pc_tail (drive, &pc)) {
- printk (KERN_ERR "ide-tape: Can't get block descriptorn");
- if (tape->tape_block_size == 0) {
- printk(KERN_WARNING "ide-tape: Cannot deal with zero block size, assume 32kn");
- tape->tape_block_size = 32768;
- }
- return;
- }
- header = (idetape_mode_parameter_header_t *) pc.buffer;
- block_descrp = (idetape_parameter_block_descriptor_t *) (pc.buffer + sizeof(idetape_mode_parameter_header_t));
- tape->tape_block_size =( block_descrp->length[0]<<16) + (block_descrp->length[1]<<8) + block_descrp->length[2];
- #if IDETAPE_DEBUG_INFO
- printk (KERN_INFO "ide-tape: Adjusted block size - %dn", tape->tape_block_size);
- #endif /* IDETAPE_DEBUG_INFO */
- }
- static void idetape_add_settings (ide_drive_t *drive)
- {
- idetape_tape_t *tape = drive->driver_data;
- /*
- * drive setting name read/write ioctl ioctl data type min max mul_factor div_factor data pointer set function
- */
- ide_add_setting(drive, "buffer", SETTING_READ, -1, -1, TYPE_SHORT, 0, 0xffff, 1, 2, &tape->capabilities.buffer_size, NULL);
- ide_add_setting(drive, "pipeline_min", SETTING_RW, -1, -1, TYPE_INT, 2, 0xffff, tape->stage_size / 1024, 1, &tape->min_pipeline, NULL);
- ide_add_setting(drive, "pipeline", SETTING_RW, -1, -1, TYPE_INT, 2, 0xffff, tape->stage_size / 1024, 1, &tape->max_stages, NULL);
- ide_add_setting(drive, "pipeline_max", SETTING_RW, -1, -1, TYPE_INT, 2, 0xffff, tape->stage_size / 1024, 1, &tape->max_pipeline, NULL);
- ide_add_setting(drive, "pipeline_used",SETTING_READ, -1, -1, TYPE_INT, 0, 0xffff, tape->stage_size / 1024, 1, &tape->nr_stages, NULL);
- ide_add_setting(drive, "pipeline_pending",SETTING_READ,-1, -1, TYPE_INT, 0, 0xffff, tape->stage_size / 1024, 1, &tape->nr_pending_stages, NULL);
- ide_add_setting(drive, "speed", SETTING_READ, -1, -1, TYPE_SHORT, 0, 0xffff, 1, 1, &tape->capabilities.speed, NULL);
- ide_add_setting(drive, "stage", SETTING_READ, -1, -1, TYPE_INT, 0, 0xffff, 1, 1024, &tape->stage_size, NULL);
- ide_add_setting(drive, "tdsc", SETTING_RW, -1, -1, TYPE_INT, IDETAPE_DSC_RW_MIN, IDETAPE_DSC_RW_MAX, 1000, HZ, &tape->best_dsc_rw_frequency, NULL);
- ide_add_setting(drive, "dsc_overlap", SETTING_RW, -1, -1, TYPE_BYTE, 0, 1, 1, 1, &drive->dsc_overlap, NULL);
- ide_add_setting(drive, "pipeline_head_speed_c",SETTING_READ, -1, -1, TYPE_INT, 0, 0xffff, 1, 1, &tape->controlled_pipeline_head_speed, NULL);
- ide_add_setting(drive, "pipeline_head_speed_u",SETTING_READ, -1, -1, TYPE_INT, 0, 0xffff, 1, 1, &tape->uncontrolled_pipeline_head_speed, NULL);
- ide_add_setting(drive, "avg_speed", SETTING_READ, -1, -1, TYPE_INT, 0, 0xffff, 1, 1, &tape->avg_speed, NULL);
- ide_add_setting(drive, "debug_level",SETTING_RW, -1, -1, TYPE_INT, 0, 0xffff, 1, 1, &tape->debug_level, NULL);
- if (tape->onstream) {
- ide_add_setting(drive, "cur_frames", SETTING_READ, -1, -1, TYPE_SHORT, 0, 0xffff, 1, 1, &tape->cur_frames, NULL);
- ide_add_setting(drive, "max_frames", SETTING_READ, -1, -1, TYPE_SHORT, 0, 0xffff, 1, 1, &tape->max_frames, NULL);
- ide_add_setting(drive, "insert_speed", SETTING_READ, -1, -1, TYPE_INT, 0, 0xffff, 1, 1, &tape->insert_speed, NULL);
- ide_add_setting(drive, "speed_control",SETTING_RW, -1, -1, TYPE_INT, 0, 0xffff, 1, 1, &tape->speed_control, NULL);
- ide_add_setting(drive, "tape_still_time",SETTING_READ, -1, -1, TYPE_INT, 0, 0xffff, 1, 1, &tape->tape_still_time, NULL);
- ide_add_setting(drive, "max_insert_speed",SETTING_RW, -1, -1, TYPE_INT, 0, 0xffff, 1, 1, &tape->max_insert_speed, NULL);
- ide_add_setting(drive, "insert_size", SETTING_READ, -1, -1, TYPE_INT, 0, 0xffff, 1, 1, &tape->insert_size, NULL);
- ide_add_setting(drive, "capacity", SETTING_READ, -1, -1, TYPE_INT, 0, 0xffff, 1, 1, &tape->capacity, NULL);
- ide_add_setting(drive, "first_frame", SETTING_READ, -1, -1, TYPE_INT, 0, 0xffff, 1, 1, &tape->first_frame_position, NULL);
- ide_add_setting(drive, "logical_blk", SETTING_READ, -1, -1, TYPE_INT, 0, 0xffff, 1, 1, &tape->logical_blk_num, NULL);
- }
- }
- /*
- * ide_setup is called to:
- *
- * 1. Initialize our various state variables.
- * 2. Ask the tape for its capabilities.
- * 3. Allocate a buffer which will be used for data
- * transfer. The buffer size is chosen based on
- * the recommendation which we received in step (2).
- *
- * Note that at this point ide.c already assigned us an irq, so that
- * we can queue requests here and wait for their completion.
- */
- static void idetape_setup (ide_drive_t *drive, idetape_tape_t *tape, int minor)
- {
- unsigned long t1, tmid, tn, t;
- int speed;
- struct idetape_id_gcw gcw;
- int stage_size;
- struct sysinfo si;
- memset (tape, 0, sizeof (idetape_tape_t));
- spin_lock_init(&tape->spinlock);
- drive->driver_data = tape;
- drive->ready_stat = 0; /* An ATAPI device ignores DRDY */
- if (strstr(drive->id->model, "OnStream DI-"))
- tape->onstream = 1;
- drive->dsc_overlap = 1;
- #ifdef CONFIG_BLK_DEV_IDEPCI
- if (!tape->onstream && HWIF(drive)->pci_dev != NULL) {
- /*
- * These two ide-pci host adapters appear to need DSC overlap disabled.
- * This probably needs further analysis.
- */
- if ((HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) ||
- (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_TTI_HPT343)) {
- printk(KERN_INFO "ide-tape: %s: disabling DSC overlapn", tape->name);
- drive->dsc_overlap = 0;
- }
- }
- #endif /* CONFIG_BLK_DEV_IDEPCI */
- tape->drive = drive;
- tape->minor = minor;
- tape->name[0] = 'h'; tape->name[1] = 't'; tape->name[2] = '0' + minor;
- tape->chrdev_direction = idetape_direction_none;
- tape->pc = tape->pc_stack;
- tape->max_insert_speed = 10000;
- tape->speed_control = 1;
- *((unsigned short *) &gcw) = drive->id->config;
- if (gcw.drq_type == 1)
- set_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags);
- tape->min_pipeline = tape->max_pipeline = tape->max_stages = 10;
-
- idetape_get_inquiry_results(drive);
- idetape_get_mode_sense_results(drive);
- idetape_get_blocksize_from_block_descriptor(drive);
- if (tape->onstream) {
- idetape_onstream_mode_sense_tape_parameter_page(drive, 1);
- idetape_configure_onstream(drive);
- }
- tape->user_bs_factor = 1;
- tape->stage_size = tape->capabilities.ctl * tape->tape_block_size;
- while (tape->stage_size > 0xffff) {
- printk (KERN_NOTICE "ide-tape: decreasing stage sizen");
- tape->capabilities.ctl /= 2;
- tape->stage_size = tape->capabilities.ctl * tape->tape_block_size;
- }
- stage_size = tape->stage_size;
- if (tape->onstream)
- stage_size = 32768 + 512;
- 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;
- }
- /*
- * Select the "best" DSC read/write polling frequency
- * and pipeline size.
- */
- speed = IDE_MAX (tape->capabilities.speed, tape->capabilities.max_speed);
- 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->min_pipeline = tape->max_stages;
- tape->max_pipeline = tape->max_stages * 2;
- t1 = (tape->stage_size * HZ) / (speed * 1000);
- tmid = (tape->capabilities.buffer_size * 32 * HZ) / (speed * 125);
- tn = (IDETAPE_FIFO_THRESHOLD * tape->stage_size * HZ) / (speed * 1000);
- if (tape->max_stages)
- t = tn;
- else
- t = t1;
- /*
- * Ensure that the number we got makes sense; limit
- * it within IDETAPE_DSC_RW_MIN and IDETAPE_DSC_RW_MAX.
- */
- tape->best_dsc_rw_frequency = IDE_MAX (IDE_MIN (t, IDETAPE_DSC_RW_MAX), IDETAPE_DSC_RW_MIN);
- printk (KERN_INFO "ide-tape: %s <-> %s: %dKBps, %d*%dkB buffer, %dkB pipeline, %lums tDSC%sn",
- drive->name, tape->name, tape->capabilities.speed, (tape->capabilities.buffer_size * 512) / tape->stage_size,
- tape->stage_size / 1024, tape->max_stages * tape->stage_size / 1024,
- tape->best_dsc_rw_frequency * 1000 / HZ, drive->using_dma ? ", DMA":"");
- idetape_add_settings(drive);
- }
- static int idetape_cleanup (ide_drive_t *drive)
- {
- idetape_tape_t *tape = drive->driver_data;
- int minor = tape->minor;
- unsigned long flags;
- save_flags (flags); /* all CPUs (overkill?) */
- cli(); /* all CPUs (overkill?) */
- if (test_bit (IDETAPE_BUSY, &tape->flags) || tape->first_stage != NULL || tape->merge_stage_size || drive->usage) {
- restore_flags(flags); /* all CPUs (overkill?) */
- return 1;
- }
- idetape_chrdevs[minor].drive = NULL;
- restore_flags (flags); /* all CPUs (overkill?) */
- DRIVER(drive)->busy = 0;
- (void) ide_unregister_subdriver (drive);
- drive->driver_data = NULL;
- devfs_unregister (tape->de_r);
- devfs_unregister (tape->de_n);
- kfree (tape);
- for (minor = 0; minor < MAX_HWIFS * MAX_DRIVES; minor++)
- if (idetape_chrdevs[minor].drive != NULL)
- return 0;
- devfs_unregister_chrdev (IDETAPE_MAJOR, "ht");
- idetape_chrdev_present = 0;
- return 0;
- }
- #ifdef CONFIG_PROC_FS
- static int proc_idetape_read_name
- (char *page, char **start, off_t off, int count, int *eof, void *data)
- {
- ide_drive_t *drive = (ide_drive_t *) data;
- idetape_tape_t *tape = drive->driver_data;
- char *out = page;
- int len;
- len = sprintf(out, "%sn", tape->name);
- PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
- }
- static ide_proc_entry_t idetape_proc[] = {
- { "name", S_IFREG|S_IRUGO, proc_idetape_read_name, NULL },
- { NULL, 0, NULL, NULL }
- };
- #else
- #define idetape_proc NULL
- #endif
- int idetape_reinit(ide_drive_t *drive);
- /*
- * IDE subdriver functions, registered with ide.c
- */
- static ide_driver_t idetape_driver = {
- name: "ide-tape",
- version: IDETAPE_VERSION,
- media: ide_tape,
- busy: 1,
- supports_dma: 1,
- supports_dsc_overlap: 1,
- cleanup: idetape_cleanup,
- standby: NULL,
- flushcache: NULL,
- do_request: idetape_do_request,
- end_request: idetape_end_request,
- ioctl: idetape_blkdev_ioctl,
- open: idetape_blkdev_open,
- release: idetape_blkdev_release,
- media_change: NULL,
- revalidate: NULL,
- pre_reset: idetape_pre_reset,
- capacity: NULL,
- proc: idetape_proc,
- reinit: idetape_reinit,
- ata_prebuilder: NULL,
- atapi_prebuilder: NULL,
- };
- int idetape_init (void);
- static ide_module_t idetape_module = {
- IDE_DRIVER_MODULE,
- idetape_init,
- &idetape_driver,
- NULL
- };
- /*
- * Our character device supporting functions, passed to register_chrdev.
- */
- static struct file_operations idetape_fops = {
- owner: THIS_MODULE,
- read: idetape_chrdev_read,
- write: idetape_chrdev_write,
- ioctl: idetape_chrdev_ioctl,
- open: idetape_chrdev_open,
- release: idetape_chrdev_release,
- };
- int idetape_reinit (ide_drive_t *drive)
- {
- #if 0
- idetape_tape_t *tape;
- int minor, failed = 0, supported = 0;
- /* DRIVER(drive)->busy++; */
- MOD_INC_USE_COUNT;
- #if ONSTREAM_DEBUG
- printk(KERN_INFO "ide-tape: MOD_INC_USE_COUNT in idetape_initn");
- #endif
- if (!idetape_chrdev_present)
- for (minor = 0; minor < MAX_HWIFS * MAX_DRIVES; minor++ )
- idetape_chrdevs[minor].drive = NULL;
- if ((drive = ide_scan_devices (ide_tape, idetape_driver.name, NULL, failed++)) == NULL) {
- ide_register_module (&idetape_module);
- MOD_DEC_USE_COUNT;
- #if ONSTREAM_DEBUG
- printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_initn");
- #endif
- return 0;
- }
- if (!idetape_chrdev_present &&
- devfs_register_chrdev (IDETAPE_MAJOR, "ht", &idetape_fops)) {
- printk (KERN_ERR "ide-tape: Failed to register character device interfacen");
- MOD_DEC_USE_COUNT;
- #if ONSTREAM_DEBUG
- printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_initn");
- #endif
- return -EBUSY;
- }
- do {
- if (!idetape_identify_device (drive, drive->id)) {
- printk (KERN_ERR "ide-tape: %s: not supported by this version of ide-tapen", drive->name);
- continue;
- }
- if (drive->scsi) {
- if (strstr(drive->id->model, "OnStream DI-30")) {
- printk("ide-tape: ide-scsi emulation is not supported for %s.n", drive->id->model);
- } else {
- printk("ide-tape: passing drive %s to ide-scsi emulation.n", drive->name);
- continue;
- }
- }
- tape = (idetape_tape_t *) kmalloc (sizeof (idetape_tape_t), GFP_KERNEL);
- if (tape == NULL) {
- printk (KERN_ERR "ide-tape: %s: Can't allocate a tape structuren", drive->name);
- continue;
- }
- if (ide_register_subdriver (drive, &idetape_driver, IDE_SUBDRIVER_VERSION)) {
- printk (KERN_ERR "ide-tape: %s: Failed to register the driver with ide.cn", drive->name);
- kfree (tape);
- continue;
- }
- for (minor = 0; idetape_chrdevs[minor].drive != NULL; minor++);
- idetape_setup (drive, tape, minor);
- idetape_chrdevs[minor].drive = drive;
- tape->de_r =
- devfs_register (drive->de, "mt", DEVFS_FL_DEFAULT,
- HWIF(drive)->major, minor,
- S_IFCHR | S_IRUGO | S_IWUGO,
- &idetape_fops, NULL);
- tape->de_n =
- devfs_register (drive->de, "mtn", DEVFS_FL_DEFAULT,
- HWIF(drive)->major, minor + 128,
- S_IFCHR | S_IRUGO | S_IWUGO,
- &idetape_fops, NULL);
- devfs_register_tape (tape->de_r);
- supported++; failed--;
- } while ((drive = ide_scan_devices (ide_tape, idetape_driver.name, NULL, failed++)) != NULL);
- if (!idetape_chrdev_present && !supported) {
- devfs_unregister_chrdev (IDETAPE_MAJOR, "ht");
- } else
- idetape_chrdev_present = 1;
- ide_register_module (&idetape_module);
- MOD_DEC_USE_COUNT;
- #if ONSTREAM_DEBUG
- printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_initn");
- #endif
- return 0;
- #else
- return 1;
- #endif
- }
- MODULE_DESCRIPTION("ATAPI Streaming TAPE Driver");
- MODULE_LICENSE("GPL");
- static void __exit idetape_exit (void)
- {
- ide_drive_t *drive;
- int minor;
- for (minor = 0; minor < MAX_HWIFS * MAX_DRIVES; minor++) {
- drive = idetape_chrdevs[minor].drive;
- if (drive != NULL && idetape_cleanup (drive))
- printk (KERN_ERR "ide-tape: %s: cleanup_module() called while still busyn", drive->name);
- }
- ide_unregister_module(&idetape_module);
- }
- /*
- * idetape_init will register the driver for each tape.
- */
- int idetape_init (void)
- {
- ide_drive_t *drive;
- idetape_tape_t *tape;
- int minor, failed = 0, supported = 0;
- /* DRIVER(drive)->busy++; */
- MOD_INC_USE_COUNT;
- #if ONSTREAM_DEBUG
- printk(KERN_INFO "ide-tape: MOD_INC_USE_COUNT in idetape_initn");
- #endif
- if (!idetape_chrdev_present)
- for (minor = 0; minor < MAX_HWIFS * MAX_DRIVES; minor++ )
- idetape_chrdevs[minor].drive = NULL;
- if ((drive = ide_scan_devices (ide_tape, idetape_driver.name, NULL, failed++)) == NULL) {
- ide_register_module (&idetape_module);
- MOD_DEC_USE_COUNT;
- #if ONSTREAM_DEBUG
- printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_initn");
- #endif
- return 0;
- }
- if (!idetape_chrdev_present &&
- devfs_register_chrdev (IDETAPE_MAJOR, "ht", &idetape_fops)) {
- printk (KERN_ERR "ide-tape: Failed to register character device interfacen");
- MOD_DEC_USE_COUNT;
- #if ONSTREAM_DEBUG
- printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_initn");
- #endif
- return -EBUSY;
- }
- do {
- if (!idetape_identify_device (drive, drive->id)) {
- printk (KERN_ERR "ide-tape: %s: not supported by this version of ide-tapen", drive->name);
- continue;
- }
- if (drive->scsi) {
- if (strstr(drive->id->model, "OnStream DI-")) {
- printk("ide-tape: ide-scsi emulation is not supported for %s.n", drive->id->model);
- } else {
- printk("ide-tape: passing drive %s to ide-scsi emulation.n", drive->name);
- continue;
- }
- }
- tape = (idetape_tape_t *) kmalloc (sizeof (idetape_tape_t), GFP_KERNEL);
- if (tape == NULL) {
- printk (KERN_ERR "ide-tape: %s: Can't allocate a tape structuren", drive->name);
- continue;
- }
- if (ide_register_subdriver (drive, &idetape_driver, IDE_SUBDRIVER_VERSION)) {
- printk (KERN_ERR "ide-tape: %s: Failed to register the driver with ide.cn", drive->name);
- kfree (tape);
- continue;
- }
- for (minor = 0; idetape_chrdevs[minor].drive != NULL; minor++);
- idetape_setup (drive, tape, minor);
- idetape_chrdevs[minor].drive = drive;
- tape->de_r =
- devfs_register (drive->de, "mt", DEVFS_FL_DEFAULT,
- HWIF(drive)->major, minor,
- S_IFCHR | S_IRUGO | S_IWUGO,
- &idetape_fops, NULL);
- tape->de_n =
- devfs_register (drive->de, "mtn", DEVFS_FL_DEFAULT,
- HWIF(drive)->major, minor + 128,
- S_IFCHR | S_IRUGO | S_IWUGO,
- &idetape_fops, NULL);
- devfs_register_tape (tape->de_r);
- supported++; failed--;
- } while ((drive = ide_scan_devices (ide_tape, idetape_driver.name, NULL, failed++)) != NULL);
- if (!idetape_chrdev_present && !supported) {
- devfs_unregister_chrdev (IDETAPE_MAJOR, "ht");
- } else
- idetape_chrdev_present = 1;
- ide_register_module (&idetape_module);
- MOD_DEC_USE_COUNT;
- #if ONSTREAM_DEBUG
- printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_initn");
- #endif
- return 0;
- }
- module_init(idetape_init);
- module_exit(idetape_exit);