diff --git a/.gitignore b/.gitignore
index 4c91d52f7..c2fa0f161 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,6 +15,4 @@ tests/build
 .env
 /tests/lpc175x_6x/build/
 /tests/lpc18xx_43xx/build/
-/demos/*/*/Board_*
-/demos/*/*/KeilBuild/
 /examples/*/*/build-*
diff --git a/examples/device/cdc_msc_hid/src/msc_disk.c b/examples/device/cdc_msc_hid/src/msc_disk.c
index 42e77ef76..ff7cb8d51 100644
--- a/examples/device/cdc_msc_hid/src/msc_disk.c
+++ b/examples/device/cdc_msc_hid/src/msc_disk.c
@@ -118,6 +118,59 @@ uint8_t msc_disk[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] =
   README_CONTENTS
 };
 
+// Invoked when received SCSI_CMD_INQUIRY
+// Application fill vendor id, product id and revision with string up to 8, 16, 4 characters respectively
+void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4])
+{
+  (void) lun;
+
+  const char vid[] = "TinyUSB";
+  const char pid[] = "Mass Storage";
+  const char rev[] = "1.0";
+
+  memcpy(vendor_id  , vid, strlen(vid));
+  memcpy(product_id , pid, strlen(pid));
+  memcpy(product_rev, rev, strlen(rev));
+}
+
+// Invoked when received Test Unit Ready command.
+// return true allowing host to read/write this LUN e.g SD card inserted
+bool tud_msc_test_unit_ready_cb(uint8_t lun)
+{
+  (void) lun;
+
+  return true; // RAM disk is always ready
+}
+
+// Invoked when received SCSI_CMD_READ_CAPACITY_10 and SCSI_CMD_READ_FORMAT_CAPACITY to determine the disk size
+// Application update block count and block size
+void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size)
+{
+  (void) lun;
+
+  *block_count = DISK_BLOCK_NUM;
+  *block_size  = DISK_BLOCK_SIZE;
+}
+
+// Invoked when received Start Stop Unit command
+// - Start = 0 : stopped power mode, if load_eject = 1 : unload disk storage
+// - Start = 1 : active mode, if load_eject = 1 : load disk storage
+void tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject)
+{
+  (void) lun;
+  (void) power_condition;
+
+  if ( load_eject )
+  {
+    if (start)
+    {
+      // load disk storage
+    }else
+    {
+      // unload disk storage
+    }
+  }
+}
 
 // Callback invoked when received READ10 command.
 // Copy disk's data to buffer (up to bufsize) and return number of copied bytes.
@@ -147,15 +200,6 @@ int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t*
   return bufsize;
 }
 
-// Callback invoked to determine disk's size
-void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size)
-{
-  (void) lun;
-
-  *block_count = DISK_BLOCK_NUM;
-  *block_size  = DISK_BLOCK_SIZE;
-}
-
 // Callback invoked when received an SCSI command not in built-in list below
 // - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, MODE_SENSE6, REQUEST_SENSE
 // - READ10 and WRITE10 has their own callbacks
@@ -171,28 +215,11 @@ int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer,
 
   switch (scsi_cmd[0])
   {
-    case SCSI_CMD_TEST_UNIT_READY:
-      // Command that host uses to check our readiness before sending other commands
-      resplen = 0;
-    break;
-
     case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL:
       // Host is about to read/write etc ... better not to disconnect disk
       resplen = 0;
     break;
 
-    case SCSI_CMD_START_STOP_UNIT:
-      // Host try to eject/safe remove/poweroff us. We could safely disconnect with disk storage, or go into lower power
-      /* scsi_start_stop_unit_t const * start_stop = (scsi_start_stop_unit_t const *) scsi_cmd;
-        // Start bit = 0 : low power mode, if load_eject = 1 : unmount disk storage as well
-        // Start bit = 1 : Ready mode, if load_eject = 1 : mount disk storage
-        start_stop->start;
-        start_stop->load_eject;
-       */
-       resplen = 0;
-    break;
-
-
     default:
       // Set Sense = Invalid Command Operation
       tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00);
diff --git a/examples/device/cdc_msc_hid/src/tusb_config.h b/examples/device/cdc_msc_hid/src/tusb_config.h
index c1210152e..e909a0d4a 100644
--- a/examples/device/cdc_msc_hid/src/tusb_config.h
+++ b/examples/device/cdc_msc_hid/src/tusb_config.h
@@ -88,15 +88,6 @@
 // Buffer size of Device Mass storage
 #define CFG_TUD_MSC_BUFSIZE         512
 
-// Vendor name included in Inquiry response, max 8 bytes
-#define CFG_TUD_MSC_VENDOR          "tinyusb"
-
-// Product name included in Inquiry response, max 16 bytes
-#define CFG_TUD_MSC_PRODUCT         "tusb msc"
-
-// Product revision string included in Inquiry response, max 4 bytes
-#define CFG_TUD_MSC_PRODUCT_REV     "1.0"
-
 //------------- HID -------------//
 
 // Should be sufficient to hold ID (if any) + Data
diff --git a/examples/device/cdc_msc_hid/src/usb_descriptors.c b/examples/device/cdc_msc_hid/src/usb_descriptors.c
index 72d280c2f..ef3cc9cef 100644
--- a/examples/device/cdc_msc_hid/src/usb_descriptors.c
+++ b/examples/device/cdc_msc_hid/src/usb_descriptors.c
@@ -117,7 +117,7 @@ enum
 
 uint8_t const desc_configuration[] =
 {
-  // Inteface count, string index, total length, attribute, power in mA
+  // Interface count, string index, total length, attribute, power in mA
   TUD_CONFIG_DESCRIPTOR(ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
 
 #if CFG_TUD_CDC
diff --git a/examples/device/cdc_msc_hid_freertos/src/msc_disk.c b/examples/device/cdc_msc_hid_freertos/src/msc_disk.c
index 961a10b30..c2a62e035 100644
--- a/examples/device/cdc_msc_hid_freertos/src/msc_disk.c
+++ b/examples/device/cdc_msc_hid_freertos/src/msc_disk.c
@@ -118,6 +118,60 @@ uint8_t msc_disk[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] =
   README_CONTENTS
 };
 
+// Invoked when received SCSI_CMD_INQUIRY
+// Application fill vendor id, product id and revision with string up to 8, 16, 4 characters respectively
+void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4])
+{
+  (void) lun;
+
+  const char vid[] = "TinyUSB";
+  const char pid[] = "Mass Storage";
+  const char rev[] = "1.0";
+
+  memcpy(vendor_id  , vid, strlen(vid));
+  memcpy(product_id , pid, strlen(pid));
+  memcpy(product_rev, rev, strlen(rev));
+}
+
+// Invoked when received Test Unit Ready command.
+// return true allowing host to read/write this LUN e.g SD card inserted
+bool tud_msc_test_unit_ready_cb(uint8_t lun)
+{
+  (void) lun;
+
+  return true; // RAM disk is always ready
+}
+
+// Invoked when received SCSI_CMD_READ_CAPACITY_10 and SCSI_CMD_READ_FORMAT_CAPACITY to determine the disk size
+// Application update block count and block size
+void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size)
+{
+  (void) lun;
+
+  *block_count = DISK_BLOCK_NUM;
+  *block_size  = DISK_BLOCK_SIZE;
+}
+
+// Invoked when received Start Stop Unit command
+// - Start = 0 : stopped power mode, if load_eject = 1 : unload disk storage
+// - Start = 1 : active mode, if load_eject = 1 : load disk storage
+void tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject)
+{
+  (void) lun;
+  (void) power_condition;
+
+  if ( load_eject )
+  {
+    if (start)
+    {
+      // load disk storage
+    }else
+    {
+      // unload disk storage
+    }
+  }
+}
+
 // Callback invoked when received READ10 command.
 // Copy disk's data to buffer (up to bufsize) and return number of copied bytes.
 int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize)
@@ -146,14 +200,6 @@ int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t*
   return bufsize;
 }
 
-void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size)
-{
-  (void) lun;
-
-  *block_count = DISK_BLOCK_NUM;
-  *block_size  = DISK_BLOCK_SIZE;
-}
-
 // Callback invoked when received an SCSI command not in built-in list below
 // - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, MODE_SENSE6, REQUEST_SENSE
 // - READ10 and WRITE10 has their own callbacks
@@ -169,11 +215,6 @@ int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer,
 
   switch (scsi_cmd[0])
   {
-    case SCSI_CMD_TEST_UNIT_READY:
-      // Command that host uses to check our readiness before sending other commands
-      resplen = 0;
-    break;
-
     case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL:
       // Host is about to read/write etc ... better not to disconnect disk
       resplen = 0;
diff --git a/examples/device/cdc_msc_hid_freertos/src/tusb_config.h b/examples/device/cdc_msc_hid_freertos/src/tusb_config.h
index 04ffaafca..c377798c1 100644
--- a/examples/device/cdc_msc_hid_freertos/src/tusb_config.h
+++ b/examples/device/cdc_msc_hid_freertos/src/tusb_config.h
@@ -88,15 +88,6 @@
 // Buffer size of Device Mass storage
 #define CFG_TUD_MSC_BUFSIZE         512
 
-// Vendor name included in Inquiry response, max 8 bytes
-#define CFG_TUD_MSC_VENDOR          "tinyusb"
-
-// Product name included in Inquiry response, max 16 bytes
-#define CFG_TUD_MSC_PRODUCT         "tusb msc"
-
-// Product revision string included in Inquiry response, max 4 bytes
-#define CFG_TUD_MSC_PRODUCT_REV     "1.0"
-
 //------------- HID -------------//
 
 // Should be sufficient to hold ID (if any) + Data
diff --git a/examples/device/hid_generic_inout/hid_test.py b/examples/device/hid_generic_inout/hid_test.py
index b6799687d..c89d89062 100644
--- a/examples/device/hid_generic_inout/hid_test.py
+++ b/examples/device/hid_generic_inout/hid_test.py
@@ -3,7 +3,9 @@ import hid
 
 USB_VID = 0xcafe
 
-for dict in hid.enumerate(0xcafe):
+print("Openning HID device with VID = 0x%X" % USB_VID)
+
+for dict in hid.enumerate(USB_VID):
     print(dict)
     dev = hid.Device(dict['vendor_id'], dict['product_id'])
     if dev:
diff --git a/examples/device/msc_dual_lun/src/msc_disk_dual.c b/examples/device/msc_dual_lun/src/msc_disk_dual.c
index 48c8f2409..fd6347300 100644
--- a/examples/device/msc_dual_lun/src/msc_disk_dual.c
+++ b/examples/device/msc_dual_lun/src/msc_disk_dual.c
@@ -205,20 +205,64 @@ uint8_t msc_disk1[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] =
 };
 
 // Invoked to determine max LUN
-uint8_t tud_msc_maxlun_cb(void)
+uint8_t tud_msc_get_maxlun_cb(void)
 {
   return 2; // dual LUN
 }
 
-// Callback invoked to determine disk's size
+// Invoked when received SCSI_CMD_INQUIRY
+// Application fill vendor id, product id and revision with string up to 8, 16, 4 characters respectively
+void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4])
+{
+  (void) lun; // use same ID for both LUNs
+
+  const char vid[] = "TinyUSB";
+  const char pid[] = "Mass Storage";
+  const char rev[] = "1.0";
+
+  memcpy(vendor_id  , vid, strlen(vid));
+  memcpy(product_id , pid, strlen(pid));
+  memcpy(product_rev, rev, strlen(rev));
+}
+
+// Invoked when received Test Unit Ready command.
+// return true allowing host to read/write this LUN e.g SD card inserted
+bool tud_msc_test_unit_ready_cb(uint8_t lun)
+{
+  (void) lun;
+
+  return true; // RAM disk is always ready
+}
+
+// Invoked when received SCSI_CMD_READ_CAPACITY_10 and SCSI_CMD_READ_FORMAT_CAPACITY to determine the disk size
+// Application update block count and block size
 void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size)
 {
-  (void) lun; // both LUNs have same size
+  (void) lun;
 
   *block_count = DISK_BLOCK_NUM;
   *block_size  = DISK_BLOCK_SIZE;
 }
 
+// Invoked when received Start Stop Unit command
+// - Start = 0 : stopped power mode, if load_eject = 1 : unload disk storage
+// - Start = 1 : active mode, if load_eject = 1 : load disk storage
+void tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject)
+{
+  (void) lun;
+  (void) power_condition;
+
+  if ( load_eject )
+  {
+    if (start)
+    {
+      // load disk storage
+    }else
+    {
+      // unload disk storage
+    }
+  }
+}
 
 // Callback invoked when received READ10 command.
 // Copy disk's data to buffer (up to bufsize) and return number of copied bytes.
@@ -259,11 +303,6 @@ int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer,
 
   switch (scsi_cmd[0])
   {
-    case SCSI_CMD_TEST_UNIT_READY:
-      // Command that host uses to check our readiness before sending other commands
-      resplen = 0;
-    break;
-
     case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL:
       // Host is about to read/write etc ... better not to disconnect disk
       resplen = 0;
diff --git a/examples/device/msc_dual_lun/src/tusb_config.h b/examples/device/msc_dual_lun/src/tusb_config.h
index 492eba5f1..939919739 100644
--- a/examples/device/msc_dual_lun/src/tusb_config.h
+++ b/examples/device/msc_dual_lun/src/tusb_config.h
@@ -81,15 +81,6 @@
 // Buffer size of Device Mass storage
 #define CFG_TUD_MSC_BUFSIZE         512
 
-// Vendor name included in Inquiry response, max 8 bytes
-#define CFG_TUD_MSC_VENDOR          "tinyusb"
-
-// Product name included in Inquiry response, max 16 bytes
-#define CFG_TUD_MSC_PRODUCT         "tusb msc"
-
-// Product revision string included in Inquiry response, max 4 bytes
-#define CFG_TUD_MSC_PRODUCT_REV     "1.0"
-
 #ifdef __cplusplus
  }
 #endif
diff --git a/examples/host/cdc_msc_hid/src/tusb_config.h b/examples/host/cdc_msc_hid/src/tusb_config.h
index 3d4d7a333..aa081f9db 100644
--- a/examples/host/cdc_msc_hid/src/tusb_config.h
+++ b/examples/host/cdc_msc_hid/src/tusb_config.h
@@ -101,15 +101,6 @@
 // Buffer size of Device Mass storage
 #define CFG_TUD_MSC_BUFSIZE         512
 
-// Vendor name included in Inquiry response, max 8 bytes
-#define CFG_TUD_MSC_VENDOR          "tinyusb"
-
-// Product name included in Inquiry response, max 16 bytes
-#define CFG_TUD_MSC_PRODUCT         "tusb msc"
-
-// Product revision string included in Inquiry response, max 4 bytes
-#define CFG_TUD_MSC_PRODUCT_REV     "1.0"
-
 //--------------------------------------------------------------------
 // HID
 //--------------------------------------------------------------------
diff --git a/src/class/msc/msc_device.c b/src/class/msc/msc_device.c
index f980e941e..c486d5e04 100644
--- a/src/class/msc/msc_device.c
+++ b/src/class/msc/msc_device.c
@@ -159,7 +159,7 @@ bool mscd_control_request(uint8_t rhport, tusb_control_request_t const * p_reque
     case MSC_REQ_GET_MAX_LUN:
     {
       uint8_t maxlun = 1;
-      if (tud_msc_maxlun_cb) maxlun = tud_msc_maxlun_cb();
+      if (tud_msc_get_maxlun_cb) maxlun = tud_msc_get_maxlun_cb();
       TU_VERIFY(maxlun);
 
       // MAX LUN is minus 1 by specs
@@ -186,30 +186,64 @@ bool mscd_control_request_complete(uint8_t rhport, tusb_control_request_t const
   return true;
 }
 
-// return length of response (copied to buffer), -1 if it is not an built-in commands
-int32_t proc_builtin_scsi(msc_cbw_t const * p_cbw, uint8_t* buffer, uint32_t bufsize)
+// return response's length (copied to buffer). Negative if it is not an built-in command or indicate Failed status (CSW)
+// In case of a failed status, sense key must be set for reason of failure
+int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_t* buffer, uint32_t bufsize)
 {
   (void) bufsize; // TODO refractor later
-  int32_t ret;
+  int32_t resplen;
 
-  switch ( p_cbw->command[0] )
+  switch ( scsi_cmd[0] )
   {
+    case SCSI_CMD_TEST_UNIT_READY:
+      resplen = 0;
+      if ( !tud_msc_test_unit_ready_cb(lun) )
+      {
+        // not ready response with Failed status and sense key = not ready
+        resplen = - 1;
+
+        // If sense key is not set by callback, default to Logical Unit Not Ready, Cause Not Reportable
+        if ( _mscd_itf.sense_key == 0 ) tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x04, 0x00);
+      }
+    break;
+
+    case SCSI_CMD_START_STOP_UNIT:
+      resplen = 0;
+
+      if (tud_msc_start_stop_cb)
+      {
+        scsi_start_stop_unit_t const * start_stop = (scsi_start_stop_unit_t const *) scsi_cmd;
+        tud_msc_start_stop_cb(lun, start_stop->power_condition, start_stop->start, start_stop->load_eject);
+      }
+    break;
+
     case SCSI_CMD_READ_CAPACITY_10:
     {
-      scsi_read_capacity10_resp_t read_capa10;
-
       uint32_t block_count;
       uint32_t block_size;
       uint16_t block_size_u16;
 
-      tud_msc_capacity_cb(p_cbw->lun, &block_count, &block_size_u16);
+      tud_msc_capacity_cb(lun, &block_count, &block_size_u16);
       block_size = (uint32_t) block_size_u16;
 
-      read_capa10.last_lba = ENDIAN_BE(block_count-1);
-      read_capa10.block_size = ENDIAN_BE(block_size);
+      // Invalid block size/count from callback, possibly unit is not ready
+      // stall this request, set sense key to NOT READY
+      if (block_count == 0 || block_size == 0)
+      {
+        resplen = -1;
 
-      ret = sizeof(read_capa10);
-      memcpy(buffer, &read_capa10, ret);
+        // If sense key is not set by callback, default to Logical Unit Not Ready, Cause Not Reportable
+        if ( _mscd_itf.sense_key == 0 ) tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x04, 0x00);
+      }else
+      {
+        scsi_read_capacity10_resp_t read_capa10;
+
+        read_capa10.last_lba = ENDIAN_BE(block_count-1);
+        read_capa10.block_size = ENDIAN_BE(block_size);
+
+        resplen = sizeof(read_capa10);
+        memcpy(buffer, &read_capa10, resplen);
+      }
     }
     break;
 
@@ -226,12 +260,24 @@ int32_t proc_builtin_scsi(msc_cbw_t const * p_cbw, uint8_t* buffer, uint32_t buf
       uint32_t block_count;
       uint16_t block_size;
 
-      tud_msc_capacity_cb(p_cbw->lun, &block_count, &block_size);
-      read_fmt_capa.block_num = ENDIAN_BE(block_count);
-      read_fmt_capa.block_size_u16 = ENDIAN_BE16(block_size);
+      tud_msc_capacity_cb(lun, &block_count, &block_size);
 
-      ret = sizeof(read_fmt_capa);
-      memcpy(buffer, &read_fmt_capa, ret);
+      // Invalid block size/count from callback, possibly unit is not ready
+      // stall this request, set sense key to NOT READY
+      if (block_count == 0 || block_size == 0)
+      {
+        resplen = -1;
+
+        // If sense key is not set by callback, default to Logical Unit Not Ready, Cause Not Reportable
+        if ( _mscd_itf.sense_key == 0 ) tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x04, 0x00);
+      }else
+      {
+        read_fmt_capa.block_num = ENDIAN_BE(block_count);
+        read_fmt_capa.block_size_u16 = ENDIAN_BE16(block_size);
+
+        resplen = sizeof(read_fmt_capa);
+        memcpy(buffer, &read_fmt_capa, resplen);
+      }
     }
     break;
 
@@ -242,23 +288,17 @@ int32_t proc_builtin_scsi(msc_cbw_t const * p_cbw, uint8_t* buffer, uint32_t buf
           .is_removable         = 1,
           .version              = 2,
           .response_data_format = 2,
-          // vendor_id, product_id, product_rev is space padded string
-          .vendor_id            = "",
-          .product_id           = "",
-          .product_rev          = "",
       };
 
-      memset(inquiry_rsp.vendor_id, ' ', sizeof(inquiry_rsp.vendor_id));
-      memcpy(inquiry_rsp.vendor_id, CFG_TUD_MSC_VENDOR, tu_min32(strlen(CFG_TUD_MSC_VENDOR), sizeof(inquiry_rsp.vendor_id)));
-
-      memset(inquiry_rsp.product_id, ' ', sizeof(inquiry_rsp.product_id));
-      memcpy(inquiry_rsp.product_id, CFG_TUD_MSC_PRODUCT, tu_min32(strlen(CFG_TUD_MSC_PRODUCT), sizeof(inquiry_rsp.product_id)));
-
+      // vendor_id, product_id, product_rev is space padded string
+      memset(inquiry_rsp.vendor_id  , ' ', sizeof(inquiry_rsp.vendor_id));
+      memset(inquiry_rsp.product_id , ' ', sizeof(inquiry_rsp.product_id));
       memset(inquiry_rsp.product_rev, ' ', sizeof(inquiry_rsp.product_rev));
-      memcpy(inquiry_rsp.product_rev, CFG_TUD_MSC_PRODUCT_REV, tu_min32(strlen(CFG_TUD_MSC_PRODUCT_REV), sizeof(inquiry_rsp.product_rev)));
 
-      ret = sizeof(inquiry_rsp);
-      memcpy(buffer, &inquiry_rsp, ret);
+      tud_msc_inquiry_cb(lun, inquiry_rsp.vendor_id, inquiry_rsp.product_id, inquiry_rsp.product_rev);
+
+      resplen = sizeof(inquiry_rsp);
+      memcpy(buffer, &inquiry_rsp, resplen);
     }
     break;
 
@@ -275,12 +315,12 @@ int32_t proc_builtin_scsi(msc_cbw_t const * p_cbw, uint8_t* buffer, uint32_t buf
 
       bool writable = true;
       if (tud_msc_is_writable_cb) {
-          writable = tud_msc_is_writable_cb(p_cbw->lun);
+          writable = tud_msc_is_writable_cb(lun);
       }
       mode_resp.write_protected = !writable;
 
-      ret = sizeof(mode_resp);
-      memcpy(buffer, &mode_resp, ret);
+      resplen = sizeof(mode_resp);
+      memcpy(buffer, &mode_resp, resplen);
     }
     break;
 
@@ -298,18 +338,18 @@ int32_t proc_builtin_scsi(msc_cbw_t const * p_cbw, uint8_t* buffer, uint32_t buf
       sense_rsp.add_sense_code      = _mscd_itf.add_sense_code;
       sense_rsp.add_sense_qualifier = _mscd_itf.add_sense_qualifier;
 
-      ret = sizeof(sense_rsp);
-      memcpy(buffer, &sense_rsp, ret);
+      resplen = sizeof(sense_rsp);
+      memcpy(buffer, &sense_rsp, resplen);
 
       // Clear sense data after copy
-      tud_msc_set_sense(p_cbw->lun, 0, 0, 0);
+      tud_msc_set_sense(lun, 0, 0, 0);
     }
     break;
 
-    default: ret = -1; break;
+    default: resplen = -1; break;
   }
 
-  return ret;
+  return resplen;
 }
 
 bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes)
@@ -348,60 +388,50 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
       else
       {
         // For other SCSI commands
-        // 1. Zero : Invoke app callback, skip DATA and move to STATUS stage
-        // 2. OUT  : queue transfer (invoke app callback after done)
-        // 3. IN   : invoke app callback to get response
-        if ( p_cbw->total_bytes == 0)
+        // 1. OUT : queue transfer (invoke app callback after done)
+        // 2. IN & Zero: Process if is built-in, else Invoke app callback. Skip DATA if zero length
+        if ( (p_cbw->total_bytes > 0 ) && !TU_BIT_TEST(p_cbw->dir, 7) )
         {
-          int32_t const cb_result = tud_msc_scsi_cb(p_cbw->lun, p_cbw->command, NULL, 0);
-
-          p_msc->total_len = 0;
-          p_msc->stage = MSC_STAGE_STATUS;
-
-          if ( cb_result < 0 )
-          {
-            p_csw->status = MSC_CSW_STATUS_FAILED;
-            tud_msc_set_sense(p_cbw->lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00); // Sense = Invalid Command Operation
-          }
-          else
-          {
-            p_csw->status = MSC_CSW_STATUS_PASSED;
-          }
-        }
-        else if ( !TU_BIT_TEST(p_cbw->dir, 7) )
-        {
-          // OUT transfer
+          // queue transfer
           TU_ASSERT( dcd_edpt_xfer(rhport, p_msc->ep_out, _mscd_buf, p_msc->total_len) );
-        }
-        else
+        }else
         {
-          // IN Transfer
-          int32_t cb_result;
+          int32_t resplen;
 
-          // first process if it is a built-in commands
-          cb_result = proc_builtin_scsi(p_cbw, _mscd_buf, sizeof(_mscd_buf));
+          // First process if it is a built-in commands
+          resplen = proc_builtin_scsi(p_cbw->lun, p_cbw->command, _mscd_buf, sizeof(_mscd_buf));
 
-          // Not an built-in command, invoke user callback
-          if ( cb_result < 0 )
+          // Not built-in, invoke user callback
+          if ( (resplen < 0) && (p_msc->sense_key == 0) )
           {
-            cb_result = tud_msc_scsi_cb(p_cbw->lun, p_cbw->command, _mscd_buf, p_msc->total_len);
+            resplen = tud_msc_scsi_cb(p_cbw->lun, p_cbw->command, _mscd_buf, p_msc->total_len);
           }
 
-          if ( cb_result > 0 )
-          {
-            p_msc->total_len = (uint32_t) cb_result;
-            p_csw->status = MSC_CSW_STATUS_PASSED;
-
-            TU_ASSERT( p_cbw->total_bytes >= p_msc->total_len ); // cannot return more than host expect
-            TU_ASSERT( dcd_edpt_xfer(rhport, p_msc->ep_in, _mscd_buf, p_msc->total_len) );
-          }else
+          if ( resplen < 0 )
           {
             p_msc->total_len = 0;
             p_csw->status = MSC_CSW_STATUS_FAILED;
             p_msc->stage = MSC_STAGE_STATUS;
 
-            tud_msc_set_sense(p_cbw->lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00); // Sense = Invalid Command Operation
-            usbd_edpt_stall(rhport, p_msc->ep_in);
+            // failed but senskey is not set: default to Illegal Request
+            if ( p_msc->sense_key == 0 ) tud_msc_set_sense(p_cbw->lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00);
+
+            /// Stall bulk In if needed
+            if (p_cbw->total_bytes) usbd_edpt_stall(rhport, p_msc->ep_in);
+          }
+          else
+          {
+            p_msc->total_len = (uint32_t) resplen;
+            p_csw->status = MSC_CSW_STATUS_PASSED;
+
+            if (p_msc->total_len)
+            {
+              TU_ASSERT( p_cbw->total_bytes >= p_msc->total_len ); // cannot return more than host expect
+              TU_ASSERT( dcd_edpt_xfer(rhport, p_msc->ep_in, _mscd_buf, p_msc->total_len) );
+            }else
+            {
+              p_msc->stage = MSC_STAGE_STATUS;
+            }
           }
         }
       }
diff --git a/src/class/msc/msc_device.h b/src/class/msc/msc_device.h
index b1e7e8da1..1baf2d19a 100644
--- a/src/class/msc/msc_device.h
+++ b/src/class/msc/msc_device.h
@@ -44,18 +44,6 @@ TU_VERIFY_STATIC(CFG_TUD_MSC_BUFSIZE < UINT16_MAX, "Size is not correct");
   #error CFG_TUD_MSC_BUFSIZE must be defined, value of a block size should work well, the more the better
 #endif
 
-#ifndef CFG_TUD_MSC_VENDOR
-  #error CFG_TUD_MSC_VENDOR 8-byte name must be defined
-#endif
-
-#ifndef CFG_TUD_MSC_PRODUCT
-  #error CFG_TUD_MSC_PRODUCT 16-byte name must be defined
-#endif
-
-#ifndef CFG_TUD_MSC_PRODUCT_REV
-  #error CFG_TUD_MSC_PRODUCT_REV 4-byte string must be defined
-#endif
-
 /** \addtogroup ClassDriver_MSC
  *  @{
  * \defgroup MSC_Device Device
@@ -105,12 +93,23 @@ int32_t tud_msc_read10_cb (uint8_t lun, uint32_t lba, uint32_t offset, void* buf
  */
 int32_t tud_msc_write10_cb (uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize);
 
+// Invoked when received SCSI_CMD_INQUIRY
+// Application fill vendor id, product id and revision with string up to 8, 16, 4 characters respectively
+void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]);
+
+// Invoked when received Test Unit Ready command.
+// return true allowing host to read/write this LUN e.g SD card inserted
+bool tud_msc_test_unit_ready_cb(uint8_t lun);
+
 // Invoked when received SCSI_CMD_READ_CAPACITY_10 and SCSI_CMD_READ_FORMAT_CAPACITY to determine the disk size
 // Application update block count and block size
 void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size);
 
 /**
- * Callback invoked when received an SCSI command not in built-in list below.
+ * Invoked when received an SCSI command not in built-in list below.
+ * - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, TEST_UNIT_READY, START_STOP_UNIT, MODE_SENSE6, REQUEST_SENSE
+ * - READ10 and WRITE10 has their own callbacks
+ *
  * \param[in]   lun         Logical unit number
  * \param[in]   scsi_cmd    SCSI command contents which application must examine to response accordingly
  * \param[out]  buffer      Buffer for SCSI Data Stage.
@@ -121,17 +120,18 @@ void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_siz
  * \return      Actual bytes processed, can be zero for no-data command.
  * \retval      negative    Indicate error e.g unsupported command, tinyusb will \b STALL the corresponding
  *                          endpoint and return failed status in command status wrapper phase.
- *
- * \note        Following command is automatically handled by tinyusb stack, callback should not be worried:
- *              - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, MODE_SENSE6, REQUEST_SENSE
- *              - READ10 and WRITE10 has their own callbacks
  */
 int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize);
 
 /*------------- Optional callbacks -------------*/
 
-// Invoked when received GET_MAX_LUN request
-ATTR_WEAK uint8_t tud_msc_maxlun_cb(void);
+// Invoked when received GET_MAX_LUN request, required for multiple LUNs implementation
+ATTR_WEAK uint8_t tud_msc_get_maxlun_cb(void);
+
+// Invoked when received Start Stop Unit command
+// - Start = 0 : stopped power mode, if load_eject = 1 : unload disk storage
+// - Start = 1 : active mode, if load_eject = 1 : load disk storage
+ATTR_WEAK void tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject);
 
 // Invoked when Read10 command is complete
 ATTR_WEAK void tud_msc_read10_complete_cb(uint8_t lun);
diff --git a/src/device/dcd.h b/src/device/dcd.h
index 63f923faa..18678f15b 100644
--- a/src/device/dcd.h
+++ b/src/device/dcd.h
@@ -107,7 +107,7 @@ void dcd_remote_wakeup(uint8_t rhport);
  *                  must be called to notify the stack
  *  - busy        : Check if endpoint transferring is complete (TODO remove)
  *  - stall       : stall endpoint
- *  - clear_stall : clear stall
+ *  - clear_stall : clear stall, data toggle is also reset to DATA0
  *------------------------------------------------------------------*/
 bool dcd_edpt_open        (uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc);
 bool dcd_edpt_xfer        (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes);
diff --git a/src/device/usbd.c b/src/device/usbd.c
index d811c471a..434a2c3d8 100644
--- a/src/device/usbd.c
+++ b/src/device/usbd.c
@@ -456,7 +456,7 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const
         case TUSB_REQ_CLEAR_FEATURE:
           if ( TUSB_REQ_FEATURE_EDPT_HALT == p_request->wValue )
           {
-            dcd_edpt_clear_stall(rhport, tu_u16_low(p_request->wIndex));
+            usbd_edpt_clear_stall(rhport, tu_u16_low(p_request->wIndex));
           }
           usbd_control_status(rhport, p_request);
         break;
diff --git a/src/portable/microchip/samd21/dcd_samd21.c b/src/portable/microchip/samd21/dcd_samd21.c
index 8ecfd3668..9a9964505 100644
--- a/src/portable/microchip/samd21/dcd_samd21.c
+++ b/src/portable/microchip/samd21/dcd_samd21.c
@@ -223,9 +223,9 @@ void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr)
   UsbDeviceEndpoint* ep = &USB->DEVICE.DeviceEndpoint[epnum];
 
   if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) {
-    ep->EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_STALLRQ1;
+    ep->EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_STALLRQ1 | USB_DEVICE_EPSTATUSCLR_DTGLIN;
   } else {
-    ep->EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_STALLRQ0;
+    ep->EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_STALLRQ0 | USB_DEVICE_EPSTATUSCLR_DTGLOUT;
   }
 }
 
diff --git a/src/portable/microchip/samd51/dcd_samd51.c b/src/portable/microchip/samd51/dcd_samd51.c
index d2e7aaf7d..6a4bd0e63 100644
--- a/src/portable/microchip/samd51/dcd_samd51.c
+++ b/src/portable/microchip/samd51/dcd_samd51.c
@@ -227,9 +227,9 @@ void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr)
   UsbDeviceEndpoint* ep = &USB->DEVICE.DeviceEndpoint[epnum];
 
   if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) {
-    ep->EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_STALLRQ1;
+    ep->EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_STALLRQ1 | USB_DEVICE_EPSTATUSCLR_DTGLIN;
   } else {
-    ep->EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_STALLRQ0;
+    ep->EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_STALLRQ0 | USB_DEVICE_EPSTATUSCLR_DTGLOUT;
   }
 }
 
diff --git a/src/portable/nordic/nrf5x/dcd_nrf5x.c b/src/portable/nordic/nrf5x/dcd_nrf5x.c
index 3e5f69f79..53f92bb19 100644
--- a/src/portable/nordic/nrf5x/dcd_nrf5x.c
+++ b/src/portable/nordic/nrf5x/dcd_nrf5x.c
@@ -322,7 +322,12 @@ void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr)
 
   if ( tu_edpt_number(ep_addr)  )
   {
+    // clear stall
     NRF_USBD->EPSTALL = (USBD_EPSTALL_STALL_UnStall << USBD_EPSTALL_STALL_Pos) | ep_addr;
+
+    // reset data toggle to DATA0
+    NRF_USBD->DTOGGLE = (USBD_DTOGGLE_VALUE_Data0 << USBD_DTOGGLE_VALUE_Pos) | ep_addr;
+
     __ISB(); __DSB();
   }
 }
diff --git a/src/tusb_option.h b/src/tusb_option.h
index cb6d573ea..4e55132b1 100644
--- a/src/tusb_option.h
+++ b/src/tusb_option.h
@@ -128,7 +128,6 @@
 */
 #ifndef CFG_TUSB_DEBUG
   #define CFG_TUSB_DEBUG 0
-  #warning CFG_TUSB_DEBUG is not defined, default value is 0
 #endif
 
 // place data in accessible RAM for usb controller
@@ -165,6 +164,14 @@
     #define CFG_TUD_MSC          0
   #endif
 
+#ifndef CFG_TUD_MIDI
+  #define CFG_TUD_MIDI            0
+#endif
+
+#ifndef CFG_TUD_CUSTOM_CLASS
+  #define CFG_TUD_CUSTOM_CLASS    0
+#endif
+
 #endif // TUSB_OPT_DEVICE_ENABLED
 
 //--------------------------------------------------------------------
diff --git a/tools/build_all.py b/tools/build_all.py
index d65bb0730..37ca1443a 100644
--- a/tools/build_all.py
+++ b/tools/build_all.py
@@ -6,7 +6,6 @@ import time
 
 travis = False
 if "TRAVIS" in os.environ and os.environ["TRAVIS"] == "true":
-    PARALLEL="-j 2"
     travis = True
 
 success_count = 0
@@ -47,10 +46,10 @@ for example in all_device_example:
 # FreeRTOS example
 #example = 'cdc_msc_hid_freertos'
 #board = 'pca10056'
-#subprocess.run("make -j2 -C examples/device/{} BOARD={} clean all".format(example, board), shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+#build_example(example, board)
 
 
 total_time = time.monotonic() - total_time
-
 print("Total build time took {:.2f}s".format(total_time))
+
 sys.exit(exit_status)