Print this page
OS-1996 mpt_sas: allow physical topology enumeration in libtopo
Reviewed by: Keith Wesolowski <keith.wesolowski@joyent.com>

@@ -20,10 +20,11 @@
  */
 
 /*
  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
  */
 
 /*
  * Copyright (c) 2000 to 2010, LSI Corporation.
  * All rights reserved.

@@ -67,10 +68,11 @@
 #include <sys/scsi/scsi.h>
 #include <sys/pci.h>
 #include <sys/file.h>
 #include <sys/cpuvar.h>
 #include <sys/policy.h>
+#include <sys/model.h>
 #include <sys/sysevent.h>
 #include <sys/sysevent/eventdefs.h>
 #include <sys/sysevent/dr.h>
 #include <sys/sata/sata_defs.h>
 #include <sys/scsi/generic/sas.h>

@@ -11949,10 +11951,100 @@
         mutex_exit(&mpt->m_mutex);
         return (status);
 }
 
 static int
+get_disk_info(mptsas_t *mpt, intptr_t data, int mode)
+{
+        int i = 0;
+        int count = 0;
+        int ret = 0;
+        mptsas_target_t *ptgt;
+        mptsas_disk_info_t *di;
+        STRUCT_DECL(mptsas_get_disk_info, gdi);
+
+        STRUCT_INIT(gdi, get_udatamodel());
+
+        if (ddi_copyin((void *)data, STRUCT_BUF(gdi), STRUCT_SIZE(gdi),
+            mode) != 0) {
+                return (EFAULT);
+        }
+
+        /* Find out how many targets there are. */
+        mutex_enter(&mpt->m_mutex);
+        ptgt = (mptsas_target_t *)mptsas_hash_traverse(&mpt->m_active->m_tgttbl,
+            MPTSAS_HASH_FIRST);
+        while (ptgt != NULL) {
+                count++;
+                ptgt = (mptsas_target_t *)mptsas_hash_traverse(
+                    &mpt->m_active->m_tgttbl, MPTSAS_HASH_NEXT);
+        }
+        mutex_exit(&mpt->m_mutex);
+
+        /*
+         * If we haven't been asked to copy out information on each target,
+         * then just return the count.
+         */
+        STRUCT_FSET(gdi, DiskCount, count);
+        if (STRUCT_FGETP(gdi, PtrDiskInfoArray) == NULL)
+                goto copy_out;
+
+        /*
+         * If we haven't been given a large enough buffer to copy out into,
+         * let the caller know.
+         */
+        if (STRUCT_FGET(gdi, DiskInfoArraySize) <
+            count * sizeof (mptsas_disk_info_t)) {
+                ret = ENOSPC;
+                goto copy_out;
+        }
+
+        di = kmem_zalloc(count * sizeof (mptsas_disk_info_t), KM_SLEEP);
+
+        mutex_enter(&mpt->m_mutex);
+        ptgt = (mptsas_target_t *)mptsas_hash_traverse(&mpt->m_active->m_tgttbl,
+            MPTSAS_HASH_FIRST);
+        while (ptgt != NULL) {
+                if (i >= count) {
+                        /*
+                         * The number of targets changed while we weren't
+                         * looking, so give up.
+                         */
+                        mutex_exit(&mpt->m_mutex);
+                        kmem_free(di, count * sizeof (mptsas_disk_info_t));
+                        return (EAGAIN);
+                }
+                di[i].Instance = mpt->m_instance;
+                di[i].Enclosure = ptgt->m_enclosure;
+                di[i].Slot = ptgt->m_slot_num;
+                di[i].SasAddress = ptgt->m_sas_wwn;
+
+                ptgt = (mptsas_target_t *)mptsas_hash_traverse(
+                    &mpt->m_active->m_tgttbl, MPTSAS_HASH_NEXT);
+                i++;
+        }
+        mutex_exit(&mpt->m_mutex);
+        STRUCT_FSET(gdi, DiskCount, i);
+
+        /* Copy out the disk information to the caller. */
+        if (ddi_copyout((void *)di, STRUCT_FGETP(gdi, PtrDiskInfoArray),
+            i * sizeof (mptsas_disk_info_t), mode) != 0) {
+                ret = EFAULT;
+        }
+
+        kmem_free(di, count * sizeof (mptsas_disk_info_t));
+
+copy_out:
+        if (ddi_copyout(STRUCT_BUF(gdi), (void *)data, STRUCT_SIZE(gdi),
+            mode) != 0) {
+                ret = EFAULT;
+        }
+
+        return (ret);
+}
+
+static int
 mptsas_ioctl(dev_t dev, int cmd, intptr_t data, int mode, cred_t *credp,
     int *rval)
 {
         int                     status = 0;
         mptsas_t                *mpt;

@@ -12069,10 +12161,13 @@
                         ndi_dc_freehdl(dcp);
                 }
                 goto out;
         }
         switch (cmd) {
+                case MPTIOCTL_GET_DISK_INFO:
+                        status = get_disk_info(mpt, data, mode);
+                        break;
                 case MPTIOCTL_UPDATE_FLASH:
                         if (ddi_copyin((void *)data, &flashdata,
                                 sizeof (struct mptsas_update_flash), mode)) {
                                 status = EFAULT;
                                 break;