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