PATCH: gets ide-tape working on 2.6
Here's the patch in plain text.
--
Bart (et al),
Here's a patch for ide-tape.c that gets ide-tape working on the 2.6 kernel.
This should be applied after your recent patch that fixed the rq->flags stuff in ide-tape.
There's nothing in here that will make it more difficult to change the rq->flags stuff later if necessary--this will just tweak a few things to get the driver functional.
Most of this stuff is just stuff to get the Seagate STT3401A Travan tape drive working, as I already submitted for the 2.4 kernel.
Thanks!
Stuart
(I'll resend this in just a moment as plain text--I have to do that from a different email account.)
ide-tape.c.26works renamed from ide-tape.c.orig +189 -63
@@ -1,5 +1,5 @@ /* - * linux/drivers/ide/ide-tape.c Version 1.17b Oct, 2002 + * linux/drivers/ide/ide-tape.c Version 1.18 Oct, 2003 * * Copyright (C) 1995 - 1999 Gadi Oxman <[email protected]> *
@@ -313,6 +313,28 @@ * Cosmetic fixes to miscellaneous debugging output messages. * Set the minimum /proc/ide/hd?/settings values for "pipeline", * "pipeline_min", and "pipeline_max" to 1. + * Ver 1.18 Oct 2003 Stuart Hayes <[email protected]> + * Check drive's write protect bit, try to return appropriate + * errors when attempting to write a write-protected tape + * Moved "idetape_read_position" call in idetape_chrdev_open + * after the "wait_ready" call + * Added IDETAPE_MEDIUM_PRESENT flag so driver would know + * not to rewind tape after ejecting it + * Fixed bug with ide_abort_pipeline (it was deleting stages + * from tape->next_stage to end, instead of from + * new_last_stage->next (tape->next_stage was set to NULL + * by idetape_discard_read_pipeline before calling!) + * Made improvements to idetape_wait_ready + * Added a few comments here and there + * Made MTOFFL unlock tape drive door before attempting to eject + * Added fixes to get Seagate STT3401A Travan working: + * handle drives that don't support 0-length reads/writes + * increased timeout (retension takes ~10 minutes before + * irq is returned) + * fixed request mode page packet command byte 3 + * Changed spinlock_irqsave to spinlock when calling + * "idetape_wait_for_request" so IRQs wouldn't be + * masked when we call "wait_for_completion" * * Here are some words from the first releases of hd.c, which are quoted * in ide.c and apply here as well:
@@ -422,7 +444,7 @@ * sharing a (fast) ATA-2 disk with any (slow) new ATAPI device. */ -#define IDETAPE_VERSION "1.17b-ac1" +#define IDETAPE_VERSION "1.18" #include <linux/config.h> #include <linux/module.h>
@@ -451,7 +473,6 @@ #include <asm/bitops.h> -#define NO_LONGER_REQUIRED (1) /* * OnStream support
@@ -653,8 +674,13 @@ /* * Some tape drives require a long irq timeout + * + * Some drives (for example, the Seagate STT3401A Travan) + * require a very long timeout, because they don't + * return an interrupt or clear their busy bit until after the + * command completes--even retension commands. */ -#define IDETAPE_WAIT_CMD (60*HZ) +#define IDETAPE_WAIT_CMD (900*HZ) /* * The following parameter is used to select the point in the internal
@@ -1032,6 +1058,10 @@ /* the door is currently locked */ int door_locked; + /* the tape hardware is write protected */ + char drv_write_prot; + /* the tape is write protected (hardware or opened as read-only) */ + char write_prot; /* * OnStream flags
@@ -1164,6 +1194,7 @@ #define IDETAPE_DRQ_INTERRUPT 6 /* DRQ interrupt device */ #define IDETAPE_READ_ERROR 7 #define IDETAPE_PIPELINE_ACTIVE 8 /* pipeline active */ +#define IDETAPE_MEDIUM_PRESENT 9 /* 0=no tape is loaded, so we don't rewind after ejecting */ /* * Supported ATAPI tape drives packet commands
@@ -1665,6 +1696,20 @@ idetape_update_buffers(pc); } + /* If error was the result of a zero-length read or write + * command, with sense key=5, asc=0x22, ascq=0, let it + * slide... some drives (Seagate STT3401A Travan) don't + * support 0-length read/writes + */ + + if ((pc->c[0] == IDETAPE_READ_CMD || pc->c[0] == IDETAPE_WRITE_CMD) + && pc->c[4] == 0 && pc->c[3] == 0 && pc->c[2] == 0) { /* length==0 */ + if (result->sense_key == 5) { + pc->error = 0; /* don't report an error, everything's ok */ + set_bit(PC_ABORT, &pc->flags); /* don't retry read/write */ + } + } + if (pc->c[0] == IDETAPE_READ_CMD && result->filemark) { pc->error = IDETAPE_ERROR_FILEMARK; set_bit(PC_ABORT, &pc->flags);
@@ -1805,10 +1850,18 @@ } } -static void idetape_abort_pipeline (ide_drive_t *drive, idetape_stage_t *last_stage) +/* + * idetape_abort_pipeline + * ---------------------- + * This will free all the pipeline stages starting from + * new_last_stage->next to the end of the list, and point + * tape->last_stage to new_last_stage. + */ + +static void idetape_abort_pipeline (ide_drive_t *drive, idetape_stage_t *new_last_stage) { idetape_tape_t *tape = drive->driver_data; - idetape_stage_t *stage = tape->next_stage; + idetape_stage_t *stage = new_last_stage->next; idetape_stage_t *nstage; #if IDETAPE_DEBUG_LOG
@@ -1822,9 +1875,9 @@ --tape->nr_pending_stages; stage = nstage; } - tape->last_stage = last_stage; - if (last_stage) - last_stage->next = NULL; + if (new_last_stage) + new_last_stage->next = NULL; + tape->last_stage = new_last_stage; tape->next_stage = NULL; }
@@ -1995,6 +2048,7 @@ { ide_init_drive_cmd(rq); rq->buffer = (char *) pc; + rq->flags &= ~(REQ_DRIVE_CMD); rq->flags |= REQ_IDETAPE_PC1; (void) ide_do_drive_cmd(drive, rq, ide_preempt); }
@@ -2430,7 +2484,11 @@ if (page_code != IDETAPE_BLOCK_DESCRIPTOR) pc->c[1] = 8; /* DBD = 1 - Don't return block descriptors */ pc->c[2] = page_code; - pc->c[3] = 255; /* Don't limit the returned information */ + /* Changed pc->c[3] (subpages) to 0... 255 will at best return * + * unused info... for SCSI, this byte is defined as subpage * + * instead of high byte of length, and some IDE drives * + * seem to interpret it this way and return an error. */ + pc->c[3] = 0; /* Don't limit the returned information */ pc->c[4] = 255; /* (We will just discard data in that case) */ if (page_code == IDETAPE_BLOCK_DESCRIPTOR) pc->request_transfer = 12;
@@ -2544,7 +2602,8 @@ if (status.b.dsc) { if (status.b.check) { /* Error detected */ - printk(KERN_ERR "ide-tape: %s: I/O error, ",tape->name); + if (pc->c[0] != IDETAPE_TEST_UNIT_READY_CMD) + printk(KERN_ERR "ide-tape: %s: I/O error, ",tape->name); /* Retry operation */ return idetape_retry_pc(drive);
@@ -3174,7 +3233,7 @@ wait_for_completion(&wait); /* The stage and its struct request have been deallocated */ tape->waiting = NULL; - spin_lock_irq(&tape->spinlock); + spin_lock(&tape->spinlock); } static ide_startstop_t idetape_read_position_callback (ide_drive_t *drive)
@@ -3271,6 +3330,7 @@ ide_init_drive_cmd(&rq); rq.buffer = (char *) pc; + rq.flags &= ~(REQ_DRIVE_CMD); rq.flags |= REQ_IDETAPE_PC1; return ide_do_drive_cmd(drive, &rq, ide_wait); }
@@ -3295,25 +3355,26 @@ { idetape_tape_t *tape = drive->driver_data; idetape_pc_t pc; - + int load_attempted = 0; /* * Wait for the tape to become ready */ + set_bit(IDETAPE_MEDIUM_PRESENT,&tape->flags); 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; + if ((tape->sense_key == 2 && tape->asc == 4 && tape->ascq == 2) + || (tape->asc == 0x3A)) { /* no media... */ + if (!load_attempted) { + idetape_create_load_unload_cmd(drive, &pc, IDETAPE_LU_LOAD_MASK); + __idetape_queue_pc_tail(drive, &pc); + load_attempted = 1; + } else return -ENOMEDIUM; + } else if (!(tape->sense_key == 2 && tape->asc == 4 && + (tape->ascq == 1 || tape->ascq == 8))) /* not about to be ready... */ + return -EIO; current->state = TASK_INTERRUPTIBLE; schedule_timeout(HZ / 10); }
@@ -3436,6 +3497,8 @@ if (tape->chrdev_direction != idetape_direction_read) return 0; + + /* Remove merge stage */ cnt = tape->merge_stage_size / tape->tape_block_size; if (test_and_clear_bit(IDETAPE_FILEMARK, &tape->flags)) ++cnt; /* Filemarks count as 1 sector */
@@ -3444,17 +3507,20 @@ __idetape_kfree_stage(tape->merge_stage); tape->merge_stage = NULL; } + + /* Clear pipeline flags */ clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags); tape->chrdev_direction = idetape_direction_none; - + + /* Remove pipeline stages */ if (tape->first_stage == NULL) return 0; - spin_lock_irqsave(&tape->spinlock, flags); + spin_lock(&tape->spinlock); tape->next_stage = NULL; if (idetape_pipeline_active(tape)) idetape_wait_for_request(drive, tape->active_data_request); - spin_unlock_irqrestore(&tape->spinlock, flags); + spin_unlock(&tape->spinlock); while (tape->first_stage != NULL) { struct request *rq_ptr = &tape->first_stage->rq;
@@ -3547,6 +3613,7 @@ #endif /* IDETAPE_DEBUG_BUGS */ ide_init_drive_cmd(&rq); + rq.flags &= ~(REQ_DRIVE_CMD); rq.special = (void *)bh; rq.flags |= cmd; rq.sector = tape->first_frame_position;
@@ -3597,6 +3664,7 @@ #endif rq = &stage->rq; ide_init_drive_cmd(rq); + rq->flags &= ~(REQ_DRIVE_CMD); rq->flags |= REQ_IDETAPE_WRITE; rq->sector = tape->first_frame_position; rq->nr_sectors = rq->current_nr_sectors = tape->capabilities.ctl;
@@ -3820,10 +3888,10 @@ if (tape->first_stage == NULL) return; - spin_lock_irqsave(&tape->spinlock, flags); + spin_lock(&tape->spinlock); if (tape->active_stage == tape->first_stage) idetape_wait_for_request(drive, tape->active_data_request); - spin_unlock_irqrestore(&tape->spinlock, flags); + spin_unlock(&tape->spinlock); } /*
@@ -3854,12 +3922,12 @@ * Pay special attention to possible race conditions. */ while ((new_stage = idetape_kmalloc_stage(tape)) == NULL) { - spin_lock_irqsave(&tape->spinlock, flags); + spin_lock(&tape->spinlock); if (idetape_pipeline_active(tape)) { idetape_wait_for_request(drive, tape->active_data_request); - spin_unlock_irqrestore(&tape->spinlock, flags); + spin_unlock(&tape->spinlock); } else { - spin_unlock_irqrestore(&tape->spinlock, flags); + spin_unlock(&tape->spinlock); idetape_insert_pipeline_into_queue(drive); if (idetape_pipeline_active(tape)) continue;
@@ -3872,6 +3940,7 @@ } rq = &new_stage->rq; ide_init_drive_cmd(rq); + rq->flags &= ~(REQ_DRIVE_CMD); rq->flags |= REQ_IDETAPE_WRITE; /* Doesn't actually matter - We always assume sequential access */ rq->sector = tape->first_frame_position;
@@ -3934,10 +4003,10 @@ while (tape->next_stage || idetape_pipeline_active(tape)) { idetape_insert_pipeline_into_queue(drive); - spin_lock_irqsave(&tape->spinlock, flags); + spin_lock(&tape->spinlock); if (idetape_pipeline_active(tape)) idetape_wait_for_request(drive, tape->active_data_request); - spin_unlock_irqrestore(&tape->spinlock, flags); + spin_unlock(&tape->spinlock); } }
@@ -4059,18 +4128,23 @@ * Issue a read 0 command to ensure that DSC handshake * is switched from completion mode to buffer available * mode. + * No point in issuing this if dsc_overlap isn't supported + * (some drives (Seagate STT3401A) will return an error). */ - bytes_read = idetape_queue_rw_tail(drive, REQ_IDETAPE_READ, 0, tape->merge_stage->bh); - if (bytes_read < 0) { - __idetape_kfree_stage(tape->merge_stage); - tape->merge_stage = NULL; - tape->chrdev_direction = idetape_direction_none; - return bytes_read; + if (drive->dsc_overlap) { + bytes_read = idetape_queue_rw_tail(drive, REQ_IDETAPE_READ, 0, tape->merge_stage->bh); + if (bytes_read < 0) { + __idetape_kfree_stage(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.flags &= ~(REQ_DRIVE_CMD); rq.flags |= REQ_IDETAPE_READ; rq.sector = tape->first_frame_position; rq.nr_sectors = rq.current_nr_sectors = blocks;
@@ -4658,7 +4732,9 @@ static ssize_t idetape_chrdev_read (struct file *file, char *buf, size_t count, loff_t *ppos) { - ide_drive_t *drive = file->private_data; + struct inode *inode = file->f_dentry->d_inode; + unsigned int minor = iminor(inode); + ide_drive_t *drive = idetape_chrdevs[minor & ~0xC0].drive; idetape_tape_t *tape = drive->driver_data; ssize_t bytes_read,temp, actually_read = 0, rc;
@@ -4887,9 +4963,9 @@ size_t count, loff_t *ppos) { struct inode *inode = file->f_dentry->d_inode; - ide_drive_t *drive = file->private_data; - idetape_tape_t *tape = drive->driver_data; unsigned int minor = iminor(inode); + ide_drive_t *drive = idetape_chrdevs[minor&~0xC0].drive; + idetape_tape_t *tape = drive->driver_data; ssize_t retval, actually_written = 0; int position;
@@ -4898,6 +4974,11 @@ return -ENXIO; } + if (tape->write_prot) { + /* The drive is write protected */ + return -EACCES; + } + #if IDETAPE_DEBUG_LOG if (tape->debug_level >= 3) printk(KERN_INFO "ide-tape: Reached idetape_chrdev_write, "
@@ -4979,13 +5060,17 @@ * Issue a write 0 command to ensure that DSC handshake * is switched from completion mode to buffer available * mode. + * No point in issuing this if dsc_overlap isn't supported + * (some drives (Seagate STT3401A) will return an error). */ - retval = idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, 0, tape->merge_stage->bh); - if (retval < 0) { - __idetape_kfree_stage(tape->merge_stage); - tape->merge_stage = NULL; - tape->chrdev_direction = idetape_direction_none; - return retval; + if (drive->dsc_overlap) { + retval = idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, 0, tape->merge_stage->bh); + if (retval < 0) { + __idetape_kfree_stage(tape->merge_stage); + tape->merge_stage = NULL; + tape->chrdev_direction = idetape_direction_none; + return retval; + } } #if ONSTREAM_DEBUG if (tape->debug_level >= 2)
@@ -5141,7 +5226,7 @@ * Note: * * MTBSF and MTBSFM are not supported when the tape doesn't - * supports spacing over filemarks in the reverse direction. + * support spacing over filemarks in the reverse direction. * In this case, MTFSFM is also usually not supported (it is * supported in the rare case in which we crossed the filemark * during our read-ahead pipelined operation mode).
@@ -5211,6 +5296,8 @@ } switch (mt_op) { case MTWEOF: + if (tape->write_prot) + return -EACCES; idetape_discard_read_pipeline(drive, 1); for (i = 0; i < mt_count; i++) { retval = idetape_write_filemark(drive);
@@ -5232,8 +5319,16 @@ case MTUNLOAD: case MTOFFL: idetape_discard_read_pipeline(drive, 0); + /* if door is locked, attempt to unlock */ + /* before attempting to eject */ + if (tape->door_locked) + if (idetape_create_prevent_cmd(drive, &pc, 0)) + if (!idetape_queue_pc_tail(drive, &pc)) + tape->door_locked = DOOR_UNLOCKED; idetape_create_load_unload_cmd(drive, &pc,!IDETAPE_LU_LOAD_MASK); - return (idetape_queue_pc_tail(drive, &pc)); + if (!(retval= idetape_queue_pc_tail(drive, &pc))) + clear_bit(IDETAPE_MEDIUM_PRESENT,&tape->flags); + return retval; case MTNOP: idetape_discard_read_pipeline(drive, 0); return (idetape_flush_tape_buffers(drive));
@@ -5363,7 +5458,7 @@ */ static int idetape_chrdev_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - ide_drive_t *drive = file->private_data; + ide_drive_t *drive = idetape_chrdevs[iminor(inode)&~0xC0].drive; idetape_tape_t *tape = drive->driver_data; struct mtop mtop; struct mtget mtget;
@@ -5403,12 +5498,15 @@ 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; + mtget.mt_gstat = 0; 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); + } else { + if (tape->drv_write_prot) mtget.mt_gstat |= GMT_WR_PROT(0xffffffff); } if (copy_to_user((char *) arg,(char *) &mtget, sizeof(struct mtget))) return -EFAULT;
@@ -5530,6 +5628,8 @@ return 1; } +static void idetape_get_blocksize_from_block_descriptor(ide_drive_t *drive); + /* * Our character device open function. */
@@ -5539,7 +5639,8 @@ ide_drive_t *drive; idetape_tape_t *tape; idetape_pc_t pc; - + int retval; + #if IDETAPE_DEBUG_LOG printk(KERN_INFO "ide-tape: Reached idetape_chrdev_open\n"); #endif /* IDETAPE_DEBUG_LOG */
@@ -5551,11 +5652,7 @@ if (test_and_set_bit(IDETAPE_BUSY, &tape->flags)) return -EBUSY; - if (!tape->onstream) { - idetape_read_position(drive); - if (!test_bit(IDETAPE_ADDRESS_VALID, &tape->flags)) - (void) idetape_rewind_tape(drive); - } else { + if (tape->onstream) { if (minor & 64) { tape->tape_block_size = tape->stage_size = 32768 + 512; tape->raw = 1;
@@ -5565,16 +5662,40 @@ } idetape_onstream_mode_sense_tape_parameter_page(drive, tape->debug_level); } - if (idetape_wait_ready(drive, 60 * HZ)) { + + /* See if the drive is ready to go */ + if ((retval = idetape_wait_ready(drive, 60 * HZ))) { clear_bit(IDETAPE_BUSY, &tape->flags); printk(KERN_ERR "ide-tape: %s: drive not ready\n", tape->name); - return -EBUSY; + return retval; } - if (tape->onstream) - idetape_read_position(drive); + + /* Read the tape position */ + idetape_read_position(drive); + if (!test_bit(IDETAPE_ADDRESS_VALID, &tape->flags)) + (void) idetape_rewind_tape(drive); + if (tape->chrdev_direction != idetape_direction_read) clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags); + /* Read block size and write protect status from drive */ + idetape_get_blocksize_from_block_descriptor(drive); + + /* Set write protect flag if device is opened as read-only */ + if ( (filp->f_flags & O_ACCMODE)==O_RDONLY) + tape->write_prot = 1; + else tape->write_prot = tape->drv_write_prot; + + /* Make sure drive isn't write protected if user wants to write */ + if (tape->write_prot) + if ( (filp->f_flags & O_ACCMODE)==O_WRONLY || + (filp->f_flags & O_ACCMODE)==O_RDWR) { + clear_bit (IDETAPE_BUSY, &tape->flags); + return -EROFS; + } + + /* Lock the tape drive door so user can't eject */ + /* (and analyze headers for OnStream drives) */ if (tape->chrdev_direction == idetape_direction_none) { if (idetape_create_prevent_cmd(drive, &pc, 1)) { if (!idetape_queue_pc_tail(drive, &pc)) {
@@ -5613,7 +5734,7 @@ */ static int idetape_chrdev_release (struct inode *inode, struct file *filp) { - ide_drive_t *drive = filp->private_data; + ide_drive_t *drive = idetape_chrdevs[iminor(inode)&~0xC0].drive; idetape_tape_t *tape; idetape_pc_t pc; unsigned int minor = iminor(inode);
@@ -5637,7 +5758,7 @@ __idetape_kfree_stage(tape->cache_stage); tape->cache_stage = NULL; } - if (minor < 128) + if ((minor < 128) && (test_bit(IDETAPE_MEDIUM_PRESENT,&tape->flags))) (void) idetape_rewind_tape(drive); if (tape->chrdev_direction == idetape_direction_none) { if (tape->door_locked == DOOR_LOCKED) {
@@ -6058,6 +6179,8 @@ 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]; + tape->drv_write_prot = tape->write_prot = (header->dsp & 0x80) >> 7; + #if IDETAPE_DEBUG_INFO printk(KERN_INFO "ide-tape: Adjusted block size - %d\n", tape->tape_block_size); #endif /* IDETAPE_DEBUG_INFO */
@@ -6137,6 +6260,9 @@ drive->dsc_overlap = 0; } } + /* Seagate Travan drives do not support DSC overlap */ + if (strstr(drive->id->model,"Seagate STT3401")) + drive->dsc_overlap = 0; #endif /* CONFIG_BLK_DEV_IDEPCI */ tape->drive = drive; tape->minor = minor;
____________________________________________________________
Enter now for a chance to win a 42" Plasma Television!
http://ad.doubleclick.net/clk;6413623;3807821;f?http://mocda1.com/1/c/563632/113422/313631/313631
AOL users go here: http://ad.doubleclick.net/clk;6413623;3807821;f?http://mocda1.com/1/c/563632/113422/313631/313631
This offer applies to U.S. Residents Only
PATCH 1/1 ide-tape update for 2.6 (Was: PATCH: gets ide-tape working on 2.6)
[ with changed subject because ide-tape _is_ already working in 2.6 ]
Quoted 10 lines · stuart hayes
Here's the patch in plain text.
--
Bart (et al),
Here's a patch for
ide-tape.cthat gets ide-tape working on the 2.6 kernel.This should be applied after your recent patch that fixed the
rq->flagsstuff in ide-tape.
Current 2.6 -bk tree already contains corrected version of my patch and fix for ide-tape character device (so no need to use iminor(inode)).
-bk snapshots are at http://www.kernel.org/pub/linux/kernel/v2.6/snapshots/
I've updated your patch accordingly.
Quoted 6 lines
There's nothing in here that will make it more difficult to change the
rq->flagsstuff later if necessary--this will just tweak a few things to get the driver functional.Most of this stuff is just stuff to get the Seagate STT3401A Travan tape drive working, as I already submitted for the 2.4 kernel.
I dropped tape->spinlock changes. They are racy, you can't use spin_lock() for tape->spinlock because this lock can be taken from IRQ context (i.e. through idetape_pc_intr() -> pc->callback() -> idetape_end_request()). I moved check for Travan drives outside CONFIG_BLK_DEV_IDEPCI.
I also removed code depending on NO_LONGER_NEEDED define to match 2.4.x kernel (it was removed in 2.4.21 kernel) and made some cosmetics.
Thanks,
--bartlomiej
[IDE] ide-tape update
From: Stuart Hayes <[email protected]>
- Check drive's write protect bit, try to return appropriate errors when attempting to write a write-protected tape.
- Moved "idetape_read_position" call in idetape_chrdev_open after the "wait_ready" call.
- Added IDETAPE_MEDIUM_PRESENT flag so driver would know not to rewind tape after ejecting it.
- Fixed bug with ide_abort_pipeline (it was deleting stages from tape->next_stage to end, instead of from new_last_stage->next (tape->next_stage was set to NULL by idetape_discard_read_pipeline before calling!).
- Made improvements to idetape_wait_ready.
- Added a few comments here and there.
- Made MTOFFL unlock tape drive door before attempting to eject.
- Added fixes to get Seagate STT3401A Travan working:
Handle drives that don't support 0-length reads/writes increased timeout (retension takes ~10 minutes before irq is returned).
Fixed request mode page packet command byte 3.
Also remove code depending on NO_LONGER_REQUIRED to match 2.4.x (me).
drivers/ide/ide-tape.c | 211 ++++++++++++++++++++++++++++++++++--------------- 1 files changed, 147 insertions(+), 64 deletions(-)
drivers/ide/ide-tape.c renamed from drivers/ide/ide-tape.c~ide-tape-update +147 -64
@@ -1,5 +1,5 @@/* -* linux/drivers/ide/ide-tape.c Version 1.17b Oct, 2002 +* linux/drivers/ide/ide-tape.c Version 1.18 Nov, 2003 * * Copyright (C) 1995 - 1999 Gadi Oxman <[email protected]> *
@@ -422,7 +422,7 @@* sharing a (fast) ATA-2 disk with any (slow) new ATAPI device. */ -#define IDETAPE_VERSION "1.17b-ac1" +#define IDETAPE_VERSION "1.18"#include <linux/config.h> #include <linux/module.h>
@@ -450,9 +450,6 @@#include <asm/unaligned.h> #include <asm/bitops.h> - -#define NO_LONGER_REQUIRED (1) -/* * OnStream support */
@@ -652,9 +649,11 @@ typedef struct {#define IDETAPE_PC_STACK (10 + IDETAPE_MAX_PC_RETRIES)/* -* Some tape drives require a long irq timeout +* Some drives (for example, Seagate STT3401A Travan) require a very long +* timeout, because they don't return an interrupt or clear their busy bit +* until after the command completes (even retension commands). */ -#define IDETAPE_WAIT_CMD (60*HZ) +#define IDETAPE_WAIT_CMD (900*HZ)/* * The following parameter is used to select the point in the internal
@@ -1032,6 +1031,10 @@ typedef struct {/* the door is currently locked */ int door_locked; +/* the tape hardware is write protected */ +char drv_write_prot; +/* the tape is write protected (hardware or opened as read-only) */ +char write_prot;/* * OnStream flags
@@ -1164,6 +1167,8 @@ typedef struct {#define IDETAPE_DRQ_INTERRUPT 6/* DRQ interrupt device */ #define IDETAPE_READ_ERROR 7#define IDETAPE_PIPELINE_ACTIVE 8/* pipeline active */ +/* 0 = no tape is loaded, so we don't rewind after ejecting */ +#define IDETAPE_MEDIUM_PRESENT 9/* * Supported ATAPI tape drives packet commands
@@ -1665,6 +1670,20 @@ static void idetape_analyze_error (ide_didetape_update_buffers (pc); } +/* +* If error was the result of a zero-length read or write command, +* with sense key=5, asc=0x22, ascq=0, let it slide. Some drives +* (i.e. Seagate STT3401A Travan) don't support 0-length read/writes. +*/ +if ((pc->c[0 ] ==IDETAPE_READ_CMD || pc->c[0 ] ==IDETAPE_WRITE_CMD ) + && pc->c[4 ] ==0 && pc->c[3 ] ==0 && pc->c[2 ] ==0 ) {/* length==0 */ +if (result->sense_key ==5 ) { +/* don't report an error, everything's ok */ + pc->error =0 ; +/* don't retry read/write */ +set_bit (PC_ABORT , &pc->flags); + } + }if (pc->c[0 ] ==IDETAPE_READ_CMD && result->filemark) { pc->error =IDETAPE_ERROR_FILEMARK ;set_bit (PC_ABORT , &pc->flags);
@@ -1805,10 +1824,15 @@ static void idetape_remove_stage_head (i } } -static void idetape_abort_pipeline (ide_drive_t *drive,idetape_stage_t *last_stage) +/* +* This will free all the pipeline stages starting from new_last_stage->next +* to the end of the list, and point tape->last_stage to new_last_stage. +*/ +static void idetape_abort_pipeline (ide_drive_t *drive, +idetape_stage_t *new_last_stage) {idetape_tape_t *tape = drive->driver_data; -idetape_stage_t *stage = tape->next_stage; +idetape_stage_t *stage = new_last_stage->next;idetape_stage_t *nstage;#if IDETAPE_DEBUG_LOG
@@ -1822,9 +1846,9 @@ static void idetape_abort_pipeline (ide_ --tape->nr_pending_stages; stage = nstage; } - tape->last_stage = last_stage; -if (last_stage) - last_stage->next =NULL ; +if (new_last_stage) + new_last_stage->next =NULL ; + tape->last_stage = new_last_stage; tape->next_stage =NULL ; }
@@ -2430,7 +2454,14 @@ static void idetape_create_mode_sense_cmif (page_code !=IDETAPE_BLOCK_DESCRIPTOR ) pc->c[1 ] =8 ;/* DBD = 1 - Don't return block descriptors */ pc->c[2 ] = page_code; - pc->c[3 ] =255 ;/* Don't limit the returned information */ +/* +* Changed pc->c[3] to 0 (255 will at best return unused info). +* +* For SCSI this byte is defined as subpage instead of high byte +* of length and some IDE drives seem to interpret it this way +* and return an error when 255 is used. +*/ + pc->c[3 ] =0 ; pc->c[4 ] =255 ;/* (We will just discard data in that case) */ if (page_code ==IDETAPE_BLOCK_DESCRIPTOR ) pc->request_transfer =12 ;
@@ -2544,8 +2575,9 @@ static ide_startstop_t idetape_media_accif (status.b.dsc) {if (status.b.check) {/* Error detected */ -printk (KERN_ERR "ide-tape: %s: I/O error, " ,tape->name); - +if (pc->c[0 ] !=IDETAPE_TEST_UNIT_READY_CMD ) +printk (KERN_ERR "ide-tape: %s: I/O error, " , + tape->name);/* Retry operation */ return idetape_retry_pc (drive); }
@@ -3295,25 +3327,28 @@ static int idetape_wait_ready(ide_drive_ {idetape_tape_t *tape = drive->driver_data;idetape_pc_t pc; +int load_attempted =0 ;/* * Wait for the tape to become ready */ +set_bit (IDETAPE_MEDIUM_PRESENT , &tape->flags); 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 ) { +if ((tape->sense_key ==2 && tape->asc ==4 && tape->ascq ==2 ) + || (tape->asc ==0x3A )) {/* no media */ +if (load_attempted) +return -ENOMEDIUM ;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 ; + load_attempted =1 ; +/* not about to be ready */ + }else if (!(tape->sense_key ==2 && tape->asc ==4 && + (tape->ascq ==1 || tape->ascq ==8 ))) +return -EIO ; current->state =TASK_INTERRUPTIBLE ;schedule_timeout (HZ /10 ); }
@@ -3369,25 +3404,10 @@ static int idetape_read_position (ide_drprintk (KERN_INFO "ide-tape: Reached idetape_read_position\n" );#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, %d\n" , tape->name, position, tape->last_frame_position, tape->blocks_in_buffer); - position = tape->last_frame_position; - tape->first_frame_position = position; - } - } - } -#endif return position; }
@@ -3436,6 +3456,8 @@ static int __idetape_discard_read_pipeliif (tape->chrdev_direction != idetape_direction_read)return 0 ; + +/* Remove merge stage. */ cnt = tape->merge_stage_size / tape->tape_block_size;if (test_and_clear_bit (IDETAPE_FILEMARK , &tape->flags)) ++cnt;/* Filemarks count as 1 sector */
@@ -3444,9 +3466,12 @@ static int __idetape_discard_read_pipeli__idetape_kfree_stage (tape->merge_stage); tape->merge_stage =NULL ; } + +/* Clear pipeline flags. */ clear_bit (IDETAPE_PIPELINE_ERROR , &tape->flags); tape->chrdev_direction = idetape_direction_none; - + +/* Remove pipeline stages. */ if (tape->first_stage ==NULL )return 0 ;
@@ -4059,13 +4084,17 @@ static int idetape_initiate_read (ide_dr* Issue a read 0 command to ensure that DSC handshake * is switched from completion mode to buffer available * mode. +* No point in issuing this if DSC overlap isn't supported, +* some drives (Seagate STT3401A) will return an error. */ - bytes_read =idetape_queue_rw_tail (drive,REQ_IDETAPE_READ ,0 , tape->merge_stage->bh); -if (bytes_read <0 ) { -__idetape_kfree_stage (tape->merge_stage); - tape->merge_stage =NULL ; - tape->chrdev_direction = idetape_direction_none; -return bytes_read; +if (drive->dsc_overlap) { + bytes_read =idetape_queue_rw_tail (drive,REQ_IDETAPE_READ ,0 , tape->merge_stage->bh); +if (bytes_read <0 ) { +__idetape_kfree_stage (tape->merge_stage); + tape->merge_stage =NULL ; + tape->chrdev_direction = idetape_direction_none; +return bytes_read; + } } }if (tape->restart_speed_control_req)
@@ -4898,6 +4927,10 @@ static ssize_t idetape_chrdev_write (strreturn -ENXIO ; } +/* The drive is write protected. */ +if (tape->write_prot) +return -EACCES ; +#if IDETAPE_DEBUG_LOG if (tape->debug_level >=3 ) printk(KERN_INFO "ide-tape: Reached idetape_chrdev_write, "
@@ -4979,13 +5012,17 @@ static ssize_t idetape_chrdev_write (str* Issue a write 0 command to ensure that DSC handshake * is switched from completion mode to buffer available * mode. +* No point in issuing this if DSC overlap isn't supported, +* some drives (Seagate STT3401A) will return an error. */ - retval =idetape_queue_rw_tail (drive,REQ_IDETAPE_WRITE ,0 , tape->merge_stage->bh); -if (retval <0 ) { -__idetape_kfree_stage (tape->merge_stage); - tape->merge_stage =NULL ; - tape->chrdev_direction = idetape_direction_none; -return retval; +if (drive->dsc_overlap) { + retval =idetape_queue_rw_tail (drive,REQ_IDETAPE_WRITE ,0 , tape->merge_stage->bh); +if (retval <0 ) { +__idetape_kfree_stage (tape->merge_stage); + tape->merge_stage =NULL ; + tape->chrdev_direction = idetape_direction_none; +return retval; + } }#if ONSTREAM_DEBUG if (tape->debug_level >=2 )
@@ -5141,7 +5178,7 @@ ok:* Note: * * MTBSF and MTBSFM are not supported when the tape doesn't -* supports spacing over filemarks in the reverse direction. +* support spacing over filemarks in the reverse direction. * In this case, MTFSFM is also usually not supported (it is * supported in the rare case in which we crossed the filemark * during our read-ahead pipelined operation mode).
@@ -5211,6 +5248,8 @@ static int idetape_mtioctop (ide_drive_t }switch (mt_op) {case MTWEOF : +if (tape->write_prot) +return -EACCES ;idetape_discard_read_pipeline (drive,1 );for (i =0 ; i < mt_count; i++) { retval =idetape_write_filemark (drive);
@@ -5231,9 +5270,21 @@ static int idetape_mtioctop (ide_drive_treturn (idetape_queue_pc_tail (drive, &pc));case MTUNLOAD :case MTOFFL : +/* +* If door is locked, attempt to unlock before +* attempting to eject. +*/ +if (tape->door_locked) { +if (idetape_create_prevent_cmd (drive, &pc,0 )) +if (!idetape_queue_pc_tail (drive, &pc)) + tape->door_locked =DOOR_UNLOCKED ; + }idetape_discard_read_pipeline (drive,0 );idetape_create_load_unload_cmd (drive, &pc,!IDETAPE_LU_LOAD_MASK ); -return (idetape_queue_pc_tail (drive, &pc)); + retval =idetape_queue_pc_tail (drive, &pc); +if (!retval) +clear_bit (IDETAPE_MEDIUM_PRESENT , &tape->flags); +return retval;case MTNOP :idetape_discard_read_pipeline (drive,0 );return (idetape_flush_tape_buffers (drive));
@@ -5409,6 +5460,8 @@ static int idetape_chrdev_ioctl (struct mtget.mt_gstat |=GMT_EOD (0xffffffff );if (position <=OS_DATA_STARTFRAME1 ) mtget.mt_gstat |=GMT_BOT (0xffffffff ); + }else if (tape->drv_write_prot) { + mtget.mt_gstat |=GMT_WR_PROT (0xffffffff ); }if (copy_to_user ((char *) arg,(char *) &mtget,sizeof (struct mtget )))return -EFAULT ;
@@ -5530,6 +5583,8 @@ ok:return 1 ; } +static void idetape_get_blocksize_from_block_descriptor (ide_drive_t *drive); +/* * Our character device open function. */
@@ -5539,7 +5594,8 @@ static int idetape_chrdev_open (struct iide_drive_t *drive;idetape_tape_t *tape;idetape_pc_t pc; - +int retval; +#if IDETAPE_DEBUG_LOG printk (KERN_INFO "ide-tape: Reached idetape_chrdev_open\n" );#endif /* IDETAPE_DEBUG_LOG */
@@ -5552,11 +5608,7 @@ static int idetape_chrdev_open (struct iif (test_and_set_bit (IDETAPE_BUSY , &tape->flags))return -EBUSY ; -if (!tape->onstream) { -idetape_read_position (drive); -if (!test_bit (IDETAPE_ADDRESS_VALID , &tape->flags)) - (void )idetape_rewind_tape (drive); - }else { +if (tape->onstream) {if (minor &64 ) { tape->tape_block_size = tape->stage_size =32768 +512 ; tape->raw =1 ;
@@ -5566,16 +5618,42 @@ static int idetape_chrdev_open (struct i }idetape_onstream_mode_sense_tape_parameter_page (drive, tape->debug_level); } -if (idetape_wait_ready (drive,60 *HZ )) { + retval =idetape_wait_ready (drive,60 *HZ ); +if (retval) {clear_bit (IDETAPE_BUSY , &tape->flags);printk (KERN_ERR "ide-tape: %s: drive not ready\n" , tape->name); -return -EBUSY ; +return retval; } -if (tape->onstream) -idetape_read_position (drive); + +idetape_read_position (drive); +if (!test_bit (IDETAPE_ADDRESS_VALID , &tape->flags)) + (void )idetape_rewind_tape (drive); +if (tape->chrdev_direction != idetape_direction_read)clear_bit (IDETAPE_PIPELINE_ERROR , &tape->flags); +/* Read block size and write protect status from drive. */ +idetape_get_blocksize_from_block_descriptor (drive); + +/* Set write protect flag if device is opened as read-only. */ +if ((filp->f_flags &O_ACCMODE ) ==O_RDONLY ) + tape->write_prot =1 ; +else + tape->write_prot = tape->drv_write_prot; + +/* Make sure drive isn't write protected if user wants to write. */ +if (tape->write_prot) { +if ((filp->f_flags &O_ACCMODE ) ==O_WRONLY || + (filp->f_flags &O_ACCMODE ) ==O_RDWR ) { +clear_bit (IDETAPE_BUSY , &tape->flags); +return -EROFS ; + } + } + +/* +* Lock the tape drive door so user can't eject. +* Analyze headers for OnStream drives. +*/ if (tape->chrdev_direction == idetape_direction_none) {if (idetape_create_prevent_cmd (drive, &pc,1 )) {if (!idetape_queue_pc_tail (drive, &pc)) {
@@ -5638,7 +5716,7 @@ static int idetape_chrdev_release (struc__idetape_kfree_stage (tape->cache_stage); tape->cache_stage =NULL ; } -if (minor <128 ) +if (minor <128 &&test_bit (IDETAPE_MEDIUM_PRESENT , &tape->flags)) (void )idetape_rewind_tape (drive);if (tape->chrdev_direction == idetape_direction_none) {if (tape->door_locked ==DOOR_LOCKED ) {
@@ -6059,6 +6137,8 @@ static void idetape_get_blocksize_from_b 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 ]; + tape->drv_write_prot = (header->dsp &0x80 ) >>7 ; +#if IDETAPE_DEBUG_INFO printk (KERN_INFO "ide-tape: Adjusted block size - %d\n" , tape->tape_block_size);#endif /* IDETAPE_DEBUG_INFO */
@@ -6139,6 +6219,9 @@ static void idetape_setup (ide_drive_t * } }#endif /* CONFIG_BLK_DEV_IDEPCI */ +/* Seagate Travan drives do not support DSC overlap. */ +if (strstr (drive->id->model,"Seagate STT3401" )) + drive->dsc_overlap =0 ; tape->drive = drive; tape->minor = minor; tape->name[0 ] ='h' ;
_