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