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  */
checkAvailablePath(di_node_t node)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 
getOidList(di_node_t root_node,MP_OID_LIST * pOidList)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
MP_GetMultipathLusPlugin(MP_OID_LIST ** ppList)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