xref: /illumos-gate/usr/src/lib/mpapi/libmpscsi_vhci/common/MP_GetMPLuOidListFromTPG.c (revision b210e77709da8e42dfe621e10ccf4be504206058)
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