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 <errno.h> 26 #include <unistd.h> 27 #include <stropts.h> 28 #include <sys/stat.h> 29 #include <fcntl.h> 30 #include <libdevinfo.h> 31 #include <sys/stat.h> 32 33 #include "mp_utils.h" 34 35 36 /* 37 * The plugin library will call MP_CMD ioctl with 38 * MP_GET_TARGET_PORT_LIST_FOR_TPG subcommand. 39 * For each target port, the plugin will get the target port name property. 40 * 41 * A scsi_vhci device with pathinfo containing matching target port name 42 * may potentially be associated with the given TPG. 43 * The plugin library will check the TPG list for qualifying scsi_vhci 44 * devices and find a matching TPG id. 45 * 46 * An rfe was filed against MDI to 47 * refresh DINFOCACHE snapshot for pathinfo update. 48 */ 49 50 51 52 53 54 /* 55 * Returns MP_TRUE if the ID found in the dev info snapshot matches the ID 56 * provided by the schi_vhci driver. 57 */ 58 59 static int checkTPGList(MP_UINT32 tpgID, MP_UINT64 objectSequenceNumber) 60 { 61 int tpg = 0; 62 int status = MP_FALSE; 63 64 MP_OID luOID; 65 66 MP_OID_LIST *ppList = NULL; 67 MP_STATUS mpStatus = MP_STATUS_SUCCESS; 68 69 MP_TARGET_PORT_GROUP_PROPERTIES tpgProps; 70 71 72 73 log(LOG_INFO, "checkTPGList()", " - enter"); 74 75 76 luOID.objectSequenceNumber = objectSequenceNumber; 77 luOID.objectType = MP_OBJECT_TYPE_MULTIPATH_LU; 78 luOID.ownerId = g_pluginOwnerID; 79 80 mpStatus = getAssociatedTPGOidList(luOID, &ppList); 81 if (MP_STATUS_SUCCESS != mpStatus) { 82 83 log(LOG_INFO, "checkTPGList()", 84 " - getAssociatedTPGOidList() failed: %d", 85 mpStatus); 86 87 return (MP_FALSE); 88 } 89 90 for (tpg = 0; tpg < ppList->oidCount; tpg++) { 91 92 mpStatus = getTargetPortGroupProperties(ppList->oids[tpg], 93 &tpgProps); 94 95 if (MP_STATUS_SUCCESS != mpStatus) { 96 97 log(LOG_INFO, "checkTPGList()", 98 " - getTargetPortGroupProperties() failed: %d", 99 mpStatus); 100 101 return (MP_FALSE); 102 } 103 104 if (tpgProps.tpgID == tpgID) { 105 106 status = MP_TRUE; 107 108 log(LOG_INFO, "checkTPGList()", 109 " - found a match"); 110 111 break; 112 } 113 } 114 115 free(ppList); 116 117 118 log(LOG_INFO, "checkTPGList()", " - exit"); 119 120 return (status); 121 } 122 123 124 125 /* 126 * Returns the number of matches found. If pOidList is not NULL, then 127 * populate it. A return values of -1 indicates and error, zerom menas 128 * no match is found. 129 */ 130 131 static int getOidList(di_node_t root_node, int tpgID, 132 MP_OID_LIST *tpList, MP_OID_LIST *pOidList) 133 { 134 di_node_t sv_node = DI_NODE_NIL; 135 di_node_t child_node = DI_NODE_NIL; 136 di_path_t path = DI_PATH_NIL; 137 138 int numNodes = 0; 139 int tp = 0; 140 int ioctlStatus = 0; 141 int match = 0; 142 int status = -1; 143 144 int sv_child_inst = 0; 145 int sv_child_major = 0; 146 MP_UINT64 osn; 147 148 int hasTpgMatch = MP_FALSE; 149 150 struct stat buffer; 151 152 char *pathName = NULL; 153 char *minorName = "c"; 154 155 char fullName[512]; 156 157 char *portName = NULL; 158 159 mp_iocdata_t mp_ioctl; 160 161 mp_target_port_prop_t tpInfo; 162 163 MP_UINT64 tpOSN = 0; 164 165 int haveList = (NULL != pOidList); 166 167 168 log(LOG_INFO, "getOidList()", " - enter"); 169 170 171 /* Look through the list of target ports for a portName that matches */ 172 for (tp = 0; tp < tpList->oidCount; tp++) { 173 174 tpOSN = tpList->oids[tp].objectSequenceNumber; 175 176 log(LOG_INFO, "getOidList()", "tpOSN = %llx", tpOSN); 177 178 (void) memset(&mp_ioctl, 0, sizeof (mp_iocdata_t)); 179 (void) memset(&tpInfo, 0, sizeof (mp_target_port_prop_t)); 180 181 mp_ioctl.mp_cmd = MP_GET_TARGET_PORT_PROP; 182 mp_ioctl.mp_ibuf = (caddr_t)&tpOSN; 183 mp_ioctl.mp_ilen = sizeof (tpOSN); 184 mp_ioctl.mp_obuf = (caddr_t)&tpInfo; 185 mp_ioctl.mp_olen = sizeof (mp_target_port_prop_t); 186 mp_ioctl.mp_xfer = MP_XFER_READ; 187 188 log(LOG_INFO, "getOidList()", 189 "mp_ioctl.mp_cmd (MP_GET_TARGET_PORT_PROP) : %d", 190 mp_ioctl.mp_cmd); 191 192 ioctlStatus = ioctl(g_scsi_vhci_fd, MP_CMD, &mp_ioctl); 193 194 log(LOG_INFO, "getOidList()", " IOCTL call returned: %d", 195 ioctlStatus); 196 197 if (ioctlStatus < 0) { 198 ioctlStatus = errno; 199 } 200 201 if (ioctlStatus != 0) { 202 log(LOG_INFO, "getOidList()", 203 "IOCTL call failed. IOCTL error is: %d", 204 ioctlStatus); 205 log(LOG_INFO, "getOidList()", 206 "IOCTL call failed. IOCTL error is: %s", 207 strerror(ioctlStatus)); 208 log(LOG_INFO, "getOidList()", 209 "IOCTL call failed. mp_ioctl.mp_errno: %x", 210 mp_ioctl.mp_errno); 211 212 log(LOG_INFO, "getOidList()", " - error exit"); 213 214 return (-1); 215 } 216 217 sv_node = di_drv_first_node("scsi_vhci", root_node); 218 if (DI_NODE_NIL == sv_node) { 219 log(LOG_INFO, "getOidList()", 220 " - di_drv_first_node() failed"); 221 222 return (-1); 223 } 224 225 child_node = di_child_node(sv_node); 226 227 while (DI_NODE_NIL != child_node) { 228 229 path = di_path_next(child_node, path); 230 231 match = 0; 232 233 while (DI_PATH_NIL != path) { 234 235 236 (void) di_path_prop_lookup_strings(path, 237 "target-port", &portName); 238 239 if (NULL != portName) { 240 241 if (0 == strncmp(portName, 242 tpInfo.portName, 243 strlen(tpInfo.portName))) { 244 245 match = 1; 246 break; 247 } 248 } 249 250 path = di_path_next(child_node, path); 251 } 252 253 if (match) { 254 255 log(LOG_INFO, "getOidList()", 256 " - got a match"); 257 258 pathName = di_devfs_path(child_node); 259 260 (void) snprintf(fullName, 511, "/devices%s:%s", 261 pathName, minorName); 262 263 di_devfs_path_free(pathName); 264 265 status = stat(fullName, &buffer); 266 if (status < 0) { 267 268 log(LOG_INFO, "getOidList()", 269 " - stat() call failed: %d", 270 status); 271 272 log(LOG_INFO, "getOidList()", 273 " - errno: [%d].", errno); 274 275 log(LOG_INFO, "getOidList()", 276 " - strerror(errno): [%s].", 277 strerror(errno)); 278 279 log(LOG_INFO, "getOidList()", 280 " - error exit."); 281 282 return (-1); 283 } 284 285 sv_child_inst = di_instance(child_node); 286 sv_child_major = di_driver_major(child_node); 287 288 osn = 0; 289 osn = MP_STORE_INST_TO_ID(sv_child_inst, osn); 290 osn = MP_STORE_MAJOR_TO_ID(sv_child_major, 291 osn); 292 293 /* 294 * OK, found an portName that matches, let's 295 * to see if the IDs match. 296 */ 297 hasTpgMatch = checkTPGList(tpgID, osn); 298 299 if (MP_TRUE != hasTpgMatch) { 300 301 child_node = 302 di_sibling_node(child_node); 303 304 continue; 305 } 306 307 if (haveList && 308 (numNodes < pOidList->oidCount)) { 309 310 pOidList->oids[numNodes]. 311 objectSequenceNumber = 312 osn; 313 314 pOidList->oids[numNodes].objectType = 315 MP_OBJECT_TYPE_MULTIPATH_LU; 316 317 pOidList->oids[numNodes].ownerId = 318 g_pluginOwnerID; 319 } 320 321 ++numNodes; 322 } 323 324 child_node = di_sibling_node(child_node); 325 } 326 } 327 328 log(LOG_INFO, "getOidList()", " - numNodes: %d", numNodes); 329 log(LOG_INFO, "getOidList()", " - exit"); 330 331 return (numNodes); 332 } 333 334 335 336 /* 337 * Called by the common layer to request a list of multipath logical units 338 * associated with a given target port group. 339 */ 340 341 MP_STATUS 342 MP_GetMPLuOidListFromTPG(MP_OID oid, MP_OID_LIST **ppList) 343 { 344 345 di_node_t root_node = DI_NODE_NIL; 346 347 int i = 0; 348 int numNodes = 0; 349 350 MP_STATUS mpStatus = MP_STATUS_SUCCESS; 351 352 MP_UINT32 sourceTpgID = 0; 353 354 MP_OID_LIST *pOidList = NULL; 355 MP_OID_LIST *tpList = NULL; 356 357 MP_TARGET_PORT_GROUP_PROPERTIES sourceTpgProps; 358 359 360 log(LOG_INFO, "MP_GetMPLuOidListFromTPG()", " - enter"); 361 362 log(LOG_INFO, "MP_GetMPLuOidListFromTPG()", 363 "oid.objectSequenceNumber = %llx", 364 oid.objectSequenceNumber); 365 366 mpStatus = getTargetPortGroupProperties(oid, &sourceTpgProps); 367 if (MP_STATUS_SUCCESS != mpStatus) { 368 369 log(LOG_INFO, "MP_GetMPLuOidListFromTPG()", 370 " - getTargetPortGroupProperties() failed: %d", 371 mpStatus); 372 373 return (mpStatus); 374 } 375 376 /* The TPG ID we will use as a serch key */ 377 sourceTpgID = sourceTpgProps.tpgID; 378 379 log(LOG_INFO, "MP_GetMPLuOidListFromTPG()", "sourceTpgID = %d", 380 sourceTpgID); 381 382 /* Get a list of target ports for the TPG */ 383 mpStatus = getTargetPortOidList(oid, &tpList); 384 if (MP_STATUS_SUCCESS != mpStatus) { 385 386 log(LOG_INFO, "getOidList()", 387 " - getTargetPortOidList() failed: %d", mpStatus); 388 389 return (mpStatus); 390 } 391 392 /* Take a snapshot */ 393 root_node = di_init("/", DINFOCACHE); 394 if (DI_NODE_NIL == root_node) { 395 log(LOG_INFO, "MP_GetMPLuOidListFromTPG()", 396 " - di_init() failed"); 397 398 free(tpList); 399 400 return (MP_STATUS_FAILED); 401 } 402 403 /* search for the number of multipath logical units that match */ 404 numNodes = getOidList(root_node, sourceTpgID, tpList, NULL); 405 406 if (numNodes < 0) { 407 408 log(LOG_INFO, "MP_GetMPLuOidListFromTPG()", 409 " - unable to get OID list."); 410 411 log(LOG_INFO, "MP_GetMPLuOidListFromTPG()", 412 " - error exit"); 413 414 free(tpList); 415 416 di_fini(root_node); 417 418 return (MP_STATUS_FAILED); 419 } 420 421 if (0 == numNodes) { 422 423 pOidList = createOidList(1); 424 if (NULL == pOidList) { 425 426 log(LOG_INFO, "MP_GetMPLuOidListFromTPG()", 427 " - unable to create OID list."); 428 429 free(tpList); 430 431 di_fini(root_node); 432 433 return (MP_STATUS_INSUFFICIENT_MEMORY); 434 } 435 436 pOidList->oids[0].objectType = MP_OBJECT_TYPE_MULTIPATH_LU; 437 pOidList->oids[0].ownerId = g_pluginOwnerID; 438 *ppList = pOidList; 439 440 log(LOG_INFO, "MP_GetMPLuOidListFromTPG()", 441 " - returning empty list."); 442 443 free(tpList); 444 445 return (MP_STATUS_SUCCESS); 446 } 447 448 *ppList = createOidList(numNodes); 449 if (NULL == *ppList) { 450 log(LOG_INFO, "MP_GetMPLuOidListFromTPG()", 451 "no memory for *ppList"); 452 log(LOG_INFO, "MP_GetMPLuOidListFromTPG()", 453 " - error exit"); 454 455 free(tpList); 456 457 return (MP_STATUS_INSUFFICIENT_MEMORY); 458 } 459 460 /* now populate the list */ 461 462 (*ppList)->oidCount = numNodes; 463 464 numNodes = getOidList(root_node, sourceTpgID, tpList, *ppList); 465 466 for (i = 0; i < (*ppList)->oidCount; i++) { 467 468 log(LOG_INFO, "MP_GetMPLuOidListFromTPG()", 469 "(*ppList)->oids[%d].objectType = %d", 470 i, (*ppList)->oids[i].objectType); 471 log(LOG_INFO, "MP_GetMPLuOidListFromTPG()", 472 "(*ppList)->oids[%d].ownerId = %d", 473 i, (*ppList)->oids[i].ownerId); 474 log(LOG_INFO, "MP_GetMPLuOidListFromTPG()", 475 "(*ppList)->oids[%d].objectSequenceNumber = %llx", 476 i, (*ppList)->oids[i].objectSequenceNumber); 477 } 478 479 free(tpList); 480 481 di_fini(root_node); 482 483 484 log(LOG_INFO, "MP_GetMPLuOidListFromTPG()", " - exit"); 485 486 return (MP_STATUS_SUCCESS); 487 } 488