Index: trunk/src/VBox/Devices/Storage/DevATA.cpp
===================================================================
--- trunk/src/VBox/Devices/Storage/DevATA.cpp	(revision 3112)
+++ trunk/src/VBox/Devices/Storage/DevATA.cpp	(revision 3113)
@@ -2526,5 +2526,5 @@
                         PVMREQ pReq;
                         rc = VMR3ReqCall(PDMDevHlpGetVM(pDevIns), &pReq, RT_INDEFINITE_WAIT,
-                                         (PFNRT)s->pDrvMount->pfnUnmount, 1, s->pDrvMount);
+                                         (PFNRT)s->pDrvMount->pfnUnmount, 2, s->pDrvMount, false);
                         AssertReleaseRC(rc);
                         VMR3ReqFree(pReq);
Index: trunk/src/VBox/Devices/Storage/DrvBlock.cpp
===================================================================
--- trunk/src/VBox/Devices/Storage/DrvBlock.cpp	(revision 3112)
+++ trunk/src/VBox/Devices/Storage/DrvBlock.cpp	(revision 3113)
@@ -509,5 +509,5 @@
 
 /** @copydoc PDMIMOUNT::pfnUnmount */
-static DECLCALLBACK(int) drvblockUnmount(PPDMIMOUNT pInterface)
+static DECLCALLBACK(int) drvblockUnmount(PPDMIMOUNT pInterface, bool fForce)
 {
     PDRVBLOCK pData = PDMIMOUNT_2_DRVBLOCK(pInterface);
@@ -521,9 +521,12 @@
         return VERR_PDM_MEDIA_NOT_MOUNTED;
     }
-    if (pData->fLocked)
+    if (pData->fLocked && !fForce)
     {
         Log(("drvblockUmount: Locked\n"));
         return VERR_PDM_MEDIA_LOCKED;
     }
+
+    /* Media is no longer locked even if it was previously. */
+    pData->fLocked = false;
 
     /*
Index: trunk/src/VBox/Devices/Storage/DrvHostBase.cpp
===================================================================
--- trunk/src/VBox/Devices/Storage/DrvHostBase.cpp	(revision 3112)
+++ trunk/src/VBox/Devices/Storage/DrvHostBase.cpp	(revision 3113)
@@ -457,5 +457,5 @@
 
 /** @copydoc PDMIMOUNT::pfnUnmount */
-static DECLCALLBACK(int) drvHostBaseUnmount(PPDMIMOUNT pInterface)
+static DECLCALLBACK(int) drvHostBaseUnmount(PPDMIMOUNT pInterface, bool fForce)
 {
      LogFlow(("drvHostBaseUnmount: returns VERR_NOT_SUPPORTED\n"));
@@ -567,14 +567,14 @@
 /**
  * Gets the BSD Name (/dev/disc[0-9]+) for the service.
- * 
- * This is done by recursing down the I/O registry until we hit upon an entry 
- * with a BSD Name. Usually we find it two levels down. (Further down under 
+ *
+ * This is done by recursing down the I/O registry until we hit upon an entry
+ * with a BSD Name. Usually we find it two levels down. (Further down under
  * the IOCDPartitionScheme, the volume (slices) BSD Name is found. We don't
  * seem to have to go this far fortunately.)
- * 
+ *
  * @return  VINF_SUCCESS if found, VERR_FILE_NOT_FOUND otherwise.
  * @param   Entry       The current I/O registry entry reference.
  * @param   pszName     Where to store the name. 128 bytes.
- * @param   cRecursions Number of recursions. This is used as an precation 
+ * @param   cRecursions Number of recursions. This is used as an precation
  *                      just to limit the depth and avoid blowing the stack
  *                      should we hit a bug or something.
@@ -610,7 +610,7 @@
 
 
-/** 
+/**
  * Callback notifying us that the async DADiskClaim()/DADiskUnmount call has completed.
- * 
+ *
  * @param   DiskRef         The disk that was attempted claimed / unmounted.
  * @param   DissenterRef    NULL on success, contains details on failure.
@@ -630,5 +630,5 @@
 /**
  * Obtain exclusive access to the DVD device, umount it if necessary.
- * 
+ *
  * @return  VBox status code.
  * @param   pThis       The driver instance.
@@ -644,5 +644,5 @@
         if (irc == kIOReturnSuccess)
         {
-            /* 
+            /*
              * This is a bit weird, but if we unmounted the DVD drive we also need to
              * unlock it afterwards or the guest won't be able to eject it later on.
@@ -661,11 +661,11 @@
         if (irc == kIOReturnExclusiveAccess)
             return VERR_SHARING_VIOLATION;      /* already used exclusivly. */
-        if (irc != kIOReturnBusy) 
+        if (irc != kIOReturnBusy)
             return VERR_GENERAL_FAILURE;        /* not mounted */
 
         /*
          * Attempt to the unmount all volumes of the device.
-         * It seems we can can do this all in one go without having to enumerate the 
-         * volumes (sessions) and deal with them one by one. This is very fortuitous 
+         * It seems we can can do this all in one go without having to enumerate the
+         * volumes (sessions) and deal with them one by one. This is very fortuitous
          * as the disk arbitration API is a bit cumbersome to deal with.
          */
@@ -683,5 +683,5 @@
                 if (pThis->pDADisk)
                 {
-                    /* 
+                    /*
                      * Try claim the device.
                      */
@@ -717,5 +717,5 @@
                     else
                         Log(("%s-%d: claim => rc32=%d & rcDA=%#x\n", pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance, rc32, rcDA));
-                    
+
                     CFRelease(pThis->pDADisk);
                     pThis->pDADisk = NULL;
@@ -1501,6 +1501,6 @@
 
 #ifdef __DARWIN__
-    /* 
-     * The unclaiming doesn't seem to mean much, the DVD is actaully 
+    /*
+     * The unclaiming doesn't seem to mean much, the DVD is actaully
      * remounted when we release exclusive access. I'm not quite sure
      * if I should put the unclaim first or not...
@@ -1563,5 +1563,10 @@
     }
 
-    if (RTCritSectIsInitialized(&pThis->CritSect))
+    /* Forget about the notifications. */
+    pThis->pDrvMountNotify = NULL;
+
+    /* Leave the instance operational if this is just a cleanup of the state
+     * after an attach error happened. So don't destry the critsect then. */
+    if (!pThis->fKeepInstance && RTCritSectIsInitialized(&pThis->CritSect))
         RTCritSectDelete(&pThis->CritSect);
     LogFlow(("%s-%d: drvHostBaseDestruct completed\n", pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance));
@@ -1591,4 +1596,5 @@
      */
     pThis->pDrvIns                          = pDrvIns;
+    pThis->fKeepInstance                    = false;
     pThis->ThreadPoller                     = NIL_RTTHREAD;
 #ifdef __DARWIN__
@@ -1722,4 +1728,11 @@
     }
 
+    /* Define whether attach failure is an error (default) or not. */
+    bool fAttachFailError;
+    rc = CFGMR3QueryBool(pCfgHandle, "AttachFailError", &fAttachFailError);
+    if (VBOX_FAILURE(rc))
+        fAttachFailError = true;
+    pThis->fAttachFailError = fAttachFailError;
+
     /* name to open & watch for */
 #ifdef __WIN__
@@ -1754,4 +1767,5 @@
 int DRVHostBaseInitFinish(PDRVHOSTBASE pThis)
 {
+    int src = VINF_SUCCESS;
     PPDMDRVINS pDrvIns = pThis->pDrvIns;
 
@@ -1851,9 +1865,19 @@
                        pszDevice);
             default:
-                return rc;
+                if (pThis->fAttachFailError)
+                    return rc;
+                else
+                {
+                    int erc = PDMDrvHlpVMSetRuntimeError(pDrvIns,
+                                                         false, "DrvHost_MOUNTFAIL",
+                                                         N_("Cannot attach to host device '%s'"), pszDevice);
+                    AssertRC(erc);
+                    src = rc;
+                }
         }
     }
 #ifdef __WIN__
-    DRVHostBaseMediaPresent(pThis);
+    if (VBOX_SUCCESS(src))
+        DRVHostBaseMediaPresent(pThis);
 #endif
 
@@ -1873,10 +1897,13 @@
 
 #ifndef __WIN__
-    /*
-     * Create the event semaphore which the poller thread will wait on.
-     */
-    rc = RTSemEventCreate(&pThis->EventPoller);
-    if (VBOX_FAILURE(rc))
-        return rc;
+    if (VBOX_SUCCESS(src))
+    {
+        /*
+         * Create the event semaphore which the poller thread will wait on.
+         */
+        rc = RTSemEventCreate(&pThis->EventPoller);
+        if (VBOX_FAILURE(rc))
+            return rc;
+    }
 #endif
 
@@ -1888,26 +1915,32 @@
         return rc;
 
-    /*
-     * Start the thread which will poll for the media.
-     */
-    rc = RTThreadCreate(&pThis->ThreadPoller, drvHostBaseMediaThread, pThis, 0,
-                        RTTHREADTYPE_INFREQUENT_POLLER, RTTHREADFLAGS_WAITABLE, "DVDMEDIA");
-    if (VBOX_FAILURE(rc))
-    {
-        AssertMsgFailed(("Failed to create poller thread. rc=%Vrc\n", rc));
+    if (VBOX_SUCCESS(src))
+    {
+        /*
+         * Start the thread which will poll for the media.
+         */
+        rc = RTThreadCreate(&pThis->ThreadPoller, drvHostBaseMediaThread, pThis, 0,
+                            RTTHREADTYPE_INFREQUENT_POLLER, RTTHREADFLAGS_WAITABLE, "DVDMEDIA");
+        if (VBOX_FAILURE(rc))
+        {
+            AssertMsgFailed(("Failed to create poller thread. rc=%Vrc\n", rc));
+            return rc;
+        }
+
+        /*
+         * Wait for the thread to start up (!w32:) and do one detection loop.
+         */
+        rc = RTThreadUserWait(pThis->ThreadPoller, 10000);
+        AssertRC(rc);
+#ifdef __WIN__
+        if (!pThis->hwndDeviceChange)
+            return VERR_GENERAL_FAILURE;
+#endif
+    }
+
+    if (VBOX_FAILURE(src))
+        return src;
+    else
         return rc;
-    }
-
-    /*
-     * Wait for the thread to start up (!w32:) and do one detection loop.
-     */
-    rc = RTThreadUserWait(pThis->ThreadPoller, 10000);
-    AssertRC(rc);
-#ifdef __WIN__
-    if (!pThis->hwndDeviceChange)
-        return VERR_GENERAL_FAILURE;
-#endif
-
-    return rc;
-}
-
+}
+
Index: trunk/src/VBox/Devices/Storage/DrvHostBase.h
===================================================================
--- trunk/src/VBox/Devices/Storage/DrvHostBase.h	(revision 3112)
+++ trunk/src/VBox/Devices/Storage/DrvHostBase.h	(revision 3113)
@@ -49,4 +49,8 @@
     /** The current readonly status. */
     bool                    fReadOnly;
+    /** Flag whether failure to attach is an error or not. */
+    bool                    fAttachFailError;
+    /** Flag whether to keep instance working (as unmounted though). */
+    bool                    fKeepInstance;
     /** Device name (MMHeap). */
     char                   *pszDevice;
Index: trunk/src/VBox/Devices/Storage/DrvHostDVD.cpp
===================================================================
--- trunk/src/VBox/Devices/Storage/DrvHostDVD.cpp	(revision 3112)
+++ trunk/src/VBox/Devices/Storage/DrvHostDVD.cpp	(revision 3113)
@@ -81,8 +81,11 @@
 
 
+/* Forward declarations. */
+
+static DECLCALLBACK(int) drvHostDvdDoLock(PDRVHOSTBASE pThis, bool fLock);
 
 
 /** @copydoc PDMIMOUNT::pfnUnmount */
-static DECLCALLBACK(int) drvHostDvdUnmount(PPDMIMOUNT pInterface)
+static DECLCALLBACK(int) drvHostDvdUnmount(PPDMIMOUNT pInterface, bool fForce)
 {
      PDRVHOSTBASE pThis = PDMIMOUNT_2_DRVHOSTBASE(pInterface);
@@ -93,6 +96,10 @@
       */
      int rc = VINF_SUCCESS;
-     if (!pThis->fLocked)
+     if (!pThis->fLocked || fForce)
      {
+        /* Unlock drive if necessary. */
+        if (pThis->fLocked)
+            drvHostDvdDoLock(pThis, false);
+
          /*
           * Eject the disc.
@@ -498,5 +505,5 @@
      * Validate configuration.
      */
-    if (!CFGMR3AreValuesValid(pCfgHandle, "Path\0Interval\0Locked\0BIOSVisible\0Passthrough\0"))
+    if (!CFGMR3AreValuesValid(pCfgHandle, "Path\0Interval\0Locked\0BIOSVisible\0AttachFailError\0Passthrough\0"))
         return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
 
@@ -539,11 +546,18 @@
          */
         rc = DRVHostBaseInitFinish(pThis);
-        if (VBOX_SUCCESS(rc))
+    }
+
+    if (VBOX_FAILURE(rc))
+    {
+        if (!pThis->fAttachFailError)
         {
-            LogFlow(("drvHostDvdConstruct: return %Vrc\n", rc));
-            return rc;
+            /* Suppressing the attach failure error must not affect the normal
+             * DRVHostBaseDestruct, so reset this flag below before leaving. */
+            pThis->fKeepInstance = true;
+            rc = VINF_SUCCESS;
         }
-    }
-    DRVHostBaseDestruct(pDrvIns);
+        DRVHostBaseDestruct(pDrvIns);
+        pThis->fKeepInstance = false;
+    }
 
     LogFlow(("drvHostDvdConstruct: returns %Vrc\n", rc));
Index: trunk/src/VBox/Devices/Storage/DrvHostFloppy.cpp
===================================================================
--- trunk/src/VBox/Devices/Storage/DrvHostFloppy.cpp	(revision 3112)
+++ trunk/src/VBox/Devices/Storage/DrvHostFloppy.cpp	(revision 3113)
@@ -181,11 +181,17 @@
          */
         rc = DRVHostBaseInitFinish(&pThis->Base);
-        if (VBOX_SUCCESS(rc))
+    }
+    if (VBOX_FAILURE(rc))
+    {
+        if (!pThis->Base.fAttachFailError)
         {
-            LogFlow(("drvHostFloppyConstruct: return %Vrc\n", rc));
-            return rc;
+            /* Suppressing the attach failure error must not affect the normal
+             * DRVHostBaseDestruct, so reset this flag below before leaving. */
+            pThis->Base.fKeepInstance = true;
+            rc = VINF_SUCCESS;
         }
-    }
-    DRVHostBaseDestruct(pDrvIns);
+        DRVHostBaseDestruct(pDrvIns);
+        pThis->Base.fKeepInstance = false;
+    }
 
     LogFlow(("drvHostFloppyConstruct: returns %Vrc\n", rc));
Index: trunk/src/VBox/Main/ConsoleImpl.cpp
===================================================================
--- trunk/src/VBox/Main/ConsoleImpl.cpp	(revision 3112)
+++ trunk/src/VBox/Main/ConsoleImpl.cpp	(revision 3113)
@@ -2839,5 +2839,5 @@
                  * Unmount the media.
                  */
-                rc = pIMount->pfnUnmount (pIMount);
+                rc = pIMount->pfnUnmount (pIMount, false);
                 if (rc == VERR_PDM_MEDIA_NOT_MOUNTED)
                     rc = VINF_SUCCESS;
