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 <string.h>
27 #include <syslog.h>
28 #include <errno.h>
29 #include <unistd.h>
30 #include <stropts.h>
31 
32 #include <libdevinfo.h>
33 
34 #include "mp_utils.h"
35 
36 
37 typedef struct walk_devlink {
38 	char *path;
39 	size_t len;
40 	char **linkpp;
41 } walk_devlink_t;
42 
43 
44 
45 static int
46 get_devlink(di_devlink_t devlink, void *arg) {
47 
48 	walk_devlink_t *warg = (walk_devlink_t *)arg;
49 
50 
51 	log(LOG_INFO, "get_devlink()", " - enter");
52 
53 
54 	*(warg->linkpp) = strdup(di_devlink_path(devlink));
55 
56 
57 	log(LOG_INFO, "get_devlink()", " - exit");
58 
59 	return (DI_WALK_TERMINATE);
60 }
61 
62 
63 char
64 *getDeviceFileName(MP_UINT64 instanceNum)
65 {
66 	char *deviceFileName = NULL;
67 
68 	di_node_t root_node = DI_NODE_NIL;
69 	di_node_t cur_node  = DI_NODE_NIL;
70 
71 	MP_UINT64 nodeInstance = 0;
72 
73 	char *pathName  = NULL;
74 	char *minorName = "c,raw";
75 	char *devLink   = NULL;
76 
77 	char fullName[512];
78 
79 	walk_devlink_t warg;
80 	di_devlink_handle_t dlHandle = NULL;
81 
82 	int diStatus = 0;
83 
84 
85 	log(LOG_INFO, "getDeviceFileName()", " - enter");
86 
87 	log(LOG_INFO, "getDeviceFileName()",
88 		" - instanceNum: %llx",
89 		instanceNum);
90 
91 	root_node = di_init("/", DINFOCACHE);
92 	if (DI_NODE_NIL == root_node) {
93 		log(LOG_INFO, "MP_GetMultipathLusPlugin()",
94 			" - $ERROR, di_init() failed");
95 
96 		return (NULL);
97 	}
98 
99 
100 	cur_node = di_drv_first_node("scsi_vhci", root_node);
101 	if (DI_NODE_NIL == cur_node) {
102 		log(LOG_INFO, "getDeviceFileName()",
103 			" - $ERROR, di_drv_first_node() failed");
104 
105 		di_fini(root_node);
106 
107 		return (NULL);
108 	}
109 
110 
111 	cur_node = di_child_node(cur_node);
112 
113 	while (DI_NODE_NIL != cur_node) {
114 
115 		nodeInstance =
116 		(MP_UINT64)di_instance(cur_node);
117 
118 		if (nodeInstance == instanceNum) {
119 
120 			log(LOG_INFO, "getDeviceFileName()",
121 				" - found node.");
122 
123 			break;
124 		}
125 
126 		cur_node = di_sibling_node(cur_node);
127 	}
128 
129 	if (DI_NODE_NIL != cur_node) {
130 
131 		dlHandle = di_devlink_init(NULL, 0);
132 		if (NULL == dlHandle) {
133 		    log(LOG_INFO, "getDeviceFileName()",
134 			    " - $ERROR, di_devlink_init() failed.");
135 
136 		    di_fini(root_node);
137 
138 		    return (NULL);
139 		}
140 
141 		pathName = di_devfs_path(cur_node);
142 
143 		(void) snprintf(fullName, 511, "%s:%s", pathName, minorName);
144 
145 		log(LOG_INFO, "getDeviceFileName()",
146 			" - fullName: {%s]", fullName);
147 
148 		(void) memset(&warg, 0, sizeof (walk_devlink_t));
149 
150 		devLink  = NULL;
151 		warg.linkpp = &devLink;
152 
153 		diStatus = di_devlink_walk(dlHandle,
154 				NULL,
155 				fullName,
156 				DI_PRIMARY_LINK,
157 				(void *)&warg,
158 				get_devlink);
159 
160 		if (diStatus != 0) {
161 
162 			log(LOG_INFO, "getDeviceFileName()",
163 			    "diStatus: %d", diStatus);
164 
165 			if (diStatus < 0) {
166 				diStatus = errno;
167 			}
168 
169 			log(LOG_INFO, "getDeviceFileName()",
170 			    "diStatus: %d", diStatus);
171 
172 			log(LOG_INFO, "getDeviceFileName()",
173 			    "strerror(diStatus): %s", strerror(diStatus));
174 		}
175 
176 		if (NULL != devLink) {
177 
178 			deviceFileName =
179 				(char *)calloc(1, strlen(devLink) + 1);
180 
181 			(void) strncpy(deviceFileName, devLink,
182 			    strlen(devLink));
183 
184 		} else {
185 
186 			log(LOG_INFO, "getDeviceFileName()",
187 				" - $ERROR, devLink is NULL.");
188 
189 			deviceFileName =
190 				(char *)calloc(1, 256);
191 
192 			(void) strncpy(deviceFileName, pathName, 255);
193 		}
194 
195 		di_devfs_path_free(pathName);
196 
197 		(void) di_devlink_fini(&dlHandle);
198 
199 	}
200 
201 
202 	di_fini(root_node);
203 
204 
205 	log(LOG_INFO, "getDeviceFileName()", " - exit");
206 
207 	return (deviceFileName);
208 }
209 
210 
211 
212 MP_STATUS
213 MP_GetMPLogicalUnitProperties(MP_OID oid,
214 				MP_MULTIPATH_LOGICAL_UNIT_PROPERTIES *pProps)
215 {
216 	mp_iocdata_t		mp_ioctl;
217 	mp_logical_unit_prop_t	luInfo;
218 
219 	MP_OID overridePathOID;
220 
221 	int ioctlStatus = 0;
222 
223 	int vendorLength   = 0;
224 	int productLength  = 0;
225 	int revisionLength = 0;
226 
227 	char *deviceFileName = NULL;
228 
229 
230 	MP_STATUS mpStatus = MP_STATUS_SUCCESS;
231 
232 
233 	log(LOG_INFO, "MP_GetMPLogicalUnitProperties()", " - enter");
234 
235 
236 	log(LOG_INFO, "MP_GetMPLogicalUnitProperties()",
237 		"oid.objectSequenceNumber = %llx",
238 		oid.objectSequenceNumber);
239 
240 	if (g_scsi_vhci_fd < 0) {
241 		log(LOG_INFO, "MP_GetMPLogicalUnitProperties()",
242 			"invalid driver file handle");
243 		log(LOG_INFO, "MP_GetMPLogicalUnitProperties()",
244 			" - error exit");
245 		return (MP_STATUS_FAILED);
246 	}
247 
248 	(void) memset(&mp_ioctl, 0, sizeof (mp_iocdata_t));
249 	(void) memset(&luInfo,   0, sizeof (mp_logical_unit_prop_t));
250 
251 	mp_ioctl.mp_cmd  = MP_GET_LU_PROP;
252 	mp_ioctl.mp_ibuf = (caddr_t)&oid.objectSequenceNumber;
253 	mp_ioctl.mp_ilen = sizeof (oid.objectSequenceNumber);
254 	mp_ioctl.mp_obuf = (caddr_t)&luInfo;
255 	mp_ioctl.mp_olen = sizeof (mp_logical_unit_prop_t);
256 	mp_ioctl.mp_xfer = MP_XFER_READ;
257 
258 	ioctlStatus = ioctl(g_scsi_vhci_fd, MP_CMD, &mp_ioctl);
259 
260 	log(LOG_INFO, "MP_GetMPLogicalUnitProperties()",
261 		" IOCTL call returned: %d", ioctlStatus);
262 
263 	if (ioctlStatus < 0) {
264 		ioctlStatus = errno;
265 	}
266 
267 	if (ioctlStatus != 0) {
268 		log(LOG_INFO, "MP_GetMPLogicalUnitProperties()",
269 			"IOCTL call failed.  IOCTL error is: %d",
270 			ioctlStatus);
271 		log(LOG_INFO, "MP_GetMPLogicalUnitProperties()",
272 			"IOCTL call failed.  IOCTL error is: %s",
273 			strerror(ioctlStatus));
274 		log(LOG_INFO, "MP_GetMPLogicalUnitProperties()",
275 			"IOCTL call failed.  mp_ioctl.mp_errno: %x",
276 			mp_ioctl.mp_errno);
277 
278 		if (ENOTSUP == ioctlStatus) {
279 			mpStatus = MP_STATUS_UNSUPPORTED;
280 		} else if (0 == mp_ioctl.mp_errno) {
281 			mpStatus = MP_STATUS_FAILED;
282 		} else {
283 			mpStatus = getStatus4ErrorCode(mp_ioctl.mp_errno);
284 		}
285 
286 		log(LOG_INFO, "MP_GetMPLogicalUnitProperties()",
287 			" - error exit");
288 
289 		return (mpStatus);
290 	}
291 
292 	(void) memset(pProps, 0, sizeof (MP_MULTIPATH_LOGICAL_UNIT_PROPERTIES));
293 
294 	pProps->asymmetric = luInfo.asymmetric;
295 	pProps->autoFailbackEnabled = luInfo.autoFailbackEnabled;
296 	pProps->autoProbingEnabled = luInfo.autoProbingEnabled;
297 	pProps->currentFailbackPollingRate = luInfo.currentFailBackPollingRate;
298 	pProps->currentLoadBalanceType = luInfo.currentLoadBalanceType;
299 	pProps->currentProbingPollingRate = luInfo.currentProbingPollingRate;
300 
301 
302 	deviceFileName = getDeviceFileName(oid.objectSequenceNumber);
303 
304 	if (NULL != deviceFileName) {
305 
306 		log(LOG_INFO, "MP_GetMPLogicalUnitProperties()",
307 			"deviceFileName: %s",
308 			deviceFileName);
309 
310 		(void) strncpy(pProps->deviceFileName,
311 				deviceFileName,
312 				sizeof (pProps->deviceFileName) - 1);
313 
314 		free(deviceFileName);
315 	}
316 
317 	pProps->failbackPollingRateMax = luInfo.failbackPollingRateMax;
318 	pProps->logicalUnitGroupID = luInfo.luGroupID;
319 
320 	(void) strncpy(pProps->name, luInfo.name, sizeof (pProps->name) - 1);
321 
322 	pProps->nameType = luInfo.nameType;
323 
324 	overridePathOID.objectSequenceNumber = luInfo.overridePathID;
325 	overridePathOID.objectType = MP_OBJECT_TYPE_PATH_LU;
326 	overridePathOID.ownerId = g_pluginOwnerID;
327 	(void) memcpy(&pProps->overridePath, &overridePathOID, sizeof (MP_OID));
328 
329 	pProps->probingPollingRateMax = luInfo.probingPollingRateMax;
330 
331 
332 	vendorLength   = sizeof (pProps->vendor);
333 	productLength  = sizeof (pProps->product);
334 	revisionLength = sizeof (pProps->revision);
335 
336 	(void) strncpy(pProps->vendor,
337 			luInfo.prodInfo.vendor,
338 			vendorLength);
339 
340 	(void) strncpy(pProps->product,
341 			luInfo.prodInfo.product,
342 			productLength);
343 
344 	(void) strncpy(pProps->revision,
345 			luInfo.prodInfo.revision,
346 			revisionLength);
347 
348 	log(LOG_INFO, "MP_GetMPLogicalUnitProperties()", " - exit");
349 
350 	return (MP_STATUS_SUCCESS);
351 }
352