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