xref: /titanic_44/usr/src/lib/libsun_ima/common/ima.c (revision 2ec7cc7fc084163eaed884efee9bbd322cc8951b)
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 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <arpa/inet.h>
27 #include <sys/socket.h>
28 #include <sys/types.h>
29 #include <stdarg.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <strings.h>
33 #include <unistd.h>
34 #include <syslog.h>
35 #include <errno.h>
36 #include <wchar.h>
37 #include <widec.h>
38 #include <libsysevent.h>
39 #include <sys/nvpair.h>
40 #include <fcntl.h>
41 #include <stdio.h>
42 #include <time.h>
43 #include <libdevinfo.h>
44 #include <sys/scsi/adapters/iscsi_if.h>
45 #include <sys/iscsi_protocol.h>
46 #include <ima.h>
47 #include <libsun_ima.h>
48 
49 #define	LIBRARY_PROPERTY_IMPLEMENTATION_VERSION	L"1.0.0"
50 #define	LIBRARY_PROPERTY_VENDOR			L"Sun Microsystems, Inc."
51 #define	OS_DEVICE_NAME 				"/devices/iscsi"
52 #define	LIBRARY_FILE_NAME			L"libsun_ima.so"
53 
54 #define	OS_DEVICE_NAME_LEN		256
55 #define	INQUIRY_CMD			0x12
56 #define	GETCAPACITY_CMD  		0x25
57 #define	INQUIRY_CMDLEN			6
58 #define	INQUIRY_REPLY_LEN		96
59 #define	USCSI_TIMEOUT_IN_SEC		10
60 #define	MAX_AUTHMETHODS			10
61 #define	NUM_SUPPORTED_AUTH_METHODS	2
62 #define	SUN_IMA_MAX_DIGEST_ALGORITHMS	2	/* NONE and CRC 32 */
63 #define	SUN_IMA_IP_ADDRESS_LEN		256
64 #define	SUN_IMA_IP_PORT_LEN		64
65 #define	SUN_IMA_MAX_RADIUS_SECRET_LEN	128
66 #define	MAX_LONG_LONG_STRING_LEN	10
67 
68 /* Forward declaration */
69 #define	BOOL_PARAM			1
70 #define	MIN_MAX_PARAM			2
71 
72 /* OK */
73 #define	DISC_ADDR_OK			0
74 /* Incorrect IP address */
75 #define	DISC_ADDR_INTEGRITY_ERROR   	1
76 /* Error converting text IP address to numeric binary form */
77 #define	DISC_ADDR_IP_CONV_ERROR		2
78 
79 /* Currently not defined in  IMA_TARGET_DISCOVERY_METHOD enum */
80 #define	IMA_TARGET_DISCOVERY_METHOD_UNKNOWN  0
81 
82 static IMA_OID		lhbaObjectId;
83 static IMA_UINT32	pluginOwnerId;
84 static sysevent_handle_t *shp;
85 
86 
87 
88 /*
89  * Custom struct to allow tgpt to be specified.
90  */
91 typedef struct _SUN_IMA_DISC_ADDRESS_KEY
92 {
93 	IMA_NODE_NAME name;
94 	IMA_ADDRESS_KEY	address;
95 	IMA_UINT16 tpgt;
96 } SUN_IMA_DISC_ADDRESS_KEY;
97 
98 /*
99  * Custom struct to allow tgpt to be specified.
100  */
101 typedef struct _SUN_IMA_DISC_ADDRESS_KEY_PROPERTIES
102 {
103 	IMA_UINT keyCount;
104 	SUN_IMA_DISC_ADDRESS_KEY keys[1];
105 } SUN_IMA_DISC_ADDRESS_KEY_PROPERTIES;
106 
107 /*
108  * Custom struct to allow tgpt to be specified.
109  */
110 typedef struct _SUN_IMA_DISC_ADDR_PROP_LIST
111 {
112 	IMA_UINT discAddrCount;
113 	IMA_DISCOVERY_ADDRESS_PROPERTIES props[1];
114 } SUN_IMA_DISC_ADDR_PROP_LIST;
115 
116 
117 static IMA_OBJECT_VISIBILITY_FN pObjectVisibilityCallback = NULL;
118 static IMA_OBJECT_PROPERTY_FN pObjectPropertyCallback = NULL;
119 
120 static IMA_STATUS getISCSINodeParameter(int paramType, IMA_OID *oid,
121     void *pProps, uint32_t paramIndex);
122 static IMA_STATUS setISCSINodeParameter(int paramType, IMA_OID *oid,
123     void *pProps, uint32_t paramIndex);
124 static IMA_STATUS setAuthMethods(IMA_OID oid, IMA_UINT *pMethodCount,
125     const IMA_AUTHMETHOD *pMethodList);
126 static IMA_STATUS getAuthMethods(IMA_OID oid, IMA_UINT *pMethodCount,
127     IMA_AUTHMETHOD *pMethodList);
128 
129 static int prepare_discovery_entry(IMA_TARGET_ADDRESS discoveryAddress,
130     entry_t *entry);
131 static IMA_STATUS configure_discovery_method(IMA_BOOL enable,
132     iSCSIDiscoveryMethod_t method);
133 static IMA_STATUS get_target_oid_list(uint32_t targetListType,
134     IMA_OID_LIST **ppList);
135 static IMA_STATUS get_target_lun_oid_list(IMA_OID * targetOid,
136 		iscsi_lun_list_t  **ppLunList);
137 static int get_lun_devlink(di_devlink_t link, void *osDeviceName);
138 static IMA_STATUS getDiscoveryAddressPropertiesList(
139 	SUN_IMA_DISC_ADDR_PROP_LIST **ppList
140 );
141 static IMA_STATUS sendTargets(IMA_TARGET_ADDRESS address,
142     SUN_IMA_DISC_ADDRESS_KEY_PROPERTIES **ppList
143 );
144 
145 static IMA_STATUS getSupportedAuthMethods(IMA_OID lhbaOid,
146     IMA_BOOL getSettableMethods, IMA_UINT *pMethodCount,
147     IMA_AUTHMETHOD *pMethodList);
148 static IMA_STATUS getLuProperties(IMA_OID luId, IMA_LU_PROPERTIES *pProps);
149 static IMA_STATUS getTargetProperties(IMA_OID targetId,
150     IMA_TARGET_PROPERTIES *pProps);
151 
152 void InitLibrary();
153 
154 static void libSwprintf(wchar_t *wcs, const wchar_t *lpszFormat, ...)
155 {
156 	va_list args;
157 	va_start(args, lpszFormat);
158 	(void) vswprintf(wcs, OS_DEVICE_NAME_LEN - 1, lpszFormat, args);
159 	va_end(args);
160 }
161 
162 static void
163 sysevent_handler(sysevent_t *ev)
164 {
165 	IMA_OID tmpOid;
166 	IMA_BOOL becomingVisible = IMA_FALSE;
167 	IMA_UINT i;
168 
169 	const char *visibility_subclasses[] = {
170 		ESC_ISCSI_STATIC_START,
171 		ESC_ISCSI_STATIC_END,
172 		ESC_ISCSI_SEND_TARGETS_START,
173 		ESC_ISCSI_SEND_TARGETS_END,
174 		ESC_ISCSI_SLP_START,
175 		ESC_ISCSI_SLP_END,
176 		ESC_ISCSI_ISNS_START,
177 		ESC_ISCSI_ISNS_END,
178 		NULL
179 	};
180 
181 	tmpOid.ownerId = pluginOwnerId;
182 	tmpOid.objectType = IMA_OBJECT_TYPE_TARGET;
183 	tmpOid.objectSequenceNumber = 0;
184 
185 	/* Make sure our event class matches what we are looking for */
186 	if (strncmp(EC_ISCSI, sysevent_get_class_name(ev),
187 	    strlen(EC_ISCSI)) != 0) {
188 		return;
189 	}
190 
191 
192 	/* Check for object property changes */
193 	if ((strncmp(ESC_ISCSI_PROP_CHANGE,
194 	    sysevent_get_subclass_name(ev),
195 	    strlen(ESC_ISCSI_PROP_CHANGE)) == 0)) {
196 		if (pObjectPropertyCallback != NULL)
197 			pObjectPropertyCallback(tmpOid);
198 	} else {
199 		i = 0;
200 		while (visibility_subclasses[i] != NULL) {
201 			if ((strncmp(visibility_subclasses[i],
202 			    sysevent_get_subclass_name(ev),
203 			    strlen(visibility_subclasses[i])) == 0) &&
204 			    pObjectVisibilityCallback != NULL) {
205 				becomingVisible = IMA_TRUE;
206 				pObjectVisibilityCallback(becomingVisible,
207 				    tmpOid);
208 			}
209 			i++;
210 		}
211 	}
212 }
213 
214 IMA_STATUS init_sysevents() {
215 	const char *subclass_list[] = {
216 		ESC_ISCSI_STATIC_START,
217 		ESC_ISCSI_STATIC_END,
218 		ESC_ISCSI_SEND_TARGETS_START,
219 		ESC_ISCSI_SEND_TARGETS_END,
220 		ESC_ISCSI_SLP_START,
221 		ESC_ISCSI_SLP_END,
222 		ESC_ISCSI_ISNS_START,
223 		ESC_ISCSI_ISNS_END,
224 		ESC_ISCSI_PROP_CHANGE,
225 	};
226 
227 	/* Bind event handler and create subscriber handle */
228 	shp = sysevent_bind_handle(sysevent_handler);
229 	if (shp == NULL) {
230 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
231 	}
232 
233 	if (sysevent_subscribe_event(shp, EC_ISCSI, subclass_list, 9) != 0) {
234 		sysevent_unbind_handle(shp);
235 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
236 	}
237 	return (IMA_STATUS_SUCCESS);
238 }
239 
240 IMA_STATUS Initialize(IMA_UINT32 pluginOid) {
241 	pluginOwnerId = pluginOid;
242 	return (init_sysevents());
243 }
244 
245 void Terminate() {
246 	if (shp != NULL) {
247 		sysevent_unsubscribe_event(shp, EC_ISCSI);
248 	}
249 
250 }
251 
252 void InitLibrary() {
253 }
254 
255 static void GetBuildTime(IMA_DATETIME* pdatetime)
256 {
257 	(void) memset(pdatetime, 0, sizeof (IMA_DATETIME));
258 }
259 
260 /*ARGSUSED*/
261 IMA_API IMA_STATUS IMA_GetNodeProperties(
262 	IMA_OID nodeOid,
263 	IMA_NODE_PROPERTIES *pProps
264 )
265 {
266 	int fd;
267 	iscsi_param_get_t pg;
268 
269 	pProps->runningInInitiatorMode = IMA_TRUE;
270 	pProps->runningInTargetMode = IMA_FALSE;
271 	pProps->nameAndAliasSettable = IMA_FALSE;
272 
273 	if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
274 		syslog(LOG_USER|LOG_DEBUG, "Cannot open %s (%d)",
275 		    ISCSI_DRIVER_DEVCTL, errno);
276 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
277 	}
278 
279 	(void) memset(&pg, 0, sizeof (iscsi_param_get_t));
280 	pg.g_vers = ISCSI_INTERFACE_VERSION;
281 	pg.g_param = ISCSI_LOGIN_PARAM_INITIATOR_NAME;
282 
283 	if (ioctl(fd, ISCSI_PARAM_GET, &pg) == -1) {
284 		pProps->nameValid = IMA_FALSE;
285 	} else {
286 		if (strlen((char *)pg.g_value.v_name) > 0) {
287 			(void) mbstowcs(pProps->name,
288 			    (char *)pg.g_value.v_name,
289 			    IMA_NODE_NAME_LEN);
290 			pProps->nameValid = IMA_TRUE;
291 		} else {
292 			pProps->nameValid = IMA_FALSE;
293 		}
294 	}
295 
296 	(void) memset(&pg, 0, sizeof (iscsi_param_get_t));
297 	pg.g_vers = ISCSI_INTERFACE_VERSION;
298 	pg.g_param = ISCSI_LOGIN_PARAM_INITIATOR_ALIAS;
299 	(void) memset(pProps->alias, 0,
300 	    sizeof (IMA_WCHAR) * IMA_NODE_ALIAS_LEN);
301 	if (ioctl(fd, ISCSI_PARAM_GET, &pg) == -1) {
302 		pProps->aliasValid = IMA_FALSE;
303 	} else {
304 		if (strlen((char *)pg.g_value.v_name) > 0) {
305 			(void) mbstowcs(pProps->alias,
306 			    (char *)pg.g_value.v_name,
307 			    IMA_NODE_ALIAS_LEN);
308 			pProps->aliasValid = IMA_TRUE;
309 		}
310 	}
311 
312 	(void) close(fd);
313 	return (IMA_STATUS_SUCCESS);
314 }
315 
316 IMA_API IMA_STATUS IMA_SetNodeName(
317 	IMA_OID nodeOid,
318 	const IMA_NODE_NAME newName
319 )
320 {
321 	int fd;
322 	iscsi_param_set_t ps;
323 
324 	if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
325 		syslog(LOG_USER|LOG_DEBUG, "Cannot open %s (%d)",
326 		    ISCSI_DRIVER_DEVCTL, errno);
327 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
328 	}
329 
330 	(void) memset(&ps, 0, sizeof (iscsi_param_set_t));
331 	ps.s_oid = nodeOid.objectSequenceNumber;
332 	ps.s_vers = ISCSI_INTERFACE_VERSION;
333 	ps.s_param = ISCSI_LOGIN_PARAM_INITIATOR_NAME;
334 	(void) wcstombs((char *)ps.s_value.v_name, newName, ISCSI_MAX_NAME_LEN);
335 	if (ioctl(fd, ISCSI_INIT_NODE_NAME_SET, &ps)) {
336 		syslog(LOG_USER|LOG_DEBUG,
337 		    "ISCSI_PARAM_SET ioctl failed, errno: %d", errno);
338 		(void) close(fd);
339 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
340 	}
341 
342 	(void) close(fd);
343 	return (IMA_STATUS_SUCCESS);
344 }
345 
346 IMA_API IMA_STATUS IMA_SetNodeAlias(
347 	IMA_OID nodeOid,
348 	const IMA_NODE_ALIAS newAlias
349 )
350 {
351 	int fd;
352 	iscsi_param_set_t ps;
353 
354 	if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
355 		syslog(LOG_USER|LOG_DEBUG, "Cannot open %s (%d)",
356 		    ISCSI_DRIVER_DEVCTL, errno);
357 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
358 	}
359 
360 	(void) memset(&ps, 0, sizeof (iscsi_param_set_t));
361 	ps.s_oid = nodeOid.objectSequenceNumber;
362 	ps.s_vers = ISCSI_INTERFACE_VERSION;
363 	ps.s_param = ISCSI_LOGIN_PARAM_INITIATOR_ALIAS;
364 
365 	/* newAlias = NULL specifies that the alias should be deleted. */
366 	if (newAlias != NULL)
367 		(void) wcstombs((char *)ps.s_value.v_name, newAlias,
368 		    ISCSI_MAX_NAME_LEN);
369 	else
370 		(void) wcstombs((char *)ps.s_value.v_name,
371 		    L"", ISCSI_MAX_NAME_LEN);
372 
373 	if (ioctl(fd, ISCSI_PARAM_SET, &ps)) {
374 		syslog(LOG_USER|LOG_DEBUG,
375 		    "ISCSI_PARAM_SET ioctl failed, errno: %d", errno);
376 		(void) close(fd);
377 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
378 	}
379 
380 	(void) close(fd);
381 	return (IMA_STATUS_SUCCESS);
382 }
383 
384 
385 IMA_API IMA_STATUS IMA_GetLhbaOidList(
386 	IMA_OID_LIST **ppList
387 )
388 {
389 	/* Always return the same object ID for the lhba */
390 	lhbaObjectId.objectType = IMA_OBJECT_TYPE_LHBA;
391 	lhbaObjectId.ownerId = pluginOwnerId;
392 	lhbaObjectId.objectSequenceNumber = ISCSI_INITIATOR_OID;
393 
394 	*ppList = (IMA_OID_LIST*)calloc(1, sizeof (IMA_OID_LIST));
395 	if (*ppList == NULL) {
396 		return (IMA_ERROR_INSUFFICIENT_MEMORY);
397 	}
398 
399 	(*ppList)->oidCount = 1;
400 	(void) memcpy(&(*ppList)->oids[0],
401 	    &lhbaObjectId, sizeof (lhbaObjectId));
402 	return (IMA_STATUS_SUCCESS);
403 }
404 
405 
406 /*
407  * Get the discovery properties of the LHBA
408  */
409 /*ARGSUSED*/
410 IMA_API IMA_STATUS IMA_GetDiscoveryProperties(
411 	IMA_OID oid,
412 	IMA_DISCOVERY_PROPERTIES *pProps
413 )
414 {
415 	int fd;
416 	iSCSIDiscoveryProperties_t discoveryProps;
417 
418 	if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
419 		syslog(LOG_USER|LOG_DEBUG, "Cannot open %s (%d)",
420 		    ISCSI_DRIVER_DEVCTL, errno);
421 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
422 	}
423 
424 	(void) memset(&discoveryProps, 0, sizeof (discoveryProps));
425 	discoveryProps.vers = ISCSI_INTERFACE_VERSION;
426 
427 	if (ioctl(fd, ISCSI_DISCOVERY_PROPS, &discoveryProps) != 0) {
428 		syslog(LOG_USER|LOG_DEBUG,
429 		    "ISCSI_DISCOVERY_PROPS ioctl failed, errno: %d", errno);
430 		(void) close(fd);
431 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
432 	}
433 
434 	pProps->iSnsDiscoverySettable = discoveryProps.iSNSDiscoverySettable;
435 	pProps->iSnsDiscoveryEnabled = discoveryProps.iSNSDiscoveryEnabled;
436 	/*
437 	 * Set the iSNS discovery method - The IMA specification indicates
438 	 * this field is valid only if iSNS discovery is enabled.
439 	 */
440 	if (pProps->iSnsDiscoveryEnabled == IMA_TRUE) {
441 		switch (discoveryProps.iSNSDiscoveryMethod) {
442 			case iSNSDiscoveryMethodStatic:
443 				pProps->iSnsDiscoveryMethod =
444 				    IMA_ISNS_DISCOVERY_METHOD_STATIC;
445 				break;
446 			case iSNSDiscoveryMethodDHCP:
447 				pProps->iSnsDiscoveryMethod =
448 				    IMA_ISNS_DISCOVERY_METHOD_DHCP;
449 				break;
450 			case iSNSDiscoveryMethodSLP:
451 				pProps->iSnsDiscoveryMethod =
452 				    IMA_ISNS_DISCOVERY_METHOD_SLP;
453 				break;
454 			default:
455 				(void) close(fd);
456 				return (IMA_ERROR_UNEXPECTED_OS_ERROR);
457 		}
458 	}
459 	(void) memcpy(pProps->iSnsHost.id.hostname,
460 	    discoveryProps.iSNSDomainName,
461 	    sizeof (pProps->iSnsHost.id.hostname));
462 	pProps->slpDiscoverySettable = discoveryProps.SLPDiscoverySettable;
463 	pProps->slpDiscoveryEnabled = discoveryProps.SLPDiscoveryEnabled;
464 	pProps->staticDiscoverySettable =
465 	    discoveryProps.StaticDiscoverySettable;
466 	pProps->staticDiscoveryEnabled = discoveryProps.StaticDiscoveryEnabled;
467 	pProps->sendTargetsDiscoverySettable =
468 	    discoveryProps.SendTargetsDiscoverySettable;
469 	pProps->sendTargetsDiscoveryEnabled =
470 	    discoveryProps.SendTargetsDiscoveryEnabled;
471 
472 	(void) close(fd);
473 	return (IMA_STATUS_SUCCESS);
474 }
475 
476 IMA_API IMA_STATUS IMA_FreeMemory(
477 	void *pMemory
478 )
479 {
480 	if (pMemory != NULL)
481 		free(pMemory);
482 	return (IMA_STATUS_SUCCESS);
483 }
484 
485 IMA_API IMA_STATUS IMA_GetNonSharedNodeOidList(
486 		IMA_OID_LIST **ppList
487 )
488 {
489 	if (ppList == NULL)
490 		return (IMA_ERROR_INVALID_PARAMETER);
491 
492 	*ppList = (IMA_OID_LIST*) calloc(1, sizeof (IMA_OID_LIST));
493 	if (*ppList == NULL) {
494 		return (IMA_ERROR_INSUFFICIENT_MEMORY);
495 	}
496 	(*ppList)->oidCount = 0;
497 
498 	return (IMA_STATUS_SUCCESS);
499 }
500 
501 IMA_API IMA_STATUS IMA_GetFirstBurstLengthProperties(
502 		IMA_OID Oid,
503 		IMA_MIN_MAX_VALUE *pProps
504 )
505 {
506 	return (getISCSINodeParameter(MIN_MAX_PARAM, &Oid, pProps,
507 	    ISCSI_LOGIN_PARAM_FIRST_BURST_LENGTH));
508 }
509 
510 IMA_API IMA_STATUS IMA_GetMaxBurstLengthProperties(
511 		IMA_OID Oid,
512 		IMA_MIN_MAX_VALUE *pProps
513 )
514 {
515 	return (getISCSINodeParameter(MIN_MAX_PARAM, &Oid, pProps,
516 	    ISCSI_LOGIN_PARAM_MAX_BURST_LENGTH));
517 }
518 
519 IMA_API IMA_STATUS IMA_GetMaxRecvDataSegmentLengthProperties(
520 		IMA_OID Oid,
521 		IMA_MIN_MAX_VALUE *pProps
522 )
523 {
524 	return (getISCSINodeParameter(MIN_MAX_PARAM, &Oid, pProps,
525 	    ISCSI_LOGIN_PARAM_MAX_RECV_DATA_SEGMENT_LENGTH));
526 }
527 
528 /*ARGSUSED*/
529 IMA_API IMA_STATUS IMA_PluginIOCtl(
530 		IMA_OID pluginOid,
531 		IMA_UINT command,
532 		const void *pInputBuffer,
533 		IMA_UINT inputBufferLength,
534 		void *pOutputBuffer,
535 		IMA_UINT *pOutputBufferLength
536 )
537 {
538 	return (IMA_ERROR_NOT_SUPPORTED);
539 }
540 
541 IMA_API	IMA_STATUS IMA_SetFirstBurstLength(
542 		IMA_OID lhbaId,
543 		IMA_UINT firstBurstLength
544 )
545 {
546 	IMA_MIN_MAX_VALUE mv;
547 
548 	mv.currentValue = firstBurstLength;
549 	return (setISCSINodeParameter(MIN_MAX_PARAM, &lhbaId, &mv,
550 	    ISCSI_LOGIN_PARAM_FIRST_BURST_LENGTH));
551 }
552 
553 IMA_API	IMA_STATUS IMA_SetMaxBurstLength(
554 		IMA_OID lhbaId,
555 		IMA_UINT maxBurstLength
556 )
557 {
558 	IMA_MIN_MAX_VALUE mv;
559 
560 	mv.currentValue = maxBurstLength;
561 	return (setISCSINodeParameter(MIN_MAX_PARAM, &lhbaId, &mv,
562 	    ISCSI_LOGIN_PARAM_MAX_BURST_LENGTH));
563 }
564 
565 IMA_API	IMA_STATUS IMA_SetMaxRecvDataSegmentLength(
566 		IMA_OID lhbaId,
567 		IMA_UINT maxRecvDataSegmentLength
568 )
569 {
570 	IMA_MIN_MAX_VALUE mv;
571 
572 	mv.currentValue = maxRecvDataSegmentLength;
573 	return (setISCSINodeParameter(MIN_MAX_PARAM, &lhbaId, &mv,
574 	    ISCSI_LOGIN_PARAM_MAX_RECV_DATA_SEGMENT_LENGTH));
575 }
576 
577 IMA_API	IMA_STATUS IMA_GetMaxConnectionsProperties(
578 		IMA_OID Oid,
579 		IMA_MIN_MAX_VALUE *pProps
580 )
581 {
582 	return (getISCSINodeParameter(MIN_MAX_PARAM, &Oid, pProps,
583 	    ISCSI_LOGIN_PARAM_MAX_CONNECTIONS));
584 }
585 
586 IMA_API	IMA_STATUS IMA_SetMaxConnections(
587 		IMA_OID lhbaId,
588 		IMA_UINT maxConnections
589 )
590 {
591 	IMA_MIN_MAX_VALUE mv;
592 
593 	mv.currentValue = maxConnections;
594 	return (setISCSINodeParameter(MIN_MAX_PARAM, &lhbaId, &mv,
595 	    ISCSI_LOGIN_PARAM_MAX_CONNECTIONS));
596 }
597 
598 IMA_API	IMA_STATUS IMA_GetDefaultTime2RetainProperties(
599 		IMA_OID lhbaId,
600 		IMA_MIN_MAX_VALUE *pProps
601 )
602 {
603 	return (getISCSINodeParameter(MIN_MAX_PARAM, &lhbaId, pProps,
604 	    ISCSI_LOGIN_PARAM_DEFAULT_TIME_2_RETAIN));
605 }
606 
607 IMA_API	IMA_STATUS IMA_SetDefaultTime2Retain(
608 		IMA_OID lhbaId,
609 		IMA_UINT defaultTime2Retain
610 )
611 {
612 	IMA_MIN_MAX_VALUE mv;
613 
614 	mv.currentValue = defaultTime2Retain;
615 	return (setISCSINodeParameter(MIN_MAX_PARAM, &lhbaId, &mv,
616 	    ISCSI_LOGIN_PARAM_DEFAULT_TIME_2_RETAIN));
617 }
618 
619 IMA_API	IMA_STATUS IMA_GetDefaultTime2WaitProperties(
620 		IMA_OID lhbaId,
621 		IMA_MIN_MAX_VALUE *pProps
622 )
623 {
624 	return (getISCSINodeParameter(MIN_MAX_PARAM, &lhbaId, pProps,
625 	    ISCSI_LOGIN_PARAM_DEFAULT_TIME_2_WAIT));
626 }
627 
628 IMA_API	IMA_STATUS IMA_SetDefaultTime2Wait(
629 		IMA_OID lhbaId,
630 		IMA_UINT defaultTime2Wait
631 )
632 {
633 	IMA_MIN_MAX_VALUE mv;
634 
635 	mv.currentValue = defaultTime2Wait;
636 	return (setISCSINodeParameter(MIN_MAX_PARAM, &lhbaId, &mv,
637 	    ISCSI_LOGIN_PARAM_DEFAULT_TIME_2_WAIT));
638 }
639 
640 IMA_API	IMA_STATUS IMA_GetMaxOutstandingR2TProperties(
641 		IMA_OID Oid,
642 		IMA_MIN_MAX_VALUE *pProps
643 )
644 {
645 	return (getISCSINodeParameter(MIN_MAX_PARAM, &Oid, pProps,
646 	    ISCSI_LOGIN_PARAM_OUTSTANDING_R2T));
647 }
648 
649 IMA_API	IMA_STATUS IMA_SetMaxOutstandingR2T(
650 		IMA_OID lhbaId,
651 		IMA_UINT maxOutstandingR2T
652 )
653 {
654 	IMA_MIN_MAX_VALUE mv;
655 
656 	mv.currentValue = maxOutstandingR2T;
657 	return (setISCSINodeParameter(MIN_MAX_PARAM, &lhbaId, &mv,
658 	    ISCSI_LOGIN_PARAM_OUTSTANDING_R2T));
659 }
660 
661 
662 IMA_API	IMA_STATUS IMA_GetErrorRecoveryLevelProperties(
663 		IMA_OID Oid,
664 		IMA_MIN_MAX_VALUE *pProps
665 )
666 {
667 	return (getISCSINodeParameter(MIN_MAX_PARAM, &Oid, pProps,
668 	    ISCSI_LOGIN_PARAM_ERROR_RECOVERY_LEVEL));
669 }
670 
671 IMA_API	IMA_STATUS IMA_SetErrorRecoveryLevel(
672 		IMA_OID Oid,
673 		IMA_UINT errorRecoveryLevel
674 )
675 {
676 	IMA_MIN_MAX_VALUE mv;
677 
678 	mv.currentValue = errorRecoveryLevel;
679 	return (setISCSINodeParameter(MIN_MAX_PARAM, &Oid, &mv,
680 	    ISCSI_LOGIN_PARAM_ERROR_RECOVERY_LEVEL));
681 }
682 
683 IMA_API	IMA_STATUS IMA_GetInitialR2TProperties(
684 		IMA_OID Oid,
685 		IMA_BOOL_VALUE *pProps
686 )
687 {
688 	return (getISCSINodeParameter(BOOL_PARAM, &Oid, pProps,
689 	    ISCSI_LOGIN_PARAM_INITIAL_R2T));
690 }
691 
692 IMA_API	IMA_STATUS IMA_SetInitialR2T(
693 		IMA_OID Oid,
694 		IMA_BOOL initialR2T
695 )
696 {
697 	IMA_BOOL_VALUE bv;
698 
699 	bv.currentValue = initialR2T;
700 	return (setISCSINodeParameter(BOOL_PARAM, &Oid, &bv,
701 	    ISCSI_LOGIN_PARAM_INITIAL_R2T));
702 }
703 
704 
705 IMA_API	IMA_STATUS IMA_GetImmediateDataProperties(
706 		IMA_OID Oid,
707 		IMA_BOOL_VALUE *pProps
708 )
709 {
710 	return (getISCSINodeParameter(BOOL_PARAM, &Oid, pProps,
711 	    ISCSI_LOGIN_PARAM_IMMEDIATE_DATA));
712 }
713 
714 IMA_API	IMA_STATUS IMA_SetImmediateData(
715 		IMA_OID Oid,
716 		IMA_BOOL immediateData
717 )
718 {
719 	IMA_BOOL_VALUE bv;
720 
721 	bv.currentValue = immediateData;
722 	return (setISCSINodeParameter(BOOL_PARAM, &Oid, &bv,
723 	    ISCSI_LOGIN_PARAM_IMMEDIATE_DATA));
724 }
725 
726 IMA_API	IMA_STATUS IMA_GetDataPduInOrderProperties(
727 		IMA_OID Oid,
728 		IMA_BOOL_VALUE *pProps
729 )
730 {
731 	return (getISCSINodeParameter(BOOL_PARAM, &Oid, pProps,
732 	    ISCSI_LOGIN_PARAM_DATA_PDU_IN_ORDER));
733 }
734 
735 IMA_API	IMA_STATUS IMA_SetDataPduInOrder(
736 		IMA_OID Oid,
737 		IMA_BOOL dataPduInOrder
738 )
739 {
740 	IMA_BOOL_VALUE bv;
741 
742 	bv.currentValue = dataPduInOrder;
743 	return (setISCSINodeParameter(BOOL_PARAM, &Oid, &bv,
744 	    ISCSI_LOGIN_PARAM_DATA_PDU_IN_ORDER));
745 }
746 
747 IMA_API	IMA_STATUS IMA_GetDataSequenceInOrderProperties(
748 		IMA_OID Oid,
749 		IMA_BOOL_VALUE *pProps
750 )
751 {
752 	return (getISCSINodeParameter(BOOL_PARAM, &Oid, pProps,
753 	    ISCSI_LOGIN_PARAM_DATA_SEQUENCE_IN_ORDER));
754 }
755 
756 IMA_API	IMA_STATUS IMA_SetDataSequenceInOrder(
757 		IMA_OID Oid,
758 		IMA_BOOL dataSequenceInOrder
759 )
760 {
761 	IMA_BOOL_VALUE bv;
762 
763 	bv.currentValue = dataSequenceInOrder;
764 	return (setISCSINodeParameter(BOOL_PARAM, &Oid, &bv,
765 	    ISCSI_LOGIN_PARAM_DATA_SEQUENCE_IN_ORDER));
766 }
767 
768 
769 /*ARGSUSED*/
770 IMA_API	IMA_STATUS IMA_SetStatisticsCollection(
771 		IMA_OID Oid,
772 		IMA_BOOL enableStatisticsCollection
773 )
774 {
775 	return (IMA_ERROR_NOT_SUPPORTED);
776 }
777 
778 
779 /*ARGSUSED*/
780 IMA_API	IMA_STATUS IMA_GetDiscoveryAddressOidList(
781 		IMA_OID Oid,
782 		IMA_OID_LIST **ppList
783 )
784 {
785 	int fd, i, addr_list_size;
786 	iscsi_addr_list_t *idlp, al_info;
787 
788 	if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
789 		syslog(LOG_USER|LOG_DEBUG, "Cannot open %s (%d)",
790 		    ISCSI_DRIVER_DEVCTL, errno);
791 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
792 	}
793 
794 	(void) memset(&al_info, 0, sizeof (al_info));
795 	al_info.al_vers = ISCSI_INTERFACE_VERSION;
796 	al_info.al_in_cnt = 0;
797 
798 	/*
799 	 * Issue ioctl to obtain the number of targets.
800 	 */
801 	if (ioctl(fd, ISCSI_DISCOVERY_ADDR_LIST_GET, &al_info) != 0) {
802 		syslog(LOG_USER|LOG_DEBUG,
803 		    "ISCSI_DISCOVERY_ADDR_LIST_GET ioctl %d failed, errno: %d",
804 		    ISCSI_DISCOVERY_ADDR_LIST_GET, errno);
805 		(void) close(fd);
806 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
807 	}
808 
809 	addr_list_size = sizeof (iscsi_addr_list_t);
810 	if (al_info.al_out_cnt > 1) {
811 		addr_list_size += (sizeof (iscsi_addr_list_t) *
812 		    al_info.al_out_cnt - 1);
813 	}
814 
815 	idlp = (iscsi_addr_list_t *)calloc(1, addr_list_size);
816 	if (idlp == NULL) {
817 		(void) close(fd);
818 		return (IMA_ERROR_INSUFFICIENT_MEMORY);
819 	}
820 
821 	idlp->al_vers = ISCSI_INTERFACE_VERSION;
822 	idlp->al_in_cnt = al_info.al_out_cnt;
823 	/* Issue the same ioctl again to obtain the OIDs. */
824 	if (ioctl(fd, ISCSI_DISCOVERY_ADDR_LIST_GET, idlp) != 0) {
825 		syslog(LOG_USER|LOG_DEBUG,
826 		    "ISCSI_TARGET_OID_LIST_GET ioctl %d failed, errno: %d",
827 		    ISCSI_DISCOVERY_ADDR_LIST_GET, errno);
828 		free(idlp);
829 		(void) close(fd);
830 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
831 	}
832 
833 	*ppList = (IMA_OID_LIST *)calloc(1, sizeof (IMA_OID_LIST) +
834 	    idlp->al_out_cnt * sizeof (IMA_OID));
835 	if (*ppList == NULL) {
836 		free(idlp);
837 		(void) close(fd);
838 		return (IMA_ERROR_INSUFFICIENT_MEMORY);
839 	}
840 	(*ppList)->oidCount = idlp->al_out_cnt;
841 
842 	for (i = 0; i < idlp->al_out_cnt; i++) {
843 		(*ppList)->oids[i].objectType =
844 		    IMA_OBJECT_TYPE_DISCOVERY_ADDRESS;
845 		(*ppList)->oids[i].ownerId = pluginOwnerId;
846 		(*ppList)->oids[i].objectSequenceNumber =
847 		    idlp->al_addrs[i].a_oid;
848 	}
849 
850 	free(idlp);
851 	(void) close(fd);
852 
853 	return (IMA_STATUS_SUCCESS);
854 }
855 
856 
857 /* ARGSUSED */
858 IMA_API	IMA_STATUS IMA_GetStaticDiscoveryTargetOidList(
859 		IMA_OID Oid,
860 		IMA_OID_LIST **ppList
861 )
862 {
863 	if (Oid.objectType == IMA_OBJECT_TYPE_PNP) {
864 		return (IMA_ERROR_OBJECT_NOT_FOUND);
865 	}
866 
867 	return (get_target_oid_list(ISCSI_STATIC_TGT_OID_LIST, ppList));
868 }
869 
870 /* ARGSUSED */
871 IMA_API	IMA_STATUS IMA_GetTargetOidList(
872 		IMA_OID Oid,
873 		IMA_OID_LIST **ppList
874 )
875 {
876 	return (get_target_oid_list(ISCSI_TGT_PARAM_OID_LIST, ppList));
877 }
878 
879 /*ARGSUSED*/
880 IMA_API	IMA_STATUS IMA_SetIsnsDiscovery(
881 		IMA_OID phbaId,
882 		IMA_BOOL enableIsnsDiscovery,
883 		IMA_ISNS_DISCOVERY_METHOD discoveryMethod,
884 		const IMA_HOST_ID *iSnsHost
885 )
886 {
887 	/* XXX need to set discovery Method and domaineName */
888 	return (configure_discovery_method(enableIsnsDiscovery,
889 	    iSCSIDiscoveryMethodISNS));
890 }
891 
892 
893 /* ARGSUSED */
894 IMA_API	IMA_STATUS IMA_SetSlpDiscovery(
895 		IMA_OID phbaId,
896 		IMA_BOOL enableSlpDiscovery
897 )
898 {
899 	return (configure_discovery_method(enableSlpDiscovery,
900 	    iSCSIDiscoveryMethodSLP));
901 }
902 
903 
904 /* ARGSUSED */
905 IMA_API	IMA_STATUS IMA_SetStaticDiscovery(
906 		IMA_OID phbaId,
907 		IMA_BOOL enableStaticDiscovery
908 )
909 {
910 	return (configure_discovery_method(enableStaticDiscovery,
911 	    iSCSIDiscoveryMethodStatic));
912 }
913 
914 /* ARGSUSED */
915 IMA_API	IMA_STATUS IMA_SetSendTargetsDiscovery(
916 		IMA_OID phbaId,
917 		IMA_BOOL enableSendTargetsDiscovery
918 )
919 {
920 	return (configure_discovery_method(enableSendTargetsDiscovery,
921 	    iSCSIDiscoveryMethodSendTargets));
922 }
923 
924 /*ARGSUSED*/
925 IMA_API IMA_STATUS IMA_RemoveDiscoveryAddress(
926 		IMA_OID	discoveryAddressOid
927 )
928 {
929 	int status, fd, i, addr_list_size;
930 	iscsi_addr_list_t *idlp, al_info;
931 	iscsi_addr_t *matched_addr = NULL;
932 	entry_t	entry;
933 
934 	if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
935 		syslog(LOG_USER|LOG_DEBUG, "Cannot open %s (%d)",
936 		    ISCSI_DRIVER_DEVCTL, errno);
937 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
938 	}
939 
940 	(void) memset(&al_info, 0, sizeof (al_info));
941 	al_info.al_vers = ISCSI_INTERFACE_VERSION;
942 	al_info.al_in_cnt = 0;
943 
944 	/*
945 	 * Issue ioctl to obtain the number of discovery address.
946 	 */
947 	if (ioctl(fd, ISCSI_DISCOVERY_ADDR_LIST_GET, &al_info) != 0) {
948 		syslog(LOG_USER|LOG_DEBUG,
949 		    "ISCSI_DISCOVERY_ADDR_LIST_GET ioctl %d failed, errno: %d",
950 		    ISCSI_DISCOVERY_ADDR_LIST_GET, errno);
951 		(void) close(fd);
952 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
953 	}
954 
955 	if (al_info.al_out_cnt == 0) {
956 		return (IMA_ERROR_OBJECT_NOT_FOUND);
957 	}
958 
959 	addr_list_size = sizeof (iscsi_addr_list_t);
960 	if (al_info.al_out_cnt > 1) {
961 		addr_list_size += (sizeof (iscsi_addr_list_t) *
962 		    al_info.al_out_cnt - 1);
963 	}
964 
965 	idlp = (iscsi_addr_list_t *)calloc(1, addr_list_size);
966 	if (idlp == NULL) {
967 		(void) close(fd);
968 		return (IMA_ERROR_INSUFFICIENT_MEMORY);
969 	}
970 
971 	idlp->al_vers = ISCSI_INTERFACE_VERSION;
972 	idlp->al_in_cnt = al_info.al_out_cnt;
973 
974 	/* Issue the same ioctl again to obtain the OIDs. */
975 	if (ioctl(fd, ISCSI_DISCOVERY_ADDR_LIST_GET, idlp) != 0) {
976 		syslog(LOG_USER|LOG_DEBUG,
977 		    "ISCSI_TARGET_OID_LIST_GET ioctl %d failed, errno: %d",
978 		    ISCSI_DISCOVERY_ADDR_LIST_GET, errno);
979 		free(idlp);
980 		(void) close(fd);
981 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
982 	}
983 
984 	for (i = 0; i < idlp->al_out_cnt; i++) {
985 		if (discoveryAddressOid.objectSequenceNumber !=
986 		    idlp->al_addrs[i].a_oid)
987 			continue;
988 		matched_addr = &(idlp->al_addrs[i]);
989 	}
990 
991 	if (matched_addr == NULL) {
992 		return (IMA_ERROR_OBJECT_NOT_FOUND);
993 	}
994 
995 
996 	(void) memset(&entry, 0, sizeof (entry_t));
997 	entry.e_vers = ISCSI_INTERFACE_VERSION;
998 	entry.e_oid  = discoveryAddressOid.objectSequenceNumber;
999 	if (matched_addr->a_addr.i_insize == sizeof (struct in_addr)) {
1000 		bcopy(&matched_addr->a_addr.i_addr.in4,
1001 		    &entry.e_u.u_in4, sizeof (entry.e_u.u_in4));
1002 		entry.e_insize = sizeof (struct in_addr);
1003 	} else if (matched_addr->a_addr.i_insize == sizeof (struct in6_addr)) {
1004 		bcopy(&matched_addr->a_addr.i_addr.in6,
1005 		    &entry.e_u.u_in6, sizeof (entry.e_u.u_in6));
1006 		entry.e_insize = sizeof (struct in6_addr);
1007 	} else {
1008 		/* Should not happen */
1009 		syslog(LOG_USER|LOG_DEBUG,
1010 		    "ISCSI_STATIC_GET returned bad address");
1011 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
1012 	}
1013 
1014 	entry.e_port = matched_addr->a_port;
1015 	entry.e_tpgt = 0;
1016 	entry.e_oid = discoveryAddressOid.objectSequenceNumber;
1017 
1018 	if (ioctl(fd, ISCSI_DISCOVERY_ADDR_CLEAR, &entry)) {
1019 		status = errno;
1020 		(void) close(fd);
1021 		syslog(LOG_USER|LOG_DEBUG,
1022 		    "ISCSI_DISCOVERY_ADDR_CLEAR ioctl failed, errno: %d",
1023 		    errno);
1024 		if (status == EBUSY) {
1025 			return (IMA_ERROR_LU_IN_USE);
1026 		} else {
1027 			return (IMA_ERROR_UNEXPECTED_OS_ERROR);
1028 		}
1029 	}
1030 
1031 	free(idlp);
1032 	(void) close(fd);
1033 	return (IMA_STATUS_SUCCESS);
1034 }
1035 
1036 
1037 /*ARGSUSED*/
1038 IMA_API IMA_STATUS IMA_AddDiscoveryAddress(
1039 		IMA_OID	oid,
1040 		const IMA_TARGET_ADDRESS discoveryAddress,
1041 		IMA_OID	*pDiscoveryAddressOid
1042 )
1043 {
1044 	entry_t	    entry;
1045 	int	    fd;
1046 
1047 	if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
1048 		syslog(LOG_USER|LOG_DEBUG, "Cannot open %s (%d)",
1049 		    ISCSI_DRIVER_DEVCTL, errno);
1050 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
1051 	}
1052 
1053 	if (prepare_discovery_entry(discoveryAddress, &entry) !=
1054 	    DISC_ADDR_OK) {
1055 		(void) close(fd);
1056 		return (IMA_ERROR_INVALID_PARAMETER);
1057 	}
1058 
1059 	if (ioctl(fd, ISCSI_DISCOVERY_ADDR_SET, &entry)) {
1060 		syslog(LOG_USER|LOG_DEBUG,
1061 		    "ISCSI_DISCOVERY_ADDR_SET ioctl failed, errno: %d",
1062 		    errno);
1063 		(void) close(fd);
1064 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
1065 	}
1066 
1067 	pDiscoveryAddressOid->ownerId = pluginOwnerId;
1068 	pDiscoveryAddressOid->objectType = IMA_OBJECT_TYPE_DISCOVERY_ADDRESS;
1069 	pDiscoveryAddressOid->objectSequenceNumber = entry.e_oid;
1070 
1071 	(void) close(fd);
1072 	return (IMA_STATUS_SUCCESS);
1073 }
1074 
1075 IMA_API IMA_STATUS IMA_GetStaticDiscoveryTargetProperties(
1076 		IMA_OID	staticTargetOid,
1077 		IMA_STATIC_DISCOVERY_TARGET_PROPERTIES *pProps
1078 )
1079 {
1080 	char static_target_addr_str[SUN_IMA_IP_ADDRESS_LEN];
1081 	char static_target_addr_port_str[SUN_IMA_IP_ADDRESS_LEN];
1082 	int af, fd, status;
1083 	iscsi_static_property_t prop;
1084 	/* LINTED */
1085 	IMA_HOST_ID *host;
1086 
1087 	if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
1088 		syslog(LOG_USER|LOG_DEBUG, "Cannot open %s (%d)",
1089 		    ISCSI_DRIVER_DEVCTL, errno);
1090 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
1091 	}
1092 
1093 	(void) memset(&prop, 0, sizeof (iscsi_static_property_t));
1094 	prop.p_vers = ISCSI_INTERFACE_VERSION;
1095 	prop.p_oid = (uint32_t)staticTargetOid.objectSequenceNumber;
1096 	if (ioctl(fd, ISCSI_STATIC_GET, &prop) != 0) {
1097 		status = errno;
1098 		(void) close(fd);
1099 		syslog(LOG_USER|LOG_DEBUG,
1100 		    "ISCSI_STATIC_GET ioctl failed, errno: %d", status);
1101 		if (status == ENOENT) {
1102 			return (IMA_ERROR_OBJECT_NOT_FOUND);
1103 
1104 		} else {
1105 			return (IMA_ERROR_UNEXPECTED_OS_ERROR);
1106 		}
1107 	}
1108 	(void) close(fd);
1109 
1110 	(void) mbstowcs(pProps->staticTarget.targetName, (char *)prop.p_name,
1111 	    sizeof (pProps->staticTarget.targetName)/sizeof (IMA_WCHAR));
1112 
1113 	if (prop.p_addr_list.al_addrs[0].a_addr.i_insize ==
1114 	    sizeof (struct in_addr)) {
1115 		/* IPv4 */
1116 		af = AF_INET;
1117 	} else if (prop.p_addr_list.al_addrs[0].a_addr.i_insize ==
1118 	    sizeof (struct in6_addr)) {
1119 		/* IPv6 */
1120 		af = AF_INET6;
1121 	} else {
1122 		/* Should not happen */
1123 		syslog(LOG_USER|LOG_DEBUG,
1124 		    "ISCSI_STATIC_GET returned bad address");
1125 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
1126 	}
1127 
1128 	if (inet_ntop(af, &prop.p_addr_list.al_addrs[0].a_addr.i_addr,
1129 	    static_target_addr_str, sizeof (static_target_addr_str)) == NULL) {
1130 		/* Should not happen */
1131 		syslog(LOG_USER|LOG_DEBUG,
1132 		    "ISCSI_STATIC_GET returned address that cannot "
1133 		    "be inet_ntop");
1134 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
1135 	} else {
1136 		if (af == AF_INET) {
1137 			(void) snprintf(static_target_addr_port_str,
1138 			    SUN_IMA_IP_ADDRESS_LEN,
1139 			    "%s:%ld",
1140 			    static_target_addr_str,
1141 			    prop.p_addr_list.al_addrs[0].a_port);
1142 		} else {
1143 			(void) snprintf(static_target_addr_port_str,
1144 			    SUN_IMA_IP_ADDRESS_LEN,
1145 			    "[%s]:%ld",
1146 			    static_target_addr_str,
1147 			    prop.p_addr_list.al_addrs[0].a_port);
1148 		}
1149 		host = &pProps->staticTarget.targetAddress.hostnameIpAddress;
1150 		(void) mbstowcs(pProps->staticTarget.
1151 		    targetAddress.hostnameIpAddress.
1152 		    id.hostname, static_target_addr_port_str,
1153 		    sizeof (host->id.hostname) / sizeof (IMA_WCHAR));
1154 	}
1155 
1156 	return (IMA_STATUS_SUCCESS);
1157 }
1158 
1159 /*ARGSUSED*/
1160 IMA_API IMA_STATUS IMA_GetDiscoveryAddressProperties(
1161 		IMA_OID	discoveryAddressOid,
1162 		IMA_DISCOVERY_ADDRESS_PROPERTIES *pProps
1163 )
1164 {
1165 	int fd;
1166 	int i;
1167 	int addr_list_size;
1168 	iscsi_addr_list_t *idlp, al_info;
1169 	iscsi_addr_t *matched_addr = NULL;
1170 	/* LINTED */
1171 	IMA_TARGET_ADDRESS *addr;
1172 
1173 	if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
1174 		syslog(LOG_USER|LOG_DEBUG, "Cannot open %s (%d)",
1175 		    ISCSI_DRIVER_DEVCTL, errno);
1176 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
1177 	}
1178 
1179 	(void) memset(&al_info, 0, sizeof (al_info));
1180 	al_info.al_vers = ISCSI_INTERFACE_VERSION;
1181 	al_info.al_in_cnt = 0;
1182 
1183 	/*
1184 	 * Issue ioctl to obtain the number of discovery addresses.
1185 	 */
1186 	if (ioctl(fd, ISCSI_DISCOVERY_ADDR_LIST_GET, &al_info) != 0) {
1187 		(void) close(fd);
1188 		syslog(LOG_USER|LOG_DEBUG,
1189 		    "ISCSI_DISCOVERY_ADDR_LIST_GET ioctl %d failed, errno: %d",
1190 		    ISCSI_DISCOVERY_ADDR_LIST_GET, errno);
1191 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
1192 	}
1193 
1194 	if (al_info.al_out_cnt == 0) {
1195 		return (IMA_ERROR_OBJECT_NOT_FOUND);
1196 	}
1197 
1198 	addr_list_size = sizeof (iscsi_addr_list_t);
1199 	if (al_info.al_out_cnt > 1) {
1200 		addr_list_size += (sizeof (iscsi_addr_list_t) *
1201 		    al_info.al_out_cnt - 1);
1202 	}
1203 
1204 	idlp = (iscsi_addr_list_t *)calloc(1, addr_list_size);
1205 	if (idlp == NULL) {
1206 		(void) close(fd);
1207 		return (IMA_ERROR_INSUFFICIENT_MEMORY);
1208 	}
1209 
1210 	idlp->al_vers = ISCSI_INTERFACE_VERSION;
1211 	idlp->al_in_cnt = al_info.al_out_cnt;
1212 
1213 	/* Issue the same ioctl again to obtain the OIDs. */
1214 	if (ioctl(fd, ISCSI_DISCOVERY_ADDR_LIST_GET, idlp) != 0) {
1215 		free(idlp);
1216 		(void) close(fd);
1217 		syslog(LOG_USER|LOG_DEBUG,
1218 		    "ISCSI_TARGET_OID_LIST_GET ioctl %d failed, errno: %d",
1219 		    ISCSI_DISCOVERY_ADDR_LIST_GET, errno);
1220 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
1221 	}
1222 
1223 	for (i = 0; i < idlp->al_out_cnt; i++) {
1224 		if (discoveryAddressOid.objectSequenceNumber !=
1225 		    idlp->al_addrs[i].a_oid)
1226 			continue;
1227 		matched_addr = &(idlp->al_addrs[i]);
1228 	}
1229 
1230 	if (matched_addr == NULL) {
1231 		return (IMA_ERROR_OBJECT_NOT_FOUND);
1232 	}
1233 
1234 	if (matched_addr->a_addr.i_insize == sizeof (struct in_addr)) {
1235 		pProps->discoveryAddress.hostnameIpAddress.id.
1236 		    ipAddress.ipv4Address = IMA_TRUE;
1237 	} else if (matched_addr->a_addr.i_insize == sizeof (struct in6_addr)) {
1238 		pProps->discoveryAddress.hostnameIpAddress.id.
1239 		    ipAddress.ipv4Address = IMA_FALSE;
1240 	} else {
1241 		/* Should not happen */
1242 		syslog(LOG_USER|LOG_DEBUG,
1243 		    "ISCSI_STATIC_GET returned bad address");
1244 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
1245 	}
1246 
1247 	addr = &pProps->discoveryAddress;
1248 	bcopy(&(matched_addr->a_addr.i_addr), pProps->discoveryAddress.
1249 	    hostnameIpAddress.id.ipAddress.ipAddress,
1250 	    sizeof (addr->hostnameIpAddress.id.ipAddress.ipAddress));
1251 
1252 	pProps->discoveryAddress.portNumber = matched_addr->a_port;
1253 
1254 	pProps->associatedLhbaOid.objectType = IMA_OBJECT_TYPE_LHBA;
1255 	pProps->associatedLhbaOid.ownerId = pluginOwnerId;
1256 	pProps->associatedLhbaOid.objectSequenceNumber = ISCSI_INITIATOR_OID;
1257 
1258 	free(idlp);
1259 	(void) close(fd);
1260 
1261 	return (IMA_STATUS_SUCCESS);
1262 }
1263 
1264 IMA_API IMA_STATUS IMA_RemoveStaticDiscoveryTarget(
1265 		IMA_OID staticTargetOid
1266 )
1267 {
1268 	entry_t	entry;
1269 	int	status, fd;
1270 
1271 	if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
1272 		syslog(LOG_USER|LOG_DEBUG, "Cannot open %s (%d)",
1273 		    ISCSI_DRIVER_DEVCTL, errno);
1274 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
1275 	}
1276 
1277 	(void) memset(&entry, 0, sizeof (entry_t));
1278 	entry.e_vers = ISCSI_INTERFACE_VERSION;
1279 	entry.e_oid = (uint32_t)staticTargetOid.objectSequenceNumber;
1280 
1281 	if (ioctl(fd, ISCSI_STATIC_CLEAR, &entry)) {
1282 		status = errno;
1283 		(void) close(fd);
1284 		syslog(LOG_USER|LOG_DEBUG,
1285 		    "ISCSI_STATIC_CLEAR ioctl failed, errno: %d", errno);
1286 		if (status == EBUSY) {
1287 			return (IMA_ERROR_LU_IN_USE);
1288 		} else {
1289 			return (IMA_ERROR_UNEXPECTED_OS_ERROR);
1290 		}
1291 	}
1292 
1293 	(void) close(fd);
1294 	return (IMA_STATUS_SUCCESS);
1295 }
1296 
1297 /*ARGSUSED*/
1298 IMA_API IMA_STATUS IMA_AddStaticDiscoveryTarget(
1299 		IMA_OID lhbaOid,
1300 		const IMA_STATIC_DISCOVERY_TARGET staticConfig,
1301 		IMA_OID *pTargetOid
1302 )
1303 {
1304 	char			tmp_target_str[SUN_IMA_IP_ADDRESS_LEN];
1305 	char			target_addr_str[SUN_IMA_IP_ADDRESS_LEN];
1306 	char			target_port_str[SUN_IMA_IP_PORT_LEN];
1307 	iscsi_target_entry_t	target;
1308 	int			fd;
1309 	int			target_in_addr_size;
1310 	int			target_port;
1311 	union {
1312 		struct in_addr	u_in4;
1313 		struct in6_addr	u_in6;
1314 	}			target_in;
1315 
1316 	/*
1317 	 * staticConfig.address may come in with port number at its trailer.
1318 	 * Parse it to separate the IP address and port number.
1319 	 * Also translate the hostname to IP address if needed.
1320 	 */
1321 	(void) wcstombs(tmp_target_str,
1322 	    staticConfig.targetAddress.hostnameIpAddress.
1323 	    id.hostname, sizeof (tmp_target_str));
1324 
1325 	if (tmp_target_str[0] == '[') {
1326 		/* IPv6 address */
1327 		char *closeBracketPos;
1328 		closeBracketPos = strchr(tmp_target_str, ']');
1329 		if (!closeBracketPos) {
1330 			return (IMA_ERROR_INVALID_PARAMETER);
1331 		}
1332 
1333 		*closeBracketPos = NULL;
1334 		(void) strlcpy(target_addr_str, &tmp_target_str[1],
1335 		    sizeof (target_addr_str));
1336 
1337 		if (inet_pton(AF_INET6, target_addr_str,
1338 		    &target_in.u_in6) != 1) {
1339 			return (IMA_ERROR_INVALID_PARAMETER);
1340 		}
1341 		target_in_addr_size = sizeof (struct in6_addr);
1342 
1343 		/* Extract the port number */
1344 		closeBracketPos++;
1345 		if (*closeBracketPos == ':') {
1346 			closeBracketPos++;
1347 
1348 			if (*closeBracketPos != NULL) {
1349 				(void) strlcpy(target_port_str, closeBracketPos,
1350 				    sizeof (target_port_str));
1351 				target_port = atoi(target_port_str);
1352 			} else {
1353 				target_port = ISCSI_LISTEN_PORT;
1354 			}
1355 		} else {
1356 			/* No port number specified; use default port */
1357 			target_port = ISCSI_LISTEN_PORT;
1358 		}
1359 	} else {
1360 		/* IPv4 address */
1361 		char *colonPos;
1362 		colonPos = strchr(tmp_target_str, ':');
1363 		if (!colonPos) {
1364 			/* No port number specified; use default port */
1365 			target_port = ISCSI_LISTEN_PORT;
1366 			(void) strlcpy(target_addr_str, tmp_target_str,
1367 			    sizeof (target_addr_str));
1368 		} else {
1369 			*colonPos = NULL;
1370 			(void) strlcpy(target_addr_str, tmp_target_str,
1371 			    sizeof (target_addr_str));
1372 			/* Extract the port number */
1373 			colonPos++;
1374 			if (*colonPos != NULL) {
1375 				(void) strlcpy(target_port_str, colonPos,
1376 				    sizeof (target_port_str));
1377 				target_port = atoi(target_port_str);
1378 			} else {
1379 				target_port = ISCSI_LISTEN_PORT;
1380 			}
1381 		}
1382 
1383 		if (inet_pton(AF_INET, target_addr_str,
1384 		    &target_in.u_in4) != 1) {
1385 			return (IMA_ERROR_INVALID_PARAMETER);
1386 		}
1387 
1388 		target_in_addr_size = sizeof (struct in_addr);
1389 	}
1390 
1391 
1392 	(void) memset(&target, 0, sizeof (iscsi_target_entry_t));
1393 	target.te_entry.e_vers = ISCSI_INTERFACE_VERSION;
1394 	target.te_entry.e_oid = ISCSI_OID_NOTSET;
1395 	target.te_entry.e_tpgt = ISCSI_DEFAULT_TPGT;
1396 
1397 	(void) wcstombs((char *)target.te_name, staticConfig.targetName,
1398 	    ISCSI_MAX_NAME_LEN);
1399 
1400 	target.te_entry.e_insize = target_in_addr_size;
1401 	if (target.te_entry.e_insize == sizeof (struct in_addr)) {
1402 		target.te_entry.e_u.u_in4.s_addr = target_in.u_in4.s_addr;
1403 	} else if (target.te_entry.e_insize == sizeof (struct in6_addr)) {
1404 		bcopy(target_in.u_in6.s6_addr,
1405 		    target.te_entry.e_u.u_in6.s6_addr,
1406 		    sizeof (struct in6_addr));
1407 	} else {
1408 		/* Should not happen */
1409 		syslog(LOG_USER|LOG_DEBUG,
1410 		    "ISCSI_STATIC_GET returned bad address");
1411 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
1412 	}
1413 
1414 	target.te_entry.e_port = target_port;
1415 
1416 	/* No target portal group specified. Default to -1. */
1417 	target.te_entry.e_tpgt = ISCSI_DEFAULT_TPGT;
1418 
1419 	if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
1420 		syslog(LOG_USER|LOG_DEBUG, "Cannot open %s (%d)",
1421 		    ISCSI_DRIVER_DEVCTL, errno);
1422 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
1423 	}
1424 
1425 	if (ioctl(fd, ISCSI_STATIC_SET, &target)) {
1426 		/*
1427 		 * Encountered problem setting the IP address and port for
1428 		 * the target just added.
1429 		 */
1430 		(void) close(fd);
1431 		syslog(LOG_USER|LOG_DEBUG,
1432 		    "ISCSI_STATIC_SET ioctl failed, errno: %d", errno);
1433 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
1434 	}
1435 
1436 	pTargetOid->objectType = IMA_OBJECT_TYPE_TARGET;
1437 	pTargetOid->ownerId = pluginOwnerId;
1438 	pTargetOid->objectSequenceNumber = target.te_entry.e_oid;
1439 
1440 	(void) close(fd);
1441 	return (IMA_STATUS_SUCCESS);
1442 }
1443 
1444 IMA_API	IMA_STATUS IMA_GetTargetProperties(
1445 		IMA_OID targetId,
1446 		IMA_TARGET_PROPERTIES *pProps
1447 )
1448 {
1449 	return (getTargetProperties(targetId, pProps));
1450 }
1451 
1452 static IMA_STATUS getTargetProperties(
1453 		IMA_OID targetId,
1454 		IMA_TARGET_PROPERTIES *pProps
1455 )
1456 {
1457 	int		    fd;
1458 	iscsi_property_t    prop;
1459 
1460 	if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
1461 		syslog(LOG_USER|LOG_DEBUG, "Cannot open %s (%d)",
1462 		    ISCSI_DRIVER_DEVCTL, errno);
1463 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
1464 	}
1465 
1466 	(void) memset(&prop, 0, sizeof (iscsi_property_t));
1467 	prop.p_vers = ISCSI_INTERFACE_VERSION;
1468 	prop.p_oid = (uint32_t)targetId.objectSequenceNumber;
1469 
1470 	if (ioctl(fd, ISCSI_TARGET_PROPS_GET, &prop) != 0) {
1471 		(void) close(fd);
1472 		syslog(LOG_USER|LOG_DEBUG,
1473 		    "ISCSI_TARGET_PROPS_GET ioctl failed, errno: %d", errno);
1474 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
1475 	}
1476 
1477 	(void) mbstowcs(pProps->name, (char *)prop.p_name, IMA_NODE_NAME_LEN);
1478 	(void) memset(pProps->alias, 0,
1479 	    sizeof (IMA_WCHAR) * IMA_NODE_ALIAS_LEN);
1480 	if (prop.p_alias_len > 0) {
1481 		(void) mbstowcs(pProps->alias, (char *)prop.p_alias,
1482 		    IMA_NODE_ALIAS_LEN);
1483 	}
1484 
1485 	/* Initialize the discovery method to unknown method. */
1486 	pProps->discoveryMethodFlags = IMA_TARGET_DISCOVERY_METHOD_UNKNOWN;
1487 	if (!((prop.p_discovery & iSCSIDiscoveryMethodStatic) ^
1488 	    iSCSIDiscoveryMethodStatic)) {
1489 		pProps->discoveryMethodFlags |=
1490 		    IMA_TARGET_DISCOVERY_METHOD_STATIC;
1491 	}
1492 
1493 	if (!((prop.p_discovery & iSCSIDiscoveryMethodSLP) ^
1494 	    iSCSIDiscoveryMethodSLP)) {
1495 		pProps->discoveryMethodFlags |=	IMA_TARGET_DISCOVERY_METHOD_SLP;
1496 	}
1497 
1498 	if (!((prop.p_discovery & iSCSIDiscoveryMethodISNS) ^
1499 	    iSCSIDiscoveryMethodISNS)) {
1500 		pProps->discoveryMethodFlags |=	iSCSIDiscoveryMethodISNS;
1501 	}
1502 
1503 	if (!((prop.p_discovery & iSCSIDiscoveryMethodSendTargets) ^
1504 	    iSCSIDiscoveryMethodSendTargets)) {
1505 		pProps->discoveryMethodFlags |= iSCSIDiscoveryMethodSendTargets;
1506 	}
1507 
1508 	(void) close(fd);
1509 	return (IMA_STATUS_SUCCESS);
1510 }
1511 
1512 /*ARGSUSED*/
1513 IMA_API	IMA_STATUS IMA_GetTargetErrorStatistics(
1514 		IMA_OID targetId,
1515 		IMA_TARGET_ERROR_STATISTICS *pStats
1516 )
1517 {
1518 	return (IMA_ERROR_NOT_SUPPORTED);
1519 }
1520 
1521 IMA_API	IMA_STATUS IMA_GetLuOidList(
1522 		IMA_OID oid,
1523 		IMA_OID_LIST **ppList
1524 )
1525 {
1526 	IMA_STATUS		status;
1527 	int			i;
1528 	iscsi_lun_list_t	*pLunList;
1529 
1530 	if (oid.objectType == IMA_OBJECT_TYPE_LHBA) {
1531 		status = get_target_lun_oid_list(NULL, &pLunList);
1532 	} else {
1533 		status = get_target_lun_oid_list(&oid, &pLunList);
1534 	}
1535 
1536 	if (!IMA_SUCCESS(status)) {
1537 		return (status);
1538 	}
1539 
1540 	*ppList = (IMA_OID_LIST *) calloc(1, (sizeof (IMA_OID_LIST) +
1541 	    (pLunList->ll_out_cnt * sizeof (IMA_OID))));
1542 	if (*ppList == NULL) {
1543 		return (IMA_ERROR_INSUFFICIENT_MEMORY);
1544 	}
1545 	(*ppList)->oidCount = pLunList->ll_out_cnt;
1546 	for (i = 0; i < pLunList->ll_out_cnt; i++) {
1547 		(*ppList)->oids[i].objectType = IMA_OBJECT_TYPE_LU;
1548 		(*ppList)->oids[i].ownerId = pluginOwnerId;
1549 		(*ppList)->oids[i].objectSequenceNumber =
1550 		    pLunList->ll_luns[i].l_oid;
1551 	}
1552 
1553 	free(pLunList);
1554 	return (IMA_STATUS_SUCCESS);
1555 }
1556 
1557 IMA_API	IMA_STATUS IMA_GetLuOid(
1558 		IMA_OID targetId,
1559 		IMA_UINT64 lun,
1560 		IMA_OID *pluId
1561 )
1562 {
1563 	IMA_STATUS		status;
1564 	int			i;
1565 	iscsi_lun_list_t	*pLunList;
1566 
1567 	status = get_target_lun_oid_list(&targetId, &pLunList);
1568 	if (!IMA_SUCCESS(status)) {
1569 		return (status);
1570 	}
1571 
1572 	for (i = 0; i < pLunList->ll_out_cnt; i++) {
1573 		if (pLunList->ll_luns[i].l_num == lun) {
1574 			pluId->objectType = IMA_OBJECT_TYPE_LU;
1575 			pluId->ownerId = pluginOwnerId;
1576 			pluId->objectSequenceNumber =
1577 			    pLunList->ll_luns[i].l_oid;
1578 			free(pLunList);
1579 			return (IMA_STATUS_SUCCESS);
1580 		}
1581 	}
1582 
1583 	free(pLunList);
1584 	return (IMA_ERROR_OBJECT_NOT_FOUND);
1585 }
1586 
1587 IMA_API	IMA_STATUS IMA_GetLuProperties(
1588 		IMA_OID luId,
1589 		IMA_LU_PROPERTIES *pProps
1590 )
1591 {
1592 	return (getLuProperties(luId, pProps));
1593 }
1594 
1595 static IMA_STATUS getLuProperties(
1596 		IMA_OID luId,
1597 		IMA_LU_PROPERTIES *pProps
1598 )
1599 {
1600 	IMA_STATUS		status;
1601 	iscsi_lun_list_t	*pLunList;
1602 	int			j;
1603 	IMA_BOOL		lunMatch = IMA_FALSE;
1604 	int			fd;
1605 	iscsi_lun_props_t	lun;
1606 	di_devlink_handle_t	hdl;
1607 
1608 	if (luId.objectType != IMA_OBJECT_TYPE_LU) {
1609 		return (IMA_ERROR_INCORRECT_OBJECT_TYPE);
1610 	}
1611 
1612 	/*
1613 	 * get list of lun oids for all targets
1614 	 */
1615 	status = get_target_lun_oid_list(NULL, &pLunList);
1616 	if (!IMA_SUCCESS(status)) {
1617 		return (status);
1618 	}
1619 	for (j = 0; j < pLunList->ll_out_cnt; j++) {
1620 		/*
1621 		 * for each lun, check if match is found
1622 		 */
1623 		if (pLunList->ll_luns[j].l_oid == luId.objectSequenceNumber) {
1624 			/*
1625 			 * match found, break out of lun loop
1626 			 */
1627 			lunMatch = IMA_TRUE;
1628 			break;
1629 		}
1630 	}
1631 
1632 	if (lunMatch == IMA_TRUE) {
1633 		(void) memset(&lun, 0, sizeof (iscsi_lun_props_t));
1634 		lun.lp_vers = ISCSI_INTERFACE_VERSION;
1635 		lun.lp_tgt_oid = pLunList->ll_luns[j].l_tgt_oid;
1636 		lun.lp_oid = pLunList->ll_luns[j].l_oid;
1637 	}
1638 
1639 	free(pLunList);
1640 
1641 	if (lunMatch == IMA_FALSE) {
1642 		return (IMA_ERROR_OBJECT_NOT_FOUND);
1643 	}
1644 
1645 	/*
1646 	 * get lun properties
1647 	 */
1648 	if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
1649 		syslog(LOG_USER|LOG_DEBUG, "Cannot open %s (%d)",
1650 		    ISCSI_DRIVER_DEVCTL, errno);
1651 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
1652 	}
1653 
1654 	if (ioctl(fd, ISCSI_LUN_PROPS_GET, &lun)) {
1655 		syslog(LOG_USER|LOG_DEBUG,
1656 		    "ISCSI_LUN_PROPS_GET ioctl failed, errno: %d", errno);
1657 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
1658 	}
1659 	(void) close(fd);
1660 
1661 	/*
1662 	 * set property values
1663 	 */
1664 	pProps->associatedTargetOid.objectType = IMA_OBJECT_TYPE_TARGET;
1665 	pProps->associatedTargetOid.ownerId = pluginOwnerId;
1666 	pProps->associatedTargetOid.objectSequenceNumber = lun.lp_tgt_oid;
1667 	pProps->targetLun = (IMA_UINT64)lun.lp_num;
1668 	pProps->exposedToOs = IMA_TRUE;
1669 	(void) memset(&pProps->timeExposedToOs, 0,
1670 	    sizeof (pProps->timeExposedToOs));
1671 
1672 	if (lun.lp_status == LunValid) {
1673 
1674 		/* add minor device delimiter */
1675 		(void) strcat(lun.lp_pathname, ":");
1676 
1677 		if ((strstr(lun.lp_pathname, "sd@") != NULL) ||
1678 		    (strstr(lun.lp_pathname, "ssd@") != NULL) ||
1679 		    (strstr(lun.lp_pathname, "disk@") != NULL)) {
1680 			/*
1681 			 * modify returned pathname to obtain the 2nd slice
1682 			 * of the raw disk
1683 			 */
1684 			(void) strcat(lun.lp_pathname, "c,raw");
1685 		}
1686 
1687 		/*
1688 		 * Pathname returned by driver is the physical device path.
1689 		 * This name needs to be converted to the OS device name.
1690 		 */
1691 		if (hdl = di_devlink_init(lun.lp_pathname, DI_MAKE_LINK)) {
1692 			pProps->osDeviceName[0] = L'\0';
1693 			(void) di_devlink_walk(hdl, NULL, lun.lp_pathname,
1694 			    DI_PRIMARY_LINK, (void *)pProps->osDeviceName,
1695 			    get_lun_devlink);
1696 			if (pProps->osDeviceName[0] != L'\0') {
1697 				/* OS device name synchronously made */
1698 				pProps->osDeviceNameValid = IMA_TRUE;
1699 			} else {
1700 				pProps->osDeviceNameValid = IMA_FALSE;
1701 			}
1702 
1703 			(void) di_devlink_fini(&hdl);
1704 		} else {
1705 			pProps->osDeviceNameValid = IMA_FALSE;
1706 		}
1707 
1708 	} else {
1709 		pProps->osDeviceNameValid = IMA_FALSE;
1710 	}
1711 
1712 	pProps->osParallelIdsValid = IMA_FALSE;
1713 
1714 	return (IMA_STATUS_SUCCESS);
1715 }
1716 
1717 /*ARGSUSED*/
1718 IMA_API	IMA_STATUS IMA_GetStatisticsProperties(
1719 		IMA_OID oid,
1720 		IMA_STATISTICS_PROPERTIES *pProps
1721 )
1722 {
1723 	return (IMA_ERROR_NOT_SUPPORTED);
1724 }
1725 
1726 /*ARGSUSED*/
1727 IMA_API	IMA_STATUS IMA_GetDeviceStatistics(
1728 		IMA_OID luId,
1729 		IMA_DEVICE_STATISTICS *pStats
1730 )
1731 {
1732 	return (IMA_ERROR_NOT_SUPPORTED);
1733 }
1734 
1735 /*ARGSUSED*/
1736 IMA_API	IMA_STATUS IMA_LuInquiry(
1737 	IMA_OID deviceId,
1738 	IMA_BOOL evpd,
1739 	IMA_BOOL cmddt,
1740 	IMA_BYTE pageCode,
1741 	IMA_BYTE *pOutputBuffer,
1742 	IMA_UINT *pOutputBufferLength,
1743 	IMA_BYTE *pSenseBuffer,
1744 	IMA_UINT *pSenseBufferLength
1745 )
1746 {
1747 	IMA_LU_PROPERTIES luProps;
1748 	IMA_STATUS status;
1749 
1750 	char cmdblk [ INQUIRY_CMDLEN ] =
1751 	    { INQUIRY_CMD,   /* command */
1752 			0,   /* lun/reserved */
1753 			0,   /* page code */
1754 			0,   /* reserved */
1755 	INQUIRY_REPLY_LEN,   /* allocation length */
1756 			0 }; /* reserved/flag/link */
1757 
1758 
1759 	int fd;
1760 	iscsi_uscsi_t uscsi;
1761 
1762 	cmdblk[2] = pageCode;
1763 
1764 	(void) memset(&uscsi, 0, sizeof (iscsi_uscsi_t));
1765 	uscsi.iu_vers 	= ISCSI_INTERFACE_VERSION;
1766 
1767 	/* iu_oid is a session oid in the driver */
1768 	if (deviceId.objectType == IMA_OBJECT_TYPE_TARGET) {
1769 		uscsi.iu_oid	= deviceId.objectSequenceNumber;
1770 		uscsi.iu_lun	= 0;
1771 	} else {
1772 		/*
1773 		 * Get LU properties and associated session oid
1774 		 * for this lun(deviceId) and put in uscsi.iu_oid
1775 		 */
1776 		status = getLuProperties(deviceId, &luProps);
1777 		if (status != IMA_STATUS_SUCCESS) {
1778 			return (status);
1779 		}
1780 		uscsi.iu_oid = (uint32_t)luProps.associatedTargetOid.
1781 		    objectSequenceNumber;
1782 		uscsi.iu_lun = luProps.targetLun;
1783 	}
1784 
1785 	uscsi.iu_ucmd.uscsi_flags = USCSI_READ;
1786 	uscsi.iu_ucmd.uscsi_timeout = USCSI_TIMEOUT_IN_SEC;
1787 	uscsi.iu_ucmd.uscsi_bufaddr = (char *)pOutputBuffer;
1788 	uscsi.iu_ucmd.uscsi_buflen = *pOutputBufferLength;
1789 	uscsi.iu_ucmd.uscsi_rqbuf = (char *)pSenseBuffer;
1790 	uscsi.iu_ucmd.uscsi_rqlen = *pSenseBufferLength;
1791 	uscsi.iu_ucmd.uscsi_cdb = &cmdblk[0];
1792 	uscsi.iu_ucmd.uscsi_cdblen = INQUIRY_CMDLEN;
1793 
1794 	if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
1795 		syslog(LOG_USER|LOG_DEBUG, "Cannot open %s (%d)",
1796 		    ISCSI_DRIVER_DEVCTL, errno);
1797 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
1798 	}
1799 
1800 	if (ioctl(fd, ISCSI_USCSI, &uscsi) != 0) {
1801 		(void) close(fd);
1802 		syslog(LOG_USER|LOG_DEBUG,
1803 		    "ISCSI_TARGET_PROPS_GET ioctl failed, errno: %d", errno);
1804 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
1805 	}
1806 
1807 	return (IMA_STATUS_SUCCESS);
1808 }
1809 
1810 /*ARGSUSED*/
1811 IMA_API	IMA_STATUS IMA_LuReadCapacity(
1812 		IMA_OID deviceId,
1813 		IMA_UINT cdbLength,
1814 		IMA_BYTE *pOutputBuffer,
1815 		IMA_UINT *pOutputBufferLength,
1816 
1817 		IMA_BYTE *pSenseBuffer,
1818 		IMA_UINT *pSenseBufferLength
1819 )
1820 {
1821 	IMA_LU_PROPERTIES luProps;
1822 	IMA_STATUS status;
1823 	int fd;
1824 	iscsi_uscsi_t uscsi;
1825 
1826 	char cmdblk [ INQUIRY_CMDLEN ] =
1827 		{ GETCAPACITY_CMD,   /* command */
1828 				0,   /* lun/reserved */
1829 				0,   /* page code */
1830 				0,   /* reserved */
1831 		INQUIRY_REPLY_LEN,   /* allocation length */
1832 				0 }; /* reserved/flag/link */
1833 
1834 
1835 
1836 	(void) memset(&uscsi, 0, sizeof (iscsi_uscsi_t));
1837 	uscsi.iu_vers 	= ISCSI_INTERFACE_VERSION;
1838 
1839 	/* iu_oid is a session oid in the driver */
1840 	if (deviceId.objectType == IMA_OBJECT_TYPE_TARGET) {
1841 		uscsi.iu_oid	= deviceId.objectSequenceNumber;
1842 		uscsi.iu_lun	= 0;
1843 	} else {
1844 		/*
1845 		 * Get LU properties and associated session oid
1846 		 * for this lun(deviceId) and put in uscsi.iu_oid
1847 		 */
1848 		status = getLuProperties(deviceId, &luProps);
1849 		if (status != IMA_STATUS_SUCCESS) {
1850 			return (status);
1851 		}
1852 		uscsi.iu_oid = (uint32_t)luProps.associatedTargetOid.
1853 		    objectSequenceNumber;
1854 		uscsi.iu_lun = luProps.targetLun;
1855 	}
1856 
1857 	uscsi.iu_ucmd.uscsi_flags = USCSI_READ;
1858 	uscsi.iu_ucmd.uscsi_timeout = 10;
1859 	uscsi.iu_ucmd.uscsi_bufaddr = (char *)pOutputBuffer;
1860 	uscsi.iu_ucmd.uscsi_buflen = *pOutputBufferLength;
1861 	uscsi.iu_ucmd.uscsi_rqbuf = (char *)pSenseBuffer;
1862 	uscsi.iu_ucmd.uscsi_rqlen = *pSenseBufferLength;
1863 	uscsi.iu_ucmd.uscsi_cdb = &cmdblk[0];
1864 	uscsi.iu_ucmd.uscsi_cdblen = INQUIRY_CMDLEN;
1865 
1866 	if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
1867 		syslog(LOG_USER|LOG_DEBUG, "Cannot open %s (%d)",
1868 		    ISCSI_DRIVER_DEVCTL, errno);
1869 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
1870 	}
1871 
1872 	if (ioctl(fd, ISCSI_USCSI, &uscsi) != 0) {
1873 		(void) close(fd);
1874 		syslog(LOG_USER|LOG_DEBUG,
1875 		    "ISCSI_TARGET_PROPS_GET ioctl failed, errno: %d", errno);
1876 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
1877 	}
1878 
1879 	return (IMA_STATUS_SUCCESS);
1880 }
1881 
1882 /*ARGSUSED*/
1883 IMA_API	IMA_STATUS IMA_LuReportLuns(
1884 		IMA_OID deviceId,
1885 		IMA_BOOL sendToWellKnownLun,
1886 		IMA_BYTE selectReport,
1887 
1888 		IMA_BYTE *pOutputBuffer,
1889 		IMA_UINT *pOutputBufferLength,
1890 
1891 		IMA_BYTE *pSenseBuffer,
1892 		IMA_UINT *pSenseBufferLength
1893 )
1894 {
1895 	IMA_LU_PROPERTIES luProps;
1896 	IMA_STATUS status;
1897 	int fd;
1898 	iscsi_uscsi_t uscsi;
1899 
1900 	char cmdblk [ INQUIRY_CMDLEN ] =
1901 	    { INQUIRY_CMD,   /* command */
1902 			0,   /* lun/reserved */
1903 			0,   /* page code */
1904 			0,   /* reserved */
1905 	INQUIRY_REPLY_LEN,   /* allocation length */
1906 			0 }; /* reserved/flag/link */
1907 
1908 	(void) memset(&uscsi, 0, sizeof (iscsi_uscsi_t));
1909 	uscsi.iu_vers 	= ISCSI_INTERFACE_VERSION;
1910 
1911 	/* iu_oid is a session oid in the driver */
1912 	if (deviceId.objectType == IMA_OBJECT_TYPE_TARGET) {
1913 		uscsi.iu_oid	= deviceId.objectSequenceNumber;
1914 		uscsi.iu_lun	= 0;
1915 	} else {
1916 		/*
1917 		 * Get LU properties and associated session oid
1918 		 * for this lun(deviceId) and put in uscsi.iu_oid
1919 		 */
1920 		status = getLuProperties(deviceId, &luProps);
1921 		if (status != IMA_STATUS_SUCCESS) {
1922 			return (status);
1923 		}
1924 		uscsi.iu_oid = (uint32_t)luProps.associatedTargetOid.
1925 		    objectSequenceNumber;
1926 		uscsi.iu_lun = luProps.targetLun;
1927 	}
1928 
1929 	uscsi.iu_ucmd.uscsi_flags = USCSI_READ;
1930 	uscsi.iu_ucmd.uscsi_timeout = 10;
1931 	uscsi.iu_ucmd.uscsi_bufaddr = (char *)pOutputBuffer;
1932 	uscsi.iu_ucmd.uscsi_buflen = *pOutputBufferLength;
1933 	uscsi.iu_ucmd.uscsi_rqbuf = (char *)pSenseBuffer;
1934 	uscsi.iu_ucmd.uscsi_rqlen = *pSenseBufferLength;
1935 	uscsi.iu_ucmd.uscsi_cdb = &cmdblk[0];
1936 	uscsi.iu_ucmd.uscsi_cdblen = INQUIRY_CMDLEN;
1937 
1938 	if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
1939 		syslog(LOG_USER|LOG_DEBUG, "Cannot open %s (%d)",
1940 		    ISCSI_DRIVER_DEVCTL, errno);
1941 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
1942 	}
1943 
1944 	if (ioctl(fd, ISCSI_USCSI, &uscsi) != 0) {
1945 		(void) close(fd);
1946 		syslog(LOG_USER|LOG_DEBUG,
1947 		    "ISCSI_TARGET_PROPS_GET ioctl failed, errno: %d", errno);
1948 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
1949 	}
1950 
1951 	return (IMA_STATUS_SUCCESS);
1952 }
1953 
1954 /*ARGSUSED*/
1955 IMA_API	IMA_STATUS IMA_ExposeLu(
1956 		IMA_OID luId
1957 )
1958 {
1959 	return (IMA_ERROR_NOT_SUPPORTED);
1960 }
1961 
1962 /*ARGSUSED*/
1963 IMA_API	IMA_STATUS IMA_UnexposeLu(
1964 		IMA_OID luId
1965 )
1966 {
1967 	return (IMA_ERROR_NOT_SUPPORTED);
1968 }
1969 
1970 IMA_API	IMA_STATUS IMA_GetAddressKeys(
1971 		IMA_OID targetOid,
1972 		IMA_ADDRESS_KEYS **ppKeys
1973 )
1974 {
1975 	IMA_STATUS status;
1976 	IMA_TARGET_PROPERTIES targetProps;
1977 	SUN_IMA_DISC_ADDR_PROP_LIST *discAddressList;
1978 	SUN_IMA_DISC_ADDRESS_KEY_PROPERTIES *pList;
1979 	int i, j, addressKeyCount = 0;
1980 	int addressKeyIdx = 0;
1981 
1982 	status = getTargetProperties(targetOid, &targetProps);
1983 	if (status != IMA_STATUS_SUCCESS) {
1984 		return (status);
1985 	}
1986 
1987 	status = getDiscoveryAddressPropertiesList(&discAddressList);
1988 	if (status != IMA_STATUS_SUCCESS) {
1989 		return (status);
1990 	}
1991 
1992 	/* Get the number of addresses to allocate */
1993 	for (i = 0; i < discAddressList->discAddrCount; i++) {
1994 		(void) sendTargets(discAddressList->props[i].discoveryAddress,
1995 		    &pList);
1996 		for (j = 0; j < pList->keyCount; j++) {
1997 			if (wcsncmp(pList->keys[j].name, targetProps.name,
1998 			    wslen(pList->keys[j].name)) == 0) {
1999 				addressKeyCount++;
2000 			}
2001 		}
2002 		(void) IMA_FreeMemory(pList);
2003 	}
2004 
2005 	*ppKeys = (IMA_ADDRESS_KEYS *)calloc(1, sizeof (IMA_ADDRESS_KEYS) +
2006 	    addressKeyCount * sizeof (IMA_ADDRESS_KEY));
2007 	if (*ppKeys == NULL) {
2008 		return (IMA_ERROR_INSUFFICIENT_MEMORY);
2009 	}
2010 	(*ppKeys)->addressKeyCount = addressKeyCount;
2011 	addressKeyIdx = 0;
2012 
2013 	for (i = 0; i < discAddressList->discAddrCount; i++) {
2014 		(void) sendTargets(discAddressList->props[i].discoveryAddress,
2015 		    &pList);
2016 		for (j = 0; j < pList->keyCount; j++) {
2017 			if (wcsncmp(pList->keys[j].name, targetProps.name,
2018 			    wslen(pList->keys[j].name)) != 0) {
2019 				continue;
2020 			}
2021 
2022 			bcopy(&(pList->keys[j].address.ipAddress),
2023 			    &((*ppKeys)->addressKeys[addressKeyIdx].
2024 			    ipAddress), sizeof (IMA_IP_ADDRESS));
2025 
2026 			(*ppKeys)->addressKeys[addressKeyIdx++].portNumber =
2027 			    pList->keys[j].address.portNumber;
2028 
2029 		}
2030 		(void) IMA_FreeMemory(pList);
2031 	}
2032 	return (IMA_STATUS_SUCCESS);
2033 }
2034 
2035 IMA_BOOL isAuthMethodValid(IMA_OID oid, IMA_AUTHMETHOD method) {
2036 	IMA_STATUS status;
2037 	IMA_AUTHMETHOD supportedList[MAX_AUTHMETHODS];
2038 	IMA_UINT i, supportedCount;
2039 	IMA_BOOL supported;
2040 	status = getSupportedAuthMethods(oid, IMA_FALSE, &supportedCount,
2041 			supportedList);
2042 	if (status != IMA_STATUS_SUCCESS)
2043 		return (IMA_FALSE);
2044 
2045 	supported = IMA_FALSE;
2046 	for (i = 0; i < supportedCount; i++) {
2047 		if (method == supportedList[i]) {
2048 			supported = IMA_TRUE;
2049 		}
2050 	}
2051 
2052 	return (supported);
2053 }
2054 
2055 IMA_BOOL isAuthMethodListValid(IMA_OID oid, const IMA_AUTHMETHOD *pMethodList,
2056 				IMA_UINT methodCount) {
2057 	IMA_UINT i, j;
2058 
2059 	if (pMethodList == NULL) {
2060 		return (IMA_FALSE);
2061 	}
2062 	/* Check list for duplicates */
2063 	for (i = 0; i < methodCount; i++) {
2064 		for (j = i + 1; j < methodCount; j++) {
2065 			if (pMethodList[i] == pMethodList[j]) {
2066 				return (IMA_FALSE);
2067 			}
2068 		}
2069 
2070 		if (isAuthMethodValid(oid, pMethodList[i]) == IMA_FALSE) {
2071 			return (IMA_FALSE);
2072 		}
2073 	}
2074 	return (IMA_TRUE);
2075 }
2076 
2077 IMA_API	IMA_STATUS IMA_GetSupportedAuthMethods(
2078 		IMA_OID lhbaOid,
2079 		IMA_BOOL getSettableMethods,
2080 		IMA_UINT *pMethodCount,
2081 		IMA_AUTHMETHOD *pMethodList
2082 )
2083 {
2084 	return (getSupportedAuthMethods(lhbaOid, getSettableMethods,
2085 	    pMethodCount, pMethodList));
2086 }
2087 
2088 
2089 /*ARGSUSED*/
2090 static IMA_STATUS getSupportedAuthMethods(
2091 		IMA_OID lhbaOid,
2092 		IMA_BOOL getSettableMethods,
2093 		IMA_UINT *pMethodCount,
2094 		IMA_AUTHMETHOD *pMethodList
2095 )
2096 {
2097 	if (pMethodList == NULL) {
2098 		*pMethodCount = 0;
2099 		return (IMA_STATUS_SUCCESS);
2100 	}
2101 
2102 	*pMethodCount = NUM_SUPPORTED_AUTH_METHODS;
2103 	if (*pMethodCount > 1) {
2104 		pMethodList[0] = IMA_AUTHMETHOD_NONE;
2105 		pMethodList[1] = IMA_AUTHMETHOD_CHAP;
2106 	}
2107 
2108 	return (IMA_STATUS_SUCCESS);
2109 }
2110 
2111 IMA_API	IMA_STATUS IMA_GetInUseInitiatorAuthMethods(
2112 		IMA_OID		lhbaOid,
2113 		IMA_UINT	*pMethodCount,
2114 		IMA_AUTHMETHOD *pMethodList
2115 )
2116 {
2117 	return (getAuthMethods(lhbaOid, pMethodCount, pMethodList));
2118 }
2119 
2120 /*ARGSUSED*/
2121 IMA_API	IMA_STATUS IMA_GetInitiatorAuthParms(
2122 		IMA_OID lhbaOid,
2123 		IMA_AUTHMETHOD method,
2124 		IMA_INITIATOR_AUTHPARMS *pParms
2125 )
2126 {
2127 	int fd;
2128 	iscsi_chap_props_t  chap_p;
2129 
2130 	if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
2131 		syslog(LOG_USER|LOG_DEBUG, "Cannot open %s (%d)",
2132 		    ISCSI_DRIVER_DEVCTL, errno);
2133 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
2134 	}
2135 
2136 	(void) memset(&chap_p, 0, sizeof (iscsi_chap_props_t));
2137 	chap_p.c_vers = ISCSI_INTERFACE_VERSION;
2138 	chap_p.c_oid = (uint32_t)lhbaOid.objectSequenceNumber;
2139 
2140 	if (method == IMA_AUTHMETHOD_CHAP) {
2141 		if (ioctl(fd, ISCSI_CHAP_GET, &chap_p) != 0) {
2142 			syslog(LOG_USER|LOG_DEBUG,
2143 			"ISCSI_CHAP_GET ioctl failed, errno: %d", errno);
2144 			(void) close(fd);
2145 			return (IMA_ERROR_UNEXPECTED_OS_ERROR);
2146 		}
2147 	} else {
2148 		return (IMA_ERROR_INVALID_PARAMETER);
2149 	}
2150 
2151 	(void) memcpy(pParms->chapParms.name, chap_p.c_user,
2152 	    chap_p.c_user_len);
2153 	pParms->chapParms.nameLength = chap_p.c_user_len;
2154 	(void) memcpy(pParms->chapParms.challengeSecret, chap_p.c_secret,
2155 	    chap_p.c_secret_len);
2156 	pParms->chapParms.challengeSecretLength = chap_p.c_secret_len;
2157 
2158 	return (IMA_STATUS_SUCCESS);
2159 }
2160 
2161 IMA_API	IMA_STATUS IMA_SetInitiatorAuthMethods(
2162 		IMA_OID lhbaOid,
2163 		IMA_UINT methodCount,
2164 		const IMA_AUTHMETHOD *pMethodList
2165 )
2166 {
2167 	if (isAuthMethodListValid(lhbaOid, pMethodList,
2168 	    methodCount) == IMA_FALSE)
2169 		return (IMA_ERROR_INVALID_PARAMETER);
2170 	return (setAuthMethods(lhbaOid, &methodCount, pMethodList));
2171 }
2172 
2173 /*
2174  * This function only sets CHAP params since we only support CHAP for now.
2175  */
2176 IMA_API	IMA_STATUS IMA_SetInitiatorAuthParms(
2177 		IMA_OID lhbaOid,
2178 		IMA_AUTHMETHOD method,
2179 		const IMA_INITIATOR_AUTHPARMS *pParms
2180 )
2181 {
2182 	int fd;
2183 	iscsi_chap_props_t  chap_p;
2184 
2185 	if (method != IMA_AUTHMETHOD_CHAP)
2186 		return (IMA_ERROR_INVALID_PARAMETER);
2187 
2188 	if (isAuthMethodValid(lhbaOid, method) == IMA_FALSE) {
2189 		return (IMA_ERROR_INVALID_PARAMETER);
2190 	}
2191 
2192 	if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
2193 		syslog(LOG_USER|LOG_DEBUG, "Cannot open %s (%d)",
2194 		    ISCSI_DRIVER_DEVCTL, errno);
2195 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
2196 	}
2197 
2198 	(void) memset(&chap_p, 0, sizeof (iscsi_chap_props_t));
2199 	chap_p.c_vers = ISCSI_INTERFACE_VERSION;
2200 	chap_p.c_oid = (uint32_t)lhbaOid.objectSequenceNumber;
2201 
2202 	chap_p.c_user_len = pParms->chapParms.nameLength;
2203 	(void) memcpy(chap_p.c_user, pParms->chapParms.name, chap_p.c_user_len);
2204 
2205 	chap_p.c_secret_len = pParms->chapParms.challengeSecretLength;
2206 	(void) memcpy(chap_p.c_secret, pParms->chapParms.challengeSecret,
2207 	    chap_p.c_secret_len);
2208 
2209 	if (method == IMA_AUTHMETHOD_CHAP) {
2210 		if (ioctl(fd, ISCSI_CHAP_SET, &chap_p) != 0) {
2211 			(void) close(fd);
2212 			syslog(LOG_USER|LOG_DEBUG,
2213 			    "ISCSI_CHAP_SET ioctl failed, errno: %d", errno);
2214 			return (IMA_ERROR_UNEXPECTED_OS_ERROR);
2215 		}
2216 	}
2217 
2218 	return (IMA_STATUS_SUCCESS);
2219 }
2220 
2221 /* A helper function to obtain iSCSI node parameters. */
2222 static IMA_STATUS
2223 getISCSINodeParameter(
2224     int paramType,
2225     IMA_OID *oid,
2226     void *pProps,
2227     uint32_t paramIndex
2228 )
2229 {
2230 	int		    fd;
2231 	iscsi_param_get_t   pg;
2232 
2233 	if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
2234 		syslog(LOG_USER|LOG_DEBUG, "Cannot open %s (%d)",
2235 		    ISCSI_DRIVER_DEVCTL, errno);
2236 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
2237 	}
2238 
2239 	(void) memset(&pg, 0, sizeof (iscsi_param_get_t));
2240 	pg.g_vers = ISCSI_INTERFACE_VERSION;
2241 	pg.g_oid = (uint32_t)oid->objectSequenceNumber;
2242 	pg.g_param = paramIndex;
2243 	pg.g_param_type = ISCSI_SESS_PARAM;
2244 
2245 	if (ioctl(fd, ISCSI_PARAM_GET, &pg) != 0) {
2246 		syslog(LOG_USER|LOG_DEBUG,
2247 		    "ISCSI_PARAM_GET ioctl failed, errno: %d", errno);
2248 		(void) close(fd);
2249 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
2250 	}
2251 
2252 	switch (paramType) {
2253 		IMA_BOOL_VALUE *bp;
2254 		IMA_MIN_MAX_VALUE *mp;
2255 
2256 		case MIN_MAX_PARAM:
2257 			mp = (IMA_MIN_MAX_VALUE *)pProps;
2258 
2259 			mp->currentValueValid =
2260 			    (pg.g_value.v_valid == B_TRUE) ?
2261 			    IMA_TRUE : IMA_FALSE;
2262 			mp->currentValue = pg.g_value.v_integer.i_current;
2263 			mp->defaultValue = pg.g_value.v_integer.i_default;
2264 			mp->minimumValue = pg.g_value.v_integer.i_min;
2265 			mp->maximumValue = pg.g_value.v_integer.i_max;
2266 			mp->incrementValue = pg.g_value.v_integer.i_incr;
2267 			break;
2268 
2269 		case BOOL_PARAM:
2270 			bp = (IMA_BOOL_VALUE *)pProps;
2271 			bp->currentValueValid =
2272 			    (pg.g_value.v_valid == B_TRUE) ?
2273 			    IMA_TRUE : IMA_FALSE;
2274 			bp->currentValue = pg.g_value.v_bool.b_current;
2275 			bp->defaultValue = pg.g_value.v_bool.b_default;
2276 			break;
2277 
2278 		default:
2279 			break;
2280 	}
2281 
2282 	(void) close(fd);
2283 	return (IMA_STATUS_SUCCESS);
2284 }
2285 
2286 /* A helper function to set iSCSI node parameters. */
2287 static IMA_STATUS
2288 setISCSINodeParameter(
2289     int paramType,
2290     IMA_OID *oid,
2291     void *pProp,
2292     uint32_t paramIndex
2293 )
2294 {
2295 	int		    fd;
2296 	iscsi_param_set_t   ps;
2297 
2298 	if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
2299 		syslog(LOG_USER|LOG_DEBUG, "Cannot open %s (%d)",
2300 		    ISCSI_DRIVER_DEVCTL, errno);
2301 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
2302 	}
2303 
2304 	(void) memset(&ps, 0, sizeof (iscsi_param_set_t));
2305 	ps.s_vers = ISCSI_INTERFACE_VERSION;
2306 	ps.s_oid = (uint32_t)oid->objectSequenceNumber;
2307 	ps.s_param = paramIndex;
2308 
2309 	switch (paramType) {
2310 		IMA_BOOL_VALUE *bp;
2311 		IMA_MIN_MAX_VALUE *mp;
2312 
2313 		case MIN_MAX_PARAM:
2314 			mp = (IMA_MIN_MAX_VALUE *)pProp;
2315 			ps.s_value.v_integer = mp->currentValue;
2316 			break;
2317 		case BOOL_PARAM:
2318 			bp = (IMA_BOOL_VALUE *)pProp;
2319 			ps.s_value.v_bool =
2320 			    (bp->currentValue == IMA_TRUE) ?
2321 			    B_TRUE : B_FALSE;
2322 			break;
2323 
2324 		default:
2325 			break;
2326 	}
2327 
2328 	if (ioctl(fd, ISCSI_PARAM_SET, &ps)) {
2329 		int tmpErrno = errno;
2330 		syslog(LOG_USER|LOG_DEBUG,
2331 		    "ISCSI_PARAM_SET ioctl failed, errno: %d", errno);
2332 		(void) close(fd);
2333 		switch (tmpErrno) {
2334 			case ENOTSUP :
2335 				return (IMA_ERROR_NOT_SUPPORTED);
2336 			default :
2337 				return (IMA_ERROR_UNEXPECTED_OS_ERROR);
2338 		}
2339 	}
2340 
2341 	(void) close(fd);
2342 	return (IMA_STATUS_SUCCESS);
2343 }
2344 
2345 static int
2346 prepare_discovery_entry(
2347     IMA_TARGET_ADDRESS discoveryAddress,
2348     entry_t *entry
2349 )
2350 {
2351 	(void) memset(entry, 0, sizeof (entry_t));
2352 	entry->e_vers = ISCSI_INTERFACE_VERSION;
2353 	entry->e_oid = ISCSI_OID_NOTSET;
2354 
2355 	if (discoveryAddress.hostnameIpAddress.id.ipAddress.ipv4Address ==
2356 	    IMA_FALSE) {
2357 		bcopy(discoveryAddress.hostnameIpAddress.id.ipAddress.ipAddress,
2358 		    entry->e_u.u_in6.s6_addr,
2359 		    sizeof (entry->e_u.u_in6.s6_addr));
2360 		entry->e_insize = sizeof (struct in6_addr);
2361 	} else {
2362 		bcopy(discoveryAddress.hostnameIpAddress.id.ipAddress.ipAddress,
2363 		    &entry->e_u.u_in4.s_addr,
2364 		    sizeof (entry->e_u.u_in4.s_addr));
2365 		entry->e_insize = sizeof (struct in_addr);
2366 	}
2367 
2368 	entry->e_port = discoveryAddress.portNumber;
2369 	entry->e_tpgt = 0;
2370 	return (DISC_ADDR_OK);
2371 }
2372 
2373 static IMA_STATUS configure_discovery_method(
2374     IMA_BOOL enable,
2375     iSCSIDiscoveryMethod_t method
2376 )
2377 {
2378 	int fd, status;
2379 
2380 	if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
2381 		syslog(LOG_USER|LOG_DEBUG, "Cannot open %s (%d)",
2382 		    ISCSI_DRIVER_DEVCTL, errno);
2383 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
2384 	}
2385 
2386 	if (enable == IMA_FALSE) {
2387 		if (ioctl(fd, ISCSI_DISCOVERY_CLEAR, &method)) {
2388 			status = errno;
2389 			(void) close(fd);
2390 			syslog(LOG_USER|LOG_DEBUG,
2391 			    "ISCSI_DISCOVERY_CLEAR ioctl failed, errno: %d",
2392 			    status);
2393 			if (status == EBUSY) {
2394 				return (IMA_ERROR_LU_IN_USE);
2395 			} else {
2396 				return (IMA_ERROR_UNEXPECTED_OS_ERROR);
2397 			}
2398 		}
2399 
2400 		(void) close(fd);
2401 		return (IMA_STATUS_SUCCESS);
2402 	} else {
2403 		/* Set the discovery method */
2404 		if (ioctl(fd, ISCSI_DISCOVERY_SET, &method)) {
2405 			(void) close(fd);
2406 			syslog(LOG_USER|LOG_DEBUG,
2407 			    "ISCSI_DISCOVERY_SET ioctl failed, errno: %d",
2408 			    errno);
2409 			return (IMA_ERROR_UNEXPECTED_OS_ERROR);
2410 		}
2411 
2412 		(void) close(fd);
2413 		return (IMA_STATUS_SUCCESS);
2414 	}
2415 }
2416 
2417 static IMA_STATUS get_target_oid_list(
2418     uint32_t targetListType,
2419     IMA_OID_LIST **ppList)
2420 {
2421 	int		    fd;
2422 	int		    i;
2423 	int		    target_list_size;
2424 	iscsi_target_list_t *idlp, tl_info;
2425 
2426 	if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
2427 		syslog(LOG_USER|LOG_DEBUG, "Cannot open %s (%d)",
2428 		    ISCSI_DRIVER_DEVCTL, errno);
2429 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
2430 	}
2431 
2432 	(void) memset(&tl_info, 0, sizeof (tl_info));
2433 	tl_info.tl_vers = ISCSI_INTERFACE_VERSION;
2434 	tl_info.tl_in_cnt = 0;
2435 	tl_info.tl_tgt_list_type = targetListType;
2436 
2437 	/*
2438 	 * Issue ioctl to obtain the number of targets.
2439 	 */
2440 	if (ioctl(fd, ISCSI_TARGET_OID_LIST_GET, &tl_info) != 0) {
2441 		(void) close(fd);
2442 		syslog(LOG_USER|LOG_DEBUG,
2443 		    "ISCSI_TARGET_OID_LIST_GET ioctl %d failed, errno: %d",
2444 		    targetListType, errno);
2445 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
2446 	}
2447 
2448 	target_list_size = sizeof (iscsi_target_list_t);
2449 	if (tl_info.tl_out_cnt > 1) {
2450 		target_list_size += (sizeof (uint32_t) *
2451 		    tl_info.tl_out_cnt - 1);
2452 	}
2453 
2454 	idlp = (iscsi_target_list_t *)calloc(1, target_list_size);
2455 	if (idlp == NULL) {
2456 		(void) close(fd);
2457 		return (IMA_ERROR_INSUFFICIENT_MEMORY);
2458 	}
2459 
2460 	idlp->tl_vers = ISCSI_INTERFACE_VERSION;
2461 	idlp->tl_in_cnt = tl_info.tl_out_cnt;
2462 	idlp->tl_tgt_list_type = targetListType;
2463 
2464 	/* Issue the same ioctl again to obtain the OIDs. */
2465 	if (ioctl(fd, ISCSI_TARGET_OID_LIST_GET, idlp) != 0) {
2466 		free(idlp);
2467 		(void) close(fd);
2468 		syslog(LOG_USER|LOG_DEBUG,
2469 		    "ISCSI_TARGET_OID_LIST_GET ioctl %d failed, errno: %d",
2470 		    targetListType, errno);
2471 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
2472 	}
2473 
2474 	*ppList = (IMA_OID_LIST *)calloc(1, sizeof (IMA_OID_LIST) +
2475 	    idlp->tl_out_cnt * sizeof (IMA_OID));
2476 	if (*ppList == NULL) {
2477 		free(idlp);
2478 		(void) close(fd);
2479 		return (IMA_ERROR_INSUFFICIENT_MEMORY);
2480 	}
2481 	(*ppList)->oidCount = idlp->tl_out_cnt;
2482 
2483 	for (i = 0; i < idlp->tl_out_cnt; i++) {
2484 
2485 		if (targetListType == ISCSI_STATIC_TGT_OID_LIST)
2486 			(*ppList)->oids[i].objectType =
2487 			    IMA_OBJECT_TYPE_STATIC_DISCOVERY_TARGET;
2488 		else
2489 			(*ppList)->oids[i].objectType = IMA_OBJECT_TYPE_TARGET;
2490 
2491 		(*ppList)->oids[i].ownerId = pluginOwnerId;
2492 		(*ppList)->oids[i].objectSequenceNumber = idlp->tl_oid_list[i];
2493 	}
2494 
2495 	free(idlp);
2496 	(void) close(fd);
2497 	return (IMA_STATUS_SUCCESS);
2498 }
2499 
2500 static IMA_STATUS get_target_lun_oid_list(
2501     IMA_OID * targetOid,
2502     iscsi_lun_list_t  **ppLunList)
2503 {
2504 	int			fd;
2505 	iscsi_lun_list_t	*illp, ll_info;
2506 	int			lun_list_size;
2507 
2508 	if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
2509 		syslog(LOG_USER|LOG_DEBUG, "Cannot open %s (%d)",
2510 		    ISCSI_DRIVER_DEVCTL, errno);
2511 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
2512 	}
2513 
2514 	(void) memset(&ll_info, 0, sizeof (ll_info));
2515 	ll_info.ll_vers = ISCSI_INTERFACE_VERSION;
2516 	if (targetOid == NULL) {
2517 		/* get lun oid list for all targets */
2518 		ll_info.ll_all_tgts = B_TRUE;
2519 	} else {
2520 		/* get lun oid list for single target */
2521 		ll_info.ll_all_tgts = B_FALSE;
2522 		ll_info.ll_tgt_oid = (uint32_t)targetOid->objectSequenceNumber;
2523 	}
2524 	ll_info.ll_in_cnt = 0;
2525 
2526 	/*
2527 	 * Issue ioctl to obtain the number of target LUNs.
2528 	 */
2529 	if (ioctl(fd, ISCSI_LUN_OID_LIST_GET, &ll_info) != 0) {
2530 		(void) close(fd);
2531 		syslog(LOG_USER|LOG_DEBUG,
2532 		    "ISCSI_LUN_LIST_GET ioctl failed, errno: %d", errno);
2533 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
2534 	}
2535 
2536 	lun_list_size = sizeof (iscsi_lun_list_t);
2537 	if (ll_info.ll_out_cnt > 1) {
2538 		lun_list_size += (sizeof (iscsi_if_lun_t) *
2539 		    (ll_info.ll_out_cnt - 1));
2540 	}
2541 
2542 	illp = (iscsi_lun_list_t *)calloc(1, lun_list_size);
2543 	if (illp == NULL) {
2544 		(void) close(fd);
2545 		return (IMA_ERROR_INSUFFICIENT_MEMORY);
2546 	}
2547 	illp->ll_vers = ISCSI_INTERFACE_VERSION;
2548 	illp->ll_all_tgts = ll_info.ll_all_tgts;
2549 	illp->ll_tgt_oid = ll_info.ll_tgt_oid;
2550 	illp->ll_in_cnt = ll_info.ll_out_cnt;
2551 
2552 	/* Issue the same ioctl again to get the target LUN list */
2553 	if (ioctl(fd, ISCSI_LUN_OID_LIST_GET, illp) != 0) {
2554 		free(illp);
2555 		(void) close(fd);
2556 		syslog(LOG_USER|LOG_DEBUG,
2557 		    "ISCSI_LUN_LIST_GET ioctl failed, errno: %d", errno);
2558 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
2559 	}
2560 
2561 	*ppLunList = illp;
2562 
2563 	(void) close(fd);
2564 	return (IMA_STATUS_SUCCESS);
2565 }
2566 
2567 
2568 /* A helper function to set authentication method. */
2569 static IMA_STATUS
2570 setAuthMethods(
2571     IMA_OID oid,
2572     IMA_UINT *pMethodCount,
2573     const IMA_AUTHMETHOD *pMethodList
2574 )
2575 {
2576 	int fd;
2577 	int i;
2578 	iscsi_auth_props_t auth;
2579 
2580 	if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
2581 		syslog(LOG_USER|LOG_DEBUG, "Cannot open %s (%d)",
2582 		    ISCSI_DRIVER_DEVCTL, errno);
2583 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
2584 	}
2585 	(void) memset(&auth, 0, sizeof (iscsi_auth_props_t));
2586 	auth.a_vers = ISCSI_INTERFACE_VERSION;
2587 	auth.a_oid = (uint32_t)oid.objectSequenceNumber;
2588 	/* First do a get because other data fields may exist */
2589 	if (ioctl(fd, ISCSI_AUTH_GET, &auth) != 0) {
2590 		/* EMPTY */
2591 		/* It is fine if there is no other data fields. */
2592 	}
2593 	auth.a_auth_method = authMethodNone;
2594 
2595 	for (i = 0; i < *pMethodCount; i++) {
2596 		switch (pMethodList[i]) {
2597 			case IMA_AUTHMETHOD_CHAP:
2598 				auth.a_auth_method |= authMethodCHAP;
2599 				break;
2600 			default:
2601 				break;
2602 		}
2603 	}
2604 
2605 	if (ioctl(fd, ISCSI_AUTH_SET, &auth) != 0) {
2606 		syslog(LOG_USER|LOG_DEBUG,
2607 		    "ISCSI_AUTH_SET failed, errno: %d", errno);
2608 		(void) close(fd);
2609 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
2610 	}
2611 
2612 	(void) close(fd);
2613 	return (IMA_STATUS_SUCCESS);
2614 }
2615 
2616 /* A helper function to get authentication method. */
2617 static IMA_STATUS
2618 getAuthMethods(
2619     IMA_OID oid,
2620     IMA_UINT	*pMethodCount,
2621     IMA_AUTHMETHOD *pMethodList
2622 )
2623 {
2624 	int fd, i;
2625 	iscsi_auth_props_t auth;
2626 
2627 	if (pMethodList == NULL) {
2628 		*pMethodCount = 0;
2629 		return (IMA_STATUS_SUCCESS);
2630 	}
2631 
2632 	if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
2633 		syslog(LOG_USER|LOG_DEBUG, "Cannot open %s (%d)",
2634 		    ISCSI_DRIVER_DEVCTL, errno);
2635 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
2636 	}
2637 
2638 	(void) memset(&auth, 0, sizeof (iscsi_auth_props_t));
2639 	auth.a_vers = ISCSI_INTERFACE_VERSION;
2640 	auth.a_oid = (uint32_t)oid.objectSequenceNumber;
2641 
2642 	if (ioctl(fd, ISCSI_AUTH_GET, &auth) != 0) {
2643 		syslog(LOG_USER|LOG_DEBUG,
2644 		    "ISCSI_AUTH_GET failed, errno: %d", errno);
2645 		(void) close(fd);
2646 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
2647 	}
2648 
2649 	i = 0;
2650 	if (auth.a_auth_method == IMA_AUTHMETHOD_NONE) {
2651 		pMethodList[i++] = IMA_AUTHMETHOD_NONE;
2652 	} else if (auth.a_auth_method & authMethodCHAP) {
2653 		pMethodList[i++] = IMA_AUTHMETHOD_CHAP;
2654 	}
2655 	*pMethodCount = i;
2656 
2657 	(void) close(fd);
2658 	return (IMA_STATUS_SUCCESS);
2659 }
2660 
2661 IMA_API IMA_STATUS IMA_GetPhbaOidList(
2662 		IMA_OID_LIST **ppList
2663 )
2664 {
2665 	*ppList = (IMA_OID_LIST*)calloc(1, sizeof (IMA_OID_LIST));
2666 	if (*ppList == NULL) {
2667 		return (IMA_ERROR_INSUFFICIENT_MEMORY);
2668 	}
2669 	(*ppList)->oidCount = 0;
2670 	return (IMA_STATUS_SUCCESS);
2671 }
2672 
2673 /* ARGSUSED */
2674 IMA_API IMA_STATUS IMA_GetPhbaProperties(
2675 		IMA_OID phbaOid,
2676 		IMA_PHBA_PROPERTIES *pProps
2677 )
2678 {
2679 	return (IMA_ERROR_OBJECT_NOT_FOUND);
2680 }
2681 
2682 /* ARGSUSED */
2683 IMA_API IMA_STATUS IMA_GetPhbaStatus(
2684 		IMA_OID phbaOid,
2685 		IMA_PHBA_STATUS *pStatus
2686 )
2687 {
2688 	return (IMA_ERROR_OBJECT_NOT_FOUND);
2689 }
2690 
2691 /* ARGSUSED */
2692 IMA_API IMA_STATUS IMA_GetPhbaDownloadProperties(
2693 		IMA_OID phbaOid,
2694 		IMA_PHBA_DOWNLOAD_PROPERTIES *pProps
2695 )
2696 {
2697 	return (IMA_ERROR_OBJECT_NOT_FOUND);
2698 }
2699 
2700 /* ARGSUSED */
2701 IMA_API IMA_STATUS IMA_IsPhbaDownloadFile(
2702 		IMA_OID phbaOid,
2703 		const IMA_WCHAR *pFileName,
2704 		IMA_PHBA_DOWNLOAD_IMAGE_PROPERTIES *pProps
2705 )
2706 {
2707 	return (IMA_ERROR_OBJECT_NOT_FOUND);
2708 }
2709 
2710 /* ARGSUSED */
2711 IMA_API IMA_STATUS IMA_PhbaDownload(
2712 		IMA_OID phbaOid,
2713 		IMA_PHBA_DOWNLOAD_IMAGE_TYPE imageType,
2714 		const IMA_WCHAR *pFileName
2715 )
2716 {
2717 	return (IMA_ERROR_OBJECT_NOT_FOUND);
2718 }
2719 
2720 IMA_API IMA_STATUS IMA_GetPnpOidList(
2721 		IMA_OID pnpOid,
2722 		IMA_OID_LIST **ppList
2723 )
2724 {
2725 	/*
2726 	 * Always return the same object ID for the pnp as the spec
2727 	 * states that this function will always return a list of at least
2728 	 * one element
2729 	 */
2730 	pnpOid.objectType = IMA_OBJECT_TYPE_PNP;
2731 	pnpOid.ownerId = pluginOwnerId;
2732 	pnpOid.objectSequenceNumber = ISCSI_INITIATOR_OID;
2733 
2734 	*ppList = (IMA_OID_LIST*)calloc(1, sizeof (IMA_OID_LIST) +
2735 	    (1* sizeof (IMA_OID)));
2736 
2737 	if (*ppList == NULL) {
2738 		return (IMA_ERROR_INSUFFICIENT_MEMORY);
2739 	}
2740 
2741 	(*ppList)->oidCount = 1;
2742 	(void) memcpy(&(*ppList)->oids[0], &pnpOid, sizeof (pnpOid));
2743 	return (IMA_STATUS_SUCCESS);
2744 }
2745 
2746 /* ARGSUSED */
2747 IMA_API IMA_STATUS IMA_GetPnpProperties(
2748 		IMA_OID pnpOid,
2749 		IMA_PNP_PROPERTIES *pProps
2750 )
2751 {
2752 	return (IMA_ERROR_OBJECT_NOT_FOUND);
2753 }
2754 
2755 /* ARGSUSED */
2756 IMA_API IMA_STATUS IMA_GetPnpStatistics(
2757 		IMA_OID pnpOid,
2758 		IMA_PNP_STATISTICS *pStats
2759 )
2760 {
2761 	return (IMA_ERROR_OBJECT_NOT_FOUND);
2762 }
2763 
2764 /* ARGSUSED */
2765 IMA_API IMA_STATUS IMA_GetIpProperties(
2766 		IMA_OID oid,
2767 		IMA_IP_PROPERTIES *pProps
2768 )
2769 {
2770 	return (IMA_ERROR_OBJECT_NOT_FOUND);
2771 }
2772 
2773 /* ARGSUSED */
2774 IMA_API IMA_STATUS IMA_SetDefaultGateway(
2775 		IMA_OID oid,
2776 		IMA_IP_ADDRESS defaultGateway
2777 )
2778 {
2779 	return (IMA_ERROR_OBJECT_NOT_FOUND);
2780 }
2781 
2782 /* ARGSUSED */
2783 IMA_API IMA_STATUS IMA_SetDnsServerAddress(
2784 		IMA_OID oid,
2785 		const IMA_IP_ADDRESS *pPrimaryDnsServerAddress,
2786 		const IMA_IP_ADDRESS *pAlternateDnsServerAddress
2787 )
2788 {
2789 	return (IMA_ERROR_OBJECT_NOT_FOUND);
2790 }
2791 
2792 /* ARGSUSED */
2793 IMA_API IMA_STATUS IMA_SetSubnetMask(
2794 		IMA_OID oid,
2795 		IMA_IP_ADDRESS subnetMask
2796 )
2797 {
2798 	return (IMA_ERROR_OBJECT_NOT_FOUND);
2799 }
2800 
2801 /* ARGSUSED */
2802 IMA_API IMA_STATUS IMA_SetIpConfigMethod(
2803 		IMA_OID oid,
2804 		IMA_BOOL enableDhcpIpConfiguration
2805 )
2806 {
2807 	return (IMA_ERROR_OBJECT_NOT_FOUND);
2808 }
2809 
2810 IMA_API IMA_STATUS IMA_RegisterForObjectPropertyChanges(
2811 		IMA_OBJECT_PROPERTY_FN pClientFn
2812 )
2813 {
2814 	pObjectPropertyCallback = pClientFn;
2815 	return (IMA_STATUS_SUCCESS);
2816 }
2817 
2818 /* ARGSUSED */
2819 IMA_API IMA_STATUS IMA_DeregisterForObjectPropertyChanges(
2820 		IMA_OBJECT_PROPERTY_FN pClientFn
2821 )
2822 {
2823 	return (IMA_STATUS_SUCCESS);
2824 }
2825 
2826 IMA_API IMA_STATUS IMA_RegisterForObjectVisibilityChanges(
2827 		IMA_OBJECT_VISIBILITY_FN pClientFn
2828 )
2829 {
2830 	pObjectVisibilityCallback = pClientFn;
2831 	return (IMA_STATUS_SUCCESS);
2832 }
2833 
2834 /* ARGSUSED */
2835 IMA_API IMA_STATUS IMA_DeregisterForObjectVisibilityChanges(
2836 		IMA_OBJECT_VISIBILITY_FN pClientFn
2837 )
2838 {
2839 	return (IMA_STATUS_SUCCESS);
2840 }
2841 
2842 /* ARGSUSED */
2843 IMA_API IMA_STATUS IMA_GetNetworkPortStatus(
2844 		IMA_OID portOid,
2845 		IMA_NETWORK_PORT_STATUS *pStaus
2846 )
2847 {
2848 	return (IMA_ERROR_OBJECT_NOT_FOUND);
2849 }
2850 
2851 /* ARGSUSED */
2852 IMA_API IMA_STATUS IMA_GetNetworkPortalOidList(
2853 		IMA_OID pnpOid,
2854 		IMA_OID_LIST **ppList
2855 )
2856 {
2857 	return (IMA_ERROR_OBJECT_NOT_FOUND);
2858 }
2859 
2860 /* ARGSUSED */
2861 IMA_API IMA_STATUS IMA_GetNetworkPortalProperties(
2862 		IMA_OID networkPortalOid,
2863 		IMA_NETWORK_PORTAL_PROPERTIES *pProps
2864 )
2865 {
2866 	return (IMA_ERROR_OBJECT_NOT_FOUND);
2867 }
2868 
2869 /* ARGSUSED */
2870 IMA_API IMA_STATUS IMA_SetNetworkPortalIpAddress(
2871 		IMA_OID networkPortalOid,
2872 		const IMA_IP_ADDRESS NewIpAddress
2873 )
2874 {
2875 	return (IMA_ERROR_OBJECT_NOT_FOUND);
2876 }
2877 
2878 /* ARGSUSED */
2879 IMA_API IMA_STATUS IMA_RemoveStaleData(
2880 		IMA_OID lhbaOid
2881 )
2882 {
2883 	return (IMA_ERROR_NOT_SUPPORTED);
2884 }
2885 
2886 /* ARGSUSED */
2887 IMA_API IMA_STATUS IMA_GetIpsecProperties(
2888 		IMA_OID oid,
2889 		IMA_IPSEC_PROPERTIES *pProps
2890 )
2891 {
2892 	pProps->ipsecSupported = IMA_TRUE;
2893 	pProps->implementedInHardware = IMA_FALSE;
2894 	pProps->implementedInSoftware = IMA_TRUE;
2895 
2896 	return (IMA_STATUS_SUCCESS);
2897 }
2898 
2899 /* ARGSUSED */
2900 IMA_API IMA_STATUS IMA_GetLhbaProperties(
2901 		IMA_OID lhbaOid,
2902 		IMA_LHBA_PROPERTIES *pProps
2903 )
2904 {
2905 
2906 	if (pProps == NULL) {
2907 		return (IMA_ERROR_INVALID_PARAMETER);
2908 	}
2909 
2910 	if (lhbaObjectId.objectSequenceNumber != ISCSI_INITIATOR_OID) {
2911 		return (IMA_ERROR_OBJECT_NOT_FOUND);
2912 	}
2913 
2914 	(void) memset(pProps, 0, sizeof (IMA_LHBA_PROPERTIES));
2915 	(void) mbstowcs(pProps->osDeviceName, OS_DEVICE_NAME,
2916 	    OS_DEVICE_NAME_LEN);
2917 	pProps->luExposingSupported = IMA_FALSE;
2918 	pProps->isDestroyable = IMA_FALSE;
2919 	pProps->staleDataRemovable = IMA_FALSE;
2920 	pProps->staleDataSize = 0;
2921 	pProps->initiatorAuthMethodsSettable = IMA_TRUE;
2922 	pProps->targetAuthMethodsSettable = IMA_FALSE;
2923 
2924 	return (IMA_STATUS_SUCCESS);
2925 }
2926 
2927 IMA_API IMA_STATUS IMA_GetLnpOidList(
2928 		IMA_OID_LIST **ppList
2929 )
2930 {
2931 	*ppList = (IMA_OID_LIST *) calloc(1, (sizeof (IMA_OID_LIST)));
2932 	if (*ppList == NULL) {
2933 		return (IMA_ERROR_INSUFFICIENT_MEMORY);
2934 	}
2935 	(*ppList)->oidCount = 0;
2936 
2937 	return (IMA_STATUS_SUCCESS);
2938 }
2939 
2940 /* ARGSUSED */
2941 IMA_API IMA_STATUS IMA_GetLnpProperties(
2942 		IMA_OID lnpOid,
2943 		IMA_LNP_PROPERTIES *pProps
2944 )
2945 {
2946 	return (IMA_ERROR_OBJECT_NOT_FOUND);
2947 }
2948 
2949 #define	IMA_DISK_DEVICE_NAME_PREFIX	"/dev/rdsk/"
2950 #define	IMA_TAPE_DEVICE_NAME_PREFIX	"/dev/rmt/"
2951 static int
2952 get_lun_devlink(di_devlink_t link, void *osDeviceName)
2953 {
2954 	if ((strncmp(IMA_DISK_DEVICE_NAME_PREFIX, di_devlink_path(link),
2955 	    strlen(IMA_DISK_DEVICE_NAME_PREFIX)) == 0) ||
2956 	    (strncmp(IMA_TAPE_DEVICE_NAME_PREFIX, di_devlink_path(link),
2957 	    strlen(IMA_TAPE_DEVICE_NAME_PREFIX)) == 0)) {
2958 		(void) mbstowcs((wchar_t *)osDeviceName, di_devlink_path(link),
2959 		    MAXPATHLEN);
2960 		return (DI_WALK_TERMINATE);
2961 	}
2962 
2963 	return (DI_WALK_CONTINUE);
2964 }
2965 
2966 /* ARGSUSED */
2967 IMA_API IMA_STATUS IMA_GetPluginProperties(
2968 	IMA_OID pluginOid,
2969 	IMA_PLUGIN_PROPERTIES *pProps
2970 )
2971 {
2972 	pProps->supportedImaVersion = 1;
2973 	libSwprintf(pProps->vendor, L"%ls", LIBRARY_PROPERTY_VENDOR);
2974 	libSwprintf(pProps->implementationVersion, L"%ls",
2975 	    LIBRARY_PROPERTY_IMPLEMENTATION_VERSION);
2976 	libSwprintf(pProps->fileName, L"%ls", LIBRARY_FILE_NAME);
2977 	GetBuildTime(&(pProps->buildTime));
2978 	pProps->lhbasCanBeCreatedAndDestroyed = IMA_FALSE;
2979 	return (IMA_STATUS_SUCCESS);
2980 }
2981 
2982 IMA_STATUS getDiscoveryAddressPropertiesList(
2983     SUN_IMA_DISC_ADDR_PROP_LIST **ppList
2984 )
2985 {
2986 	int		    fd;
2987 	int		    i;
2988 	int		    discovery_addr_list_size;
2989 	iscsi_addr_list_t   *ialp, al_info;
2990 
2991 	if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
2992 		syslog(LOG_USER|LOG_DEBUG, "Cannot open %s (%d)",
2993 		    ISCSI_DRIVER_DEVCTL, errno);
2994 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
2995 	}
2996 
2997 	(void) memset(&al_info, 0, sizeof (al_info));
2998 	al_info.al_vers = ISCSI_INTERFACE_VERSION;
2999 	al_info.al_in_cnt = 0;
3000 
3001 	/*
3002 	 * Issue ISCSI_DISCOVERY_ADDR_LIST_GET ioctl to obtain the number of
3003 	 * discovery addresses.
3004 	 */
3005 	if (ioctl(fd, ISCSI_DISCOVERY_ADDR_LIST_GET, &al_info) != 0) {
3006 		(void) close(fd);
3007 		syslog(LOG_USER|LOG_DEBUG,
3008 		    "ISCSI_DISCOVERY_ADDR_LIST_GET ioctl failed, errno: %d",
3009 		    errno);
3010 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
3011 	}
3012 
3013 	discovery_addr_list_size = sizeof (iscsi_addr_list_t);
3014 	if (al_info.al_out_cnt > 1) {
3015 		discovery_addr_list_size += (sizeof (iscsi_addr_t) *
3016 		    al_info.al_out_cnt - 1);
3017 	}
3018 
3019 	ialp = (iscsi_addr_list_t *)calloc(1, discovery_addr_list_size);
3020 	if (ialp == NULL) {
3021 		(void) close(fd);
3022 		return (IMA_ERROR_INSUFFICIENT_MEMORY);
3023 	}
3024 	ialp->al_vers = ISCSI_INTERFACE_VERSION;
3025 	ialp->al_in_cnt = al_info.al_out_cnt;
3026 
3027 	/*
3028 	 * Issue ISCSI_DISCOVERY_ADDR_LIST_GET ioctl again to obtain the
3029 	 * discovery addresses.
3030 	 */
3031 	if (ioctl(fd, ISCSI_DISCOVERY_ADDR_LIST_GET, ialp) != 0) {
3032 		free(ialp);
3033 		(void) close(fd);
3034 		syslog(LOG_USER|LOG_DEBUG,
3035 		    "ISCSI_DISCOVERY_ADDR_LIST_GET ioctl failed, errno: %d",
3036 		    errno);
3037 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
3038 	}
3039 
3040 	*ppList = (SUN_IMA_DISC_ADDR_PROP_LIST *)
3041 	    calloc(1, sizeof (SUN_IMA_DISC_ADDR_PROP_LIST) +
3042 	    ialp->al_out_cnt * sizeof (IMA_DISCOVERY_ADDRESS_PROPERTIES));
3043 
3044 	if (*ppList == NULL) {
3045 		free(ialp);
3046 		(void) close(fd);
3047 		return (IMA_ERROR_INSUFFICIENT_MEMORY);
3048 	}
3049 	(*ppList)->discAddrCount = ialp->al_out_cnt;
3050 
3051 	for (i = 0; i < ialp->al_out_cnt; i++) {
3052 		if (ialp->al_addrs[i].a_addr.i_insize ==
3053 		    sizeof (struct in_addr)) {
3054 			(*ppList)->props[i].discoveryAddress.hostnameIpAddress.
3055 			id.ipAddress.ipv4Address = IMA_TRUE;
3056 		} else if (ialp->al_addrs[i].a_addr.i_insize ==
3057 		    sizeof (struct in6_addr)) {
3058 			(*ppList)->props[i].discoveryAddress.
3059 			hostnameIpAddress.id.ipAddress.ipv4Address = IMA_FALSE;
3060 		} else {
3061 			/* Should not happen */
3062 			syslog(LOG_USER|LOG_DEBUG,
3063 			"ISCSI_STATIC_GET returned bad address");
3064 			return (IMA_ERROR_UNEXPECTED_OS_ERROR);
3065 		}
3066 
3067 		bcopy(&ialp->al_addrs[i].a_addr.i_addr,	(*ppList)->props[i].
3068 		    discoveryAddress.hostnameIpAddress.id.ipAddress.ipAddress,
3069 		    sizeof ((*ppList)->props[i].discoveryAddress.
3070 		    hostnameIpAddress.id.ipAddress.ipAddress));
3071 
3072 		(*ppList)->props[i].discoveryAddress.portNumber =
3073 		    ialp->al_addrs[i].a_port;
3074 	}
3075 
3076 	free(ialp);
3077 	(void) close(fd);
3078 	return (IMA_STATUS_SUCCESS);
3079 }
3080 
3081 
3082 /* ARGSUSED */
3083 IMA_STATUS sendTargets(
3084     IMA_TARGET_ADDRESS address,
3085     SUN_IMA_DISC_ADDRESS_KEY_PROPERTIES **ppList
3086 )
3087 {
3088 	char	*colonPos;
3089 	char	discAddrStr[SUN_IMA_IP_ADDRESS_LEN];
3090 	int	fd;
3091 	int	ctr;
3092 	int	stl_sz;
3093 	iscsi_sendtgts_list_t	*stl_hdr = NULL;
3094 	IMA_BOOL		retry = IMA_TRUE;
3095 
3096 #define	SENDTGTS_DEFAULT_NUM_TARGETS	10
3097 
3098 	stl_sz = sizeof (*stl_hdr) + ((SENDTGTS_DEFAULT_NUM_TARGETS - 1) *
3099 	    sizeof (iscsi_sendtgts_entry_t));
3100 	stl_hdr = (iscsi_sendtgts_list_t *)calloc(1, stl_sz);
3101 	if (stl_hdr == NULL) {
3102 		return (IMA_ERROR_INSUFFICIENT_MEMORY);
3103 	}
3104 	stl_hdr->stl_entry.e_vers = ISCSI_INTERFACE_VERSION;
3105 	stl_hdr->stl_in_cnt = SENDTGTS_DEFAULT_NUM_TARGETS;
3106 
3107 	colonPos = strchr(discAddrStr, ':');
3108 	if (colonPos == NULL) {
3109 		/* IPv4 */
3110 		stl_hdr->stl_entry.e_insize = sizeof (struct in_addr);
3111 	} else {
3112 		/* IPv6 */
3113 		stl_hdr->stl_entry.e_insize = sizeof (struct in6_addr);
3114 	}
3115 
3116 
3117 	bcopy(address.hostnameIpAddress.id.ipAddress.ipAddress,
3118 	    &stl_hdr->stl_entry.e_u,
3119 	    sizeof (address.hostnameIpAddress.id.ipAddress.ipAddress));
3120 	stl_hdr->stl_entry.e_port = address.portNumber;
3121 
3122 	if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
3123 		syslog(LOG_USER|LOG_DEBUG, "Cannot open %s (%d)",
3124 		    ISCSI_DRIVER_DEVCTL, errno);
3125 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
3126 	}
3127 
3128 retry_sendtgts:
3129 	/*
3130 	 * Issue ioctl to obtain the SendTargets list
3131 	 */
3132 	if (ioctl(fd, ISCSI_SENDTGTS_GET, stl_hdr) != 0) {
3133 		syslog(LOG_USER|LOG_DEBUG,
3134 		    "ISCSI_SENDTGTS_GET ioctl failed, errno: %d", errno);
3135 		(void) close(fd);
3136 		free(stl_hdr);
3137 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
3138 	}
3139 
3140 	/* check if all targets received */
3141 	if (stl_hdr->stl_in_cnt < stl_hdr->stl_out_cnt) {
3142 		if (retry == IMA_TRUE) {
3143 			stl_sz = sizeof (*stl_hdr) +
3144 			    ((stl_hdr->stl_out_cnt - 1) *
3145 			    sizeof (iscsi_sendtgts_entry_t));
3146 			stl_hdr = (iscsi_sendtgts_list_t *)
3147 			    realloc(stl_hdr, stl_sz);
3148 			if (stl_hdr == NULL) {
3149 				(void) close(fd);
3150 				return (IMA_ERROR_INSUFFICIENT_MEMORY);
3151 			}
3152 			stl_hdr->stl_in_cnt = stl_hdr->stl_out_cnt;
3153 			retry = IMA_FALSE;
3154 			goto retry_sendtgts;
3155 		} else {
3156 			/*
3157 			 * don't retry after 2 attempts.  The target list
3158 			 * shouldn't continue to growing. Justs continue
3159 			 * on and display what was found.
3160 			 */
3161 			syslog(LOG_USER|LOG_DEBUG,
3162 			    "ISCSI_SENDTGTS_GET overflow: "
3163 			    "failed to obtain all targets");
3164 			stl_hdr->stl_out_cnt = stl_hdr->stl_in_cnt;
3165 		}
3166 	}
3167 
3168 	(void) close(fd);
3169 
3170 	/* allocate for caller return buffer */
3171 	*ppList = (SUN_IMA_DISC_ADDRESS_KEY_PROPERTIES *)calloc(1,
3172 	    sizeof (SUN_IMA_DISC_ADDRESS_KEY_PROPERTIES) +
3173 	    stl_hdr->stl_out_cnt * sizeof (SUN_IMA_DISC_ADDRESS_KEY));
3174 	if (*ppList == NULL) {
3175 		free(stl_hdr);
3176 		return (IMA_ERROR_INSUFFICIENT_MEMORY);
3177 	}
3178 
3179 	(*ppList)->keyCount = stl_hdr->stl_out_cnt;
3180 
3181 	for (ctr = 0; ctr < stl_hdr->stl_out_cnt; ctr++) {
3182 		(void) mbstowcs((*ppList)->keys[ctr].name,
3183 		    (char *)stl_hdr->stl_list[ctr].ste_name,
3184 		    IMA_NODE_NAME_LEN);
3185 
3186 		(*ppList)->keys[ctr].tpgt = stl_hdr->stl_list[ctr].ste_tpgt;
3187 
3188 		(*ppList)->keys[ctr].address.portNumber =
3189 		    stl_hdr->stl_list[ctr].ste_ipaddr.a_port;
3190 
3191 		if (stl_hdr->stl_list[ctr].ste_ipaddr.a_addr.i_insize ==
3192 		    sizeof (struct in_addr)) {
3193 			(*ppList)->keys[ctr].address.ipAddress.ipv4Address =
3194 			    IMA_TRUE;
3195 		} else if (stl_hdr->stl_list[ctr].ste_ipaddr.a_addr.i_insize ==
3196 		    sizeof (struct in6_addr)) {
3197 			(*ppList)->keys[ctr].address.ipAddress.ipv4Address =
3198 			    IMA_FALSE;
3199 		} else {
3200 			free(stl_hdr);
3201 			syslog(LOG_USER|LOG_DEBUG,
3202 			"ISCSI_STATIC_GET returned bad address");
3203 			return (IMA_ERROR_UNEXPECTED_OS_ERROR);
3204 		}
3205 
3206 
3207 		(void) memcpy(&(*ppList)->keys[ctr].address.ipAddress.ipAddress,
3208 		    &(stl_hdr->stl_list[ctr].ste_ipaddr.a_addr.i_addr),
3209 		    stl_hdr->stl_list[ctr].ste_ipaddr.a_addr.i_insize);
3210 	}
3211 	free(stl_hdr);
3212 
3213 	return (IMA_STATUS_SUCCESS);
3214 }
3215 
3216 IMA_API IMA_STATUS SUN_IMA_GetTunableProperties(
3217 	IMA_OID oid,
3218 	ISCSI_TUNABLE_PARAM *param)
3219 {
3220 	int fd;
3221 	iscsi_tunable_object_t pg;
3222 
3223 	if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
3224 		syslog(LOG_USER|LOG_DEBUG, "Cannot open %s (%d)",
3225 		    ISCSI_DRIVER_DEVCTL, errno);
3226 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
3227 	}
3228 	(void) memset(&pg, 0, sizeof (iscsi_tunable_object_t));
3229 	pg.t_param = param->tunable_objectType;
3230 	pg.t_oid = (uint32_t)oid.objectSequenceNumber;
3231 	if (ioctl(fd, ISCSI_TUNABLE_PARAM_GET, &pg) == -1) {
3232 		syslog(LOG_USER|LOG_DEBUG,
3233 		    "ISCSI_TUNABLE_PARAM_GET ioctl failed, errno: %d", errno);
3234 		(void) close(fd);
3235 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
3236 	} else {
3237 		long long value;
3238 		char tmp[MAX_LONG_LONG_STRING_LEN], *ptr = NULL;
3239 		if (pg.t_set == B_FALSE) {
3240 			/* default value */
3241 			(void) close(fd);
3242 			return (IMA_STATUS_SUCCESS);
3243 		}
3244 		value = (long long)pg.t_value.v_integer;
3245 		ptr = lltostr(value, tmp);
3246 		if ((ptr != NULL) && (ptr != tmp)) {
3247 			*(tmp + 1) = '\0';
3248 		} else {
3249 			(void) close(fd);
3250 			return (IMA_ERROR_UNEXPECTED_OS_ERROR);
3251 		}
3252 		switch (param->tunable_objectType) {
3253 			case ISCSI_RX_TIMEOUT_VALUE:
3254 				(void) strlcpy(param->tunable_objectValue,
3255 				    ptr, strlen(ptr));
3256 				break;
3257 			case ISCSI_CONN_DEFAULT_LOGIN_MAX:
3258 				(void) strlcpy(param->tunable_objectValue,
3259 				    ptr, strlen(ptr));
3260 				break;
3261 			case ISCSI_LOGIN_POLLING_DELAY:
3262 				(void) strlcpy(param->tunable_objectValue,
3263 				    ptr, strlen(ptr));
3264 				break;
3265 			default:
3266 				break;
3267 		}
3268 	}
3269 	(void) close(fd);
3270 	return (IMA_STATUS_SUCCESS);
3271 }
3272 
3273 IMA_API IMA_STATUS SUN_IMA_SetTunableProperties(
3274 	IMA_OID oid,
3275 	ISCSI_TUNABLE_PARAM *param)
3276 {
3277 	int fd;
3278 	iscsi_tunable_object_t	ps;
3279 
3280 	if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
3281 		syslog(LOG_USER|LOG_DEBUG, "Cannot open %s (%d)",
3282 		    ISCSI_DRIVER_DEVCTL, errno);
3283 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
3284 	}
3285 
3286 	(void) memset(&ps, 0, sizeof (iscsi_tunable_object_t));
3287 	ps.t_oid = oid.objectSequenceNumber;
3288 	ps.t_param = param->tunable_objectType;
3289 	switch (param->tunable_objectType) {
3290 		long tmp;
3291 		case ISCSI_RX_TIMEOUT_VALUE:
3292 		case ISCSI_CONN_DEFAULT_LOGIN_MAX:
3293 		case ISCSI_LOGIN_POLLING_DELAY:
3294 			tmp = strtol(param->tunable_objectValue,
3295 			    NULL, 10);
3296 			if (((tmp == 0) && (errno == EINVAL)) ||
3297 			    ((tmp == LONG_MAX) && (errno == ERANGE)) ||
3298 			    ((tmp == LONG_MIN) && (errno == ERANGE))) {
3299 				(void) close(fd);
3300 				return (IMA_ERROR_INVALID_PARAMETER);
3301 			}
3302 			ps.t_value.v_integer = (uint32_t)tmp;
3303 			break;
3304 		default:
3305 			break;
3306 	}
3307 	if (ioctl(fd, ISCSI_TUNABLE_PARAM_SET, &ps)) {
3308 		int tmpErrno = errno;
3309 		syslog(LOG_USER|LOG_DEBUG,
3310 		    "ISCSI_TUNABLE_PARAM_SET ioctl failed, errno: %d", errno);
3311 		(void) close(fd);
3312 		switch (tmpErrno) {
3313 			case ENOTSUP :
3314 				return (IMA_ERROR_NOT_SUPPORTED);
3315 			default:
3316 				return (IMA_ERROR_UNEXPECTED_OS_ERROR);
3317 		}
3318 	}
3319 	(void) close(fd);
3320 	return (IMA_STATUS_SUCCESS);
3321 }
3322