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 * Copyright (c) 2013, Joyent, Inc. All rights reserved. 13 */ 14 15 #include <stdlib.h> 16 #include <sys/types.h> 17 #include <sys/stat.h> 18 #include <fcntl.h> 19 #include <unistd.h> 20 #include <stropts.h> 21 #include <string.h> 22 #include <strings.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 #include "disk.h" 33 #include "disk_drivers.h" 34 35 /* 36 * Request the SAS address of the disk (if any) attached to this mpt_sas 37 * instance at (Enclosure Number, Slot Number). 38 * 39 * Returns: 40 * -2 /devices node (*devctl) does not exist 41 * -1 All other failures 42 * 0 Success 43 */ 44 static int 45 get_sas_address(topo_mod_t *mod, char *devctl, uint32_t enclosure, 46 uint32_t slot, char **sas_address) 47 { 48 int fd, err, i; 49 mptsas_get_disk_info_t gdi; 50 mptsas_disk_info_t *di; 51 size_t disz; 52 53 bzero(&gdi, sizeof (gdi)); 54 55 if ((fd = open(devctl, O_RDWR)) == -1) { 56 int rc = (errno == ENOENT ? -2 : -1); 57 topo_mod_dprintf(mod, "could not open '%s' for ioctl: %s\n", 58 devctl, strerror(errno)); 59 return (rc); 60 } 61 62 if (ioctl(fd, MPTIOCTL_GET_DISK_INFO, &gdi) == -1) { 63 topo_mod_dprintf(mod, "ioctl 1 on '%s' failed: %s\n", devctl, 64 strerror(errno)); 65 (void) close(fd); 66 return (-1); 67 } 68 69 gdi.DiskInfoArraySize = disz = sizeof (mptsas_disk_info_t) * 70 gdi.DiskCount; 71 gdi.PtrDiskInfoArray = di = topo_mod_alloc(mod, disz); 72 if (di == NULL) { 73 topo_mod_dprintf(mod, "memory allocation failed\n"); 74 (void) close(fd); 75 return (-1); 76 } 77 78 if (ioctl(fd, MPTIOCTL_GET_DISK_INFO, &gdi) == -1) { 79 topo_mod_dprintf(mod, "ioctl 2 on '%s' failed: %s\n", devctl, 80 strerror(errno)); 81 topo_mod_free(mod, di, disz); 82 (void) close(fd); 83 return (-1); 84 } 85 86 err = -1; 87 for (i = 0; i < gdi.DiskCount; i++) { 88 if (di[i].Enclosure == enclosure && di[i].Slot == slot) { 89 char sas[17]; /* 16 hex digits and NUL */ 90 (void) snprintf(sas, 17, "%llx", di[i].SasAddress); 91 topo_mod_dprintf(mod, "found mpt_sas disk (%d/%d) " 92 "with adddress %s\n", enclosure, slot, sas); 93 *sas_address = topo_mod_strdup(mod, sas); 94 err = 0; 95 break; 96 } 97 } 98 99 topo_mod_free(mod, di, disz); 100 (void) close(fd); 101 return (err); 102 } 103 104 int 105 disk_mptsas_find_disk(topo_mod_t *mod, tnode_t *baynode, char **sas_address) 106 { 107 char *devctl = NULL; 108 uint32_t enclosure, slot; 109 int err; 110 char *elem, *lastp; 111 int ret = -1; 112 113 /* 114 * Get the required properties from the node. These come from 115 * the static XML mapping. 116 */ 117 if (topo_prop_get_string(baynode, TOPO_PGROUP_BINDING, 118 TOPO_BINDING_DEVCTL, &devctl, &err) != 0 || 119 topo_prop_get_uint32(baynode, TOPO_PGROUP_BINDING, 120 TOPO_BINDING_ENCLOSURE, &enclosure, &err) != 0 || 121 topo_prop_get_uint32(baynode, TOPO_PGROUP_BINDING, 122 TOPO_BINDING_SLOT, &slot, &err) != 0) { 123 if (devctl != NULL) 124 topo_mod_strfree(mod, devctl); 125 topo_mod_dprintf(mod, "bay node was missing mpt_sas binding " 126 "properties\n"); 127 return (-1); 128 } 129 130 /* 131 * devctl is a (potentially) pipe-separated list of different device 132 * paths to try. 133 */ 134 if ((elem = topo_mod_strsplit(mod, devctl, "|", &lastp)) != NULL) { 135 do { 136 topo_mod_dprintf(mod, "trying mpt_sas instance at %s\n", 137 elem); 138 139 ret = get_sas_address(mod, elem, enclosure, 140 slot, sas_address); 141 142 topo_mod_strfree(mod, elem); 143 144 /* 145 * Only try further devctl paths from the list if this 146 * one was not found: 147 */ 148 if (ret != -2) { 149 break; 150 } else { 151 topo_mod_dprintf(mod, "instance not found\n"); 152 } 153 154 } while ((elem = topo_mod_strsplit(mod, NULL, "|", 155 &lastp)) != NULL); 156 } 157 158 topo_mod_strfree(mod, devctl); 159 return (ret); 160 }