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
checkTPGList(MP_UINT32 tpgID,MP_UINT64 objectSequenceNumber)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
getOidList(di_node_t root_node,int tpgID,MP_OID_LIST * tpList,MP_OID_LIST * pOidList)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
MP_GetMPLuOidListFromTPG(MP_OID oid,MP_OID_LIST ** ppList)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