Enscript Output

extractedLnx/linux-2.2.26/drivers/scsi/st.c_st_int_ioctl.c


/* Internal ioctl function */
	static int
st_int_ioctl(struct inode * inode,
	     unsigned int cmd_in, unsigned long arg)
{
   int timeout;
   long ltmp;
   int i, ioctl_result;
   int chg_eof = TRUE;
   unsigned char cmd[10];
   Scsi_Cmnd * SCpnt;
   Scsi_Tape * STp;
   ST_partstat * STps;
   int fileno, blkno, at_sm, undone, datalen;
   int dev = TAPE_NR(inode->i_rdev);

   STp = &(scsi_tapes[dev]);
   if (STp->ready != ST_READY && cmd_in != MTLOAD) {
     if (STp->ready == ST_NO_TAPE)
       return (-ENOMEDIUM);
     else
       return (-EIO);
   }
   timeout = STp->long_timeout;
   STps = &(STp->ps[STp->partition]);
   fileno = STps->drv_file;
   blkno = STps->drv_block;
   at_sm = STps->at_sm;

   memset(cmd, 0, 10);
   datalen = 0;
   switch (cmd_in) {
     case MTFSFM:
       chg_eof = FALSE; /* Changed from the FSF after this */
     case MTFSF:
       cmd[0] = SPACE;
       cmd[1] = 0x01; /* Space FileMarks */
       cmd[2] = (arg >> 16);
       cmd[3] = (arg >> 8);
       cmd[4] = arg;
#if DEBUG
       if (debugging)
	 printk(ST_DEB_MSG "st%d: Spacing tape forward over %d filemarks.\n",
		dev, cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
#endif
       if (fileno >= 0)
	 fileno += arg;
       blkno = 0;
       at_sm &= (arg == 0);
       break;
     case MTBSFM:
       chg_eof = FALSE; /* Changed from the FSF after this */
     case MTBSF:
       cmd[0] = SPACE;
       cmd[1] = 0x01; /* Space FileMarks */
       ltmp = (-arg);
       cmd[2] = (ltmp >> 16);
       cmd[3] = (ltmp >> 8);
       cmd[4] = ltmp;
#if DEBUG
       if (debugging) {
	 if (cmd[2] & 0x80)
	   ltmp = 0xff000000;
	 ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4];
	 printk(ST_DEB_MSG "st%d: Spacing tape backward over %ld filemarks.\n",
		dev, (-ltmp));
       }
#endif
       if (fileno >= 0)
	 fileno -= arg;
       blkno = (-1);  /* We can't know the block number */
       at_sm &= (arg == 0);
       break;
     case MTFSR:
       cmd[0] = SPACE;
       cmd[1] = 0x00; /* Space Blocks */
       cmd[2] = (arg >> 16);
       cmd[3] = (arg >> 8);
       cmd[4] = arg;
#if DEBUG
       if (debugging)
	 printk(ST_DEB_MSG "st%d: Spacing tape forward %d blocks.\n", dev,
		cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
#endif
       if (blkno >= 0)
	 blkno += arg;
       at_sm &= (arg == 0);
       break;
     case MTBSR:
       cmd[0] = SPACE;
       cmd[1] = 0x00; /* Space Blocks */
       ltmp = (-arg);
       cmd[2] = (ltmp >> 16);
       cmd[3] = (ltmp >> 8);
       cmd[4] = ltmp;
#if DEBUG
       if (debugging) {
	 if (cmd[2] & 0x80)
	   ltmp = 0xff000000;
	 ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4];
	 printk(ST_DEB_MSG "st%d: Spacing tape backward %ld blocks.\n", dev, (-ltmp));
       }
#endif
       if (blkno >= 0)
	 blkno -= arg;
       at_sm &= (arg == 0);
       break;
     case MTFSS:
       cmd[0] = SPACE;
       cmd[1] = 0x04; /* Space Setmarks */
       cmd[2] = (arg >> 16);
       cmd[3] = (arg >> 8);
       cmd[4] = arg;
#if DEBUG
       if (debugging)
	 printk(ST_DEB_MSG "st%d: Spacing tape forward %d setmarks.\n", dev,
		cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
#endif
       if (arg != 0) {
	 blkno = fileno = (-1);
	 at_sm = 1;
       }
       break;
     case MTBSS:
       cmd[0] = SPACE;
       cmd[1] = 0x04; /* Space Setmarks */
       ltmp = (-arg);
       cmd[2] = (ltmp >> 16);
       cmd[3] = (ltmp >> 8);
       cmd[4] = ltmp;
#if DEBUG
       if (debugging) {
	 if (cmd[2] & 0x80)
	   ltmp = 0xff000000;
	 ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4];
	 printk(ST_DEB_MSG "st%d: Spacing tape backward %ld setmarks.\n",
		dev, (-ltmp));
       }
#endif
       if (arg != 0) {
	 blkno = fileno = (-1);
	 at_sm = 1;
       }
       break;
     case MTWEOF:
     case MTWSM:
       if (STp->write_prot)
	 return (-EACCES);
       cmd[0] = WRITE_FILEMARKS;
       if (cmd_in == MTWSM)
	 cmd[1] = 2;
       cmd[2] = (arg >> 16);
       cmd[3] = (arg >> 8);
       cmd[4] = arg;
       timeout = STp->timeout;
#if DEBUG
       if (debugging) {
	 if (cmd_in == MTWEOF)
	   printk(ST_DEB_MSG "st%d: Writing %d filemarks.\n", dev,
		  cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
	 else
	   printk(ST_DEB_MSG "st%d: Writing %d setmarks.\n", dev,
		  cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
       }
#endif
       if (fileno >= 0)
	 fileno += arg;
       blkno = 0;
       at_sm = (cmd_in == MTWSM);
       break;
     case MTREW:
       cmd[0] = REZERO_UNIT;
#if ST_NOWAIT
       cmd[1] = 1;  /* Don't wait for completion */
       timeout = STp->timeout;
#endif
#if DEBUG
       if (debugging)
	 printk(ST_DEB_MSG "st%d: Rewinding tape.\n", dev);
#endif
       fileno = blkno = at_sm = 0 ;
       break;
     case MTOFFL:
     case MTLOAD:
     case MTUNLOAD:
       cmd[0] = START_STOP;
       if (cmd_in == MTLOAD)
	 cmd[4] |= 1;
       /*
        * If arg >= 1 && arg <= 6 Enhanced load/unload in HP C1553A
       */
       if (cmd_in != MTOFFL &&
	   arg >= 1 + MT_ST_HPLOADER_OFFSET
	   && arg <= 6 + MT_ST_HPLOADER_OFFSET) {
#if DEBUG
	   if (debugging) {
	       printk(ST_DEB_MSG "st%d: Enhanced %sload slot %2ld.\n",
		      dev, (cmd[4]) ? "" : "un",
		      arg - MT_ST_HPLOADER_OFFSET);
	   }
#endif
	   cmd[3] = arg - MT_ST_HPLOADER_OFFSET; /* MediaID field of C1553A */
       }
#if ST_NOWAIT
       cmd[1] = 1;  /* Don't wait for completion */
       timeout = STp->timeout;
#else
       timeout = STp->long_timeout;
#endif
#if DEBUG
       if (debugging) {
	 if (cmd_in != MTLOAD)
	   printk(ST_DEB_MSG "st%d: Unloading tape.\n", dev);
	 else
	   printk(ST_DEB_MSG "st%d: Loading tape.\n", dev);
       }
#endif
       fileno = blkno = at_sm = 0 ;
       break;
     case MTNOP:
#if DEBUG
       if (debugging)
	 printk(ST_DEB_MSG "st%d: No op on tape.\n", dev);
#endif
       return 0;  /* Should do something ? */
       break;
     case MTRETEN:
       cmd[0] = START_STOP;
#if ST_NOWAIT
       cmd[1] = 1;  /* Don't wait for completion */
       timeout = STp->timeout;
#endif
       cmd[4] = 3;
#if DEBUG
       if (debugging)
	 printk(ST_DEB_MSG "st%d: Retensioning tape.\n", dev);
#endif
       fileno = blkno = at_sm = 0;
       break;
     case MTEOM:
       if (!STp->fast_mteom) {
	 /* space to the end of tape */
	 ioctl_result = st_int_ioctl(inode, MTFSF, 0x3fff);
	 fileno = STps->drv_file;
	 if (STps->eof >= ST_EOD_1)
	   return 0;
	 /* The next lines would hide the number of spaced FileMarks
	    That's why I inserted the previous lines. I had no luck
	    with detecting EOM with FSF, so we go now to EOM.
	    Joerg Weule */
       }
       else
	 fileno = (-1);
       cmd[0] = SPACE;
       cmd[1] = 3;
#if DEBUG
       if (debugging)
	 printk(ST_DEB_MSG "st%d: Spacing to end of recorded medium.\n", dev);
#endif
       blkno = 0;
       at_sm = 0;
       break;
     case MTERASE:
       if (STp->write_prot)
	 return (-EACCES);
       cmd[0] = ERASE;
       cmd[1] = 1;  /* To the end of tape */
#if ST_NOWAIT
       cmd[1] |= 2;  /* Don't wait for completion */
       timeout = STp->timeout;
#else
       timeout = STp->long_timeout * 8;
#endif
#if DEBUG
       if (debugging)
	 printk(ST_DEB_MSG "st%d: Erasing tape.\n", dev);
#endif
       fileno = blkno = at_sm = 0 ;
       break;
     case MTLOCK:
       chg_eof = FALSE;
       cmd[0] = ALLOW_MEDIUM_REMOVAL;
       cmd[4] = SCSI_REMOVAL_PREVENT;
#if DEBUG
       if (debugging)
	 printk(ST_DEB_MSG "st%d: Locking drive door.\n", dev);
#endif;
       break;
     case MTUNLOCK:
       chg_eof = FALSE;
       cmd[0] = ALLOW_MEDIUM_REMOVAL;
       cmd[4] = SCSI_REMOVAL_ALLOW;
#if DEBUG
       if (debugging)
	 printk(ST_DEB_MSG "st%d: Unlocking drive door.\n", dev);
#endif;
       break;
     case MTSETBLK:  /* Set block length */
     case MTSETDENSITY: /* Set tape density */
     case MTSETDRVBUFFER: /* Set drive buffering */
     case SET_DENS_AND_BLK: /* Set density and block size */
       chg_eof = FALSE;
       if (STp->dirty || (STp->buffer)->buffer_bytes != 0)
	 return (-EIO);   /* Not allowed if data in buffer */
       if ((cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) &&
	   (arg & MT_ST_BLKSIZE_MASK) != 0 &&
	   ((arg & MT_ST_BLKSIZE_MASK) < STp->min_block ||
	    (arg & MT_ST_BLKSIZE_MASK) > STp->max_block ||
	    (arg & MT_ST_BLKSIZE_MASK) > st_buffer_size)) {
	 printk(KERN_WARNING "st%d: Illegal block size.\n", dev);
	 return (-EINVAL);
       }
       cmd[0] = MODE_SELECT;
       if ((STp->use_pf & USE_PF))
	 cmd[1] = 0x10;
       cmd[4] = datalen = 12;

       memset((STp->buffer)->b_data, 0, 12);
       if (cmd_in == MTSETDRVBUFFER)
	 (STp->buffer)->b_data[2] = (arg & 7) << 4;
       else
	 (STp->buffer)->b_data[2] =
	   STp->drv_buffer << 4;
       (STp->buffer)->b_data[3] = 8;     /* block descriptor length */
       if (cmd_in == MTSETDENSITY) {
	 (STp->buffer)->b_data[4] = arg;
	 STp->density_changed = TRUE;  /* At least we tried ;-) */
       }
       else if (cmd_in == SET_DENS_AND_BLK)
	 (STp->buffer)->b_data[4] = arg >> 24;
       else
	 (STp->buffer)->b_data[4] = STp->density;
       if (cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) {
	 ltmp = arg & MT_ST_BLKSIZE_MASK;
	 if (cmd_in == MTSETBLK)
	   STp->blksize_changed = TRUE;  /* At least we tried ;-) */
       }
       else
	 ltmp = STp->block_size;
       (STp->buffer)->b_data[9] = (ltmp >> 16);
       (STp->buffer)->b_data[10] = (ltmp >> 8);
       (STp->buffer)->b_data[11] = ltmp;
       timeout = STp->timeout;
#if DEBUG
       if (debugging) {
	 if (cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK)
	   printk(ST_DEB_MSG "st%d: Setting block size to %d bytes.\n", dev,
		  (STp->buffer)->b_data[9] * 65536 +
		  (STp->buffer)->b_data[10] * 256 +
		  (STp->buffer)->b_data[11]);
	 if (cmd_in == MTSETDENSITY || cmd_in == SET_DENS_AND_BLK)
	   printk(ST_DEB_MSG "st%d: Setting density code to %x.\n", dev,
		  (STp->buffer)->b_data[4]);
	 if (cmd_in == MTSETDRVBUFFER)
	   printk(ST_DEB_MSG "st%d: Setting drive buffer code to %d.\n", dev,
		  ((STp->buffer)->b_data[2] >> 4) & 7);
       }
#endif
       break;
     default:
       return (-ENOSYS);
     }

   SCpnt = st_do_scsi(NULL, STp, cmd, datalen, timeout, MAX_RETRIES, TRUE);
   if (!SCpnt)
     return (-EBUSY);

   ioctl_result = (STp->buffer)->last_result_fatal;

   if (!ioctl_result) {  /* SCSI command successful */
     scsi_release_command(SCpnt);
     SCpnt = NULL;
     STps->drv_block = blkno;
     STps->drv_file = fileno;
     STps->at_sm = at_sm;

     if (cmd_in == MTLOCK)
       STp->door_locked = ST_LOCKED_EXPLICIT;
     else if (cmd_in == MTUNLOCK)
       STp->door_locked = ST_UNLOCKED;

     if (cmd_in == MTBSFM)
       ioctl_result = st_int_ioctl(inode, MTFSF, 1);
     else if (cmd_in == MTFSFM)
       ioctl_result = st_int_ioctl(inode, MTBSF, 1);

     if (cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) {
       STp->block_size = arg & MT_ST_BLKSIZE_MASK;
       if (STp->block_size != 0)
	 (STp->buffer)->buffer_blocks =
	   (STp->buffer)->buffer_size / STp->block_size;
       (STp->buffer)->buffer_bytes = (STp->buffer)->read_pointer = 0;
       if (cmd_in == SET_DENS_AND_BLK)
         STp->density = arg >> MT_ST_DENSITY_SHIFT;
     }
     else if (cmd_in == MTSETDRVBUFFER)
       STp->drv_buffer = (arg & 7);
     else if (cmd_in == MTSETDENSITY)
       STp->density = arg;

     if (cmd_in == MTEOM)
       STps->eof = ST_EOD;
     else if (cmd_in == MTFSF)
       STps->eof = ST_FM;
     else if (chg_eof)
       STps->eof = ST_NOEOF;


     if (cmd_in == MTOFFL || cmd_in == MTUNLOAD)
       STp->rew_at_close = 0;
     else if (cmd_in == MTLOAD) {
       STp->rew_at_close = (MINOR(inode->i_rdev) & 0x80) == 0;
       for (i=0; i < ST_NBR_PARTITIONS; i++) {
	 STp->ps[i].rw = ST_IDLE;
	 STp->ps[i].last_block_valid = FALSE;
       }
       STp->partition = 0;
     }

   } else {  /* SCSI command was not completely successful. Don't return
	        from this block without releasing the SCSI command block! */

     if (SCpnt->sense_buffer[2] & 0x40) {
       if (cmd_in != MTBSF && cmd_in != MTBSFM &&
	   cmd_in != MTBSR && cmd_in != MTBSS)
	   STps->eof = ST_EOM_OK;
       STps->drv_block = 0;
     }

     undone = (
	  (SCpnt->sense_buffer[3] << 24) +
	  (SCpnt->sense_buffer[4] << 16) +
	  (SCpnt->sense_buffer[5] << 8) +
	  SCpnt->sense_buffer[6] );
     if (cmd_in == MTWEOF &&
       (SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
       (SCpnt->sense_buffer[2] & 0x4f) == 0x40 &&
       ((SCpnt->sense_buffer[0] & 0x80) == 0 || undone == 0)) {
       ioctl_result = 0;  /* EOF written succesfully at EOM */
       if (fileno >= 0)
	 fileno++;
       STps->drv_file = fileno;
       STps->eof = ST_NOEOF;
     }
     else if ( (cmd_in == MTFSF) || (cmd_in == MTFSFM) ) {
       if (fileno >= 0)
	 STps->drv_file = fileno - undone ;
       else
	 STps->drv_file = fileno;
       STps->drv_block = 0;
       STps->eof = ST_NOEOF;
     }
     else if ( (cmd_in == MTBSF) || (cmd_in == MTBSFM) ) {
       if (STps->drv_file >= 0)
         STps->drv_file = fileno + undone ;
       else
	 STps->drv_file = fileno;
       STps->drv_block = 0;
       STps->eof = ST_NOEOF;
     }
     else if (cmd_in == MTFSR) {
       if (SCpnt->sense_buffer[2] & 0x80) { /* Hit filemark */
	 if (STps->drv_file >= 0)
	   STps->drv_file++;
	 STps->drv_block = 0;
	 STps->eof = ST_FM;
       }
       else {
	 if (blkno >= undone)
	   STps->drv_block = blkno - undone;
	 else
	   STps->drv_block = (-1);
	 STps->eof = ST_NOEOF;
       }
     }
     else if (cmd_in == MTBSR) {
       if (SCpnt->sense_buffer[2] & 0x80) { /* Hit filemark */
	 STps->drv_file--;
	 STps->drv_block = (-1);
       }
       else {
	 if (STps->drv_block >= 0)
	   STps->drv_block = blkno + undone;
	 else
	   STps->drv_block = (-1);
       }
       STps->eof = ST_NOEOF;
     }
     else if (cmd_in == MTEOM) {
       STps->drv_file = (-1);
       STps->drv_block = (-1);
       STps->eof = ST_EOD;
     }
     else if (cmd_in == MTSETBLK ||
              cmd_in == MTSETDENSITY ||
              cmd_in == MTSETDRVBUFFER ||
              cmd_in == SET_DENS_AND_BLK) {
       if ((SCpnt->sense_buffer[2] & 0x0f) == ILLEGAL_REQUEST &&
           !(STp->use_pf & PF_TESTED)) {
         /* Try the other possible state of Page Format if not
            already tried */
         STp->use_pf = !STp->use_pf | PF_TESTED;
         scsi_release_command(SCpnt);
         SCpnt = NULL;
         return st_int_ioctl(inode, cmd_in, arg);
       }
     }
     else if (chg_eof)
       STps->eof = ST_NOEOF;

     if ((SCpnt->sense_buffer[2] & 0x0f) == BLANK_CHECK)
       STps->eof = ST_EOD;

     if (cmd_in == MTLOCK)
       STp->door_locked = ST_LOCK_FAILS;

     scsi_release_command(SCpnt);
     SCpnt = NULL;
   }

   return ioctl_result;
}

Generated by GNU enscript 1.6.4.