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 */
40static 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
65static 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
154MP_STATUS
155MP_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