Merge Fedora Core 2 Updates kernel-2.6.10-1.771_FC2
[linux-2.6.git] / drivers / scsi / scsi_ioctl.c
index faab1a0..d459bb7 100644 (file)
@@ -5,23 +5,22 @@
  *   for the ones that remain
  */
 #include <linux/module.h>
-
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <asm/page.h>
-
+#include <linux/blkdev.h>
 #include <linux/interrupt.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/string.h>
+#include <asm/uaccess.h>
 
-#include <linux/blkdev.h>
-#include "scsi.h"
+#include <scsi/scsi.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_eh.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_ioctl.h>
+#include <scsi/scsi_request.h>
+#include <scsi/sg.h>
 
 #include "scsi_logging.h"
 
@@ -393,6 +392,21 @@ int scsi_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
        if (!scsi_block_when_processing_errors(sdev))
                return -ENODEV;
 
+       /* Check for deprecated ioctls ... all the ioctls which don't
+        * follow the new unique numbering scheme are deprecated */
+       switch (cmd) {
+       case SCSI_IOCTL_SEND_COMMAND:
+       case SCSI_IOCTL_TEST_UNIT_READY:
+       case SCSI_IOCTL_BENCHMARK_COMMAND:
+       case SCSI_IOCTL_SYNC:
+       case SCSI_IOCTL_START_UNIT:
+       case SCSI_IOCTL_STOP_UNIT:
+               printk(KERN_WARNING "program %s is using a deprecated SCSI ioctl, please convert it to SG_IO\n", current->comm);
+               break;
+       default:
+               break;
+       }
+
        switch (cmd) {
        case SCSI_IOCTL_GET_IDLUN:
                if (verify_area(VERIFY_WRITE, arg, sizeof(struct scsi_idlun)))
@@ -419,12 +433,8 @@ int scsi_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
        case SCSI_IOCTL_DOORUNLOCK:
                return scsi_set_medium_removal(sdev, SCSI_REMOVAL_ALLOW);
        case SCSI_IOCTL_TEST_UNIT_READY:
-               scsi_cmd[0] = TEST_UNIT_READY;
-               scsi_cmd[1] = 0;
-               scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
-               scsi_cmd[4] = 0;
-               return ioctl_internal_command(sdev, scsi_cmd,
-                                  IOCTL_NORMAL_TIMEOUT, NORMAL_RETRIES);
+               return scsi_test_unit_ready(sdev, IOCTL_NORMAL_TIMEOUT,
+                                           NORMAL_RETRIES);
        case SCSI_IOCTL_START_UNIT:
                scsi_cmd[0] = START_STOP;
                scsi_cmd[1] = 0;
@@ -447,3 +457,51 @@ int scsi_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
        }
        return -EINVAL;
 }
+
+/*
+ * the scsi_nonblock_ioctl() function is designed for ioctls which may
+ * be executed even if the device is in recovery.
+ */
+int scsi_nonblockable_ioctl(struct scsi_device *sdev, int cmd,
+                           void __user *arg, struct file *filp)
+{
+       int val, result;
+
+       /* The first set of iocts may be executed even if we're doing
+        * error processing, as long as the device was opened
+        * non-blocking */
+       if (filp && filp->f_flags & O_NONBLOCK) {
+               if (test_bit(SHOST_RECOVERY,
+                            &sdev->host->shost_state))
+                       return -ENODEV;
+       } else if (!scsi_block_when_processing_errors(sdev))
+               return -ENODEV;
+
+       switch (cmd) {
+       case SG_SCSI_RESET:
+               result = get_user(val, (int __user *)arg);
+               if (result)
+                       return result;
+               if (val == SG_SCSI_RESET_NOTHING)
+                       return 0;
+               switch (val) {
+               case SG_SCSI_RESET_DEVICE:
+                       val = SCSI_TRY_RESET_DEVICE;
+                       break;
+               case SG_SCSI_RESET_BUS:
+                       val = SCSI_TRY_RESET_BUS;
+                       break;
+               case SG_SCSI_RESET_HOST:
+                       val = SCSI_TRY_RESET_HOST;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
+                       return -EACCES;
+               return (scsi_reset_provider(sdev, val) ==
+                       SUCCESS) ? 0 : -EIO;
+       }
+       return -ENODEV;
+}
+EXPORT_SYMBOL(scsi_nonblockable_ioctl);