[zircon] Finish switching away from ioctl_device_*

ZX-3410 #comment Move the rest of zircon off

Change-Id: I80fbdefa0a0206e367f69fd06182b62ef581a988
diff --git a/zircon/system/dev/nand/broker/rules.mk b/zircon/system/dev/nand/broker/rules.mk
index 58b9d1b..8f87f4f 100644
--- a/zircon/system/dev/nand/broker/rules.mk
+++ b/zircon/system/dev/nand/broker/rules.mk
@@ -67,6 +67,7 @@
     system/ulib/zircon \
 
 MODULE_FIDL_LIBS := \
+    system/fidl/fuchsia-device \
     system/fidl/fuchsia-nand \
     system/fidl/fuchsia-hardware-nand \
 
@@ -101,6 +102,7 @@
     system/ulib/zircon \
 
 MODULE_FIDL_LIBS := \
+    system/fidl/fuchsia-device \
     system/fidl/fuchsia-nand \
     system/fidl/fuchsia-hardware-nand \
 
diff --git a/zircon/system/dev/nand/broker/test/broker-test.cpp b/zircon/system/dev/nand/broker/test/broker-test.cpp
index fdd33a3..0adc915 100644
--- a/zircon/system/dev/nand/broker/test/broker-test.cpp
+++ b/zircon/system/dev/nand/broker/test/broker-test.cpp
@@ -10,12 +10,12 @@
 
 #include <fbl/algorithm.h>
 #include <fbl/unique_fd.h>
+#include <fuchsia/device/c/fidl.h>
 #include <fuchsia/nand/c/fidl.h>
 #include <lib/fdio/watcher.h>
 #include <lib/fzl/fdio.h>
 #include <lib/fzl/vmo-mapper.h>
 #include <lib/zx/vmo.h>
-#include <zircon/device/device.h>
 #include <zircon/syscalls.h>
 #include <zxtest/zxtest.h>
 
@@ -54,8 +54,8 @@
     NandDevice();
     ~NandDevice() {
         if (linked_) {
-            fbl::unique_fd broker = caller_.release();
-            ioctl_device_unbind(broker.get());
+            zx_status_t call_status;
+            fuchsia_device_ControllerUnbind(channel(), &call_status);
         }
     }
 
@@ -106,8 +106,19 @@
     if (parent_->IsBroker()) {
         caller_.reset(fbl::unique_fd(open(parent_->Path(), O_RDWR)));
     } else {
+        fdio_t* io = fdio_unsafe_fd_to_io(parent_->get());
+        if (io == nullptr) {
+            return;
+        }
+        zx_status_t call_status;
         const char kBroker[] = "/boot/driver/nand-broker.so";
-        if (ioctl_device_bind(parent_->get(), kBroker, sizeof(kBroker) - 1) < 0) {
+        zx_status_t status = fuchsia_device_ControllerBind(fdio_unsafe_borrow_channel(io), kBroker,
+                                                           strlen(kBroker), &call_status);
+        fdio_unsafe_release(io);
+        if (status == ZX_OK) {
+            status = call_status;
+        }
+        if (status != ZX_OK) {
             printf("Failed to bind broker\n");
             return;
         }
diff --git a/zircon/system/uapp/disk-pave/device-partitioner.cpp b/zircon/system/uapp/disk-pave/device-partitioner.cpp
index e0f07a7..9e8ae26 100644
--- a/zircon/system/uapp/disk-pave/device-partitioner.cpp
+++ b/zircon/system/uapp/disk-pave/device-partitioner.cpp
@@ -11,9 +11,11 @@
 #include <fbl/auto_call.h>
 #include <fbl/function.h>
 #include <fs-management/fvm.h>
+#include <fuchsia/device/c/fidl.h>
 #include <fuchsia/hardware/block/c/fidl.h>
 #include <fuchsia/hardware/skipblock/c/fidl.h>
 #include <gpt/cros.h>
+#include <lib/fdio/unsafe.h>
 #include <lib/fdio/util.h>
 #include <lib/fdio/watcher.h>
 #include <lib/fzl/fdio.h>
@@ -298,16 +300,28 @@
             continue;
         }
         out->Set(PATH_MAX, '\0');
-        ssize_t r = ioctl_device_get_topo_path(fd.get(), const_cast<char*>(out->data()), PATH_MAX);
-        if (r < 0) {
-            continue;
-        }
 
         block_info_t info;
+        ssize_t r;
         if ((r = ioctl_block_get_info(fd.get(), &info) < 0)) {
             continue;
         }
 
+        zx::channel dev;
+        zx_status_t status = fdio_get_service_handle(fd.release(), dev.reset_and_get_address());
+        if (status != ZX_OK) {
+            continue;
+        }
+        size_t path_len;
+        zx_status_t call_status;
+        char* data = const_cast<char*>(out->data());
+        status = fuchsia_device_ControllerGetTopologicalPath(dev.get(), &call_status, data,
+                                                             PATH_MAX - 1, &path_len);
+        if (status != ZX_OK || call_status != ZX_OK) {
+            continue;
+        }
+        data[path_len] = 0;
+
         // TODO(ZX-1344): This is a hack, but practically, will work for our
         // usage.
         //
@@ -363,9 +377,20 @@
             ERROR("Failed to re-read GPT\n");
             return ZX_ERR_BAD_STATE;
         }
+
+        fdio_t* io = fdio_unsafe_fd_to_io(fd.get());
+        if (io == nullptr) {
+            ERROR("Failed to convert to io\n");
+            return ZX_ERR_BAD_STATE;
+        }
+        zx_status_t call_status;
         // Manually re-bind the GPT driver, since it is almost certainly
         // too late to be noticed by the block watcher.
-        if ((rc = ioctl_device_bind(fd.get(), kGptDriverName, strlen(kGptDriverName))) != ZX_OK) {
+        zx_status_t status = fuchsia_device_ControllerBind(
+                fdio_unsafe_borrow_channel(io), kGptDriverName, strlen(kGptDriverName),
+                &call_status);
+        fdio_unsafe_release(io);
+        if (status != ZX_OK || call_status != ZX_OK) {
             ERROR("Failed to bind GPT\n");
             return ZX_ERR_BAD_STATE;
         }
@@ -1047,14 +1072,26 @@
         return ZX_OK;
     }
 
+    zx::channel block_dev;
+    status = fdio_get_service_handle(block_fd.release(), block_dev.reset_and_get_address());
+    if (status != ZX_OK) {
+        ERROR("Warning: Could not get block service handle: %s\n", zx_status_get_string(status));
+        return status;
+    }
     char name[PATH_MAX + 1];
-    ssize_t result;
-    if ((result = ioctl_device_get_topo_path(block_fd.get(), name, PATH_MAX)) < 0) {
-        status = static_cast<zx_status_t>(result);
+    size_t name_len;
+    zx_status_t call_status;
+    status = fuchsia_device_ControllerGetTopologicalPath(block_dev.get(), &call_status, name,
+                                                         sizeof(name) - 1, &name_len);
+    if (status == ZX_OK) {
+        status = call_status;
+    }
+    if (status != ZX_OK) {
         ERROR("Warning: Could not get name for partition: %s\n",
               zx_status_get_string(status));
         return status;
     }
+    name[name_len] = 0;
 
     const char* parent = dirname(name);
 
diff --git a/zircon/system/uapp/disk-pave/pave-lib.cpp b/zircon/system/uapp/disk-pave/pave-lib.cpp
index e4cf2e3..554bc3b 100644
--- a/zircon/system/uapp/disk-pave/pave-lib.cpp
+++ b/zircon/system/uapp/disk-pave/pave-lib.cpp
@@ -19,10 +19,12 @@
 #include <fs-management/fvm.h>
 #include <fs-management/mount.h>
 #include <ramdevice-client/ramdisk.h>
+#include <fuchsia/device/c/fidl.h>
 #include <fuchsia/hardware/skipblock/c/fidl.h>
 #include <fvm/fvm-sparse.h>
 #include <fvm/sparse-reader.h>
 #include <lib/cksum.h>
+#include <lib/fdio/fdio.h>
 #include <lib/fzl/fdio.h>
 #include <lib/fzl/resizeable-vmo-mapper.h>
 #include <lib/fzl/vmo-mapper.h>
@@ -30,7 +32,6 @@
 #include <lib/zx/vmo.h>
 #include <zircon/boot/image.h>
 #include <zircon/device/block.h>
-#include <zircon/device/device.h>
 #include <zircon/status.h>
 #include <zircon/syscalls.h>
 #include <zxcrypt/volume.h>
@@ -79,14 +80,38 @@
 // TODO(aarongreen): Replace this with a value supplied by ulib/zxcrypt.
 constexpr size_t kZxcryptExtraSlices = 1;
 
+// Looks up the topological path of a device.
+// |buf| is the buffer the path will be written to.  |buf_len| is the total
+// capcity of the buffer, including space for a null byte.
+// Upon success, |buf| will contain the null-terminated topological path.
+zx_status_t GetTopoPathFromFd(const fbl::unique_fd& fd, char* buf, size_t buf_len) {
+    fdio_t* io = fdio_unsafe_fd_to_io(fd.get());
+    if (io == nullptr) {
+        return ZX_ERR_BAD_STATE;
+    }
+    zx_status_t call_status;
+    size_t path_len;
+    zx_status_t status = fuchsia_device_ControllerGetTopologicalPath(
+            fdio_unsafe_borrow_channel(io), &call_status, buf, buf_len - 1, &path_len);
+    fdio_unsafe_release(io);
+    if (status != ZX_OK) {
+        return status;
+    }
+    if (call_status != ZX_OK) {
+        return call_status;
+    }
+    buf[path_len] = 0;
+    return ZX_OK;
+}
+
 // Confirm that the file descriptor to the underlying partition exists within an
 // FVM, not, for example, a GPT or MBR.
 //
 // |out| is true if |fd| is a VPartition, else false.
 zx_status_t FvmIsVirtualPartition(const fbl::unique_fd& fd, bool* out) {
     char path[PATH_MAX];
-    const ssize_t r = ioctl_device_get_topo_path(fd.get(), path, sizeof(path));
-    if (r < 0) {
+    zx_status_t status = GetTopoPathFromFd(fd, path, sizeof(path));
+    if (status != ZX_OK) {
         return ZX_ERR_IO;
     }
 
@@ -373,15 +398,26 @@
 fbl::unique_fd TryBindToFvmDriver(const fbl::unique_fd& partition_fd,
                                   zx::duration timeout) {
     char path[PATH_MAX];
-    ssize_t r = ioctl_device_get_topo_path(partition_fd.get(), path, sizeof(path));
-    if (r < 0) {
+    zx_status_t status = GetTopoPathFromFd(partition_fd, path, sizeof(path));
+    if (status != ZX_OK) {
         ERROR("Failed to get topological path\n");
         return fbl::unique_fd();
     }
 
+    fdio_t* io = fdio_unsafe_fd_to_io(partition_fd.get());
+    if (io == nullptr) {
+        ERROR("Failed to convert to io\n");
+        return fbl::unique_fd();
+    }
+    zx_status_t call_status;
     constexpr char kFvmDriverLib[] = "/boot/driver/fvm.so";
-    r = ioctl_device_bind(partition_fd.get(), kFvmDriverLib, sizeof(kFvmDriverLib));
-    if (r < 0) {
+    status = fuchsia_device_ControllerBind(fdio_unsafe_borrow_channel(io), kFvmDriverLib,
+                                           strlen(kFvmDriverLib), &call_status);
+    fdio_unsafe_release(io);
+    if (status == ZX_OK) {
+        status = call_status;
+    }
+    if (status != ZX_OK) {
         ERROR("Could not bind fvm driver\n");
         return fbl::unique_fd();
     }
@@ -464,9 +500,8 @@
     zx_status_t status;
 
     char path[PATH_MAX];
-    ssize_t r;
-    if ((r = ioctl_device_get_topo_path(part->new_part.get(), path, sizeof(path))) < 0) {
-        status = static_cast<zx_status_t>(r);
+    status = GetTopoPathFromFd(part->new_part, path, sizeof(path));
+    if (status != ZX_OK) {
         ERROR("Failed to get topological path\n");
         return status;
     }
@@ -502,6 +537,7 @@
     req.offset = allocated - reserved;
     req.length = needed - allocated;
 
+    ssize_t r;
     if ((r = ioctl_block_fvm_extend(part->new_part.get(), &req)) < 0) {
         status = static_cast<zx_status_t>(r);
         ERROR("Failed to extend zxcrypt volume: %s\n", zx_status_get_string(status));
@@ -515,14 +551,13 @@
 zx_status_t FvmPartitionIsChild(const fbl::unique_fd& fvm_fd, const fbl::unique_fd& partition_fd) {
     char fvm_path[PATH_MAX];
     char part_path[PATH_MAX];
-    ssize_t r;
-    if ((r = ioctl_device_get_topo_path(fvm_fd.get(), fvm_path, sizeof(fvm_path))) < 0) {
+    zx_status_t status;
+    if ((status = GetTopoPathFromFd(fvm_fd, fvm_path, sizeof(fvm_path))) != ZX_OK) {
         ERROR("Couldn't get topological path of FVM\n");
-        return static_cast<zx_status_t>(r);
-    } else if ((r = ioctl_device_get_topo_path(partition_fd.get(), part_path,
-                                               sizeof(part_path))) < 0) {
+        return status;
+    } else if ((status = GetTopoPathFromFd(partition_fd, part_path, sizeof(part_path))) != ZX_OK) {
         ERROR("Couldn't get topological path of partition\n");
-        return static_cast<zx_status_t>(r);
+        return status;
     }
     if (strncmp(fvm_path, part_path, strlen(fvm_path))) {
         ERROR("Partition does not exist within FVM\n");
@@ -1013,7 +1048,15 @@
         return ZX_ERR_NOT_FOUND;
     }
 
-    switch (detect_disk_format(part_fd.get())) {
+    auto disk_format = detect_disk_format(part_fd.get());
+    zx::channel part_dev;
+    status = fdio_get_service_handle(part_fd.release(), part_dev.reset_and_get_address());
+    if (status != ZX_OK) {
+        ERROR("failed to get service handle\n");
+        return ZX_ERR_NOT_FOUND;
+    }
+
+    switch (disk_format) {
     case DISK_FORMAT_MINFS:
         // If the disk we found is actually minfs, we can just use the block
         // device path we were given by open_partition.
@@ -1023,13 +1066,22 @@
     case DISK_FORMAT_ZXCRYPT:
         // Compute the topological path of the FVM block driver, and then tack
         // the zxcrypt-device string onto the end. This should be improved.
-        ioctl_device_get_topo_path(part_fd.get(), path, sizeof(path));
+        zx_status_t call_status;
+        size_t path_len;
+        status = fuchsia_device_ControllerGetTopologicalPath(part_dev.get(), &call_status, path,
+                                                             sizeof(path) - 1, &path_len);
+        if (status != ZX_OK || call_status != ZX_OK) {
+            path[0] = 0;
+        } else {
+            path[path_len] = 0;
+        }
         snprintf(minfs_path, sizeof(minfs_path), "%s/zxcrypt/block", path);
 
         // TODO(security): ZX-1130. We need to bind with channel in order to
         // pass a key here. Where does the key come from? We need to determine
         // if this is unattended.
-        ioctl_device_bind(part_fd.get(), ZXCRYPT_DRIVER_LIB, strlen(ZXCRYPT_DRIVER_LIB));
+        fuchsia_device_ControllerBind(part_dev.get(), ZXCRYPT_DRIVER_LIB,
+                                      strlen(ZXCRYPT_DRIVER_LIB), &call_status);
 
         if ((status = wait_for_device(minfs_path, ZX_SEC(5))) != ZX_OK) {
             ERROR("zxcrypt bind error: %s\n", zx_status_get_string(status));
diff --git a/zircon/system/uapp/disk-pave/test/device-partitioner-test.cpp b/zircon/system/uapp/disk-pave/test/device-partitioner-test.cpp
index c136494..cfdb9e8 100644
--- a/zircon/system/uapp/disk-pave/test/device-partitioner-test.cpp
+++ b/zircon/system/uapp/disk-pave/test/device-partitioner-test.cpp
@@ -12,13 +12,15 @@
 #include <fbl/string.h>
 #include <fbl/string_piece.h>
 #include <fbl/unique_ptr.h>
+#include <fuchsia/device/c/fidl.h>
 #include <fuchsia/hardware/nand/c/fidl.h>
+#include <lib/fdio/directory.h>
+#include <lib/fdio/unsafe.h>
 #include <lib/fzl/vmo-mapper.h>
 #include <ramdevice-client/ramnand.h>
 #include <ramdevice-client/ramdisk.h>
 #include <unittest/unittest.h>
 #include <zircon/boot/image.h>
-#include <zircon/device/device.h>
 #include <zircon/hw/gpt.h>
 #include <zircon/syscalls.h>
 #include <zircon/types.h>
@@ -149,9 +151,22 @@
 
 bool FilterRealBlockDevices(const fbl::unique_fd& fd) {
     char topo_path[PATH_MAX] = {'\0'};
-    if (ioctl_device_get_topo_path(fd.get(), topo_path, PATH_MAX) < 0) {
+
+    fdio_t* io = fdio_unsafe_fd_to_io(fd.get());
+    if (io == nullptr) {
         return false;
     }
+    zx_status_t call_status;
+    size_t path_len;
+    zx_status_t status = fuchsia_device_ControllerGetTopologicalPath(
+            fdio_unsafe_borrow_channel(io), &call_status, topo_path, sizeof(topo_path) - 1 ,
+            &path_len);
+    fdio_unsafe_release(io);
+    if (status != ZX_OK || call_status != ZX_OK) {
+        return false;
+    }
+    topo_path[path_len] = 0;
+
     for (const auto& device : test_block_devices) {
         if (strstr(topo_path, device.data()) == topo_path) {
             return false;
@@ -168,12 +183,21 @@
 
 bool InsertTestDevices(fbl::StringPiece path) {
     BEGIN_HELPER;
-    fbl::unique_fd fd(open(path.data(), O_RDWR));
-    ASSERT_TRUE(fd.is_valid());
-    fbl::String topo_path(PATH_MAX, '\0');
-    ASSERT_GE(ioctl_device_get_topo_path(fd.get(), const_cast<char*>(topo_path.data()), PATH_MAX),
-              0);
-    test_block_devices.push_back(std::move(topo_path));
+    zx::channel device, device_remote;
+    ASSERT_EQ(zx::channel::create(0, &device, &device_remote), ZX_OK);
+    ASSERT_EQ(fdio_service_connect(path.data(), device_remote.release()), ZX_OK);
+
+    char topo_path[PATH_MAX] = {};
+    zx_status_t call_status;
+    size_t path_len;
+    ASSERT_EQ(fuchsia_device_ControllerGetTopologicalPath(device.get(), &call_status, topo_path,
+                                                          sizeof(topo_path) - 1, &path_len),
+              ZX_OK);
+    ASSERT_EQ(call_status, ZX_OK);
+    topo_path[path_len] = 0;
+
+    fbl::String topo_path_str(topo_path);
+    test_block_devices.push_back(std::move(topo_path_str));
     END_HELPER;
 }
 
diff --git a/zircon/system/uapp/driverctl/driverctl.c b/zircon/system/uapp/driverctl/driverctl.c
index 33b3d346..8830800 100644
--- a/zircon/system/uapp/driverctl/driverctl.c
+++ b/zircon/system/uapp/driverctl/driverctl.c
@@ -3,12 +3,14 @@
 // found in the LICENSE file.
 
 #include <ddk/debug.h>
-#include <zircon/device/device.h>
+#include <lib/fdio/directory.h>
+#include <fuchsia/device/c/fidl.h>
 #include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <zircon/syscalls.h>
 
 static void usage(void) {
     fprintf(stderr,
@@ -73,17 +75,23 @@
         return -1;
     }
 
-    int fd = open(path, O_RDWR);
-    if (fd < 0) {
+    zx_handle_t device, device_remote;
+    if (zx_channel_create(0, &device, &device_remote) != ZX_OK) {
+        fprintf(stderr, "could not create channel\n");
+        return -1;
+    }
+    zx_status_t status = fdio_service_connect(path, device_remote);
+    if (status != ZX_OK) {
         fprintf(stderr, "could not open %s\n", path);
         return -1;
     }
 
     if (argc == 3) {
         uint32_t flags;
-        ret = ioctl_device_get_log_flags(fd, &flags);
-        if (ret < 0) {
-            fprintf(stderr, "ioctl_device_get_log_flags failed for %s\n", path);
+        zx_status_t call_status;
+        status = fuchsia_device_ControllerGetDriverLogFlags(device, &call_status, &flags);
+        if (status != ZX_OK || call_status != ZX_OK) {
+            fprintf(stderr, "GetDriverLogFlags failed for %s\n", path);
         } else {
             printf("Log flags:");
             if (flags & DDK_LOG_ERROR) {
@@ -118,7 +126,8 @@
         goto out;
     }
 
-    driver_log_flags_t flags = {0, 0};
+    uint32_t clear_flags = 0;
+    uint32_t set_flags = 0;
     char* toggle_arg = NULL;
     char* non_toggle_arg = NULL;
 
@@ -168,25 +177,27 @@
         }
 
         if (toggle == '+') {
-            flags.set |= flag;
+            set_flags |= flag;
         } else if (toggle == '-') {
-            flags.clear |= flag;
+            clear_flags |= flag;
         } else {
-            flags.set |= flag;
+            set_flags |= flag;
         }
     }
 
     if (!toggle_arg) {
         // clear all flags not explicitly set if we aren't using flag toggles
-        flags.clear = ~flags.set;
+        clear_flags = ~set_flags;
     }
 
-    ret = ioctl_device_set_log_flags(fd, &flags);
-    if (ret < 0) {
-        fprintf(stderr, "ioctl_device_set_log_flags failed for %s\n", path);
+    zx_status_t call_status;
+    status = fuchsia_device_ControllerSetDriverLogFlags(device, clear_flags, set_flags,
+                                                        &call_status);
+    if (status != ZX_OK || call_status != ZX_OK) {
+        fprintf(stderr, "SetDriverLogFlags failed for %s\n", path);
     }
 
 out:
-    close(fd);
+    zx_handle_close(device);
     return ret;
 }
diff --git a/zircon/system/uapp/driverctl/rules.mk b/zircon/system/uapp/driverctl/rules.mk
index d3113bb..be57cbd 100644
--- a/zircon/system/uapp/driverctl/rules.mk
+++ b/zircon/system/uapp/driverctl/rules.mk
@@ -16,4 +16,7 @@
 
 MODULE_HEADER_DEPS := system/ulib/ddk
 
+MODULE_FIDL_LIBS := \
+    system/fidl/fuchsia-device \
+
 include make/module.mk
diff --git a/zircon/system/uapp/lsblk/main.c b/zircon/system/uapp/lsblk/main.c
index 691a214..b951f77 100644
--- a/zircon/system/uapp/lsblk/main.c
+++ b/zircon/system/uapp/lsblk/main.c
@@ -14,6 +14,7 @@
 #include <unistd.h>
 #include <limits.h>
 
+#include <fuchsia/device/c/fidl.h>
 #include <fuchsia/hardware/skipblock/c/fidl.h>
 #include <lib/fdio/unsafe.h>
 #include <pretty/hexdump.h>
@@ -56,6 +57,26 @@
     char sizestr[6];
 } blkinfo_t;
 
+static void populate_topo_path(int fd, blkinfo_t* info) {
+    fdio_t* io = fdio_unsafe_fd_to_io(fd);
+    if (io == NULL) {
+        goto fail;
+    }
+    zx_status_t call_status;
+    size_t path_len;
+    zx_status_t status = fuchsia_device_ControllerGetTopologicalPath(
+            fdio_unsafe_borrow_channel(io), &call_status, info->topo, sizeof(info->topo) - 1,
+            &path_len);
+    fdio_unsafe_release(io);
+    if (status != ZX_OK || call_status != ZX_OK) {
+        goto fail;
+    }
+    info->topo[path_len] = 0;
+    return;
+fail:
+    strcpy(info->topo, "UNKNOWN");
+}
+
 static int cmd_list_blk(void) {
     struct dirent* de;
     DIR* dir = opendir(DEV_BLOCK);
@@ -80,9 +101,7 @@
             fprintf(stderr, "Error opening %s\n", info.path);
             goto devdone;
         }
-        if (ioctl_device_get_topo_path(fd, info.topo, sizeof(info.topo)) < 0) {
-            strcpy(info.topo, "UNKNOWN");
-        }
+        populate_topo_path(fd, &info);
 
         block_info_t block_info;
         if (ioctl_block_get_info(fd, &block_info) > 0) {
@@ -139,9 +158,7 @@
             fprintf(stderr, "Error opening %s\n", info.path);
             goto devdone;
         }
-        if (ioctl_device_get_topo_path(fd, info.topo, sizeof(info.topo)) < 0) {
-            strcpy(info.topo, "UNKNOWN");
-        }
+        populate_topo_path(fd, &info);
 
         fdio_t* io = fdio_unsafe_fd_to_io(fd);
         zx_handle_t channel = fdio_unsafe_borrow_channel(io);
diff --git a/zircon/system/uapp/lsblk/rules.mk b/zircon/system/uapp/lsblk/rules.mk
index 986450a..4a20709 100644
--- a/zircon/system/uapp/lsblk/rules.mk
+++ b/zircon/system/uapp/lsblk/rules.mk
@@ -22,6 +22,8 @@
 
 MODULE_LIBS := system/ulib/zircon system/ulib/fdio system/ulib/c
 
-MODULE_FIDL_LIBS := system/fidl/fuchsia-hardware-skipblock
+MODULE_FIDL_LIBS := \
+    system/fidl/fuchsia-device \
+    system/fidl/fuchsia-hardware-skipblock \
 
 include make/module.mk
diff --git a/zircon/system/uapp/nand-util/main.cpp b/zircon/system/uapp/nand-util/main.cpp
index 0a1dd2b..778a0c0 100644
--- a/zircon/system/uapp/nand-util/main.cpp
+++ b/zircon/system/uapp/nand-util/main.cpp
@@ -12,9 +12,11 @@
 #include <fbl/algorithm.h>
 #include <fbl/unique_fd.h>
 #include <fbl/unique_ptr.h>
+#include <fuchsia/device/c/fidl.h>
 #include <fuchsia/hardware/nand/c/fidl.h>
 #include <fuchsia/nand/c/fidl.h>
 #include <lib/cksum.h>
+#include <lib/fdio/unsafe.h>
 #include <lib/fdio/util.h>
 #include <lib/fdio/watcher.h>
 #include <lib/fzl/owned-vmo-mapper.h>
@@ -22,7 +24,6 @@
 #include <lib/zx/vmo.h>
 #include <pretty/hexdump.h>
 #include <zircon/assert.h>
-#include <zircon/device/device.h>
 #include <zircon/status.h>
 #include <zircon/syscalls.h>
 
@@ -283,11 +284,23 @@
         // The passed-in device is already a broker.
         return true;
     }
-    const char kBroker[] = "/boot/driver/nand-broker.so";
-    if (ioctl_device_bind(device_.get(), kBroker, sizeof(kBroker) - 1) < 0) {
-        printf("Failed to issue bind command\n");
+
+    fdio_t* io = fdio_unsafe_fd_to_io(device_.get());
+    if (io == nullptr) {
+        printf("Could not convert fd to io\n");
         return false;
     }
+    zx_status_t call_status;
+    const char kBroker[] = "/boot/driver/nand-broker.so";
+    zx_status_t status = fuchsia_device_ControllerBind(fdio_unsafe_borrow_channel(io),
+                                                       kBroker, sizeof(kBroker) - 1,
+                                                       &call_status);
+    fdio_unsafe_release(io);
+    if (status != ZX_OK || call_status != ZX_OK) {
+        fprintf(stderr, "Failed to issue bind command\n");
+        return false;
+    }
+
     device_ = OpenBroker(path_);
     if (!device_) {
         printf("Failed to bind broker\n");
diff --git a/zircon/system/uapp/nand-util/rules.mk b/zircon/system/uapp/nand-util/rules.mk
index 67e694a..97ff8ca 100644
--- a/zircon/system/uapp/nand-util/rules.mk
+++ b/zircon/system/uapp/nand-util/rules.mk
@@ -28,6 +28,7 @@
     system/ulib/zircon \
 
 MODULE_FIDL_LIBS := \
+    system/fidl/fuchsia-device \
     system/fidl/fuchsia-nand \
     system/fidl/fuchsia-hardware-nand \
 
diff --git a/zircon/system/uapp/usb-fwloader/rules.mk b/zircon/system/uapp/usb-fwloader/rules.mk
index b7b81e1..24dd4ec 100644
--- a/zircon/system/uapp/usb-fwloader/rules.mk
+++ b/zircon/system/uapp/usb-fwloader/rules.mk
@@ -22,6 +22,7 @@
     system/ulib/c \
 
 MODULE_FIDL_LIBS := \
+    system/fidl/fuchsia-device \
     system/fidl/fuchsia-mem \
     system/fidl/fuchsia-hardware-usb-fwloader \
     system/fidl/fuchsia-hardware-usb-tester
diff --git a/zircon/system/uapp/usb-fwloader/usb-fwloader.cpp b/zircon/system/uapp/usb-fwloader/usb-fwloader.cpp
index 0d9f913..18d36d8 100644
--- a/zircon/system/uapp/usb-fwloader/usb-fwloader.cpp
+++ b/zircon/system/uapp/usb-fwloader/usb-fwloader.cpp
@@ -5,15 +5,16 @@
 #include <fbl/auto_call.h>
 #include <fbl/unique_fd.h>
 #include <fbl/unique_ptr.h>
+#include <fuchsia/device/c/fidl.h>
 #include <fuchsia/hardware/usb/tester/c/fidl.h>
 #include <fuchsia/hardware/usb/fwloader/c/fidl.h>
 #include <fuchsia/mem/c/fidl.h>
+#include <lib/fdio/unsafe.h>
 #include <lib/fdio/util.h>
 #include <lib/fdio/watcher.h>
 #include <lib/fzl/fdio.h>
 #include <lib/zx/channel.h>
 #include <lib/zx/vmo.h>
-#include <zircon/device/device.h>
 #include <zircon/hw/usb.h>
 #include <zircon/types.h>
 
@@ -66,10 +67,20 @@
 
 zx_status_t fd_matches_name(const fbl::unique_fd& fd, const char* dev_name, bool* out_match) {
     char path[PATH_MAX];
-    const ssize_t r = ioctl_device_get_topo_path(fd.get(), path, sizeof(path));
-    if (r < 0) {
+    fdio_t* io = fdio_unsafe_fd_to_io(fd.get());
+    if (io == nullptr) {
+        return ZX_ERR_BAD_STATE;
+    }
+    zx_status_t call_status;
+    size_t path_len;
+    zx_status_t status = fuchsia_device_ControllerGetTopologicalPath(
+            fdio_unsafe_borrow_channel(io), &call_status, path, sizeof(path) - 1 , &path_len);
+    fdio_unsafe_release(io);
+    if (status != ZX_OK || call_status != ZX_OK) {
         return ZX_ERR_IO;
     }
+    path[path_len] = 0;
+
     *out_match = dev_name == nullptr || strstr(path, dev_name) != nullptr;
     return ZX_OK;
 }
diff --git a/zircon/system/uapp/waitfor/rules.mk b/zircon/system/uapp/waitfor/rules.mk
index 49f9743..8ceca86 100644
--- a/zircon/system/uapp/waitfor/rules.mk
+++ b/zircon/system/uapp/waitfor/rules.mk
@@ -22,4 +22,7 @@
     system/ulib/zxcpp \
     third_party/ulib/cksum \
 
+MODULE_FIDL_LIBS := \
+    system/fidl/fuchsia-device \
+
 include make/module.mk
diff --git a/zircon/system/uapp/waitfor/waitfor.c b/zircon/system/uapp/waitfor/waitfor.c
index 9f8d325..11d8f45 100644
--- a/zircon/system/uapp/waitfor/waitfor.c
+++ b/zircon/system/uapp/waitfor/waitfor.c
@@ -8,6 +8,8 @@
 #include <string.h>
 #include <unistd.h>
 
+#include <fuchsia/device/c/fidl.h>
+#include <lib/fdio/unsafe.h>
 #include <lib/fdio/watcher.h>
 
 // for guid printing
@@ -17,7 +19,6 @@
 #include <zircon/syscalls.h>
 
 #include <zircon/device/block.h>
-#include <zircon/device/device.h>
 
 void usage(void) {
     fprintf(stderr,
@@ -106,17 +107,27 @@
 
 zx_status_t expr_topo(const char* arg, int fd) {
     char topo[1024+1];
-    int r = ioctl_device_get_topo_path(fd, topo, sizeof(topo) - 1);
-    if (r < 0) {
+
+    fdio_t* io = fdio_unsafe_fd_to_io(fd);
+    if (io == NULL) {
+        return ZX_ERR_NEXT;
+    }
+    zx_status_t call_status;
+    size_t path_len;
+    zx_status_t status = fuchsia_device_ControllerGetTopologicalPath(
+            fdio_unsafe_borrow_channel(io), &call_status, topo, sizeof(topo) - 1, &path_len);
+    fdio_unsafe_release(io);
+    if (status != ZX_OK || call_status != ZX_OK) {
         fprintf(stderr, "waitfor: warning: cannot read topo path\n");
         return ZX_ERR_NEXT;
     }
-    topo[r] = 0;
+    topo[path_len] = 0;
+
     if (verbose) {
         fprintf(stderr, "waitfor: topo='%s'\n", topo);
     }
-    int len = strlen(arg);
-    if ((r < len) || strncmp(arg, topo, len)) {
+    size_t len = strlen(arg);
+    if ((path_len < len) || strncmp(arg, topo, len)) {
         return ZX_ERR_NEXT;
     } else {
         return ZX_OK;