[RAMEN9610-11980][COMMON] usb: gadget: add vendor specific command in mass storage
authorKisang Lee <kisang80.lee@samsung.com>
Thu, 27 Dec 2018 11:03:37 +0000 (20:03 +0900)
committerCosmin Tanislav <demonsingur@gmail.com>
Mon, 22 Apr 2024 17:23:15 +0000 (20:23 +0300)
Change-Id: If8b4e8a89bbff020beee88618693514b61cffd22
Signed-off-by: Kisang Lee <kisang80.lee@samsung.com>
drivers/usb/gadget/function/f_mass_storage.c
include/scsi/scsi_proto.h

index 41b5baa1f43b7da0d6662d31aeeaedc51bafc0ca..bfc733f06b229e630fb09cbce45b02c1c2398b42 100644 (file)
 #include <linux/kthread.h>
 #include <linux/sched/signal.h>
 #include <linux/limits.h>
+#include <linux/reboot.h>
 #include <linux/rwsem.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 
 /*------------------------------------------------------------------------*/
 
-#define FSG_DRIVER_DESC                "Mass Storage Function"
+#define FSG_DRIVER_DESC                "mass_storage"
 #define FSG_DRIVER_VERSION     "2009/09/11"
 
+enum fsg_restart_type {
+       FSG_RESTART_NONE,
+       FSG_REBOOT,
+       FSG_REBOOT_BL,
+};
+
+
 static const char fsg_string_interface[] = "Mass Storage";
 
 #include "storage_common.h"
@@ -316,6 +324,8 @@ struct fsg_common {
        char inquiry_string[INQUIRY_STRING_LEN];
 
        struct kref             ref;
+       enum fsg_restart_type   restart_type;
+       struct delayed_work     restart_work;
 };
 
 struct fsg_dev {
@@ -2030,6 +2040,35 @@ static int do_scsi_command(struct fsg_common *common)
                        reply = do_write(common);
                break;
 
+       case SC_REBOOT:
+               common->data_size_from_cmnd = 0;
+               reply = check_command(common, common->cmnd_size,
+                                       DATA_DIR_NONE, 0, 0, "REBOOT BL");
+               if (reply == 0) {
+                       common->curlun->sense_data = SS_INVALID_COMMAND;
+                       reply = -EINVAL;
+               } else {
+                       pr_err("Triggered Reboot from SCSI Command\n");
+                       common->restart_type = FSG_REBOOT;
+                       schedule_delayed_work(&common->restart_work,
+                                               msecs_to_jiffies(1000));
+               }
+               break;
+       case SC_REBOOT_2:
+               common->data_size_from_cmnd = 0;
+               reply = check_command(common, common->cmnd_size,
+                                       DATA_DIR_NONE, 0, 0, "REBOOT");
+               if (reply == 0) {
+                       common->curlun->sense_data = SS_INVALID_COMMAND;
+                       reply = -EINVAL;
+               } else {
+                       pr_err("Triggered Reboot BL from SCSI Command\n");
+                       common->restart_type = FSG_REBOOT_BL;
+                       schedule_delayed_work(&common->restart_work,
+                                               msecs_to_jiffies(1000));
+               }
+               break;
+
        /*
         * Some mandatory commands that we recognize but don't implement.
         * They don't mean much in this setting.  It's left as an exercise
@@ -2580,6 +2619,32 @@ void fsg_common_put(struct fsg_common *common)
 }
 EXPORT_SYMBOL_GPL(fsg_common_put);
 
+static int disable_restarts;
+module_param(disable_restarts, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(disable_restarts, "Disable SCSI Initiated Reboots");
+static void fsg_restart_work(struct work_struct *work)
+{
+       struct fsg_common *common = container_of(work,
+                                       struct fsg_common,
+                                       restart_work.work);
+
+       if (disable_restarts) {
+               pr_err("SCSI Reboots Disabled\n");
+               return;
+       }
+
+       switch (common->restart_type) {
+       case FSG_REBOOT:
+               kernel_restart("");
+               break;
+       case FSG_REBOOT_BL:
+               kernel_restart("bootloader");
+               break;
+       default:
+               break;
+       }
+}
+
 static struct fsg_common *fsg_common_setup(struct fsg_common *common)
 {
        if (!common) {
@@ -2596,6 +2661,7 @@ static struct fsg_common *fsg_common_setup(struct fsg_common *common)
        init_completion(&common->thread_notifier);
        init_waitqueue_head(&common->io_wait);
        init_waitqueue_head(&common->fsg_wait);
+       INIT_DELAYED_WORK(&common->restart_work, fsg_restart_work);
        common->state = FSG_STATE_TERMINATED;
        memset(common->luns, 0, sizeof(common->luns));
 
index 68e7e3e18004c5b61520cebeeff38af55d75e0a6..9474d60969125b44b9f2b70096d44dabb395990e 100644 (file)
 
 /* Vendor specific CDBs start here */
 #define VENDOR_SPECIFIC_CDB 0xc0
+#define SC_REBOOT          0xd7
+#define SC_REBOOT_2        0xd8
 
 /*
  *     SCSI command lengths