1 /*
   2  * This file and its contents are supplied under the terms of the
   3  * Common Development and Distribution License ("CDDL"), version 1.0.
   4  * You may only use this file in accordance with the terms of version
   5  * 1.0 of the CDDL.
   6  *
   7  * A full copy of the text of the CDDL should have accompanied this
   8  * source.  A copy of the CDDL is also available via the Internet at
   9  * http://www.illumos.org/license/CDDL.
  10  */
  11 
  12 /*
  13  * Copyright (c) 2012, Joyent, Inc. All rights reserved.
  14  */
  15 
  16 #include <stdlib.h>
  17 #include <sys/types.h>
  18 #include <sys/stat.h>
  19 #include <fcntl.h>
  20 #include <unistd.h>
  21 #include <stropts.h>
  22 #include <string.h>
  23 
  24 #include <fm/topo_mod.h>
  25 #include <fm/topo_list.h>
  26 
  27 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_type.h>
  28 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2.h>
  29 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_init.h>
  30 #include <sys/scsi/adapters/mpt_sas/mptsas_ioctl.h>
  31 
  32 static int
  33 get_sas_address(topo_mod_t *mod, char *devctl, uint32_t enclosure,
  34     uint32_t slot, char **sas_address)
  35 {
  36         int err = -1;
  37         int fd, i;
  38         mptsas_get_disk_info_t gdi;
  39         mptsas_disk_info_t *di = NULL;
  40         size_t disz;
  41 
  42         bzero(&gdi, sizeof (gdi));
  43 
  44         fd = open(devctl, O_RDWR);
  45         if (fd == -1) {
  46                 topo_mod_dprintf(mod, "could not open '%s' for ioctl: %s\n",
  47                     devctl, strerror(errno));
  48                 return (-1);
  49         }
  50 
  51         if (ioctl(fd, MPTIOCTL_GET_DISK_INFO, &gdi) == -1) {
  52                 topo_mod_dprintf(mod, "ioctl 1 on '%s' failed: %s\n", devctl,
  53                     strerror(errno));
  54                 goto out;
  55         }
  56 
  57         gdi.DiskInfoArraySize = disz = sizeof (mptsas_disk_info_t) *
  58             gdi.DiskCount;
  59         gdi.PtrDiskInfoArray = di = topo_mod_alloc(mod, disz);
  60         if (di == NULL) {
  61                 topo_mod_dprintf(mod, "memory allocation failed\n");
  62                 goto out;
  63         }
  64 
  65         if (ioctl(fd, MPTIOCTL_GET_DISK_INFO, &gdi) == -1) {
  66                 topo_mod_dprintf(mod, "ioctl 2 on '%s' failed: %s\n", devctl,
  67                     strerror(errno));
  68                 goto out;
  69         }
  70 
  71         for (i = 0; i < gdi.DiskCount; i++) {
  72                 if (di[i].Enclosure == enclosure && di[i].Slot == slot) {
  73                         char sas[17]; /* 16 hex digits and NUL */
  74                         (void) snprintf(sas, 17, "%llx", di[i].SasAddress);
  75                         topo_mod_dprintf(mod, "found mpt_sas disk (%d/%d) "
  76                             "with adddress %s\n", enclosure, slot, sas);
  77                         *sas_address = topo_mod_strdup(mod, sas);
  78                         err = 0;
  79                         break;
  80                 }
  81         }
  82 
  83 out:
  84         if (di != NULL)
  85                 topo_mod_free(mod, di, disz);
  86         (void) close(fd);
  87         return (err);
  88 }
  89 
  90 int
  91 disk_mptsas_find_disk(topo_mod_t *mod, tnode_t *baynode, char **sas_address)
  92 {
  93         char *devctl = NULL;
  94         uint32_t enclosure, slot;
  95         int err;
  96 
  97         /*
  98          * Get the required properties from the node.  These come from
  99          * the static XML mapping.
 100          */
 101         if (topo_prop_get_string(baynode, TOPO_PGROUP_BINDING,
 102             TOPO_BINDING_DEVCTL, &devctl, &err) != 0 ||
 103             topo_prop_get_uint32(baynode, TOPO_PGROUP_BINDING,
 104             TOPO_BINDING_ENCLOSURE, &enclosure, &err) != 0 ||
 105             topo_prop_get_uint32(baynode, TOPO_PGROUP_BINDING,
 106             TOPO_BINDING_SLOT, &slot, &err) != 0) {
 107                 if (devctl != NULL)
 108                         topo_mod_strfree(mod, devctl);
 109                 topo_mod_dprintf(mod, "bay node was missing mpt_sas binding "
 110                     "properties\n");
 111                 return (-1);
 112         }
 113 
 114         err = get_sas_address(mod, devctl, enclosure, slot, sas_address);
 115         topo_mod_strfree(mod, devctl);
 116         return (err);
 117 }