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