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