Index: /trunk/include/VBox/scsi.h
===================================================================
--- /trunk/include/VBox/scsi.h	(revision 19967)
+++ /trunk/include/VBox/scsi.h	(revision 19968)
@@ -33,6 +33,10 @@
 #include <iprt/assert.h>
 
-#define SCSI_MAX_BUFFER_SIZE (100 * _1K)
-
+#ifdef RT_OS_FREEBSD
+/* The cam subsystem doesn't allow more */
+# define SCSI_MAX_BUFFER_SIZE (64  * _1K)
+#else
+# define SCSI_MAX_BUFFER_SIZE (100 * _1K)
+#endif
 
 /**
Index: /trunk/src/VBox/Devices/Builtins.cpp
===================================================================
--- /trunk/src/VBox/Devices/Builtins.cpp	(revision 19967)
+++ /trunk/src/VBox/Devices/Builtins.cpp	(revision 19968)
@@ -207,5 +207,5 @@
     if (RT_FAILURE(rc))
         return rc;
-#if defined(RT_OS_DARWIN) || defined(RT_OS_LINUX) || defined(RT_OS_SOLARIS) || defined(RT_OS_WINDOWS)
+#if defined(RT_OS_DARWIN) || defined(RT_OS_LINUX) || defined(RT_OS_SOLARIS) || defined(RT_OS_WINDOWS) || defined(RT_OS_FREEBSD)
     rc = pCallbacks->pfnRegister(pCallbacks, &g_DrvHostDVD);
     if (RT_FAILURE(rc))
Index: /trunk/src/VBox/Devices/Makefile.kmk
===================================================================
--- /trunk/src/VBox/Devices/Makefile.kmk	(revision 19967)
+++ /trunk/src/VBox/Devices/Makefile.kmk	(revision 19968)
@@ -736,5 +736,5 @@
 ifeq ($(KBUILD_TARGET),freebsd)
 Drivers_SOURCES      := $(filter-out \
-	Storage/DrvHost% \
+	Storage/DrvHostFloppy% \
 	, $(Drivers_SOURCES)) \
 	Audio/ossaudio.c
Index: /trunk/src/VBox/Devices/Storage/DrvHostBase.cpp
===================================================================
--- /trunk/src/VBox/Devices/Storage/DrvHostBase.cpp	(revision 19967)
+++ /trunk/src/VBox/Devices/Storage/DrvHostBase.cpp	(revision 19968)
@@ -101,4 +101,15 @@
         /*IN*/ FS_INFORMATION_CLASS FileSystemInformationClass );
 
+#elif defined(RT_OS_FREEBSD)
+# include <sys/cdefs.h>
+# include <sys/param.h>
+# include <errno.h>
+# include <stdio.h>
+# include <cam/cam.h>
+# include <cam/cam_ccb.h>
+# include <cam/scsi/scsi_message.h>
+# include <cam/scsi/scsi_pass.h>
+# include <VBox/scsi.h>
+# include <iprt/log.h>
 #else
 # error "Unsupported Platform."
@@ -140,9 +151,12 @@
         &&  pThis->ppScsiTaskDI
         &&  pThis->cbBlock)
+#elif RT_OS_FREEBSD
+    if (    pThis->fMediaPresent
+        &&  pThis->cbBlock)
 #else
     if (pThis->fMediaPresent)
 #endif
     {
-#ifdef RT_OS_DARWIN
+#if defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD)
         /*
          * Issue a READ(12) request.
@@ -214,5 +228,5 @@
         if (pThis->fMediaPresent)
         {
-#ifdef RT_OS_DARWIN
+#if defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD)
             /** @todo write support... */
             rc = VERR_WRITE_PROTECT;
@@ -259,5 +273,5 @@
     if (pThis->fMediaPresent)
     {
-#ifdef RT_OS_DARWIN
+#if defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD)
         rc = VINF_SUCCESS;
         /** @todo scsi device buffer flush... */
@@ -934,4 +948,75 @@
     return VINF_SUCCESS;
 
+#elif defined(RT_OS_FREEBSD)
+    int rc = VINF_SUCCESS;
+    RTFILE FileDevice;
+
+    rc = RTFileOpen(&FileDevice, pThis->pszDeviceOpen, RTFILE_O_READWRITE);
+    if (RT_FAILURE(rc))
+        return rc;
+
+    /*
+     * The current device handle can't passthrough SCSI commands.
+     * We have to get he passthrough device path and open this.
+     */
+    union ccb DeviceCCB;
+    memset(&DeviceCCB, 0, sizeof(DeviceCCB));
+
+    DeviceCCB.ccb_h.func_code = XPT_GDEVLIST;
+    int rcBSD = ioctl(FileDevice, CAMGETPASSTHRU, &DeviceCCB);
+    if (!rcBSD)
+    {
+        char *pszPassthroughDevice = NULL;
+        rc = RTStrAPrintf(&pszPassthroughDevice, "/dev/%s%u",
+                          DeviceCCB.cgdl.periph_name, DeviceCCB.cgdl.unit_number);
+        if (RT_SUCCESS(rc))
+        {
+            RTFILE PassthroughDevice;
+
+            rc = RTFileOpen(&PassthroughDevice, pszPassthroughDevice, RTFILE_O_READWRITE);
+
+            RTStrFree(pszPassthroughDevice);
+
+            if (RT_SUCCESS(rc))
+            {
+                /* Get needed device parameters. */
+                union ccb DeviceCCB;
+
+                /*
+                 * The device path, target id and lun id. Those are
+                 * needed for the SCSI passthrough ioctl.
+                 */
+                memset(&DeviceCCB, 0, sizeof(DeviceCCB));
+                DeviceCCB.ccb_h.func_code = XPT_GDEVLIST;
+
+                rcBSD = ioctl(PassthroughDevice, CAMGETPASSTHRU, &DeviceCCB);
+                if (!rcBSD)
+                {
+                    if (DeviceCCB.cgdl.status != CAM_GDEVLIST_ERROR)
+                    {
+                        pThis->ScsiBus      = DeviceCCB.ccb_h.path_id;
+                        pThis->ScsiTargetID = DeviceCCB.ccb_h.target_id;
+                        pThis->ScsiLunID    = DeviceCCB.ccb_h.target_lun;
+                        *pFileDevice = PassthroughDevice;
+                    }
+                    else
+                    {
+                        /* The passthrough device wasn't found. */
+                        rc = VERR_NOT_FOUND;
+                    }
+                }
+                else
+                    rc = RTErrConvertFromErrno(errno);
+
+                if (RT_FAILURE(rc))
+                    RTFileClose(PassthroughDevice);
+            }
+        }
+    }
+    else
+        rc = RTErrConvertFromErrno(errno);
+
+    RTFileClose(FileDevice);
+    return rc;
 #else
     return RTFileOpen(pFileDevice, pThis->pszDeviceOpen,
@@ -1037,5 +1122,5 @@
 static int drvHostBaseGetMediaSize(PDRVHOSTBASE pThis, uint64_t *pcb)
 {
-#ifdef RT_OS_DARWIN
+#if defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD)
     /*
      * Try a READ_CAPACITY command...
@@ -1115,5 +1200,5 @@
 
 
-#ifdef RT_OS_DARWIN
+#if defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD)
 /**
  * Execute a SCSI command.
@@ -1226,4 +1311,84 @@
     (*ppScsiTaskI)->Release(ppScsiTaskI);
 
+# elif defined(RT_OS_FREEBSD)
+    int rc = VINF_SUCCESS;
+    int rcBSD = 0;
+    union ccb DeviceCCB;
+    union ccb *pDeviceCCB = &DeviceCCB;
+    u_int32_t fFlags;
+
+    memset(pDeviceCCB, 0, sizeof(DeviceCCB));
+    pDeviceCCB->ccb_h.path_id   = pThis->ScsiBus;
+    pDeviceCCB->ccb_h.target_id = pThis->ScsiTargetID;
+    pDeviceCCB->ccb_h.target_lun = pThis->ScsiLunID;
+
+    /* The SCSI INQUIRY command can't be passed through directly. */
+    if (pbCmd[0] == SCSI_INQUIRY)
+    {
+        pDeviceCCB->ccb_h.func_code = XPT_GDEV_TYPE;
+
+        rcBSD = ioctl(pThis->FileDevice, CAMIOCOMMAND, pDeviceCCB);
+        if (!rcBSD)
+        {
+            uint32_t cbCopy =   cbBuf < sizeof(struct scsi_inquiry_data)
+                              ? cbBuf
+                              : sizeof(struct scsi_inquiry_data);;
+            memcpy(pvBuf, &pDeviceCCB->cgd.inq_data, cbCopy);
+            memset(pbSense, 0, cbSense);
+
+            if (pcbBuf)
+                *pcbBuf = cbCopy;
+        }
+        else
+            rc = RTErrConvertFromErrno(errno);
+    }
+    else
+    {
+        /* Copy the CDB. */
+        memcpy(&pDeviceCCB->csio.cdb_io.cdb_bytes, pbCmd, cbCmd);
+
+        /* Set direction. */
+        if (enmTxDir == PDMBLOCKTXDIR_NONE)
+            fFlags = CAM_DIR_NONE;
+        else if (enmTxDir == PDMBLOCKTXDIR_FROM_DEVICE)
+            fFlags = CAM_DIR_IN;
+        else
+            fFlags = CAM_DIR_OUT;
+
+        fFlags |= CAM_DEV_QFRZDIS;
+
+        cam_fill_csio(&pDeviceCCB->csio, 1, NULL, fFlags, MSG_SIMPLE_Q_TAG,
+                      (u_int8_t *)pvBuf, cbBuf, cbSense, cbCmd,
+                      cTimeoutMillies ? cTimeoutMillies : 30000/* timeout */);
+
+        /* Send command */
+        rcBSD = ioctl(pThis->FileDevice, CAMIOCOMMAND, pDeviceCCB);
+        if (!rcBSD)
+        {
+            switch (pDeviceCCB->ccb_h.status & CAM_STATUS_MASK)
+            {
+                case CAM_REQ_CMP:
+                    rc = VINF_SUCCESS;
+                    break;
+                case CAM_SEL_TIMEOUT:
+                    rc = VERR_DEV_IO_ERROR;
+                    break;
+                case CAM_CMD_TIMEOUT:
+                    rc = VERR_TIMEOUT;
+                    break;
+                default:
+                    rc = VERR_DEV_IO_ERROR;
+            }
+
+            if (pcbBuf)
+                *pcbBuf = cbBuf - pDeviceCCB->csio.resid;
+
+            if (pbSense)
+                memcpy(pbSense, &pDeviceCCB->csio.sense_data,
+                       cbSense - pDeviceCCB->csio.sense_resid);
+        }
+        else
+            rc = RTErrConvertFromErrno(errno);
+    }
 # endif
 
@@ -1926,5 +2091,5 @@
      * Open the device.
      */
-#ifdef RT_OS_DARWIN
+#if defined(RT_OS_DARWIN)
     rc = drvHostBaseOpen(pThis, NULL, pThis->fReadOnlyConfig);
 #else
Index: /trunk/src/VBox/Devices/Storage/DrvHostBase.h
===================================================================
--- /trunk/src/VBox/Devices/Storage/DrvHostBase.h	(revision 19967)
+++ /trunk/src/VBox/Devices/Storage/DrvHostBase.h	(revision 19968)
@@ -81,5 +81,5 @@
      * This is invalid if no drive is in the drive. */
     uint64_t volatile       cbSize;
-#ifndef RT_OS_DARWIN
+#if !defined(RT_OS_DARWIN)
     /** The filehandle of the device. */
     RTFILE                  FileDevice;
@@ -137,4 +137,14 @@
 #endif
 
+#ifdef RT_OS_FREEBSD
+    /** The block size. Set when querying the media size. */
+    uint32_t                cbBlock;
+    /** SCSI bus number. */
+    path_id_t               ScsiBus;
+    /** target ID of the passthrough device. */
+    target_id_t             ScsiTargetID;
+    /** LUN of the passthrough device. */
+    lun_id_t                ScsiLunID;
+#endif
 
     /**
@@ -176,5 +186,5 @@
 void DRVHostBaseMediaNotPresent(PDRVHOSTBASE pThis);
 DECLCALLBACK(void) DRVHostBaseDestruct(PPDMDRVINS pDrvIns);
-#ifdef RT_OS_DARWIN
+#if defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD)
 DECLCALLBACK(int) DRVHostBaseScsiCmd(PDRVHOSTBASE pThis, const uint8_t *pbCmd, size_t cbCmd, PDMBLOCKTXDIR enmTxDir,
                                      void *pvBuf, uint32_t *pcbBuf, uint8_t *pbSense, size_t cbSense, uint32_t cTimeoutMillies);
Index: /trunk/src/VBox/Devices/Storage/DrvHostDVD.cpp
===================================================================
--- /trunk/src/VBox/Devices/Storage/DrvHostDVD.cpp	(revision 19967)
+++ /trunk/src/VBox/Devices/Storage/DrvHostDVD.cpp	(revision 19968)
@@ -84,4 +84,12 @@
 # undef USE_MEDIA_POLLING
 
+#elif defined(RT_OS_FREEBSD)
+# include <sys/cdefs.h>
+# include <sys/param.h>
+# include <stdio.h>
+# include <cam/cam.h>
+# include <cam/cam_ccb.h>
+# define USE_MEDIA_POLLING
+
 #else
 # error "Unsupported Platform."
@@ -129,5 +137,5 @@
           * Eject the disc.
           */
-#ifdef RT_OS_DARWIN
+#if defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD)
          uint8_t abCmd[16] =
          {
@@ -306,6 +314,8 @@
      * Poll for media change.
      */
+#if defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD)
 #ifdef RT_OS_DARWIN
     AssertReturn(pThis->ppScsiTaskDI, VERR_INTERNAL_ERROR);
+#endif
 
     /*
@@ -376,5 +386,5 @@
          * Poll for media change.
          */
-#if defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS)
+#if defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
         /* taken care of above. */
 #elif defined(RT_OS_LINUX)
@@ -406,5 +416,5 @@
     LogFlow(("%s: cmd[0]=%#04x txdir=%d pcbBuf=%d timeout=%d\n", __FUNCTION__, pbCmd[0], enmTxDir, *pcbBuf, cTimeoutMillies));
 
-#ifdef RT_OS_DARWIN
+#if defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD)
     /*
      * Pass the request on to the internal scsi command interface.
Index: /trunk/src/VBox/Main/HostImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/HostImpl.cpp	(revision 19967)
+++ /trunk/src/VBox/Main/HostImpl.cpp	(revision 19968)
@@ -87,4 +87,9 @@
 #endif /* RT_OS_WINDOWS */
 
+#ifdef RT_OS_FREEBSD
+# ifdef VBOX_USE_LIBHAL
+#  include "vbox-libhal.h"
+# endif
+#endif
 
 #include "HostImpl.h"
@@ -396,5 +401,11 @@
         RTMemFree(freeMe);
     }
-
+#elif defined(RT_OS_FREEBSD)
+# ifdef VBOX_USE_LIBHAL
+    if (!getDVDInfoFromHal(list))
+# endif
+    {
+        /** @todo: Scan for accessible /dev/cd* devices. */
+    }
 #else
     /* PORTME */
@@ -1597,6 +1608,6 @@
 ////////////////////////////////////////////////////////////////////////////////
 
-#if defined(RT_OS_SOLARIS) && defined(VBOX_USE_LIBHAL)
-/* Solaris hosts, loading libhal at runtime */
+#if (defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)) && defined(VBOX_USE_LIBHAL)
+/* Solaris and FreeBSD hosts, loading libhal at runtime */
 
 /**
@@ -1643,4 +1654,23 @@
                             devNode = tmp;
 #endif
+
+#ifdef RT_OS_FREEBSD
+                            /*
+                             * Don't show devices handled by the 'acd' driver.
+                             * The ioctls don't work with it.
+                             */
+                            char *driverName = gLibHalDeviceGetPropertyString(halContext,
+                                                       halDevices[i], "freebsd.driver", &dbusError);
+                            if (driverName)
+                            {
+                                if (RTStrCmp(driverName, "acd") == 0)
+                                {
+                                    gLibHalFreeString(devNode);
+                                    devNode = NULL;
+                                }
+                                gLibHalFreeString(driverName);
+                            }
+#endif
+
                             if (devNode != 0)
                             {
Index: /trunk/src/VBox/Main/Makefile.kmk
===================================================================
--- /trunk/src/VBox/Main/Makefile.kmk	(revision 19967)
+++ /trunk/src/VBox/Main/Makefile.kmk	(revision 19968)
@@ -228,4 +228,5 @@
 # VBoxSVC_DEFS.linux += VBOX_USE_LIBHAL
 VBoxSVC_DEFS.solaris += VBOX_USE_LIBHAL
+VBoxSVC_DEFS.freebsd += VBOX_USE_LIBHAL
 ifdef VBOX_SOLARIS_NSL_RESOLVED
  VBoxSVC_DEFS.solaris += VBOX_SOLARIS_NSL_RESOLVED
@@ -336,4 +337,7 @@
 	solaris/DynLoadLibSolaris.cpp
 
+VBoxSVC_SOURCES.freebsd = \
+	linux/vbox-libhal.cpp
+
 ifdef VBOX_WITH_USB
  VBoxSVC_SOURCES  += \
Index: /trunk/src/VBox/Main/include/HostImpl.h
===================================================================
--- /trunk/src/VBox/Main/include/HostImpl.h	(revision 19967)
+++ /trunk/src/VBox/Main/include/HostImpl.h	(revision 19968)
@@ -133,9 +133,10 @@
 private:
 
-#if defined(RT_OS_SOLARIS)
-# if defined(VBOX_USE_LIBHAL)
+#if (defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)) && defined(VBOX_USE_LIBHAL)
     bool getDVDInfoFromHal(std::list <ComObjPtr <HostDVDDrive> > &list);
     bool getFloppyInfoFromHal(std::list <ComObjPtr <HostFloppyDrive> > &list);
-# endif
+#endif
+
+#if defined(RT_OS_SOLARIS)
     void parseMountTable(char *mountTable, std::list <ComObjPtr <HostDVDDrive> > &list);
     bool validateDevice(const char *deviceNode, bool isCDROM);
