1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 25 #include <syslog.h> 26 #include <errno.h> 27 #include <unistd.h> 28 #include <stropts.h> 29 30 #include "mp_utils.h" 31 32 #include <libdevinfo.h> 33 34 /* 35 * Checks whether there is online path or not. 36 * - no path found returns -1. 37 * - online/standby path found returns 1. 38 * - path exists but no online/standby path found returns 0. 39 */ 40 static int checkAvailablePath(di_node_t node) 41 { 42 di_path_t path; 43 di_path_state_t state; 44 45 if ((path = di_path_client_next_path(node, DI_PATH_NIL)) 46 == DI_PATH_NIL) { 47 log(LOG_INFO, "checkAvailalblePath()", 48 " - No path found"); 49 return (-1); 50 } 51 52 do { 53 /* ignore the path that is neither online nor standby. */ 54 if (((state = di_path_state(path)) == DI_PATH_STATE_ONLINE) || 55 (state == DI_PATH_STATE_STANDBY)) { 56 return (1); 57 } 58 } while ((path = di_path_client_next_path(node, path)) != DI_PATH_NIL); 59 60 /* return 0 for the case that there is no online path to the node. */ 61 log(LOG_INFO, "checkAvailalblePath()", " - No online path found"); 62 return (0); 63 } 64 65 static int getOidList(di_node_t root_node, MP_OID_LIST *pOidList) 66 { 67 int numNodes = 0, state; 68 69 int instNum; 70 int majorNum; 71 MP_UINT64 osn; 72 73 di_node_t sv_node = DI_NODE_NIL; 74 di_node_t sv_child_node = DI_NODE_NIL; 75 76 int haveList = (NULL != pOidList); 77 78 79 log(LOG_INFO, "getOidList()", " - enter"); 80 81 82 sv_node = di_drv_first_node("scsi_vhci", root_node); 83 if (DI_NODE_NIL == sv_node) { 84 log(LOG_INFO, "getOidList()", 85 " - di_drv_first_node() failed"); 86 87 return (-1); 88 } 89 90 sv_child_node = di_child_node(sv_node); 91 92 while (DI_NODE_NIL != sv_child_node) { 93 94 /* skip the node which is offline, down or detached. */ 95 state = di_state(sv_child_node); 96 if ((state & DI_DEVICE_DOWN) || 97 (state & DI_DEVICE_OFFLINE)) { 98 sv_child_node = di_sibling_node(sv_child_node); 99 continue; 100 } 101 102 /* 103 * skip if the node doesn't have any path avaialble. 104 * If any path is found from the DINFOCACHE snaphost 105 * that means the driver keeps track of the path regadless 106 * of state. 107 */ 108 if (checkAvailablePath(sv_child_node) == -1) { 109 sv_child_node = di_sibling_node(sv_child_node); 110 continue; 111 } 112 113 if (haveList && (numNodes < pOidList->oidCount)) { 114 instNum = di_instance(sv_child_node); 115 majorNum = di_driver_major(sv_child_node); 116 117 log(LOG_INFO, "getOidList()", 118 "instNum = %d", instNum); 119 log(LOG_INFO, "getOidList()", 120 "majorNum = %d", majorNum); 121 122 osn = 0; 123 osn = MP_STORE_INST_TO_ID(instNum, osn); 124 osn = MP_STORE_MAJOR_TO_ID(majorNum, osn); 125 126 pOidList->oids[numNodes].objectType = 127 MP_OBJECT_TYPE_MULTIPATH_LU; 128 129 pOidList->oids[numNodes].ownerId = 130 g_pluginOwnerID; 131 132 pOidList->oids[numNodes].objectSequenceNumber = 133 osn; 134 } 135 136 ++numNodes; 137 138 sv_child_node = di_sibling_node(sv_child_node); 139 } 140 141 log(LOG_INFO, 142 "getOidList()", 143 " - numNodes: %d", 144 numNodes); 145 146 147 148 log(LOG_INFO, "getOidList()", " - exit"); 149 150 return (numNodes); 151 } 152 153 154 MP_STATUS 155 MP_GetMultipathLusPlugin(MP_OID_LIST **ppList) 156 { 157 di_node_t root_node = DI_NODE_NIL; 158 MP_OID_LIST *pOidList = NULL; 159 160 int numNodes = 0; 161 int i = 0; 162 163 log(LOG_INFO, "MP_GetMultipathLusPlugin()", " - enter"); 164 165 166 root_node = di_init("/", DINFOCACHE); 167 if (DI_NODE_NIL == root_node) { 168 log(LOG_INFO, "MP_GetMultipathLusPlugin()", 169 " - di_init() failed"); 170 171 return (MP_STATUS_FAILED); 172 } 173 174 numNodes = getOidList(root_node, NULL); 175 176 if (numNodes < 0) { 177 178 log(LOG_INFO, 179 "MP_GetMultipathLusPlugin()", 180 " - unable to get OID list."); 181 182 log(LOG_INFO, "MP_GetMultipathLusPlugin()", 183 " - error exit"); 184 185 di_fini(root_node); 186 187 return (MP_STATUS_FAILED); 188 } 189 190 if (0 == numNodes) { 191 192 pOidList = createOidList(1); 193 if (NULL == pOidList) { 194 195 log(LOG_INFO, 196 "MP_GetMultipathLusPlugin()", 197 " - unable to create OID list."); 198 199 di_fini(root_node); 200 201 return (MP_STATUS_INSUFFICIENT_MEMORY); 202 } 203 204 pOidList->oids[0].objectType = 205 MP_OBJECT_TYPE_MULTIPATH_LU; 206 207 pOidList->oids[0].ownerId = 208 g_pluginOwnerID; 209 210 *ppList = pOidList; 211 212 log(LOG_INFO, "MP_GetMultipathLusPlugin()", 213 " - returning empty list."); 214 215 di_fini(root_node); 216 217 return (MP_STATUS_SUCCESS); 218 } 219 220 *ppList = createOidList(numNodes); 221 if (NULL == *ppList) { 222 log(LOG_INFO, "MP_GetMultipathLusPlugin()", 223 "no memory for *ppList"); 224 log(LOG_INFO, "MP_GetMultipathLusPlugin()", 225 " - error exit"); 226 return (MP_STATUS_INSUFFICIENT_MEMORY); 227 } 228 229 (*ppList)->oidCount = numNodes; 230 231 numNodes = getOidList(root_node, *ppList); 232 233 for (i = 0; i < (*ppList)->oidCount; i++) { 234 235 log(LOG_INFO, "MP_GetMultipathLusPlugin()", 236 "(*ppList)->oids[%d].objectType = %d", 237 i, (*ppList)->oids[i].objectType); 238 log(LOG_INFO, "MP_GetMultipathLusPlugin()", 239 "(*ppList)->oids[%d].ownerId = %d", 240 i, (*ppList)->oids[i].ownerId); 241 log(LOG_INFO, "MP_GetMultipathLusPlugin()", 242 "(*ppList)->oids[%d].objectSequenceNumber = %llx", 243 i, (*ppList)->oids[i].objectSequenceNumber); 244 } 245 246 247 di_fini(root_node); 248 249 log(LOG_INFO, "MP_GetMultipathLusPlugin()", " - exit"); 250 251 return (MP_STATUS_SUCCESS); 252 253 } 254