1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2012 Milan Jurik. All rights reserved.
24 */
25
26#include <stdlib.h>
27#include <stdio.h>
28#include <wchar.h>
29#include <strings.h>
30#include <sys/types.h>
31#include <sys/stat.h>
32#include <fcntl.h>
33#include <unistd.h>
34#include <libintl.h>
35#include <errno.h>
36#include <string.h>
37#include <assert.h>
38#include <libnvpair.h>
39#include <pthread.h>
40#include <syslog.h>
41#include <libstmf.h>
42#include <netinet/in.h>
43#include <inttypes.h>
44#include <store.h>
45#include <locale.h>
46#include <math.h>
47#include <libstmf_impl.h>
48#include <sys/stmf_ioctl.h>
49#include <sys/stmf_sbd_ioctl.h>
50#include <sys/pppt_ioctl.h>
51#include <macros.h>
52
53#define	STMF_PATH    "/devices/pseudo/stmf@0:admin"
54#define	SBD_PATH    "/devices/pseudo/stmf_sbd@0:admin"
55#define	PPPT_PATH    "/devices/pseudo/pppt@0:pppt"
56
57#define	EUI "eui."
58#define	WWN "wwn."
59#define	IQN "iqn."
60#define	LU_ASCII_GUID_SIZE 32
61#define	LU_GUID_SIZE 16
62#define	OUI_ASCII_SIZE 6
63#define	HOST_ID_ASCII_SIZE 8
64#define	OUI_SIZE 3
65#define	HOST_ID_SIZE 4
66#define	IDENT_LENGTH_BYTE 3
67
68/* various initial allocation values */
69#define	ALLOC_LU		8192
70#define	ALLOC_TARGET_PORT	2048
71#define	ALLOC_PROVIDER		64
72#define	ALLOC_GROUP		2048
73#define	ALLOC_SESSION		2048
74#define	ALLOC_VE		256
75#define	ALLOC_PP_DATA_SIZE	128*1024
76#define	ALLOC_GRP_MEMBER	256
77
78#define	MAX_ISCSI_NAME	223
79#define	MAX_SERIAL_SIZE 252 + 1
80#define	MAX_LU_ALIAS_SIZE 256
81#define	MAX_SBD_PROPS	MAXPATHLEN + MAX_SERIAL_SIZE + MAX_LU_ALIAS_SIZE
82
83#define	OPEN_STMF 0
84#define	OPEN_EXCL_STMF O_EXCL
85
86#define	OPEN_SBD 0
87#define	OPEN_EXCL_SBD O_EXCL
88
89#define	OPEN_PPPT 0
90#define	OPEN_EXCL_PPPT O_EXCL
91
92#define	LOGICAL_UNIT_TYPE 0
93#define	TARGET_TYPE 1
94#define	STMF_SERVICE_TYPE 2
95
96#define	HOST_GROUP   1
97#define	TARGET_GROUP 2
98
99/* set default persistence here */
100#define	STMF_DEFAULT_PERSIST	STMF_PERSIST_SMF
101
102#define	MAX_PROVIDER_RETRY 30
103
104static int openStmf(int, int *fd);
105static int openSbd(int, int *fd);
106static int openPppt(int, int *fd);
107static int groupIoctl(int fd, int cmd, stmfGroupName *);
108static int loadStore(int fd);
109static int initializeConfig();
110static int groupMemberIoctl(int fd, int cmd, stmfGroupName *, stmfDevid *);
111static int guidCompare(const void *, const void *);
112static int addViewEntryIoctl(int fd, stmfGuid *, stmfViewEntry *);
113static int loadHostGroups(int fd, stmfGroupList *);
114static int loadTargetGroups(int fd, stmfGroupList *);
115static int getStmfState(stmf_state_desc_t *);
116static int setStmfState(int fd, stmf_state_desc_t *, int);
117static int setProviderData(int fd, char *, nvlist_t *, int, uint64_t *);
118static int createDiskResource(luResourceImpl *);
119static int createDiskLu(diskResource *, stmfGuid *);
120static int deleteDiskLu(stmfGuid *luGuid);
121static int getDiskProp(luResourceImpl *, uint32_t, char *, size_t *);
122static int getDiskAllProps(stmfGuid *luGuid, luResource *hdl);
123static int loadDiskPropsFromDriver(luResourceImpl *, sbd_lu_props_t *);
124static int removeGuidFromDiskStore(stmfGuid *);
125static int addGuidToDiskStore(stmfGuid *, char *);
126static int persistDiskGuid(stmfGuid *, char *, boolean_t);
127static int setDiskProp(luResourceImpl *, uint32_t, const char *);
128static int getDiskGlobalProp(uint32_t prop, char *propVal, size_t *propLen);
129static int checkHexUpper(char *);
130static int strToShift(const char *);
131static int niceStrToNum(const char *, uint64_t *);
132static void diskError(uint32_t, int *);
133static int importDiskLu(char *fname, stmfGuid *);
134static int modifyDiskLu(diskResource *, stmfGuid *, const char *);
135static int modifyDiskLuProp(stmfGuid *, const char *, uint32_t, const char *);
136static int validateModifyDiskProp(uint32_t);
137static uint8_t iGetPersistMethod();
138static int groupListIoctl(stmfGroupList **, int);
139static int iLoadGroupFromPs(stmfGroupList **, int);
140static int groupMemberListIoctl(stmfGroupName *, stmfGroupProperties **, int);
141static int getProviderData(char *, nvlist_t **, int, uint64_t *);
142static int setDiskStandby(stmfGuid *luGuid);
143static int setDiskGlobalProp(uint32_t, const char *);
144static int viewEntryCompare(const void *, const void *);
145static void deleteNonActiveLus();
146static int loadStmfProp(int fd);
147
148static pthread_mutex_t persistenceTypeLock = PTHREAD_MUTEX_INITIALIZER;
149static int iPersistType = 0;
150/* when B_TRUE, no need to access SMF anymore. Just use iPersistType */
151static boolean_t iLibSetPersist = B_FALSE;
152
153/*
154 * Open for stmf module
155 *
156 * flag - open flag (OPEN_STMF, OPEN_EXCL_STMF)
157 * fd - pointer to integer. On success, contains the stmf file descriptor
158 */
159static int
160openStmf(int flag, int *fd)
161{
162	int ret = STMF_STATUS_ERROR;
163
164	if ((*fd = open(STMF_PATH, O_NDELAY | O_RDONLY | flag)) != -1) {
165		ret = STMF_STATUS_SUCCESS;
166	} else {
167		if (errno == EBUSY) {
168			ret = STMF_ERROR_BUSY;
169		} else if (errno == EACCES) {
170			ret = STMF_ERROR_PERM;
171		} else {
172			ret = STMF_STATUS_ERROR;
173		}
174		syslog(LOG_DEBUG, "openStmf:open failure:%s:errno(%d)",
175		    STMF_PATH, errno);
176	}
177
178	return (ret);
179}
180
181/*
182 * Open for sbd module
183 *
184 * flag - open flag (OPEN_SBD, OPEN_EXCL_SBD)
185 * fd - pointer to integer. On success, contains the stmf file descriptor
186 */
187static int
188openSbd(int flag, int *fd)
189{
190	int ret = STMF_STATUS_ERROR;
191
192	if ((*fd = open(SBD_PATH, O_NDELAY | O_RDONLY | flag)) != -1) {
193		ret = STMF_STATUS_SUCCESS;
194	} else {
195		if (errno == EBUSY) {
196			ret = STMF_ERROR_BUSY;
197		} else if (errno == EACCES) {
198			ret = STMF_ERROR_PERM;
199		} else {
200			ret = STMF_STATUS_ERROR;
201		}
202		syslog(LOG_DEBUG, "openSbd:open failure:%s:errno(%d)",
203		    SBD_PATH, errno);
204	}
205
206	return (ret);
207}
208
209/*
210 * Open for pppt module
211 *
212 * flag - open flag (OPEN_PPPT, OPEN_EXCL_PPPT)
213 * fd - pointer to integer. On success, contains the stmf file descriptor
214 */
215static int
216openPppt(int flag, int *fd)
217{
218	int ret = STMF_STATUS_ERROR;
219
220	if ((*fd = open(PPPT_PATH, O_RDONLY | flag)) != -1) {
221		ret = STMF_STATUS_SUCCESS;
222	} else {
223		if (errno == EBUSY) {
224			ret = STMF_ERROR_BUSY;
225		} else if (errno == EACCES) {
226			ret = STMF_ERROR_PERM;
227		} else {
228			ret = STMF_STATUS_ERROR;
229		}
230		syslog(LOG_DEBUG, "openPppt:open failure:%s:errno(%d)",
231		    PPPT_PATH, errno);
232	}
233
234	return (ret);
235}
236
237/*
238 * initializeConfig
239 *
240 * This routine should be called before any ioctl requiring initialization
241 * which is basically everything except stmfGetState(), setStmfState() and
242 * stmfLoadConfig().
243 */
244static int
245initializeConfig()
246{
247	int ret;
248	stmfState state;
249
250
251	ret = stmfGetState(&state);
252	if (ret != STMF_STATUS_SUCCESS) {
253		return (ret);
254	}
255
256	/* if we've already initialized or in the process, return success */
257	if (state.configState == STMF_CONFIG_STATE_INIT_DONE ||
258	    state.configState == STMF_CONFIG_STATE_INIT) {
259		return (STMF_STATUS_SUCCESS);
260	}
261
262	ret = stmfLoadConfig();
263	if (ret != STMF_STATUS_SUCCESS) {
264		syslog(LOG_DEBUG,
265		    "initializeConfig:stmfLoadConfig:error(%d)", ret);
266		return (ret);
267	}
268
269	ret = stmfGetState(&state);
270	if (ret != STMF_STATUS_SUCCESS) {
271		syslog(LOG_DEBUG,
272		    "initializeConfig:stmfGetState:error(%d)", ret);
273		return (ret);
274	}
275
276	if (state.configState != STMF_CONFIG_STATE_INIT_DONE) {
277		syslog(LOG_DEBUG, "initializeConfig:state.configState(%d)",
278		    state.configState);
279		ret = STMF_STATUS_ERROR;
280	}
281
282	return (ret);
283}
284
285
286/*
287 * groupIoctl
288 *
289 * Purpose: issue ioctl for create/delete on group
290 *
291 * cmd - valid STMF ioctl group cmd
292 * groupName - groupName to create or delete
293 */
294static int
295groupIoctl(int fd, int cmd, stmfGroupName *groupName)
296{
297	int ret = STMF_STATUS_SUCCESS;
298	int ioctlRet;
299	stmf_iocdata_t stmfIoctl;
300	stmf_group_name_t iGroupName;
301
302	bzero(&iGroupName, sizeof (iGroupName));
303
304	bcopy(groupName, &iGroupName.name, strlen((char *)groupName));
305
306	iGroupName.name_size = strlen((char *)groupName);
307
308	bzero(&stmfIoctl, sizeof (stmfIoctl));
309	/*
310	 * Issue ioctl to create the host group
311	 */
312	stmfIoctl.stmf_version = STMF_VERSION_1;
313	stmfIoctl.stmf_ibuf_size = sizeof (iGroupName);
314	stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&iGroupName;
315	ioctlRet = ioctl(fd, cmd, &stmfIoctl);
316	if (ioctlRet != 0) {
317		switch (errno) {
318			case EPERM:
319			case EACCES:
320				ret = STMF_ERROR_PERM;
321				break;
322			default:
323				switch (stmfIoctl.stmf_error) {
324					case STMF_IOCERR_TG_EXISTS:
325					case STMF_IOCERR_HG_EXISTS:
326						ret = STMF_ERROR_EXISTS;
327						break;
328					case STMF_IOCERR_TG_IN_USE:
329					case STMF_IOCERR_HG_IN_USE:
330						ret = STMF_ERROR_GROUP_IN_USE;
331						break;
332					case STMF_IOCERR_INVALID_HG:
333					case STMF_IOCERR_INVALID_TG:
334						ret = STMF_ERROR_NOT_FOUND;
335						break;
336					default:
337						syslog(LOG_DEBUG,
338						    "groupIoctl:error(%d)",
339						    stmfIoctl.stmf_error);
340						ret = STMF_STATUS_ERROR;
341						break;
342				}
343				break;
344		}
345	}
346done:
347	return (ret);
348}
349
350/*
351 * groupMemberIoctl
352 *
353 * Purpose: issue ioctl for add/remove member on group
354 *
355 * cmd - valid STMF ioctl group member cmd
356 * groupName - groupName to add to or remove from
357 * devid - group member to add or remove
358 */
359static int
360groupMemberIoctl(int fd, int cmd, stmfGroupName *groupName, stmfDevid *devid)
361{
362	int ret = STMF_STATUS_SUCCESS;
363	int ioctlRet;
364	stmf_iocdata_t stmfIoctl;
365	stmf_group_op_data_t stmfGroupData;
366
367	bzero(&stmfGroupData, sizeof (stmfGroupData));
368
369	bcopy(groupName, &stmfGroupData.group.name, strlen((char *)groupName));
370
371	stmfGroupData.group.name_size = strlen((char *)groupName);
372	stmfGroupData.ident[IDENT_LENGTH_BYTE] = devid->identLength;
373	bcopy(&(devid->ident), &stmfGroupData.ident[IDENT_LENGTH_BYTE + 1],
374	    devid->identLength);
375
376	bzero(&stmfIoctl, sizeof (stmfIoctl));
377	/*
378	 * Issue ioctl to add to the host group
379	 */
380	stmfIoctl.stmf_version = STMF_VERSION_1;
381	stmfIoctl.stmf_ibuf_size = sizeof (stmfGroupData);
382	stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&stmfGroupData;
383	ioctlRet = ioctl(fd, cmd, &stmfIoctl);
384	if (ioctlRet != 0) {
385		switch (errno) {
386			case EBUSY:
387				switch (stmfIoctl.stmf_error) {
388					case STMF_IOCERR_TG_NEED_TG_OFFLINE:
389						ret = STMF_ERROR_TG_ONLINE;
390						break;
391					default:
392						ret = STMF_ERROR_BUSY;
393						break;
394				}
395				break;
396			case EPERM:
397			case EACCES:
398				ret = STMF_ERROR_PERM;
399				break;
400			default:
401				switch (stmfIoctl.stmf_error) {
402					case STMF_IOCERR_TG_ENTRY_EXISTS:
403					case STMF_IOCERR_HG_ENTRY_EXISTS:
404						ret = STMF_ERROR_EXISTS;
405						break;
406					case STMF_IOCERR_INVALID_TG_ENTRY:
407					case STMF_IOCERR_INVALID_HG_ENTRY:
408						ret =
409						    STMF_ERROR_MEMBER_NOT_FOUND;
410						break;
411					case STMF_IOCERR_INVALID_TG:
412					case STMF_IOCERR_INVALID_HG:
413						ret =
414						    STMF_ERROR_GROUP_NOT_FOUND;
415						break;
416					default:
417						syslog(LOG_DEBUG,
418						    "groupMemberIoctl:error"
419						    "(%d)",
420						    stmfIoctl.stmf_error);
421						ret = STMF_STATUS_ERROR;
422						break;
423				}
424				break;
425		}
426	}
427done:
428	return (ret);
429}
430
431/*
432 * qsort function
433 * sort on veIndex
434 */
435static int
436viewEntryCompare(const void *p1, const void *p2)
437{
438
439	stmfViewEntry *v1 = (stmfViewEntry *)p1, *v2 = (stmfViewEntry *)p2;
440	if (v1->veIndex > v2->veIndex)
441		return (1);
442	if (v1->veIndex < v2->veIndex)
443		return (-1);
444	return (0);
445}
446
447/*
448 * guidCompare
449 *
450 * qsort function
451 * sort on guid
452 */
453static int
454guidCompare(const void *p1, const void *p2)
455{
456
457	stmfGuid *g1 = (stmfGuid *)p1, *g2 = (stmfGuid *)p2;
458	int i;
459
460	for (i = 0; i < sizeof (stmfGuid); i++) {
461		if (g1->guid[i] > g2->guid[i])
462			return (1);
463		if (g1->guid[i] < g2->guid[i])
464			return (-1);
465	}
466
467	return (0);
468}
469
470/*
471 * stmfAddToHostGroup
472 *
473 * Purpose: Adds an initiator to an existing host group
474 *
475 * hostGroupName - name of an existing host group
476 * hostName - name of initiator to add
477 */
478int
479stmfAddToHostGroup(stmfGroupName *hostGroupName, stmfDevid *hostName)
480{
481	int ret;
482	int fd;
483
484	if (hostGroupName == NULL ||
485	    (strnlen((char *)hostGroupName, sizeof (stmfGroupName))
486	    == sizeof (stmfGroupName)) || hostName == NULL) {
487		return (STMF_ERROR_INVALID_ARG);
488	}
489
490	/* call init */
491	ret = initializeConfig();
492	if (ret != STMF_STATUS_SUCCESS) {
493		return (ret);
494	}
495
496	/*
497	 * Open control node for stmf
498	 */
499	if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
500		return (ret);
501
502	if ((ret = groupMemberIoctl(fd, STMF_IOCTL_ADD_HG_ENTRY, hostGroupName,
503	    hostName)) != STMF_STATUS_SUCCESS) {
504		goto done;
505	}
506
507	if (iGetPersistMethod() == STMF_PERSIST_NONE) {
508		goto done;
509	}
510
511	ret = psAddHostGroupMember((char *)hostGroupName,
512	    (char *)hostName->ident);
513	switch (ret) {
514		case STMF_PS_SUCCESS:
515			ret = STMF_STATUS_SUCCESS;
516			break;
517		case STMF_PS_ERROR_EXISTS:
518			ret = STMF_ERROR_EXISTS;
519			break;
520		case STMF_PS_ERROR_GROUP_NOT_FOUND:
521			ret = STMF_ERROR_GROUP_NOT_FOUND;
522			break;
523		case STMF_PS_ERROR_BUSY:
524			ret = STMF_ERROR_BUSY;
525			break;
526		case STMF_PS_ERROR_SERVICE_NOT_FOUND:
527			ret = STMF_ERROR_SERVICE_NOT_FOUND;
528			break;
529		case STMF_PS_ERROR_VERSION_MISMATCH:
530			ret = STMF_ERROR_SERVICE_DATA_VERSION;
531			break;
532		default:
533			syslog(LOG_DEBUG,
534			    "stmfAddToHostGroup:psAddHostGroupMember:error(%d)",
535			    ret);
536			ret = STMF_STATUS_ERROR;
537			break;
538	}
539
540done:
541	(void) close(fd);
542	return (ret);
543}
544
545/*
546 * stmfAddToTargetGroup
547 *
548 * Purpose: Adds a local port to an existing target group
549 *
550 * targetGroupName - name of an existing target group
551 * targetName - name of target to add
552 */
553int
554stmfAddToTargetGroup(stmfGroupName *targetGroupName, stmfDevid *targetName)
555{
556	int ret;
557	int fd;
558
559	if (targetGroupName == NULL ||
560	    (strnlen((char *)targetGroupName, sizeof (stmfGroupName))
561	    == sizeof (stmfGroupName)) || targetName == NULL) {
562		return (STMF_ERROR_INVALID_ARG);
563	}
564
565	/* call init */
566	ret = initializeConfig();
567	if (ret != STMF_STATUS_SUCCESS) {
568		return (ret);
569	}
570
571	/*
572	 * Open control node for stmf
573	 */
574	if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
575		return (ret);
576
577	if ((ret = groupMemberIoctl(fd, STMF_IOCTL_ADD_TG_ENTRY,
578	    targetGroupName, targetName)) != STMF_STATUS_SUCCESS) {
579		goto done;
580	}
581
582	if (iGetPersistMethod() == STMF_PERSIST_NONE) {
583		goto done;
584	}
585
586	ret = psAddTargetGroupMember((char *)targetGroupName,
587	    (char *)targetName->ident);
588	switch (ret) {
589		case STMF_PS_SUCCESS:
590			ret = STMF_STATUS_SUCCESS;
591			break;
592		case STMF_PS_ERROR_EXISTS:
593			ret = STMF_ERROR_EXISTS;
594			break;
595		case STMF_PS_ERROR_GROUP_NOT_FOUND:
596			ret = STMF_ERROR_GROUP_NOT_FOUND;
597			break;
598		case STMF_PS_ERROR_BUSY:
599			ret = STMF_ERROR_BUSY;
600			break;
601		case STMF_PS_ERROR_SERVICE_NOT_FOUND:
602			ret = STMF_ERROR_SERVICE_NOT_FOUND;
603			break;
604		case STMF_PS_ERROR_VERSION_MISMATCH:
605			ret = STMF_ERROR_SERVICE_DATA_VERSION;
606			break;
607		default:
608			syslog(LOG_DEBUG,
609			    "stmfAddToTargetGroup:psAddTargetGroupMember:"
610			    "error(%d)", ret);
611			ret = STMF_STATUS_ERROR;
612			break;
613	}
614
615done:
616	(void) close(fd);
617	return (ret);
618}
619
620/*
621 * addViewEntryIoctl
622 *
623 * Purpose: Issues ioctl to add a view entry
624 *
625 * lu - Logical Unit identifier to which the view entry is added
626 * viewEntry - view entry to add
627 * init - When set to B_TRUE, we are in the init state, i.e. don't call open
628 */
629static int
630addViewEntryIoctl(int fd, stmfGuid *lu, stmfViewEntry *viewEntry)
631{
632	int ret = STMF_STATUS_SUCCESS;
633	int ioctlRet;
634	stmf_iocdata_t stmfIoctl;
635	stmf_view_op_entry_t ioctlViewEntry;
636
637	bzero(&ioctlViewEntry, sizeof (ioctlViewEntry));
638	/*
639	 * don't set ve_ndx or ve_ndx_valid as ve_ndx_valid should be
640	 * false on input
641	 */
642	ioctlViewEntry.ve_lu_number_valid = viewEntry->luNbrValid;
643	ioctlViewEntry.ve_all_hosts = viewEntry->allHosts;
644	ioctlViewEntry.ve_all_targets = viewEntry->allTargets;
645
646	if (viewEntry->allHosts == B_FALSE) {
647		bcopy(viewEntry->hostGroup, &ioctlViewEntry.ve_host_group.name,
648		    sizeof (stmfGroupName));
649		ioctlViewEntry.ve_host_group.name_size =
650		    strlen((char *)viewEntry->hostGroup);
651	}
652	if (viewEntry->allTargets == B_FALSE) {
653		bcopy(viewEntry->targetGroup,
654		    &ioctlViewEntry.ve_target_group.name,
655		    sizeof (stmfGroupName));
656		ioctlViewEntry.ve_target_group.name_size =
657		    strlen((char *)viewEntry->targetGroup);
658	}
659	if (viewEntry->luNbrValid) {
660		bcopy(viewEntry->luNbr, &ioctlViewEntry.ve_lu_nbr,
661		    sizeof (ioctlViewEntry.ve_lu_nbr));
662	}
663	bcopy(lu, &ioctlViewEntry.ve_guid, sizeof (stmfGuid));
664
665	bzero(&stmfIoctl, sizeof (stmfIoctl));
666	/*
667	 * Issue ioctl to add to the view entry
668	 */
669	stmfIoctl.stmf_version = STMF_VERSION_1;
670	stmfIoctl.stmf_ibuf_size = sizeof (ioctlViewEntry);
671	stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&ioctlViewEntry;
672	stmfIoctl.stmf_obuf_size = sizeof (ioctlViewEntry);
673	stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)&ioctlViewEntry;
674	ioctlRet = ioctl(fd, STMF_IOCTL_ADD_VIEW_ENTRY, &stmfIoctl);
675	if (ioctlRet != 0) {
676		switch (errno) {
677			case EBUSY:
678				ret = STMF_ERROR_BUSY;
679				break;
680			case EPERM:
681				ret = STMF_ERROR_PERM;
682				break;
683			case EACCES:
684				switch (stmfIoctl.stmf_error) {
685					case STMF_IOCERR_UPDATE_NEED_CFG_INIT:
686						ret = STMF_ERROR_CONFIG_NONE;
687						break;
688					default:
689						ret = STMF_ERROR_PERM;
690						break;
691				}
692				break;
693			default:
694				switch (stmfIoctl.stmf_error) {
695					case STMF_IOCERR_LU_NUMBER_IN_USE:
696						ret = STMF_ERROR_LUN_IN_USE;
697						break;
698					case STMF_IOCERR_VIEW_ENTRY_CONFLICT:
699						ret = STMF_ERROR_VE_CONFLICT;
700						break;
701					case STMF_IOCERR_UPDATE_NEED_CFG_INIT:
702						ret = STMF_ERROR_CONFIG_NONE;
703						break;
704					case STMF_IOCERR_INVALID_HG:
705						ret = STMF_ERROR_INVALID_HG;
706						break;
707					case STMF_IOCERR_INVALID_TG:
708						ret = STMF_ERROR_INVALID_TG;
709						break;
710					default:
711						syslog(LOG_DEBUG,
712						    "addViewEntryIoctl"
713						    ":error(%d)",
714						    stmfIoctl.stmf_error);
715						ret = STMF_STATUS_ERROR;
716						break;
717				}
718				break;
719		}
720		goto done;
721	}
722
723	/* copy lu nbr back to caller's view entry on success */
724	viewEntry->veIndex = ioctlViewEntry.ve_ndx;
725	if (ioctlViewEntry.ve_lu_number_valid) {
726		bcopy(&ioctlViewEntry.ve_lu_nbr, viewEntry->luNbr,
727		    sizeof (ioctlViewEntry.ve_lu_nbr));
728	}
729	viewEntry->luNbrValid = B_TRUE;
730
731done:
732	return (ret);
733}
734
735/*
736 * stmfAddViewEntry
737 *
738 * Purpose: Adds a view entry to a logical unit
739 *
740 * lu - guid of the logical unit to which the view entry is added
741 * viewEntry - view entry structure to add
742 */
743int
744stmfAddViewEntry(stmfGuid *lu, stmfViewEntry *viewEntry)
745{
746	int ret;
747	int fd;
748	stmfViewEntry iViewEntry;
749
750	if (lu == NULL || viewEntry == NULL) {
751		return (STMF_ERROR_INVALID_ARG);
752	}
753
754	/* initialize and set internal view entry */
755	bzero(&iViewEntry, sizeof (iViewEntry));
756
757	if (!viewEntry->allHosts) {
758		bcopy(viewEntry->hostGroup, iViewEntry.hostGroup,
759		    sizeof (iViewEntry.hostGroup));
760	} else {
761		iViewEntry.allHosts = B_TRUE;
762	}
763
764	if (!viewEntry->allTargets) {
765		bcopy(viewEntry->targetGroup, iViewEntry.targetGroup,
766		    sizeof (iViewEntry.targetGroup));
767	} else {
768		iViewEntry.allTargets = B_TRUE;
769	}
770
771	if (viewEntry->luNbrValid) {
772		iViewEntry.luNbrValid = B_TRUE;
773		bcopy(viewEntry->luNbr, iViewEntry.luNbr,
774		    sizeof (iViewEntry.luNbr));
775	}
776
777	/*
778	 * set users return view entry index valid flag to false
779	 * in case of failure
780	 */
781	viewEntry->veIndexValid = B_FALSE;
782
783	/* Check to ensure service exists */
784	if (psCheckService() != STMF_STATUS_SUCCESS) {
785		return (STMF_ERROR_SERVICE_NOT_FOUND);
786	}
787
788	/* call init */
789	ret = initializeConfig();
790	if (ret != STMF_STATUS_SUCCESS) {
791		return (ret);
792	}
793
794	/*
795	 * Open control node for stmf
796	 */
797	if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
798		return (ret);
799
800	/*
801	 * First add the view entry to the driver
802	 */
803	ret = addViewEntryIoctl(fd, lu, &iViewEntry);
804	if (ret != STMF_STATUS_SUCCESS) {
805		goto done;
806	}
807
808	if (iGetPersistMethod() == STMF_PERSIST_NONE) {
809		goto done;
810	}
811
812	/*
813	 * If the add to driver was successful, add it to the persistent
814	 * store.
815	 */
816	ret = psAddViewEntry(lu, &iViewEntry);
817	switch (ret) {
818		case STMF_PS_SUCCESS:
819			ret = STMF_STATUS_SUCCESS;
820			break;
821		case STMF_PS_ERROR_NOT_FOUND:
822			ret = STMF_ERROR_NOT_FOUND;
823			break;
824		case STMF_PS_ERROR_BUSY:
825			ret = STMF_ERROR_BUSY;
826			break;
827		case STMF_PS_ERROR_SERVICE_NOT_FOUND:
828			ret = STMF_ERROR_SERVICE_NOT_FOUND;
829			break;
830		case STMF_PS_ERROR_VERSION_MISMATCH:
831			ret = STMF_ERROR_SERVICE_DATA_VERSION;
832			break;
833		default:
834			syslog(LOG_DEBUG,
835			    "stmfAddViewEntry:psAddViewEntry:error(%d)", ret);
836			ret = STMF_STATUS_ERROR;
837			break;
838	}
839
840done:
841	(void) close(fd);
842
843	if (ret == STMF_STATUS_SUCCESS) {
844		/* set caller's view entry on success */
845		viewEntry->veIndexValid = iViewEntry.veIndexValid;
846		viewEntry->veIndex = iViewEntry.veIndex;
847		viewEntry->luNbrValid = B_TRUE;
848		bcopy(iViewEntry.luNbr, viewEntry->luNbr,
849		    sizeof (iViewEntry.luNbr));
850	}
851	return (ret);
852}
853
854/*
855 * stmfClearProviderData
856 *
857 * Purpose: delete all provider data for specified provider
858 *
859 * providerName - name of provider for which data should be deleted
860 */
861int
862stmfClearProviderData(char *providerName, int providerType)
863{
864	int ret;
865	int fd;
866	int ioctlRet;
867	int savedErrno;
868	stmf_iocdata_t stmfIoctl;
869	stmf_ppioctl_data_t ppi;
870
871	/* call init */
872	ret = initializeConfig();
873	if (ret != STMF_STATUS_SUCCESS) {
874		return (ret);
875	}
876
877	if (providerName == NULL) {
878		return (STMF_ERROR_INVALID_ARG);
879	}
880
881	if (providerType != STMF_LU_PROVIDER_TYPE &&
882	    providerType != STMF_PORT_PROVIDER_TYPE) {
883		return (STMF_ERROR_INVALID_ARG);
884	}
885
886	/*
887	 * Open control node for stmf
888	 */
889	if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
890		return (ret);
891
892	bzero(&ppi, sizeof (ppi));
893
894	(void) strncpy(ppi.ppi_name, providerName, sizeof (ppi.ppi_name));
895
896	switch (providerType) {
897		case STMF_LU_PROVIDER_TYPE:
898			ppi.ppi_lu_provider = 1;
899			break;
900		case STMF_PORT_PROVIDER_TYPE:
901			ppi.ppi_port_provider = 1;
902			break;
903		default:
904			ret = STMF_ERROR_INVALID_ARG;
905			goto done;
906	}
907
908	bzero(&stmfIoctl, sizeof (stmfIoctl));
909
910	stmfIoctl.stmf_version = STMF_VERSION_1;
911	stmfIoctl.stmf_ibuf_size = sizeof (stmf_ppioctl_data_t);
912	stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&ppi;
913
914	ioctlRet = ioctl(fd, STMF_IOCTL_CLEAR_PP_DATA, &stmfIoctl);
915	if (ioctlRet != 0) {
916		savedErrno = errno;
917		switch (savedErrno) {
918			case EBUSY:
919				ret = STMF_ERROR_BUSY;
920				break;
921			case EPERM:
922			case EACCES:
923				ret = STMF_ERROR_PERM;
924				break;
925			default:
926				syslog(LOG_DEBUG,
927				    "stmfClearProviderData:ioctl error(%d)",
928				    ioctlRet);
929				ret = STMF_STATUS_ERROR;
930				break;
931		}
932		if (savedErrno != ENOENT) {
933			goto done;
934		}
935	}
936
937	if (iGetPersistMethod() == STMF_PERSIST_NONE) {
938		goto done;
939	}
940
941	ret = psClearProviderData(providerName, providerType);
942	switch (ret) {
943		case STMF_PS_SUCCESS:
944			ret = STMF_STATUS_SUCCESS;
945			break;
946		case STMF_PS_ERROR_NOT_FOUND:
947			ret = STMF_ERROR_NOT_FOUND;
948			break;
949		case STMF_PS_ERROR_BUSY:
950			ret = STMF_ERROR_BUSY;
951			break;
952		case STMF_PS_ERROR_SERVICE_NOT_FOUND:
953			ret = STMF_ERROR_SERVICE_NOT_FOUND;
954			break;
955		case STMF_PS_ERROR_VERSION_MISMATCH:
956			ret = STMF_ERROR_SERVICE_DATA_VERSION;
957			break;
958		default:
959			syslog(LOG_DEBUG,
960			    "stmfClearProviderData:psClearProviderData"
961			    ":error(%d)", ret);
962			ret = STMF_STATUS_ERROR;
963			break;
964	}
965
966done:
967	(void) close(fd);
968	return (ret);
969}
970
971/*
972 * stmfCreateHostGroup
973 *
974 * Purpose: Create a new initiator group
975 *
976 * hostGroupName - name of host group to create
977 */
978int
979stmfCreateHostGroup(stmfGroupName *hostGroupName)
980{
981	int ret;
982	int fd;
983
984	if (hostGroupName == NULL ||
985	    (strnlen((char *)hostGroupName, sizeof (stmfGroupName))
986	    == sizeof (stmfGroupName))) {
987		return (STMF_ERROR_INVALID_ARG);
988	}
989
990	/* Check to ensure service exists */
991	if (psCheckService() != STMF_STATUS_SUCCESS) {
992		return (STMF_ERROR_SERVICE_NOT_FOUND);
993	}
994
995	/* call init */
996	ret = initializeConfig();
997	if (ret != STMF_STATUS_SUCCESS) {
998		return (ret);
999	}
1000
1001	/*
1002	 * Open control node for stmf
1003	 */
1004	if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
1005		return (ret);
1006
1007	if ((ret = groupIoctl(fd, STMF_IOCTL_CREATE_HOST_GROUP,
1008	    hostGroupName)) != STMF_STATUS_SUCCESS) {
1009		goto done;
1010	}
1011
1012	if (iGetPersistMethod() == STMF_PERSIST_NONE) {
1013		goto done;
1014	}
1015
1016	ret = psCreateHostGroup((char *)hostGroupName);
1017	switch (ret) {
1018		case STMF_PS_SUCCESS:
1019			ret = STMF_STATUS_SUCCESS;
1020			break;
1021		case STMF_PS_ERROR_EXISTS:
1022			ret = STMF_ERROR_EXISTS;
1023			break;
1024		case STMF_PS_ERROR_BUSY:
1025			ret = STMF_ERROR_BUSY;
1026			break;
1027		case STMF_PS_ERROR_SERVICE_NOT_FOUND:
1028			ret = STMF_ERROR_SERVICE_NOT_FOUND;
1029			break;
1030		case STMF_PS_ERROR_VERSION_MISMATCH:
1031			ret = STMF_ERROR_SERVICE_DATA_VERSION;
1032			break;
1033		default:
1034			syslog(LOG_DEBUG,
1035			    "stmfCreateHostGroup:psCreateHostGroup:error(%d)",
1036			    ret);
1037			ret = STMF_STATUS_ERROR;
1038			break;
1039	}
1040
1041done:
1042	(void) close(fd);
1043	return (ret);
1044}
1045
1046/*
1047 * stmfCreateLu
1048 *
1049 * Purpose: Create a logical unit
1050 *
1051 * hdl - handle to logical unit resource created via stmfCreateLuResource
1052 *
1053 * luGuid - If non-NULL, on success, contains the guid of the created logical
1054 *	    unit
1055 */
1056int
1057stmfCreateLu(luResource hdl, stmfGuid *luGuid)
1058{
1059	int ret = STMF_STATUS_SUCCESS;
1060	luResourceImpl *luPropsHdl = hdl;
1061
1062	if (hdl == NULL) {
1063		return (STMF_ERROR_INVALID_ARG);
1064	}
1065
1066	if (luPropsHdl->type == STMF_DISK) {
1067		ret = createDiskLu((diskResource *)luPropsHdl->resource,
1068		    luGuid);
1069	} else {
1070		return (STMF_ERROR_INVALID_ARG);
1071	}
1072
1073	return (ret);
1074}
1075
1076/*
1077 * stmfCreateLuResource
1078 *
1079 * Purpose: Create resource handle for a logical unit
1080 *
1081 * dType - Type of logical unit resource to create
1082 *	   Can be: STMF_DISK
1083 *
1084 * hdl - pointer to luResource
1085 */
1086int
1087stmfCreateLuResource(uint16_t dType, luResource *hdl)
1088{
1089	int ret = STMF_STATUS_SUCCESS;
1090
1091	if (dType != STMF_DISK || hdl == NULL) {
1092		return (STMF_ERROR_INVALID_ARG);
1093	}
1094
1095	*hdl = calloc(1, sizeof (luResourceImpl));
1096	if (*hdl == NULL) {
1097		return (STMF_ERROR_NOMEM);
1098	}
1099
1100	ret = createDiskResource((luResourceImpl *)*hdl);
1101	if (ret != STMF_STATUS_SUCCESS) {
1102		free(*hdl);
1103		return (ret);
1104	}
1105
1106	return (STMF_STATUS_SUCCESS);
1107}
1108
1109/*
1110 * Creates a disk logical unit
1111 *
1112 * disk - pointer to diskResource structure that represents the properties
1113 *        for the disk logical unit to be created.
1114 */
1115static int
1116createDiskLu(diskResource *disk, stmfGuid *createdGuid)
1117{
1118	int ret = STMF_STATUS_SUCCESS;
1119	int dataFileNameLen = 0;
1120	int metaFileNameLen = 0;
1121	int serialNumLen = 0;
1122	int luAliasLen = 0;
1123	int luMgmtUrlLen = 0;
1124	int sluBufSize = 0;
1125	int bufOffset = 0;
1126	int fd = 0;
1127	int ioctlRet;
1128	int savedErrno;
1129	stmfGuid guid;
1130	stmf_iocdata_t sbdIoctl = {0};
1131
1132	sbd_create_and_reg_lu_t *sbdLu = NULL;
1133
1134	/*
1135	 * Open control node for sbd
1136	 */
1137	if ((ret = openSbd(OPEN_SBD, &fd)) != STMF_STATUS_SUCCESS)
1138		return (ret);
1139
1140	/* data file name must be specified */
1141	if (disk->luDataFileNameValid) {
1142		dataFileNameLen = strlen(disk->luDataFileName);
1143	} else {
1144		(void) close(fd);
1145		return (STMF_ERROR_MISSING_PROP_VAL);
1146	}
1147
1148	sluBufSize += dataFileNameLen + 1;
1149
1150	if (disk->luMetaFileNameValid) {
1151		metaFileNameLen = strlen(disk->luMetaFileName);
1152		sluBufSize += metaFileNameLen + 1;
1153	}
1154
1155	serialNumLen = strlen(disk->serialNum);
1156	sluBufSize += serialNumLen;
1157
1158	if (disk->luAliasValid) {
1159		luAliasLen = strlen(disk->luAlias);
1160		sluBufSize += luAliasLen + 1;
1161	}
1162
1163	if (disk->luMgmtUrlValid) {
1164		luMgmtUrlLen = strlen(disk->luMgmtUrl);
1165		sluBufSize += luMgmtUrlLen + 1;
1166	}
1167
1168	/*
1169	 * 8 is the size of the buffer set aside for
1170	 * concatenation of variable length fields
1171	 */
1172	sbdLu = (sbd_create_and_reg_lu_t *)calloc(1,
1173	    sizeof (sbd_create_and_reg_lu_t) + sluBufSize - 8);
1174	if (sbdLu == NULL) {
1175		return (STMF_ERROR_NOMEM);
1176	}
1177
1178	sbdLu->slu_struct_size = sizeof (sbd_create_and_reg_lu_t) +
1179	    sluBufSize - 8;
1180
1181	if (metaFileNameLen) {
1182		sbdLu->slu_meta_fname_valid = 1;
1183		sbdLu->slu_meta_fname_off = bufOffset;
1184		bcopy(disk->luMetaFileName, &(sbdLu->slu_buf[bufOffset]),
1185		    metaFileNameLen + 1);
1186		bufOffset += metaFileNameLen + 1;
1187	}
1188
1189	bcopy(disk->luDataFileName, &(sbdLu->slu_buf[bufOffset]),
1190	    dataFileNameLen + 1);
1191	sbdLu->slu_data_fname_off = bufOffset;
1192	bufOffset += dataFileNameLen + 1;
1193
1194	/* currently, serial # is not passed null terminated to the driver */
1195	if (disk->serialNumValid) {
1196		sbdLu->slu_serial_valid = 1;
1197		sbdLu->slu_serial_off = bufOffset;
1198		sbdLu->slu_serial_size = serialNumLen;
1199		bcopy(disk->serialNum, &(sbdLu->slu_buf[bufOffset]),
1200		    serialNumLen);
1201		bufOffset += serialNumLen;
1202	}
1203
1204	if (disk->luAliasValid) {
1205		sbdLu->slu_alias_valid = 1;
1206		sbdLu->slu_alias_off = bufOffset;
1207		bcopy(disk->luAlias, &(sbdLu->slu_buf[bufOffset]),
1208		    luAliasLen + 1);
1209		bufOffset += luAliasLen + 1;
1210	}
1211
1212	if (disk->luMgmtUrlValid) {
1213		sbdLu->slu_mgmt_url_valid = 1;
1214		sbdLu->slu_mgmt_url_off = bufOffset;
1215		bcopy(disk->luMgmtUrl, &(sbdLu->slu_buf[bufOffset]),
1216		    luMgmtUrlLen + 1);
1217		bufOffset += luMgmtUrlLen + 1;
1218	}
1219
1220	if (disk->luSizeValid) {
1221		sbdLu->slu_lu_size_valid = 1;
1222		sbdLu->slu_lu_size = disk->luSize;
1223	}
1224
1225	if (disk->luGuidValid) {
1226		sbdLu->slu_guid_valid = 1;
1227		bcopy(disk->luGuid, sbdLu->slu_guid, sizeof (disk->luGuid));
1228	}
1229
1230	if (disk->vidValid) {
1231		sbdLu->slu_vid_valid = 1;
1232		bcopy(disk->vid, sbdLu->slu_vid, sizeof (disk->vid));
1233	}
1234
1235	if (disk->pidValid) {
1236		sbdLu->slu_pid_valid = 1;
1237		bcopy(disk->pid, sbdLu->slu_pid, sizeof (disk->pid));
1238	}
1239
1240	if (disk->revValid) {
1241		sbdLu->slu_rev_valid = 1;
1242		bcopy(disk->rev, sbdLu->slu_rev, sizeof (disk->rev));
1243	}
1244
1245	if (disk->companyIdValid) {
1246		sbdLu->slu_company_id_valid = 1;
1247		sbdLu->slu_company_id = disk->companyId;
1248	}
1249
1250	if (disk->hostIdValid) {
1251		sbdLu->slu_host_id_valid = 1;
1252		sbdLu->slu_host_id = disk->hostId;
1253	}
1254
1255	if (disk->blkSizeValid) {
1256		sbdLu->slu_blksize_valid = 1;
1257		sbdLu->slu_blksize = disk->blkSize;
1258	}
1259
1260	if (disk->writeProtectEnableValid) {
1261		if (disk->writeProtectEnable) {
1262			sbdLu->slu_write_protected = 1;
1263		}
1264	}
1265
1266	if (disk->writebackCacheDisableValid) {
1267		sbdLu->slu_writeback_cache_disable_valid = 1;
1268		if (disk->writebackCacheDisable) {
1269			sbdLu->slu_writeback_cache_disable = 1;
1270		}
1271	}
1272
1273	sbdIoctl.stmf_version = STMF_VERSION_1;
1274	sbdIoctl.stmf_ibuf_size = sbdLu->slu_struct_size;
1275	sbdIoctl.stmf_ibuf = (uint64_t)(unsigned long)sbdLu;
1276	sbdIoctl.stmf_obuf_size = sbdLu->slu_struct_size;
1277	sbdIoctl.stmf_obuf = (uint64_t)(unsigned long)sbdLu;
1278
1279	ioctlRet = ioctl(fd, SBD_IOCTL_CREATE_AND_REGISTER_LU, &sbdIoctl);
1280	if (ioctlRet != 0) {
1281		savedErrno = errno;
1282		switch (savedErrno) {
1283			case EBUSY:
1284				ret = STMF_ERROR_BUSY;
1285				break;
1286			case EPERM:
1287			case EACCES:
1288				ret = STMF_ERROR_PERM;
1289				break;
1290			default:
1291				diskError(sbdIoctl.stmf_error, &ret);
1292				if (ret == STMF_STATUS_ERROR) {
1293					syslog(LOG_DEBUG,
1294					"createDiskLu:ioctl "
1295					"error(%d) (%d) (%d)", ioctlRet,
1296					    sbdIoctl.stmf_error, savedErrno);
1297				}
1298				break;
1299		}
1300	}
1301
1302	if (ret != STMF_STATUS_SUCCESS) {
1303		goto done;
1304	}
1305
1306	/*
1307	 * on success, copy the resulting guid into the caller's guid if not
1308	 * NULL
1309	 */
1310	if (createdGuid) {
1311		bcopy(sbdLu->slu_guid, createdGuid->guid,
1312		    sizeof (sbdLu->slu_guid));
1313	}
1314
1315	bcopy(sbdLu->slu_guid, guid.guid, sizeof (sbdLu->slu_guid));
1316	if (disk->luMetaFileNameValid) {
1317		ret = addGuidToDiskStore(&guid, disk->luMetaFileName);
1318	} else {
1319		ret = addGuidToDiskStore(&guid, disk->luDataFileName);
1320	}
1321done:
1322	free(sbdLu);
1323	(void) close(fd);
1324	return (ret);
1325}
1326
1327
1328/*
1329 * stmfImportLu
1330 *
1331 * Purpose: Import a previously created logical unit
1332 *
1333 * dType - Type of logical unit
1334 *         Can be: STMF_DISK
1335 *
1336 * luGuid - If non-NULL, on success, contains the guid of the imported logical
1337 *	    unit
1338 *
1339 * fname - A file name where the metadata resides
1340 *
1341 */
1342int
1343stmfImportLu(uint16_t dType, char *fname, stmfGuid *luGuid)
1344{
1345	int ret = STMF_STATUS_SUCCESS;
1346
1347	if (dType == STMF_DISK) {
1348		ret = importDiskLu(fname, luGuid);
1349	} else {
1350		return (STMF_ERROR_INVALID_ARG);
1351	}
1352
1353	return (ret);
1354}
1355
1356/*
1357 * importDiskLu
1358 *
1359 * filename - filename to import
1360 * createdGuid - if not NULL, on success contains the imported guid
1361 *
1362 */
1363static int
1364importDiskLu(char *fname, stmfGuid *createdGuid)
1365{
1366	int ret = STMF_STATUS_SUCCESS;
1367	int fd = 0;
1368	int ioctlRet;
1369	int savedErrno;
1370	int metaFileNameLen;
1371	stmfGuid iGuid;
1372	int iluBufSize = 0;
1373	sbd_import_lu_t *sbdLu = NULL;
1374	stmf_iocdata_t sbdIoctl = {0};
1375
1376	if (fname == NULL) {
1377		return (STMF_ERROR_INVALID_ARG);
1378	}
1379
1380	/*
1381	 * Open control node for sbd
1382	 */
1383	if ((ret = openSbd(OPEN_SBD, &fd)) != STMF_STATUS_SUCCESS)
1384		return (ret);
1385
1386	metaFileNameLen = strlen(fname);
1387	iluBufSize += metaFileNameLen + 1;
1388
1389	/*
1390	 * 8 is the size of the buffer set aside for
1391	 * concatenation of variable length fields
1392	 */
1393	sbdLu = (sbd_import_lu_t *)calloc(1,
1394	    sizeof (sbd_import_lu_t) + iluBufSize - 8);
1395	if (sbdLu == NULL) {
1396		(void) close(fd);
1397		return (STMF_ERROR_NOMEM);
1398	}
1399
1400	/*
1401	 * Accept either a data file or meta data file.
1402	 * sbd will do the right thing here either way.
1403	 * i.e. if it's a data file, it assumes that the
1404	 * meta data is shared with the data.
1405	 */
1406	(void) strncpy(sbdLu->ilu_meta_fname, fname, metaFileNameLen);
1407
1408	sbdLu->ilu_struct_size = sizeof (sbd_import_lu_t) + iluBufSize - 8;
1409
1410	sbdIoctl.stmf_version = STMF_VERSION_1;
1411	sbdIoctl.stmf_ibuf_size = sbdLu->ilu_struct_size;
1412	sbdIoctl.stmf_ibuf = (uint64_t)(unsigned long)sbdLu;
1413	sbdIoctl.stmf_obuf_size = sbdLu->ilu_struct_size;
1414	sbdIoctl.stmf_obuf = (uint64_t)(unsigned long)sbdLu;
1415
1416	ioctlRet = ioctl(fd, SBD_IOCTL_IMPORT_LU, &sbdIoctl);
1417	if (ioctlRet != 0) {
1418
1419		if (createdGuid && sbdIoctl.stmf_error ==
1420		    SBD_RET_FILE_ALREADY_REGISTERED) {
1421			bcopy(sbdLu->ilu_ret_guid, createdGuid->guid,
1422			    sizeof (sbdLu->ilu_ret_guid));
1423		}
1424
1425		savedErrno = errno;
1426		switch (savedErrno) {
1427			case EBUSY:
1428				ret = STMF_ERROR_BUSY;
1429				break;
1430			case EPERM:
1431			case EACCES:
1432				ret = STMF_ERROR_PERM;
1433				break;
1434			default:
1435				diskError(sbdIoctl.stmf_error, &ret);
1436				if (ret == STMF_STATUS_ERROR) {
1437					syslog(LOG_DEBUG,
1438					"importDiskLu:ioctl "
1439					"error(%d) (%d) (%d)", ioctlRet,
1440					    sbdIoctl.stmf_error, savedErrno);
1441				}
1442				break;
1443		}
1444	}
1445
1446
1447	if (ret != STMF_STATUS_SUCCESS) {
1448		goto done;
1449	}
1450
1451	/*
1452	 * on success, copy the resulting guid into the caller's guid if not
1453	 * NULL and add it to the persistent store for sbd
1454	 */
1455	if (createdGuid) {
1456		bcopy(sbdLu->ilu_ret_guid, createdGuid->guid,
1457		    sizeof (sbdLu->ilu_ret_guid));
1458		ret = addGuidToDiskStore(createdGuid, fname);
1459	} else {
1460		bcopy(sbdLu->ilu_ret_guid, iGuid.guid,
1461		    sizeof (sbdLu->ilu_ret_guid));
1462		ret = addGuidToDiskStore(&iGuid, fname);
1463	}
1464done:
1465	free(sbdLu);
1466	(void) close(fd);
1467	return (ret);
1468}
1469
1470/*
1471 * diskError
1472 *
1473 * Purpose: Translate sbd driver error
1474 */
1475static void
1476diskError(uint32_t stmfError, int *ret)
1477{
1478	switch (stmfError) {
1479		case SBD_RET_META_CREATION_FAILED:
1480		case SBD_RET_ZFS_META_CREATE_FAILED:
1481			*ret = STMF_ERROR_META_CREATION;
1482			break;
1483		case SBD_RET_INVALID_BLKSIZE:
1484			*ret = STMF_ERROR_INVALID_BLKSIZE;
1485			break;
1486		case SBD_RET_FILE_ALREADY_REGISTERED:
1487			*ret = STMF_ERROR_FILE_IN_USE;
1488			break;
1489		case SBD_RET_GUID_ALREADY_REGISTERED:
1490			*ret = STMF_ERROR_GUID_IN_USE;
1491			break;
1492		case SBD_RET_META_PATH_NOT_ABSOLUTE:
1493		case SBD_RET_META_FILE_LOOKUP_FAILED:
1494		case SBD_RET_META_FILE_OPEN_FAILED:
1495		case SBD_RET_META_FILE_GETATTR_FAILED:
1496		case SBD_RET_NO_META:
1497			*ret = STMF_ERROR_META_FILE_NAME;
1498			break;
1499		case SBD_RET_DATA_PATH_NOT_ABSOLUTE:
1500		case SBD_RET_DATA_FILE_LOOKUP_FAILED:
1501		case SBD_RET_DATA_FILE_OPEN_FAILED:
1502		case SBD_RET_DATA_FILE_GETATTR_FAILED:
1503			*ret = STMF_ERROR_DATA_FILE_NAME;
1504			break;
1505		case SBD_RET_FILE_SIZE_ERROR:
1506			*ret = STMF_ERROR_FILE_SIZE_INVALID;
1507			break;
1508		case SBD_RET_SIZE_OUT_OF_RANGE:
1509			*ret = STMF_ERROR_SIZE_OUT_OF_RANGE;
1510			break;
1511		case SBD_RET_LU_BUSY:
1512			*ret = STMF_ERROR_LU_BUSY;
1513			break;
1514		case SBD_RET_WRITE_CACHE_SET_FAILED:
1515			*ret = STMF_ERROR_WRITE_CACHE_SET;
1516			break;
1517		case SBD_RET_ACCESS_STATE_FAILED:
1518			*ret = STMF_ERROR_ACCESS_STATE_SET;
1519			break;
1520		default:
1521			*ret = STMF_STATUS_ERROR;
1522			break;
1523	}
1524}
1525
1526/*
1527 * Creates a logical unit resource of type STMF_DISK.
1528 *
1529 * No defaults should be set here as all defaults are derived from the
1530 * driver's default settings.
1531 */
1532static int
1533createDiskResource(luResourceImpl *hdl)
1534{
1535	hdl->type = STMF_DISK;
1536
1537	hdl->resource = calloc(1, sizeof (diskResource));
1538	if (hdl->resource == NULL) {
1539		return (STMF_ERROR_NOMEM);
1540	}
1541
1542	return (STMF_STATUS_SUCCESS);
1543}
1544
1545/*
1546 * stmfDeleteLu
1547 *
1548 * Purpose: Delete a logical unit
1549 *
1550 * hdl - handle to logical unit resource created via stmfCreateLuResource
1551 *
1552 * luGuid - If non-NULL, on success, contains the guid of the created logical
1553 *	    unit
1554 */
1555int
1556stmfDeleteLu(stmfGuid *luGuid)
1557{
1558	int ret = STMF_STATUS_SUCCESS;
1559	stmfLogicalUnitProperties luProps;
1560
1561	if (luGuid == NULL) {
1562		return (STMF_ERROR_INVALID_ARG);
1563	}
1564
1565	/* Check logical unit provider name to call correct dtype function */
1566	if ((ret = stmfGetLogicalUnitProperties(luGuid, &luProps))
1567	    != STMF_STATUS_SUCCESS) {
1568		return (ret);
1569	} else {
1570		if (strcmp(luProps.providerName, "sbd") == 0) {
1571			ret = deleteDiskLu(luGuid);
1572		} else if (luProps.status == STMF_LOGICAL_UNIT_UNREGISTERED) {
1573			return (STMF_ERROR_NOT_FOUND);
1574		} else {
1575			return (STMF_ERROR_INVALID_ARG);
1576		}
1577	}
1578
1579	return (ret);
1580}
1581
1582static int
1583deleteDiskLu(stmfGuid *luGuid)
1584{
1585	int ret = STMF_STATUS_SUCCESS;
1586	int fd;
1587	int savedErrno;
1588	int ioctlRet;
1589	sbd_delete_lu_t deleteLu = {0};
1590
1591	stmf_iocdata_t sbdIoctl = {0};
1592
1593	/*
1594	 * Open control node for sbd
1595	 */
1596	if ((ret = openSbd(OPEN_SBD, &fd)) != STMF_STATUS_SUCCESS)
1597		return (ret);
1598
1599	ret = removeGuidFromDiskStore(luGuid);
1600	if (ret != STMF_STATUS_SUCCESS) {
1601		goto done;
1602	}
1603
1604	bcopy(luGuid, deleteLu.dlu_guid, sizeof (deleteLu.dlu_guid));
1605	deleteLu.dlu_by_guid = 1;
1606
1607	sbdIoctl.stmf_version = STMF_VERSION_1;
1608	sbdIoctl.stmf_ibuf_size = sizeof (deleteLu);
1609	sbdIoctl.stmf_ibuf = (uint64_t)(unsigned long)&deleteLu;
1610	ioctlRet = ioctl(fd, SBD_IOCTL_DELETE_LU, &sbdIoctl);
1611	if (ioctlRet != 0) {
1612		savedErrno = errno;
1613		switch (savedErrno) {
1614			case EBUSY:
1615				ret = STMF_ERROR_BUSY;
1616				break;
1617			case EPERM:
1618			case EACCES:
1619				ret = STMF_ERROR_PERM;
1620				break;
1621			case ENOENT:
1622				ret = STMF_ERROR_NOT_FOUND;
1623				break;
1624			default:
1625				syslog(LOG_DEBUG,
1626				    "deleteDiskLu:ioctl error(%d) (%d) (%d)",
1627				    ioctlRet, sbdIoctl.stmf_error, savedErrno);
1628				ret = STMF_STATUS_ERROR;
1629				break;
1630		}
1631	}
1632
1633done:
1634	(void) close(fd);
1635	return (ret);
1636}
1637
1638/*
1639 * stmfLuStandby
1640 *
1641 * Purpose: Sets access state to standby
1642 *
1643 * luGuid - guid of registered logical unit
1644 *
1645 */
1646int
1647stmfLuStandby(stmfGuid *luGuid)
1648{
1649	int ret = STMF_STATUS_SUCCESS;
1650	stmfLogicalUnitProperties luProps;
1651
1652	if (luGuid == NULL) {
1653		return (STMF_ERROR_INVALID_ARG);
1654	}
1655
1656	/* Check logical unit provider name to call correct dtype function */
1657	if ((ret = stmfGetLogicalUnitProperties(luGuid, &luProps))
1658	    != STMF_STATUS_SUCCESS) {
1659		return (ret);
1660	} else {
1661		if (strcmp(luProps.providerName, "sbd") == 0) {
1662			ret = setDiskStandby(luGuid);
1663		} else if (luProps.status == STMF_LOGICAL_UNIT_UNREGISTERED) {
1664			return (STMF_ERROR_NOT_FOUND);
1665		} else {
1666			return (STMF_ERROR_INVALID_ARG);
1667		}
1668	}
1669
1670	return (ret);
1671}
1672
1673static int
1674setDiskStandby(stmfGuid *luGuid)
1675{
1676	int ret = STMF_STATUS_SUCCESS;
1677	stmf_iocdata_t sbdIoctl = {0};
1678	sbd_set_lu_standby_t sbdLu = {0};
1679	int ioctlRet;
1680	int savedErrno;
1681	int fd = 0;
1682
1683	/*
1684	 * Open control node for sbd
1685	 */
1686	if ((ret = openSbd(OPEN_SBD, &fd)) != STMF_STATUS_SUCCESS)
1687		return (ret);
1688
1689	bcopy(luGuid, &sbdLu.stlu_guid, sizeof (stmfGuid));
1690
1691	sbdIoctl.stmf_version = STMF_VERSION_1;
1692	sbdIoctl.stmf_ibuf_size = sizeof (sbd_set_lu_standby_t);
1693	sbdIoctl.stmf_ibuf = (uint64_t)(unsigned long)&sbdLu;
1694
1695	ioctlRet = ioctl(fd, SBD_IOCTL_SET_LU_STANDBY, &sbdIoctl);
1696	if (ioctlRet != 0) {
1697		savedErrno = errno;
1698		switch (savedErrno) {
1699			case EBUSY:
1700				ret = STMF_ERROR_BUSY;
1701				break;
1702			case EPERM:
1703			case EACCES:
1704				ret = STMF_ERROR_PERM;
1705				break;
1706			default:
1707				diskError(sbdIoctl.stmf_error, &ret);
1708				if (ret == STMF_STATUS_ERROR) {
1709					syslog(LOG_DEBUG,
1710					"setDiskStandby:ioctl "
1711					"error(%d) (%d) (%d)", ioctlRet,
1712					    sbdIoctl.stmf_error, savedErrno);
1713				}
1714				break;
1715		}
1716	}
1717	(void) close(fd);
1718	return (ret);
1719}
1720
1721/*
1722 * stmfModifyLu
1723 *
1724 * Purpose: Modify properties of a logical unit
1725 *
1726 * luGuid - guid of registered logical unit
1727 * prop - property to modify
1728 * propVal - property value to set
1729 *
1730 */
1731int
1732stmfModifyLu(stmfGuid *luGuid, uint32_t prop, const char *propVal)
1733{
1734	int ret = STMF_STATUS_SUCCESS;
1735	stmfLogicalUnitProperties luProps;
1736
1737	if (luGuid == NULL) {
1738		return (STMF_ERROR_INVALID_ARG);
1739	}
1740
1741	/* Check logical unit provider name to call correct dtype function */
1742	if ((ret = stmfGetLogicalUnitProperties(luGuid, &luProps))
1743	    != STMF_STATUS_SUCCESS) {
1744		return (ret);
1745	} else {
1746		if (strcmp(luProps.providerName, "sbd") == 0) {
1747			ret = modifyDiskLuProp(luGuid, NULL, prop, propVal);
1748		} else if (luProps.status == STMF_LOGICAL_UNIT_UNREGISTERED) {
1749			return (STMF_ERROR_NOT_FOUND);
1750		} else {
1751			return (STMF_ERROR_INVALID_ARG);
1752		}
1753	}
1754
1755	return (ret);
1756}
1757
1758/*
1759 * stmfModifyLuByFname
1760 *
1761 * Purpose: Modify a device by filename. Device does not need to be registered.
1762 *
1763 * dType - type of device to modify
1764 *         STMF_DISK
1765 *
1766 * fname - filename or meta filename
1767 * prop - valid property identifier
1768 * propVal - property value
1769 *
1770 */
1771int
1772stmfModifyLuByFname(uint16_t dType, const char *fname, uint32_t prop,
1773    const char *propVal)
1774{
1775	int ret = STMF_STATUS_SUCCESS;
1776	if (fname == NULL) {
1777		return (STMF_ERROR_INVALID_ARG);
1778	}
1779
1780	if (dType == STMF_DISK) {
1781		ret = modifyDiskLuProp(NULL, fname, prop, propVal);
1782	} else {
1783		return (STMF_ERROR_INVALID_ARG);
1784	}
1785
1786	return (ret);
1787}
1788
1789static int
1790modifyDiskLuProp(stmfGuid *luGuid, const char *fname, uint32_t prop,
1791    const char *propVal)
1792{
1793	int ret = STMF_STATUS_SUCCESS;
1794	luResource hdl = NULL;
1795	luResourceImpl *luPropsHdl;
1796
1797	ret = stmfCreateLuResource(STMF_DISK, &hdl);
1798	if (ret != STMF_STATUS_SUCCESS) {
1799		return (ret);
1800	}
1801	ret = validateModifyDiskProp(prop);
1802	if (ret != STMF_STATUS_SUCCESS) {
1803		(void) stmfFreeLuResource(hdl);
1804		return (STMF_ERROR_INVALID_PROP);
1805	}
1806	ret = stmfSetLuProp(hdl, prop, propVal);
1807	if (ret != STMF_STATUS_SUCCESS) {
1808		(void) stmfFreeLuResource(hdl);
1809		return (ret);
1810	}
1811	luPropsHdl = hdl;
1812	ret = modifyDiskLu((diskResource *)luPropsHdl->resource, luGuid, fname);
1813	(void) stmfFreeLuResource(hdl);
1814	return (ret);
1815}
1816
1817static int
1818validateModifyDiskProp(uint32_t prop)
1819{
1820	switch (prop) {
1821		case STMF_LU_PROP_ALIAS:
1822		case STMF_LU_PROP_SIZE:
1823		case STMF_LU_PROP_MGMT_URL:
1824		case STMF_LU_PROP_WRITE_PROTECT:
1825		case STMF_LU_PROP_WRITE_CACHE_DISABLE:
1826			return (STMF_STATUS_SUCCESS);
1827		default:
1828			return (STMF_STATUS_ERROR);
1829	}
1830}
1831
1832static int
1833modifyDiskLu(diskResource *disk, stmfGuid *luGuid, const char *fname)
1834{
1835	int ret = STMF_STATUS_SUCCESS;
1836	int luAliasLen = 0;
1837	int luMgmtUrlLen = 0;
1838	int mluBufSize = 0;
1839	int bufOffset = 0;
1840	int fd = 0;
1841	int ioctlRet;
1842	int savedErrno;
1843	int fnameSize = 0;
1844	stmf_iocdata_t sbdIoctl = {0};
1845
1846	sbd_modify_lu_t *sbdLu = NULL;
1847
1848	if (luGuid == NULL && fname == NULL) {
1849		return (STMF_ERROR_INVALID_ARG);
1850	}
1851
1852	if (fname) {
1853		fnameSize = strlen(fname) + 1;
1854		mluBufSize += fnameSize;
1855	}
1856
1857	/*
1858	 * Open control node for sbd
1859	 */
1860	if ((ret = openSbd(OPEN_SBD, &fd)) != STMF_STATUS_SUCCESS)
1861		return (ret);
1862
1863	if (disk->luAliasValid) {
1864		luAliasLen = strlen(disk->luAlias);
1865		mluBufSize += luAliasLen + 1;
1866	}
1867
1868	if (disk->luMgmtUrlValid) {
1869		luMgmtUrlLen = strlen(disk->luMgmtUrl);
1870		mluBufSize += luMgmtUrlLen + 1;
1871	}
1872
1873	/*
1874	 * 8 is the size of the buffer set aside for
1875	 * concatenation of variable length fields
1876	 */
1877	sbdLu = (sbd_modify_lu_t *)calloc(1,
1878	    sizeof (sbd_modify_lu_t) + mluBufSize - 8 + fnameSize);
1879	if (sbdLu == NULL) {
1880		(void) close(fd);
1881		return (STMF_ERROR_NOMEM);
1882	}
1883
1884	sbdLu->mlu_struct_size = sizeof (sbd_modify_lu_t) +
1885	    mluBufSize - 8 + fnameSize;
1886
1887	if (disk->luAliasValid) {
1888		sbdLu->mlu_alias_valid = 1;
1889		sbdLu->mlu_alias_off = bufOffset;
1890		bcopy(disk->luAlias, &(sbdLu->mlu_buf[bufOffset]),
1891		    luAliasLen + 1);
1892		bufOffset += luAliasLen + 1;
1893	}
1894
1895	if (disk->luMgmtUrlValid) {
1896		sbdLu->mlu_mgmt_url_valid = 1;
1897		sbdLu->mlu_mgmt_url_off = bufOffset;
1898		bcopy(disk->luMgmtUrl, &(sbdLu->mlu_buf[bufOffset]),
1899		    luMgmtUrlLen + 1);
1900		bufOffset += luMgmtUrlLen + 1;
1901	}
1902
1903	if (disk->luSizeValid) {
1904		sbdLu->mlu_lu_size_valid = 1;
1905		sbdLu->mlu_lu_size = disk->luSize;
1906	}
1907
1908	if (disk->writeProtectEnableValid) {
1909		sbdLu->mlu_write_protected_valid = 1;
1910		if (disk->writeProtectEnable) {
1911			sbdLu->mlu_write_protected = 1;
1912		}
1913	}
1914
1915	if (disk->writebackCacheDisableValid) {
1916		sbdLu->mlu_writeback_cache_disable_valid = 1;
1917		if (disk->writebackCacheDisable) {
1918			sbdLu->mlu_writeback_cache_disable = 1;
1919		}
1920	}
1921
1922	if (luGuid) {
1923		bcopy(luGuid, sbdLu->mlu_input_guid, sizeof (stmfGuid));
1924		sbdLu->mlu_by_guid = 1;
1925	} else {
1926		sbdLu->mlu_fname_off = bufOffset;
1927		bcopy(fname, &(sbdLu->mlu_buf[bufOffset]), fnameSize + 1);
1928		sbdLu->mlu_by_fname = 1;
1929	}
1930
1931	sbdIoctl.stmf_version = STMF_VERSION_1;
1932	sbdIoctl.stmf_ibuf_size = sbdLu->mlu_struct_size;
1933	sbdIoctl.stmf_ibuf = (uint64_t)(unsigned long)sbdLu;
1934
1935	ioctlRet = ioctl(fd, SBD_IOCTL_MODIFY_LU, &sbdIoctl);
1936	if (ioctlRet != 0) {
1937		savedErrno = errno;
1938		switch (savedErrno) {
1939			case EBUSY:
1940				ret = STMF_ERROR_BUSY;
1941				break;
1942			case EPERM:
1943			case EACCES:
1944				ret = STMF_ERROR_PERM;
1945				break;
1946			default:
1947				diskError(sbdIoctl.stmf_error, &ret);
1948				if (ret == STMF_STATUS_ERROR) {
1949					syslog(LOG_DEBUG,
1950					"modifyDiskLu:ioctl "
1951					"error(%d) (%d) (%d)", ioctlRet,
1952					    sbdIoctl.stmf_error, savedErrno);
1953				}
1954				break;
1955		}
1956	}
1957
1958	if (ret != STMF_STATUS_SUCCESS) {
1959		goto done;
1960	}
1961
1962done:
1963	free(sbdLu);
1964	(void) close(fd);
1965	return (ret);
1966}
1967
1968/*
1969 * removeGuidFromDiskStore
1970 *
1971 * Purpose: delete a logical unit from the sbd provider data
1972 */
1973static int
1974removeGuidFromDiskStore(stmfGuid *guid)
1975{
1976	return (persistDiskGuid(guid, NULL, B_FALSE));
1977}
1978
1979
1980/*
1981 * addGuidToDiskStore
1982 *
1983 * Purpose: add a logical unit to the sbd provider data
1984 */
1985static int
1986addGuidToDiskStore(stmfGuid *guid, char *filename)
1987{
1988	return (persistDiskGuid(guid, filename, B_TRUE));
1989}
1990
1991
1992/*
1993 * persistDiskGuid
1994 *
1995 * Purpose: Persist or unpersist a guid for the sbd provider data
1996 *
1997 */
1998static int
1999persistDiskGuid(stmfGuid *guid, char *filename, boolean_t persist)
2000{
2001	char	    guidAsciiBuf[LU_ASCII_GUID_SIZE + 1] = {0};
2002	nvlist_t    *nvl = NULL;
2003
2004	uint64_t    setToken;
2005	boolean_t   retryGetProviderData = B_FALSE;
2006	boolean_t   newData = B_FALSE;
2007	int	    ret = STMF_STATUS_SUCCESS;
2008	int	    retryCnt = 0;
2009	int	    stmfRet;
2010
2011	/* if we're persisting a guid, there must be a filename */
2012	if (persist && !filename) {
2013		return (1);
2014	}
2015
2016	/* guid is stored in lowercase ascii hex */
2017	(void) snprintf(guidAsciiBuf, sizeof (guidAsciiBuf),
2018	    "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
2019	    "%02x%02x%02x%02x%02x%02x",
2020	    guid->guid[0], guid->guid[1], guid->guid[2], guid->guid[3],
2021	    guid->guid[4], guid->guid[5], guid->guid[6], guid->guid[7],
2022	    guid->guid[8], guid->guid[9], guid->guid[10], guid->guid[11],
2023	    guid->guid[12], guid->guid[13], guid->guid[14], guid->guid[15]);
2024
2025
2026	do {
2027		retryGetProviderData = B_FALSE;
2028		stmfRet = stmfGetProviderDataProt("sbd", &nvl,
2029		    STMF_LU_PROVIDER_TYPE, &setToken);
2030		if (stmfRet != STMF_STATUS_SUCCESS) {
2031			if (persist && stmfRet == STMF_ERROR_NOT_FOUND) {
2032				ret = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0);
2033				if (ret != 0) {
2034					syslog(LOG_DEBUG,
2035					    "unpersistGuid:nvlist_alloc(%d)",
2036					    ret);
2037					ret = STMF_STATUS_ERROR;
2038					goto done;
2039				}
2040				newData = B_TRUE;
2041			} else {
2042				/*
2043				 * if we're persisting the data, it's
2044				 * an error. Otherwise, just return
2045				 */
2046				if (persist) {
2047					ret = stmfRet;
2048				}
2049				goto done;
2050			}
2051		}
2052		if (persist) {
2053			ret = nvlist_add_string(nvl, guidAsciiBuf, filename);
2054		} else {
2055			ret = nvlist_remove(nvl, guidAsciiBuf,
2056			    DATA_TYPE_STRING);
2057			if (ret == ENOENT) {
2058				ret = 0;
2059			}
2060		}
2061		if (ret == 0) {
2062			if (newData) {
2063				stmfRet = stmfSetProviderDataProt("sbd", nvl,
2064				    STMF_LU_PROVIDER_TYPE, NULL);
2065			} else {
2066				stmfRet = stmfSetProviderDataProt("sbd", nvl,
2067				    STMF_LU_PROVIDER_TYPE, &setToken);
2068			}
2069			if (stmfRet != STMF_STATUS_SUCCESS) {
2070				if (stmfRet == STMF_ERROR_BUSY) {
2071					/* get/set failed, try again */
2072					retryGetProviderData = B_TRUE;
2073					if (retryCnt++ > MAX_PROVIDER_RETRY) {
2074						ret = stmfRet;
2075						break;
2076					}
2077					continue;
2078				} else if (stmfRet ==
2079				    STMF_ERROR_PROV_DATA_STALE) {
2080					/* update failed, try again */
2081					nvlist_free(nvl);
2082					nvl = NULL;
2083					retryGetProviderData = B_TRUE;
2084					if (retryCnt++ > MAX_PROVIDER_RETRY) {
2085						ret = stmfRet;
2086						break;
2087					}
2088					continue;
2089				} else {
2090					syslog(LOG_DEBUG,
2091					    "unpersistGuid:error(%x)", stmfRet);
2092					ret = stmfRet;
2093				}
2094				break;
2095			}
2096		} else {
2097			syslog(LOG_DEBUG,
2098			    "unpersistGuid:error nvlist_add/remove(%d)",
2099			    ret);
2100			ret = STMF_STATUS_ERROR;
2101		}
2102	} while (retryGetProviderData);
2103
2104done:
2105	nvlist_free(nvl);
2106	return (ret);
2107}
2108
2109
2110/*
2111 * stmfGetLuProp
2112 *
2113 * Purpose: Get current value for a resource property
2114 *
2115 * hdl - luResource from a previous call to stmfCreateLuResource
2116 *
2117 * resourceProp - a valid resource property type
2118 *
2119 * propVal - void pointer to a pointer of the value to be retrieved
2120 */
2121int
2122stmfGetLuProp(luResource hdl, uint32_t prop, char *propVal, size_t *propLen)
2123{
2124	int ret = STMF_STATUS_SUCCESS;
2125	luResourceImpl *luPropsHdl = hdl;
2126	if (hdl == NULL || propLen == NULL || propVal == NULL) {
2127		return (STMF_ERROR_INVALID_ARG);
2128	}
2129
2130	if (luPropsHdl->type == STMF_DISK) {
2131		ret = getDiskProp(luPropsHdl, prop, propVal, propLen);
2132	} else {
2133		return (STMF_ERROR_INVALID_ARG);
2134	}
2135
2136	return (ret);
2137}
2138
2139/*
2140 * stmfGetLuResource
2141 *
2142 * Purpose: Get a logical unit resource handle for a given logical unit.
2143 *
2144 * hdl - pointer to luResource
2145 */
2146int
2147stmfGetLuResource(stmfGuid *luGuid, luResource *hdl)
2148{
2149	int ret = STMF_STATUS_SUCCESS;
2150	stmfLogicalUnitProperties luProps;
2151
2152	if (hdl == NULL) {
2153		return (STMF_ERROR_INVALID_ARG);
2154	}
2155
2156	/* Check logical unit provider name to call correct dtype function */
2157	if ((ret = stmfGetLogicalUnitProperties(luGuid, &luProps))
2158	    != STMF_STATUS_SUCCESS) {
2159		return (ret);
2160	} else {
2161		if (strcmp(luProps.providerName, "sbd") == 0) {
2162			ret = getDiskAllProps(luGuid, hdl);
2163		} else if (luProps.status == STMF_LOGICAL_UNIT_UNREGISTERED) {
2164			return (STMF_ERROR_NOT_FOUND);
2165		} else {
2166			return (STMF_ERROR_INVALID_ARG);
2167		}
2168	}
2169
2170	return (ret);
2171}
2172
2173/*
2174 * getDiskAllProps
2175 *
2176 * Purpose: load all disk properties from sbd driver
2177 *
2178 * luGuid - guid of disk device for which properties are to be retrieved
2179 * hdl - allocated luResource into which properties are to be copied
2180 *
2181 */
2182static int
2183getDiskAllProps(stmfGuid *luGuid, luResource *hdl)
2184{
2185	int ret = STMF_STATUS_SUCCESS;
2186	int fd;
2187	sbd_lu_props_t *sbdProps;
2188	int ioctlRet;
2189	int savedErrno;
2190	int sbdPropsSize = sizeof (*sbdProps) + MAX_SBD_PROPS;
2191	stmf_iocdata_t sbdIoctl = {0};
2192
2193	/*
2194	 * Open control node for sbd
2195	 */
2196	if ((ret = openSbd(OPEN_SBD, &fd)) != STMF_STATUS_SUCCESS)
2197		return (ret);
2198
2199
2200	*hdl = calloc(1, sizeof (luResourceImpl));
2201	if (*hdl == NULL) {
2202		(void) close(fd);
2203		return (STMF_ERROR_NOMEM);
2204	}
2205
2206	sbdProps = calloc(1, sbdPropsSize);
2207	if (sbdProps == NULL) {
2208		free(*hdl);
2209		(void) close(fd);
2210		return (STMF_ERROR_NOMEM);
2211	}
2212
2213	ret = createDiskResource((luResourceImpl *)*hdl);
2214	if (ret != STMF_STATUS_SUCCESS) {
2215		free(*hdl);
2216		free(sbdProps);
2217		(void) close(fd);
2218		return (ret);
2219	}
2220
2221	sbdProps->slp_input_guid = 1;
2222	bcopy(luGuid, sbdProps->slp_guid, sizeof (sbdProps->slp_guid));
2223
2224	sbdIoctl.stmf_version = STMF_VERSION_1;
2225	sbdIoctl.stmf_ibuf_size = sbdPropsSize;
2226	sbdIoctl.stmf_ibuf = (uint64_t)(unsigned long)sbdProps;
2227	sbdIoctl.stmf_obuf_size = sbdPropsSize;
2228	sbdIoctl.stmf_obuf = (uint64_t)(unsigned long)sbdProps;
2229	ioctlRet = ioctl(fd, SBD_IOCTL_GET_LU_PROPS, &sbdIoctl);
2230	if (ioctlRet != 0) {
2231		savedErrno = errno;
2232		switch (savedErrno) {
2233			case EBUSY:
2234				ret = STMF_ERROR_BUSY;
2235				break;
2236			case EPERM:
2237			case EACCES:
2238				ret = STMF_ERROR_PERM;
2239				break;
2240			case ENOENT:
2241				ret = STMF_ERROR_NOT_FOUND;
2242				break;
2243			default:
2244				syslog(LOG_DEBUG,
2245				    "getDiskAllProps:ioctl error(%d) (%d) (%d)",
2246				    ioctlRet, sbdIoctl.stmf_error, savedErrno);
2247				ret = STMF_STATUS_ERROR;
2248				break;
2249		}
2250	}
2251
2252	if (ret == STMF_STATUS_SUCCESS) {
2253		ret = loadDiskPropsFromDriver((luResourceImpl *)*hdl, sbdProps);
2254	}
2255
2256	free(sbdProps);
2257	(void) close(fd);
2258	return (ret);
2259}
2260
2261/*
2262 * loadDiskPropsFromDriver
2263 *
2264 * Purpose: Retrieve all disk type properties from sbd driver
2265 *
2266 * hdl - Allocated luResourceImpl
2267 * sbdProps - sbd_lu_props_t structure returned from sbd driver
2268 *
2269 */
2270static int
2271loadDiskPropsFromDriver(luResourceImpl *hdl, sbd_lu_props_t *sbdProps)
2272{
2273	int ret = STMF_STATUS_SUCCESS;
2274	diskResource *diskLu = hdl->resource;
2275	/* copy guid */
2276	diskLu->luGuidValid = B_TRUE;
2277	bcopy(sbdProps->slp_guid, diskLu->luGuid, sizeof (sbdProps->slp_guid));
2278
2279	if (sbdProps->slp_separate_meta && sbdProps->slp_meta_fname_valid) {
2280		diskLu->luMetaFileNameValid = B_TRUE;
2281		if (strlcpy(diskLu->luMetaFileName,
2282		    (char *)&(sbdProps->slp_buf[sbdProps->slp_meta_fname_off]),
2283		    sizeof (diskLu->luMetaFileName)) >=
2284		    sizeof (diskLu->luMetaFileName)) {
2285			return (STMF_STATUS_ERROR);
2286		}
2287	}
2288
2289	if (sbdProps->slp_data_fname_valid) {
2290		diskLu->luDataFileNameValid = B_TRUE;
2291		if (strlcpy(diskLu->luDataFileName,
2292		    (char *)&(sbdProps->slp_buf[sbdProps->slp_data_fname_off]),
2293		    sizeof (diskLu->luDataFileName)) >=
2294		    sizeof (diskLu->luDataFileName)) {
2295			return (STMF_STATUS_ERROR);
2296		}
2297	}
2298
2299	if (sbdProps->slp_serial_valid) {
2300		diskLu->serialNumValid = B_TRUE;
2301		bcopy(&(sbdProps->slp_buf[sbdProps->slp_serial_off]),
2302		    diskLu->serialNum, sbdProps->slp_serial_size);
2303	}
2304
2305	if (sbdProps->slp_mgmt_url_valid) {
2306		diskLu->luMgmtUrlValid = B_TRUE;
2307		if (strlcpy(diskLu->luMgmtUrl,
2308		    (char *)&(sbdProps->slp_buf[sbdProps->slp_mgmt_url_off]),
2309		    sizeof (diskLu->luMgmtUrl)) >=
2310		    sizeof (diskLu->luMgmtUrl)) {
2311			return (STMF_STATUS_ERROR);
2312		}
2313	}
2314
2315	if (sbdProps->slp_alias_valid) {
2316		diskLu->luAliasValid = B_TRUE;
2317		if (strlcpy(diskLu->luAlias,
2318		    (char *)&(sbdProps->slp_buf[sbdProps->slp_alias_off]),
2319		    sizeof (diskLu->luAlias)) >=
2320		    sizeof (diskLu->luAlias)) {
2321			return (STMF_STATUS_ERROR);
2322		}
2323	} else { /* set alias to data filename if not set */
2324		if (sbdProps->slp_data_fname_valid) {
2325			diskLu->luAliasValid = B_TRUE;
2326			if (strlcpy(diskLu->luAlias,
2327			    (char *)&(sbdProps->slp_buf[
2328			    sbdProps->slp_data_fname_off]),
2329			    sizeof (diskLu->luAlias)) >=
2330			    sizeof (diskLu->luAlias)) {
2331				return (STMF_STATUS_ERROR);
2332			}
2333		}
2334	}
2335
2336	diskLu->vidValid = B_TRUE;
2337	bcopy(sbdProps->slp_vid, diskLu->vid, sizeof (diskLu->vid));
2338
2339	diskLu->pidValid = B_TRUE;
2340	bcopy(sbdProps->slp_pid, diskLu->pid, sizeof (diskLu->pid));
2341
2342	diskLu->revValid = B_TRUE;
2343	bcopy(sbdProps->slp_rev, diskLu->rev, sizeof (diskLu->rev));
2344
2345	diskLu->writeProtectEnableValid = B_TRUE;
2346	if (sbdProps->slp_write_protected) {
2347		diskLu->writeProtectEnable = B_TRUE;
2348	}
2349
2350	diskLu->writebackCacheDisableValid = B_TRUE;
2351	if (sbdProps->slp_writeback_cache_disable_cur) {
2352		diskLu->writebackCacheDisable = B_TRUE;
2353	}
2354
2355	diskLu->blkSizeValid = B_TRUE;
2356	diskLu->blkSize = sbdProps->slp_blksize;
2357
2358	diskLu->luSizeValid = B_TRUE;
2359	diskLu->luSize = sbdProps->slp_lu_size;
2360
2361	diskLu->accessState = sbdProps->slp_access_state;
2362
2363	return (ret);
2364}
2365
2366/*
2367 * stmfGetGlobalLuProp
2368 *
2369 * Purpose: get a global property for a device type
2370 *
2371 */
2372int
2373stmfGetGlobalLuProp(uint16_t dType, uint32_t prop, char *propVal,
2374    size_t *propLen)
2375{
2376	int ret = STMF_STATUS_SUCCESS;
2377	if (dType != STMF_DISK || propVal == NULL) {
2378		return (STMF_ERROR_INVALID_ARG);
2379	}
2380
2381	ret = getDiskGlobalProp(prop, propVal, propLen);
2382
2383	return (ret);
2384}
2385
2386/*
2387 * getDiskGlobalProp
2388 *
2389 * Purpose: get global property from sbd driver
2390 *
2391 */
2392static int
2393getDiskGlobalProp(uint32_t prop, char *propVal, size_t *propLen)
2394{
2395	int ret = STMF_STATUS_SUCCESS;
2396	int fd;
2397	sbd_global_props_t *sbdProps;
2398	void *sbd_realloc;
2399	int retryCnt = 0;
2400	boolean_t retry;
2401	int ioctlRet;
2402	int savedErrno;
2403	int sbdPropsSize = sizeof (*sbdProps) + MAX_SBD_PROPS;
2404	stmf_iocdata_t sbdIoctl = {0};
2405	size_t reqLen;
2406
2407	switch (prop) {
2408		case STMF_LU_PROP_MGMT_URL:
2409			break;
2410		default:
2411			return (STMF_ERROR_INVALID_PROP);
2412	}
2413
2414	/*
2415	 * Open control node for sbd
2416	 */
2417	if ((ret = openSbd(OPEN_SBD, &fd)) != STMF_STATUS_SUCCESS)
2418		return (ret);
2419
2420	sbdProps = calloc(1, sbdPropsSize);
2421	if (sbdProps == NULL) {
2422		(void) close(fd);
2423		return (STMF_ERROR_NOMEM);
2424	}
2425
2426	do {
2427		retry = B_FALSE;
2428		sbdIoctl.stmf_version = STMF_VERSION_1;
2429		sbdIoctl.stmf_obuf_size = sbdPropsSize;
2430		sbdIoctl.stmf_obuf = (uint64_t)(unsigned long)sbdProps;
2431		ioctlRet = ioctl(fd, SBD_IOCTL_GET_GLOBAL_LU, &sbdIoctl);
2432		if (ioctlRet != 0) {
2433			savedErrno = errno;
2434			switch (savedErrno) {
2435				case EBUSY:
2436					ret = STMF_ERROR_BUSY;
2437					break;
2438				case EPERM:
2439				case EACCES:
2440					ret = STMF_ERROR_PERM;
2441					break;
2442				case ENOMEM:
2443					if (sbdIoctl.stmf_error ==
2444					    SBD_RET_INSUFFICIENT_BUF_SPACE &&
2445					    retryCnt++ < 3) {
2446						sbdPropsSize =
2447						    sizeof (*sbdProps) +
2448						    sbdProps->
2449						    mlu_buf_size_needed;
2450
2451						sbd_realloc = sbdProps;
2452						sbdProps = realloc(sbdProps,
2453						    sbdPropsSize);
2454						if (sbdProps == NULL) {
2455							free(sbd_realloc);
2456							ret = STMF_ERROR_NOMEM;
2457							break;
2458						}
2459						retry = B_TRUE;
2460					} else {
2461						ret = STMF_ERROR_NOMEM;
2462					}
2463					break;
2464				default:
2465					syslog(LOG_DEBUG,
2466					    "getDiskGlobalProp:ioctl error(%d)"
2467					    "(%d)(%d)", ioctlRet,
2468					    sbdIoctl.stmf_error, savedErrno);
2469					ret = STMF_STATUS_ERROR;
2470					break;
2471			}
2472
2473		}
2474	} while (retry);
2475
2476	if (ret != STMF_STATUS_SUCCESS) {
2477		goto done;
2478	}
2479
2480	switch (prop) {
2481		case STMF_LU_PROP_MGMT_URL:
2482			if (sbdProps->mlu_mgmt_url_valid == 0) {
2483				ret = STMF_ERROR_NO_PROP;
2484				goto done;
2485			}
2486			if ((reqLen = strlcpy(propVal, (char *)&(
2487			    sbdProps->mlu_buf[sbdProps->mlu_mgmt_url_off]),
2488			    *propLen)) >= *propLen) {
2489				*propLen = reqLen + 1;
2490				ret = STMF_ERROR_INVALID_ARG;
2491				goto done;
2492			}
2493			break;
2494	}
2495
2496done:
2497	free(sbdProps);
2498	(void) close(fd);
2499	return (ret);
2500}
2501
2502/*
2503 * stmfSetGlobalLuProp
2504 *
2505 * Purpose: set a global property for a device type
2506 *
2507 */
2508int
2509stmfSetGlobalLuProp(uint16_t dType, uint32_t prop, const char *propVal)
2510{
2511	int ret = STMF_STATUS_SUCCESS;
2512	if (dType != STMF_DISK || propVal == NULL) {
2513		return (STMF_ERROR_INVALID_ARG);
2514	}
2515
2516	ret = setDiskGlobalProp(prop, propVal);
2517
2518	return (ret);
2519}
2520
2521/*
2522 * setDiskGlobalProp
2523 *
2524 * Purpose: set properties for resource of type disk
2525 *
2526 * resourceProp - valid resource identifier
2527 * propVal - valid resource value
2528 */
2529static int
2530setDiskGlobalProp(uint32_t resourceProp, const char *propVal)
2531{
2532	int ret = STMF_STATUS_SUCCESS;
2533	sbd_global_props_t *sbdGlobalProps = NULL;
2534	int sbdGlobalPropsSize = 0;
2535	int propLen;
2536	int mluBufSize = 0;
2537	int fd;
2538	int savedErrno;
2539	int ioctlRet;
2540	stmf_iocdata_t sbdIoctl = {0};
2541
2542	switch (resourceProp) {
2543		case STMF_LU_PROP_MGMT_URL:
2544			break;
2545		default:
2546			return (STMF_ERROR_INVALID_PROP);
2547	}
2548
2549	/*
2550	 * Open control node for sbd
2551	 */
2552	if ((ret = openSbd(OPEN_SBD, &fd)) != STMF_STATUS_SUCCESS)
2553		return (ret);
2554
2555	propLen = strlen(propVal);
2556	mluBufSize += propLen + 1;
2557	sbdGlobalPropsSize += sizeof (sbd_global_props_t) - 8 +
2558	    max(8, mluBufSize);
2559	/*
2560	 * 8 is the size of the buffer set aside for
2561	 * concatenation of variable length fields
2562	 */
2563	sbdGlobalProps = (sbd_global_props_t *)calloc(1, sbdGlobalPropsSize);
2564	if (sbdGlobalProps == NULL) {
2565		(void) close(fd);
2566		return (STMF_ERROR_NOMEM);
2567	}
2568
2569	sbdGlobalProps->mlu_struct_size = sbdGlobalPropsSize;
2570
2571	switch (resourceProp) {
2572		case STMF_LU_PROP_MGMT_URL:
2573			sbdGlobalProps->mlu_mgmt_url_valid = 1;
2574			bcopy(propVal, &(sbdGlobalProps->mlu_buf),
2575			    propLen + 1);
2576			break;
2577		default:
2578			ret = STMF_ERROR_NO_PROP;
2579			goto done;
2580	}
2581
2582	sbdIoctl.stmf_version = STMF_VERSION_1;
2583	sbdIoctl.stmf_ibuf_size = sbdGlobalProps->mlu_struct_size;
2584	sbdIoctl.stmf_ibuf = (uint64_t)(unsigned long)sbdGlobalProps;
2585
2586	ioctlRet = ioctl(fd, SBD_IOCTL_SET_GLOBAL_LU, &sbdIoctl);
2587	if (ioctlRet != 0) {
2588		savedErrno = errno;
2589		switch (savedErrno) {
2590			case EBUSY:
2591				ret = STMF_ERROR_BUSY;
2592				break;
2593			case EPERM:
2594			case EACCES:
2595				ret = STMF_ERROR_PERM;
2596				break;
2597			default:
2598				diskError(sbdIoctl.stmf_error, &ret);
2599				if (ret == STMF_STATUS_ERROR) {
2600					syslog(LOG_DEBUG,
2601					"modifyDiskLu:ioctl "
2602					"error(%d) (%d) (%d)", ioctlRet,
2603					    sbdIoctl.stmf_error, savedErrno);
2604				}
2605				break;
2606		}
2607	}
2608
2609done:
2610	free(sbdGlobalProps);
2611	(void) close(fd);
2612	return (ret);
2613}
2614
2615
2616/*
2617 * stmfSetLuProp
2618 *
2619 * Purpose: set a property on an luResource
2620 *
2621 * hdl - allocated luResource
2622 * prop - property identifier
2623 * propVal - property value to be set
2624 */
2625int
2626stmfSetLuProp(luResource hdl, uint32_t prop, const char *propVal)
2627{
2628	int ret = STMF_STATUS_SUCCESS;
2629	luResourceImpl *luPropsHdl = hdl;
2630	if (hdl == NULL) {
2631		return (STMF_ERROR_INVALID_ARG);
2632	}
2633
2634	if (luPropsHdl->type == STMF_DISK) {
2635		ret = setDiskProp(luPropsHdl, prop, propVal);
2636	} else {
2637		return (STMF_ERROR_INVALID_ARG);
2638	}
2639
2640	return (ret);
2641}
2642
2643/*
2644 * getDiskProp
2645 *
2646 * Purpose: retrieve a given property from a logical unit resource of type disk
2647 *
2648 * hdl - allocated luResourceImpl
2649 * prop - property identifier
2650 * propVal - pointer to character to contain the retrieved property value
2651 * propLen - On input this is the length of propVal. On failure, it contains the
2652 *           number of bytes required for propVal
2653 */
2654static int
2655getDiskProp(luResourceImpl *hdl, uint32_t prop, char *propVal, size_t *propLen)
2656{
2657	int ret = STMF_STATUS_SUCCESS;
2658	diskResource *diskLu = hdl->resource;
2659	char accessState[20];
2660	size_t reqLen;
2661
2662	if (prop == STMF_LU_PROP_ACCESS_STATE) {
2663		if (diskLu->accessState == SBD_LU_ACTIVE) {
2664			(void) strlcpy(accessState, STMF_ACCESS_ACTIVE,
2665			    sizeof (accessState));
2666		} else if (diskLu->accessState == SBD_LU_TRANSITION_TO_ACTIVE) {
2667			(void) strlcpy(accessState,
2668			    STMF_ACCESS_STANDBY_TO_ACTIVE,
2669			    sizeof (accessState));
2670		} else if (diskLu->accessState == SBD_LU_STANDBY) {
2671			(void) strlcpy(accessState, STMF_ACCESS_STANDBY,
2672			    sizeof (accessState));
2673		} else if (diskLu->accessState ==
2674		    SBD_LU_TRANSITION_TO_STANDBY) {
2675			(void) strlcpy(accessState,
2676			    STMF_ACCESS_ACTIVE_TO_STANDBY,
2677			    sizeof (accessState));
2678		}
2679		if ((reqLen = strlcpy(propVal, accessState,
2680		    *propLen)) >= *propLen) {
2681			*propLen = reqLen + 1;
2682			return (STMF_ERROR_INVALID_ARG);
2683		}
2684		return (0);
2685	}
2686
2687	if (diskLu->accessState != SBD_LU_ACTIVE) {
2688		return (STMF_ERROR_NO_PROP_STANDBY);
2689	}
2690
2691	switch (prop) {
2692		case STMF_LU_PROP_BLOCK_SIZE:
2693			if (diskLu->blkSizeValid == B_FALSE) {
2694				return (STMF_ERROR_NO_PROP);
2695			}
2696			reqLen = snprintf(propVal, *propLen, "%llu",
2697			    (u_longlong_t)diskLu->blkSize);
2698			if (reqLen >= *propLen) {
2699				*propLen = reqLen + 1;
2700				return (STMF_ERROR_INVALID_ARG);
2701			}
2702			break;
2703		case STMF_LU_PROP_FILENAME:
2704			if (diskLu->luDataFileNameValid == B_FALSE) {
2705				return (STMF_ERROR_NO_PROP);
2706			}
2707			if ((reqLen = strlcpy(propVal, diskLu->luDataFileName,
2708			    *propLen)) >= *propLen) {
2709				*propLen = reqLen + 1;
2710				return (STMF_ERROR_INVALID_ARG);
2711			}
2712			break;
2713		case STMF_LU_PROP_META_FILENAME:
2714			if (diskLu->luMetaFileNameValid == B_FALSE) {
2715				return (STMF_ERROR_NO_PROP);
2716			}
2717			if ((reqLen = strlcpy(propVal, diskLu->luMetaFileName,
2718			    *propLen)) >= *propLen) {
2719				*propLen = reqLen + 1;
2720				return (STMF_ERROR_INVALID_ARG);
2721			}
2722			break;
2723		case STMF_LU_PROP_MGMT_URL:
2724			if (diskLu->luMgmtUrlValid == B_FALSE) {
2725				return (STMF_ERROR_NO_PROP);
2726			}
2727			if ((reqLen = strlcpy(propVal, diskLu->luMgmtUrl,
2728			    *propLen)) >= *propLen) {
2729				*propLen = reqLen + 1;
2730				return (STMF_ERROR_INVALID_ARG);
2731			}
2732			break;
2733		case STMF_LU_PROP_GUID:
2734			if (diskLu->luGuidValid == B_FALSE) {
2735				return (STMF_ERROR_NO_PROP);
2736			}
2737			reqLen = snprintf(propVal, *propLen,
2738			    "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X"
2739			    "%02X%02X%02X%02X",
2740			    diskLu->luGuid[0], diskLu->luGuid[1],
2741			    diskLu->luGuid[2], diskLu->luGuid[3],
2742			    diskLu->luGuid[4], diskLu->luGuid[5],
2743			    diskLu->luGuid[6], diskLu->luGuid[7],
2744			    diskLu->luGuid[8], diskLu->luGuid[9],
2745			    diskLu->luGuid[10], diskLu->luGuid[11],
2746			    diskLu->luGuid[12], diskLu->luGuid[13],
2747			    diskLu->luGuid[14], diskLu->luGuid[15]);
2748			if (reqLen >= *propLen) {
2749				*propLen = reqLen + 1;
2750				return (STMF_ERROR_INVALID_ARG);
2751			}
2752			break;
2753		case STMF_LU_PROP_SERIAL_NUM:
2754			if (diskLu->serialNumValid == B_FALSE) {
2755				return (STMF_ERROR_NO_PROP);
2756			}
2757			if ((reqLen = strlcpy(propVal, diskLu->serialNum,
2758			    *propLen)) >= *propLen) {
2759				*propLen = reqLen + 1;
2760				return (STMF_ERROR_INVALID_ARG);
2761			}
2762			break;
2763		case STMF_LU_PROP_SIZE:
2764			if (diskLu->luSizeValid == B_FALSE) {
2765				return (STMF_ERROR_NO_PROP);
2766			}
2767			(void) snprintf(propVal, *propLen, "%llu",
2768			    (u_longlong_t)diskLu->luSize);
2769			break;
2770		case STMF_LU_PROP_ALIAS:
2771			if (diskLu->luAliasValid == B_FALSE) {
2772				return (STMF_ERROR_NO_PROP);
2773			}
2774			if ((reqLen = strlcpy(propVal, diskLu->luAlias,
2775			    *propLen)) >= *propLen) {
2776				*propLen = reqLen + 1;
2777				return (STMF_ERROR_INVALID_ARG);
2778			}
2779			break;
2780		case STMF_LU_PROP_VID:
2781			if (diskLu->vidValid == B_FALSE) {
2782				return (STMF_ERROR_NO_PROP);
2783			}
2784			if (*propLen <= sizeof (diskLu->vid)) {
2785				return (STMF_ERROR_INVALID_ARG);
2786			}
2787			bcopy(diskLu->vid, propVal, sizeof (diskLu->vid));
2788			propVal[sizeof (diskLu->vid)] = 0;
2789			break;
2790		case STMF_LU_PROP_PID:
2791			if (diskLu->pidValid == B_FALSE) {
2792				return (STMF_ERROR_NO_PROP);
2793			}
2794			if (*propLen <= sizeof (diskLu->pid)) {
2795				return (STMF_ERROR_INVALID_ARG);
2796			}
2797			bcopy(diskLu->pid, propVal, sizeof (diskLu->pid));
2798			propVal[sizeof (diskLu->pid)] = 0;
2799			break;
2800		case STMF_LU_PROP_WRITE_PROTECT:
2801			if (diskLu->writeProtectEnableValid == B_FALSE) {
2802				return (STMF_ERROR_NO_PROP);
2803			}
2804			if (diskLu->writeProtectEnable) {
2805				if ((reqLen = strlcpy(propVal, "true",
2806				    *propLen)) >= *propLen) {
2807					*propLen = reqLen + 1;
2808					return (STMF_ERROR_INVALID_ARG);
2809				}
2810			} else {
2811				if ((reqLen = strlcpy(propVal, "false",
2812				    *propLen)) >= *propLen) {
2813					*propLen = reqLen + 1;
2814					return (STMF_ERROR_INVALID_ARG);
2815				}
2816			}
2817			break;
2818		case STMF_LU_PROP_WRITE_CACHE_DISABLE:
2819			if (diskLu->writebackCacheDisableValid == B_FALSE) {
2820				return (STMF_ERROR_NO_PROP);
2821			}
2822			if (diskLu->writebackCacheDisable) {
2823				if ((reqLen = strlcpy(propVal, "true",
2824				    *propLen)) >= *propLen) {
2825					*propLen = reqLen + 1;
2826					return (STMF_ERROR_INVALID_ARG);
2827				}
2828			} else {
2829				if ((reqLen = strlcpy(propVal, "false",
2830				    *propLen)) >= *propLen) {
2831					*propLen = reqLen + 1;
2832					return (STMF_ERROR_INVALID_ARG);
2833				}
2834			}
2835			break;
2836		default:
2837			ret = STMF_ERROR_INVALID_PROP;
2838			break;
2839	}
2840
2841	return (ret);
2842}
2843
2844/*
2845 * setDiskProp
2846 *
2847 * Purpose: set properties for resource of type disk
2848 *
2849 * hdl - allocated luResourceImpl
2850 * resourceProp - valid resource identifier
2851 * propVal - valid resource value
2852 */
2853static int
2854setDiskProp(luResourceImpl *hdl, uint32_t resourceProp, const char *propVal)
2855{
2856	int ret = STMF_STATUS_SUCCESS;
2857	int i;
2858	diskResource *diskLu = hdl->resource;
2859	unsigned long long numericProp = 0;
2860	char guidProp[LU_ASCII_GUID_SIZE + 1];
2861	char ouiProp[OUI_ASCII_SIZE + 1];
2862	char hostIdProp[HOST_ID_ASCII_SIZE + 1];
2863	unsigned int oui[OUI_SIZE];
2864	unsigned int hostId[HOST_ID_SIZE];
2865	unsigned int guid[LU_GUID_SIZE];
2866	int propSize;
2867
2868
2869	if (propVal == NULL) {
2870		return (STMF_ERROR_INVALID_ARG);
2871	}
2872
2873	switch (resourceProp) {
2874		case STMF_LU_PROP_ALIAS:
2875			if (strlcpy(diskLu->luAlias, propVal,
2876			    sizeof (diskLu->luAlias)) >=
2877			    sizeof (diskLu->luAlias)) {
2878				return (STMF_ERROR_INVALID_PROPSIZE);
2879			}
2880			diskLu->luAliasValid = B_TRUE;
2881			break;
2882		case STMF_LU_PROP_BLOCK_SIZE: {
2883			const char *tmp = propVal;
2884			while (*tmp) {
2885				if (!isdigit(*tmp++)) {
2886					return (STMF_ERROR_INVALID_ARG);
2887				}
2888			}
2889			(void) sscanf(propVal, "%llu", &numericProp);
2890			if (numericProp > UINT16_MAX) {
2891				return (STMF_ERROR_INVALID_PROPSIZE);
2892			}
2893			diskLu->blkSize = numericProp;
2894			diskLu->blkSizeValid = B_TRUE;
2895			break;
2896		}
2897		case STMF_LU_PROP_COMPANY_ID:
2898			if ((strlcpy(ouiProp, propVal, sizeof (ouiProp))) >=
2899			    sizeof (ouiProp)) {
2900				return (STMF_ERROR_INVALID_ARG);
2901			}
2902			if (checkHexUpper(ouiProp) != 0) {
2903				return (STMF_ERROR_INVALID_ARG);
2904			}
2905			(void) sscanf(ouiProp, "%2X%2X%2X",
2906			    &oui[0], &oui[1], &oui[2]);
2907
2908			diskLu->companyId = 0;
2909			diskLu->companyId += oui[0] << 16;
2910			diskLu->companyId += oui[1] << 8;
2911			diskLu->companyId += oui[2];
2912			if (diskLu->companyId == 0) {
2913				return (STMF_ERROR_INVALID_ARG);
2914			}
2915			diskLu->companyIdValid = B_TRUE;
2916			break;
2917		case STMF_LU_PROP_HOST_ID:
2918			if ((strlcpy(hostIdProp, propVal,
2919			    sizeof (hostIdProp))) >= sizeof (hostIdProp)) {
2920				return (STMF_ERROR_INVALID_ARG);
2921			}
2922			if (checkHexUpper(hostIdProp) != 0) {
2923				return (STMF_ERROR_INVALID_ARG);
2924			}
2925			(void) sscanf(hostIdProp, "%2X%2X%2X%2X",
2926			    &hostId[0], &hostId[1], &hostId[2], &hostId[3]);
2927
2928			diskLu->hostId = 0;
2929			diskLu->hostId += hostId[0] << 24;
2930			diskLu->hostId += hostId[1] << 16;
2931			diskLu->hostId += hostId[2] << 8;
2932			diskLu->hostId += hostId[3];
2933			if (diskLu->hostId == 0) {
2934				return (STMF_ERROR_INVALID_ARG);
2935			}
2936			diskLu->hostIdValid = B_TRUE;
2937			break;
2938		case STMF_LU_PROP_GUID:
2939			if (strlen(propVal) != LU_ASCII_GUID_SIZE) {
2940				return (STMF_ERROR_INVALID_PROPSIZE);
2941			}
2942
2943			if ((strlcpy(guidProp, propVal, sizeof (guidProp))) >=
2944			    sizeof (guidProp)) {
2945				return (STMF_ERROR_INVALID_ARG);
2946			}
2947
2948			if (checkHexUpper(guidProp) != 0) {
2949				return (STMF_ERROR_INVALID_ARG);
2950			}
2951
2952			(void) sscanf(guidProp,
2953			    "%2X%2X%2X%2X%2X%2X%2X%2X%2X%2X%2X%2X%2X%2X%2X%2X",
2954			    &guid[0], &guid[1], &guid[2], &guid[3], &guid[4],
2955			    &guid[5], &guid[6], &guid[7], &guid[8], &guid[9],
2956			    &guid[10], &guid[11], &guid[12], &guid[13],
2957			    &guid[14], &guid[15]);
2958			for (i = 0; i < sizeof (diskLu->luGuid); i++) {
2959				diskLu->luGuid[i] = guid[i];
2960			}
2961			diskLu->luGuidValid = B_TRUE;
2962			break;
2963		case STMF_LU_PROP_FILENAME:
2964			if ((strlcpy(diskLu->luDataFileName, propVal,
2965			    sizeof (diskLu->luDataFileName))) >=
2966			    sizeof (diskLu->luDataFileName)) {
2967				return (STMF_ERROR_INVALID_PROPSIZE);
2968			}
2969			diskLu->luDataFileNameValid = B_TRUE;
2970			break;
2971		case STMF_LU_PROP_META_FILENAME:
2972			if ((strlcpy(diskLu->luMetaFileName, propVal,
2973			    sizeof (diskLu->luMetaFileName))) >=
2974			    sizeof (diskLu->luMetaFileName)) {
2975				return (STMF_ERROR_INVALID_PROPSIZE);
2976			}
2977			diskLu->luMetaFileNameValid = B_TRUE;
2978			break;
2979		case STMF_LU_PROP_MGMT_URL:
2980			if ((strlcpy(diskLu->luMgmtUrl, propVal,
2981			    sizeof (diskLu->luMgmtUrl))) >=
2982			    sizeof (diskLu->luMgmtUrl)) {
2983				return (STMF_ERROR_INVALID_PROPSIZE);
2984			}
2985			diskLu->luMgmtUrlValid = B_TRUE;
2986			break;
2987		case STMF_LU_PROP_PID:
2988			if ((propSize = strlen(propVal)) >
2989			    sizeof (diskLu->pid)) {
2990				return (STMF_ERROR_INVALID_PROPSIZE);
2991			}
2992			(void) strncpy(diskLu->pid, propVal, propSize);
2993			diskLu->pidValid = B_TRUE;
2994			break;
2995		case STMF_LU_PROP_SERIAL_NUM:
2996			if ((propSize = strlen(propVal)) >
2997			    (sizeof (diskLu->serialNum) - 1)) {
2998				return (STMF_ERROR_INVALID_PROPSIZE);
2999			}
3000			(void) strncpy(diskLu->serialNum, propVal, propSize);
3001			diskLu->serialNumValid = B_TRUE;
3002			break;
3003		case STMF_LU_PROP_SIZE:
3004			if ((niceStrToNum(propVal, &diskLu->luSize) != 0)) {
3005				return (STMF_ERROR_INVALID_ARG);
3006			}
3007			diskLu->luSizeValid = B_TRUE;
3008			break;
3009		case STMF_LU_PROP_VID:
3010			if ((propSize = strlen(propVal)) >
3011			    sizeof (diskLu->vid)) {
3012				return (STMF_ERROR_INVALID_PROPSIZE);
3013			}
3014			(void) strncpy(diskLu->vid, propVal, propSize);
3015			diskLu->vidValid = B_TRUE;
3016			break;
3017		case STMF_LU_PROP_WRITE_PROTECT:
3018			if (strcasecmp(propVal, "TRUE") == 0) {
3019				diskLu->writeProtectEnable = B_TRUE;
3020			} else if (strcasecmp(propVal, "FALSE") == 0) {
3021				diskLu->writeProtectEnable = B_FALSE;
3022			} else {
3023				return (STMF_ERROR_INVALID_ARG);
3024			}
3025			diskLu->writeProtectEnableValid = B_TRUE;
3026			break;
3027		case STMF_LU_PROP_WRITE_CACHE_DISABLE:
3028			if (strcasecmp(propVal, "TRUE") == 0) {
3029				diskLu->writebackCacheDisable = B_TRUE;
3030			} else if (strcasecmp(propVal, "FALSE") == 0) {
3031				diskLu->writebackCacheDisable = B_FALSE;
3032			} else {
3033				return (STMF_ERROR_INVALID_ARG);
3034			}
3035			diskLu->writebackCacheDisableValid = B_TRUE;
3036			break;
3037		case STMF_LU_PROP_ACCESS_STATE:
3038			ret = STMF_ERROR_INVALID_PROP;
3039			break;
3040		default:
3041			ret = STMF_ERROR_INVALID_PROP;
3042			break;
3043	}
3044	return (ret);
3045}
3046
3047static int
3048checkHexUpper(char *buf)
3049{
3050	int i;
3051
3052	for (i = 0; i < strlen(buf); i++) {
3053		if (isxdigit(buf[i])) {
3054			buf[i] = toupper(buf[i]);
3055			continue;
3056		}
3057		return (-1);
3058	}
3059
3060	return (0);
3061}
3062
3063/*
3064 * Given a numeric suffix, convert the value into a number of bits that the
3065 * resulting value must be shifted.
3066 * Code lifted from libzfs_util.c
3067 */
3068static int
3069strToShift(const char *buf)
3070{
3071	const char *ends = "BKMGTPE";
3072	int i;
3073
3074	if (buf[0] == '\0')
3075		return (0);
3076
3077	for (i = 0; i < strlen(ends); i++) {
3078		if (toupper(buf[0]) == ends[i])
3079			return (10*i);
3080	}
3081
3082	return (-1);
3083}
3084
3085int
3086stmfFreeLuResource(luResource hdl)
3087{
3088	int ret = STMF_STATUS_SUCCESS;
3089	if (hdl == NULL) {
3090		return (STMF_ERROR_INVALID_ARG);
3091	}
3092
3093	luResourceImpl *hdlImpl = hdl;
3094	free(hdlImpl->resource);
3095	free(hdlImpl);
3096	return (ret);
3097}
3098
3099/*
3100 * Convert a string of the form '100G' into a real number. Used when setting
3101 * the size of a logical unit.
3102 * Code lifted from libzfs_util.c
3103 */
3104static int
3105niceStrToNum(const char *value, uint64_t *num)
3106{
3107	char *end;
3108	int shift;
3109
3110	*num = 0;
3111
3112	/* Check to see if this looks like a number.  */
3113	if ((value[0] < '0' || value[0] > '9') && value[0] != '.') {
3114		return (-1);
3115	}
3116
3117	/* Rely on stroull() to process the numeric portion.  */
3118	errno = 0;
3119	*num = strtoull(value, &end, 10);
3120
3121	/*
3122	 * Check for ERANGE, which indicates that the value is too large to fit
3123	 * in a 64-bit value.
3124	 */
3125	if (errno == ERANGE) {
3126		return (-1);
3127	}
3128
3129	/*
3130	 * If we have a decimal value, then do the computation with floating
3131	 * point arithmetic.  Otherwise, use standard arithmetic.
3132	 */
3133	if (*end == '.') {
3134		double fval = strtod(value, &end);
3135
3136		if ((shift = strToShift(end)) == -1) {
3137			return (-1);
3138		}
3139
3140		fval *= pow(2, shift);
3141
3142		if (fval > UINT64_MAX) {
3143			return (-1);
3144		}
3145
3146		*num = (uint64_t)fval;
3147	} else {
3148		if ((shift = strToShift(end)) == -1) {
3149			return (-1);
3150		}
3151
3152		/* Check for overflow */
3153		if (shift >= 64 || (*num << shift) >> shift != *num) {
3154			return (-1);
3155		}
3156
3157		*num <<= shift;
3158	}
3159
3160	return (0);
3161}
3162
3163/*
3164 * stmfCreateTargetGroup
3165 *
3166 * Purpose: Create a local port group
3167 *
3168 * targetGroupName - name of local port group to create
3169 */
3170int
3171stmfCreateTargetGroup(stmfGroupName *targetGroupName)
3172{
3173	int ret;
3174	int fd;
3175
3176	if (targetGroupName == NULL ||
3177	    (strnlen((char *)targetGroupName, sizeof (stmfGroupName))
3178	    == sizeof (stmfGroupName))) {
3179		return (STMF_ERROR_INVALID_ARG);
3180	}
3181
3182	/* Check to ensure service exists */
3183	if (psCheckService() != STMF_STATUS_SUCCESS) {
3184		return (STMF_ERROR_SERVICE_NOT_FOUND);
3185	}
3186
3187	/* call init */
3188	ret = initializeConfig();
3189	if (ret != STMF_STATUS_SUCCESS) {
3190		return (ret);
3191	}
3192
3193	/*
3194	 * Open control node for stmf
3195	 */
3196	if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
3197		return (ret);
3198
3199	/*
3200	 * Add the group to the driver
3201	 */
3202	if ((ret = groupIoctl(fd, STMF_IOCTL_CREATE_TARGET_GROUP,
3203	    targetGroupName)) != STMF_STATUS_SUCCESS) {
3204		goto done;
3205	}
3206
3207	if (iGetPersistMethod() == STMF_PERSIST_NONE) {
3208		goto done;
3209	}
3210
3211	/*
3212	 * If the add to the driver was successful, add it to the persistent
3213	 * store.
3214	 */
3215	ret = psCreateTargetGroup((char *)targetGroupName);
3216	switch (ret) {
3217		case STMF_PS_SUCCESS:
3218			ret = STMF_STATUS_SUCCESS;
3219			break;
3220		case STMF_PS_ERROR_EXISTS:
3221			ret = STMF_ERROR_EXISTS;
3222			break;
3223		case STMF_PS_ERROR_BUSY:
3224			ret = STMF_ERROR_BUSY;
3225			break;
3226		case STMF_PS_ERROR_SERVICE_NOT_FOUND:
3227			ret = STMF_ERROR_SERVICE_NOT_FOUND;
3228			break;
3229		case STMF_PS_ERROR_VERSION_MISMATCH:
3230			ret = STMF_ERROR_SERVICE_DATA_VERSION;
3231			break;
3232		default:
3233			syslog(LOG_DEBUG,
3234			    "stmfCreateTargetGroup:psCreateTargetGroup"
3235			    ":error(%d)", ret);
3236			ret = STMF_STATUS_ERROR;
3237			break;
3238	}
3239
3240done:
3241	(void) close(fd);
3242	return (ret);
3243}
3244
3245/*
3246 * stmfDeleteHostGroup
3247 *
3248 * Purpose: Delete an initiator or local port group
3249 *
3250 * hostGroupName - group to delete
3251 */
3252int
3253stmfDeleteHostGroup(stmfGroupName *hostGroupName)
3254{
3255	int ret;
3256	int fd;
3257
3258	if (hostGroupName == NULL) {
3259		return (STMF_ERROR_INVALID_ARG);
3260	}
3261
3262	/* Check to ensure service exists */
3263	if (psCheckService() != STMF_STATUS_SUCCESS) {
3264		return (STMF_ERROR_SERVICE_NOT_FOUND);
3265	}
3266
3267	/* call init */
3268	ret = initializeConfig();
3269	if (ret != STMF_STATUS_SUCCESS) {
3270		return (ret);
3271	}
3272
3273	/*
3274	 * Open control node for stmf
3275	 */
3276	if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
3277		return (ret);
3278
3279	/*
3280	 * Remove the group from the driver
3281	 */
3282	if ((ret = groupIoctl(fd, STMF_IOCTL_REMOVE_HOST_GROUP,
3283	    hostGroupName)) != STMF_STATUS_SUCCESS) {
3284		goto done;
3285	}
3286
3287	if (iGetPersistMethod() == STMF_PERSIST_NONE) {
3288		goto done;
3289	}
3290
3291	/*
3292	 * If the remove from the driver was successful, remove it from the
3293	 * persistent store.
3294	 */
3295	ret = psDeleteHostGroup((char *)hostGroupName);
3296	switch (ret) {
3297		case STMF_PS_SUCCESS:
3298			ret = STMF_STATUS_SUCCESS;
3299			break;
3300		case STMF_PS_ERROR_NOT_FOUND:
3301			ret = STMF_ERROR_NOT_FOUND;
3302			break;
3303		case STMF_PS_ERROR_BUSY:
3304			ret = STMF_ERROR_BUSY;
3305			break;
3306		case STMF_PS_ERROR_SERVICE_NOT_FOUND:
3307			ret = STMF_ERROR_SERVICE_NOT_FOUND;
3308			break;
3309		case STMF_PS_ERROR_VERSION_MISMATCH:
3310			ret = STMF_ERROR_SERVICE_DATA_VERSION;
3311			break;
3312		default:
3313			syslog(LOG_DEBUG,
3314			    "stmfDeleteHostGroup:psDeleteHostGroup:error(%d)",
3315			    ret);
3316			ret = STMF_STATUS_ERROR;
3317			break;
3318	}
3319
3320done:
3321	(void) close(fd);
3322	return (ret);
3323}
3324
3325/*
3326 * stmfDeleteTargetGroup
3327 *
3328 * Purpose: Delete an initiator or local port group
3329 *
3330 * targetGroupName - group to delete
3331 */
3332int
3333stmfDeleteTargetGroup(stmfGroupName *targetGroupName)
3334{
3335	int ret = STMF_STATUS_SUCCESS;
3336	int fd;
3337
3338	if (targetGroupName == NULL) {
3339		return (STMF_ERROR_INVALID_ARG);
3340	}
3341
3342	/* Check to ensure service exists */
3343	if (psCheckService() != STMF_STATUS_SUCCESS) {
3344		return (STMF_ERROR_SERVICE_NOT_FOUND);
3345	}
3346
3347	/* call init */
3348	ret = initializeConfig();
3349	if (ret != STMF_STATUS_SUCCESS) {
3350		return (ret);
3351	}
3352
3353	/*
3354	 * Open control node for stmf
3355	 */
3356	if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
3357		return (ret);
3358
3359	/*
3360	 * Remove the group from the driver
3361	 */
3362	if ((ret = groupIoctl(fd, STMF_IOCTL_REMOVE_TARGET_GROUP,
3363	    targetGroupName)) != STMF_STATUS_SUCCESS) {
3364		goto done;
3365	}
3366
3367	if (iGetPersistMethod() == STMF_PERSIST_NONE) {
3368		goto done;
3369	}
3370
3371	/*
3372	 * If the remove from the driver was successful, remove it from the
3373	 * persistent store.
3374	 */
3375	ret = psDeleteTargetGroup((char *)targetGroupName);
3376	switch (ret) {
3377		case STMF_PS_SUCCESS:
3378			ret = STMF_STATUS_SUCCESS;
3379			break;
3380		case STMF_PS_ERROR_NOT_FOUND:
3381			ret = STMF_ERROR_NOT_FOUND;
3382			break;
3383		case STMF_PS_ERROR_BUSY:
3384			ret = STMF_ERROR_BUSY;
3385			break;
3386		case STMF_PS_ERROR_SERVICE_NOT_FOUND:
3387			ret = STMF_ERROR_SERVICE_NOT_FOUND;
3388			break;
3389		case STMF_PS_ERROR_VERSION_MISMATCH:
3390			ret = STMF_ERROR_SERVICE_DATA_VERSION;
3391			break;
3392		default:
3393			syslog(LOG_DEBUG,
3394			    "stmfDeleteTargetGroup:psDeleteTargetGroup"
3395			    ":error(%d)", ret);
3396			ret = STMF_STATUS_ERROR;
3397			break;
3398	}
3399
3400done:
3401	(void) close(fd);
3402	return (ret);
3403}
3404
3405/*
3406 * stmfDevidFromIscsiName
3407 *
3408 * Purpose: convert an iSCSI name to an stmf devid
3409 *
3410 * iscsiName - unicode nul terminated utf-8 encoded iSCSI name
3411 * devid - on success, contains the converted iscsi name
3412 */
3413int
3414stmfDevidFromIscsiName(char *iscsiName, stmfDevid *devid)
3415{
3416	if (devid == NULL || iscsiName == NULL)
3417		return (STMF_ERROR_INVALID_ARG);
3418
3419	bzero(devid, sizeof (stmfDevid));
3420
3421	/* Validate size of target */
3422	if ((devid->identLength = strlen(iscsiName)) > MAX_ISCSI_NAME ||
3423	    devid->identLength < strlen(EUI) ||
3424	    devid->identLength < strlen(IQN)) {
3425		return (STMF_ERROR_INVALID_ARG);
3426	}
3427
3428	if ((strncmp(iscsiName, EUI, strlen(EUI)) != 0) &&
3429	    strncmp(iscsiName, IQN, strlen(IQN)) != 0) {
3430		return (STMF_ERROR_INVALID_ARG);
3431	}
3432
3433	/* copy UTF-8 bytes to ident */
3434	bcopy(iscsiName, devid->ident, devid->identLength);
3435
3436	return (STMF_STATUS_SUCCESS);
3437}
3438
3439/*
3440 * stmfDevidFromWwn
3441 *
3442 * Purpose: convert a WWN to an stmf devid
3443 *
3444 * wwn - 8-byte wwn identifier
3445 * devid - on success, contains the converted wwn
3446 */
3447int
3448stmfDevidFromWwn(uchar_t *wwn, stmfDevid *devid)
3449{
3450	if (wwn == NULL || devid == NULL)
3451		return (STMF_ERROR_INVALID_ARG);
3452
3453	bzero(devid, sizeof (stmfDevid));
3454
3455	/* Copy eui prefix */
3456	(void) bcopy(WWN, devid->ident, strlen(WWN));
3457
3458	/* Convert to ASCII uppercase hexadecimal string */
3459	(void) snprintf((char *)&devid->ident[strlen(WWN)],
3460	    sizeof (devid->ident), "%02X%02X%02X%02X%02X%02X%02X%02X",
3461	    wwn[0], wwn[1], wwn[2], wwn[3], wwn[4], wwn[5], wwn[6], wwn[7]);
3462
3463	devid->identLength = strlen((char *)devid->ident);
3464
3465	return (STMF_STATUS_SUCCESS);
3466}
3467
3468/*
3469 * stmfFreeMemory
3470 *
3471 * Purpose: Free memory allocated by this library
3472 *
3473 * memory - previously allocated pointer of memory managed by library
3474 */
3475void
3476stmfFreeMemory(void *memory)
3477{
3478	free(memory);
3479}
3480
3481/*
3482 * get host group, target group list from stmf
3483 *
3484 * groupType - HOST_GROUP, TARGET_GROUP
3485 */
3486static int
3487groupListIoctl(stmfGroupList **groupList, int groupType)
3488{
3489	int ret;
3490	int fd;
3491	int ioctlRet;
3492	int i;
3493	int cmd;
3494	stmf_iocdata_t stmfIoctl;
3495	/* framework group list */
3496	stmf_group_name_t *iGroupList = NULL;
3497	uint32_t groupListSize;
3498
3499	if (groupList == NULL) {
3500		return (STMF_ERROR_INVALID_ARG);
3501	}
3502
3503	if (groupType == HOST_GROUP) {
3504		cmd = STMF_IOCTL_GET_HG_LIST;
3505	} else if (groupType == TARGET_GROUP) {
3506		cmd = STMF_IOCTL_GET_TG_LIST;
3507	} else {
3508		return (STMF_ERROR_INVALID_ARG);
3509	}
3510
3511	/* call init */
3512	ret = initializeConfig();
3513	if (ret != STMF_STATUS_SUCCESS) {
3514		return (ret);
3515	}
3516
3517	/*
3518	 * Open control node for stmf
3519	 */
3520	if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
3521		return (ret);
3522
3523	/*
3524	 * Allocate ioctl input buffer
3525	 */
3526	groupListSize = ALLOC_GROUP;
3527	groupListSize = groupListSize * (sizeof (stmf_group_name_t));
3528	iGroupList = (stmf_group_name_t *)calloc(1, groupListSize);
3529	if (iGroupList == NULL) {
3530		ret = STMF_ERROR_NOMEM;
3531		goto done;
3532	}
3533
3534	bzero(&stmfIoctl, sizeof (stmfIoctl));
3535	/*
3536	 * Issue ioctl to get the group list
3537	 */
3538	stmfIoctl.stmf_version = STMF_VERSION_1;
3539	stmfIoctl.stmf_obuf_size = groupListSize;
3540	stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)iGroupList;
3541	ioctlRet = ioctl(fd, cmd, &stmfIoctl);
3542	if (ioctlRet != 0) {
3543		switch (errno) {
3544			case EBUSY:
3545				ret = STMF_ERROR_BUSY;
3546				break;
3547			case EPERM:
3548			case EACCES:
3549				ret = STMF_ERROR_PERM;
3550				break;
3551			default:
3552				syslog(LOG_DEBUG,
3553				    "groupListIoctl:ioctl errno(%d)",
3554				    errno);
3555				ret = STMF_STATUS_ERROR;
3556				break;
3557		}
3558		goto done;
3559	}
3560	/*
3561	 * Check whether input buffer was large enough
3562	 */
3563	if (stmfIoctl.stmf_obuf_max_nentries > ALLOC_GROUP) {
3564		groupListSize = stmfIoctl.stmf_obuf_max_nentries *
3565		    sizeof (stmf_group_name_t);
3566		iGroupList = realloc(iGroupList, groupListSize);
3567		if (iGroupList == NULL) {
3568			ret = STMF_ERROR_NOMEM;
3569			goto done;
3570		}
3571		stmfIoctl.stmf_obuf_size = groupListSize;
3572		stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)iGroupList;
3573		ioctlRet = ioctl(fd, cmd, &stmfIoctl);
3574		if (ioctlRet != 0) {
3575			switch (errno) {
3576				case EBUSY:
3577					ret = STMF_ERROR_BUSY;
3578					break;
3579				case EPERM:
3580				case EACCES:
3581					ret = STMF_ERROR_PERM;
3582					break;
3583				default:
3584					syslog(LOG_DEBUG,
3585					    "groupListIoctl:ioctl errno(%d)",
3586					    errno);
3587					ret = STMF_STATUS_ERROR;
3588					break;
3589			}
3590			goto done;
3591		}
3592	}
3593
3594	/* allocate and copy to caller's buffer */
3595	*groupList = (stmfGroupList *)calloc(1, sizeof (stmfGroupList) +
3596	    sizeof (stmfGroupName) * stmfIoctl.stmf_obuf_nentries);
3597	if (*groupList == NULL) {
3598		ret = STMF_ERROR_NOMEM;
3599		goto done;
3600	}
3601	(*groupList)->cnt = stmfIoctl.stmf_obuf_nentries;
3602	for (i = 0; i < stmfIoctl.stmf_obuf_nentries; i++) {
3603		bcopy(iGroupList[i].name, (*groupList)->name[i],
3604		    sizeof (stmfGroupName));
3605	}
3606
3607done:
3608	free(iGroupList);
3609	(void) close(fd);
3610	return (ret);
3611}
3612
3613/*
3614 * get host group members, target group members from stmf
3615 *
3616 * groupProps - allocated on success
3617 *
3618 * groupType - HOST_GROUP, TARGET_GROUP
3619 */
3620static int
3621groupMemberListIoctl(stmfGroupName *groupName, stmfGroupProperties **groupProps,
3622    int groupType)
3623{
3624	int ret;
3625	int fd;
3626	int ioctlRet;
3627	int i;
3628	int cmd;
3629	stmf_iocdata_t stmfIoctl;
3630	/* framework group list */
3631	stmf_group_name_t iGroupName;
3632	stmf_ge_ident_t *iGroupMembers;
3633	uint32_t groupListSize;
3634
3635	if (groupName == NULL) {
3636		return (STMF_ERROR_INVALID_ARG);
3637	}
3638
3639	if (groupType == HOST_GROUP) {
3640		cmd = STMF_IOCTL_GET_HG_ENTRIES;
3641	} else if (groupType == TARGET_GROUP) {
3642		cmd = STMF_IOCTL_GET_TG_ENTRIES;
3643	} else {
3644		return (STMF_ERROR_INVALID_ARG);
3645	}
3646
3647	/* call init */
3648	ret = initializeConfig();
3649	if (ret != STMF_STATUS_SUCCESS) {
3650		return (ret);
3651	}
3652
3653	/*
3654	 * Open control node for stmf
3655	 */
3656	if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
3657		return (ret);
3658
3659	bzero(&iGroupName, sizeof (iGroupName));
3660
3661	bcopy(groupName, &iGroupName.name, strlen((char *)groupName));
3662
3663	iGroupName.name_size = strlen((char *)groupName);
3664
3665	/*
3666	 * Allocate ioctl input buffer
3667	 */
3668	groupListSize = ALLOC_GRP_MEMBER;
3669	groupListSize = groupListSize * (sizeof (stmf_ge_ident_t));
3670	iGroupMembers = (stmf_ge_ident_t *)calloc(1, groupListSize);
3671	if (iGroupMembers == NULL) {
3672		ret = STMF_ERROR_NOMEM;
3673		goto done;
3674	}
3675
3676	bzero(&stmfIoctl, sizeof (stmfIoctl));
3677	/*
3678	 * Issue ioctl to get the group list
3679	 */
3680	stmfIoctl.stmf_version = STMF_VERSION_1;
3681	stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&iGroupName;
3682	stmfIoctl.stmf_ibuf_size = sizeof (stmf_group_name_t);
3683	stmfIoctl.stmf_obuf_size = groupListSize;
3684	stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)iGroupMembers;
3685	ioctlRet = ioctl(fd, cmd, &stmfIoctl);
3686	if (ioctlRet != 0) {
3687		switch (errno) {
3688			case EBUSY:
3689				ret = STMF_ERROR_BUSY;
3690				break;
3691			case EPERM:
3692			case EACCES:
3693				ret = STMF_ERROR_PERM;
3694				break;
3695			default:
3696				syslog(LOG_DEBUG,
3697				    "groupListIoctl:ioctl errno(%d)",
3698				    errno);
3699				ret = STMF_STATUS_ERROR;
3700				break;
3701		}
3702		goto done;
3703	}
3704	/*
3705	 * Check whether input buffer was large enough
3706	 */
3707	if (stmfIoctl.stmf_obuf_max_nentries > ALLOC_GRP_MEMBER) {
3708		groupListSize = stmfIoctl.stmf_obuf_max_nentries *
3709		    sizeof (stmf_ge_ident_t);
3710		iGroupMembers = realloc(iGroupMembers, groupListSize);
3711		if (iGroupMembers == NULL) {
3712			ret = STMF_ERROR_NOMEM;
3713			goto done;
3714		}
3715		stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&iGroupName;
3716		stmfIoctl.stmf_ibuf_size = sizeof (stmf_group_name_t);
3717		stmfIoctl.stmf_obuf_size = groupListSize;
3718		stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)iGroupMembers;
3719		ioctlRet = ioctl(fd, cmd, &stmfIoctl);
3720		if (ioctlRet != 0) {
3721			switch (errno) {
3722				case EBUSY:
3723					ret = STMF_ERROR_BUSY;
3724					break;
3725				case EPERM:
3726				case EACCES:
3727					ret = STMF_ERROR_PERM;
3728					break;
3729				default:
3730					syslog(LOG_DEBUG,
3731					    "groupListIoctl:ioctl errno(%d)",
3732					    errno);
3733					ret = STMF_STATUS_ERROR;
3734					break;
3735			}
3736			goto done;
3737		}
3738	}
3739
3740	/* allocate and copy to caller's buffer */
3741	*groupProps = (stmfGroupProperties *)calloc(1,
3742	    sizeof (stmfGroupProperties) +
3743	    sizeof (stmfDevid) * stmfIoctl.stmf_obuf_nentries);
3744	if (*groupProps == NULL) {
3745		ret = STMF_ERROR_NOMEM;
3746		goto done;
3747	}
3748	(*groupProps)->cnt = stmfIoctl.stmf_obuf_nentries;
3749	for (i = 0; i < stmfIoctl.stmf_obuf_nentries; i++) {
3750		(*groupProps)->name[i].identLength =
3751		    iGroupMembers[i].ident_size;
3752		bcopy(iGroupMembers[i].ident, (*groupProps)->name[i].ident,
3753		    iGroupMembers[i].ident_size);
3754	}
3755
3756done:
3757	free(iGroupMembers);
3758	(void) close(fd);
3759	return (ret);
3760}
3761
3762/*
3763 * Purpose: access persistent config data for host groups and target groups
3764 */
3765static int
3766iLoadGroupFromPs(stmfGroupList **groupList, int type)
3767{
3768	int ret;
3769
3770	if (groupList == NULL) {
3771		return (STMF_ERROR_INVALID_ARG);
3772	}
3773
3774	if (type == HOST_GROUP) {
3775		ret = psGetHostGroupList(groupList);
3776	} else if (type == TARGET_GROUP) {
3777		ret = psGetTargetGroupList(groupList);
3778	} else {
3779		return (STMF_ERROR_INVALID_ARG);
3780	}
3781	switch (ret) {
3782		case STMF_PS_SUCCESS:
3783			ret = STMF_STATUS_SUCCESS;
3784			break;
3785		case STMF_PS_ERROR_NOT_FOUND:
3786			ret = STMF_ERROR_NOT_FOUND;
3787			break;
3788		case STMF_PS_ERROR_BUSY:
3789			ret = STMF_ERROR_BUSY;
3790			break;
3791		case STMF_PS_ERROR_SERVICE_NOT_FOUND:
3792			ret = STMF_ERROR_SERVICE_NOT_FOUND;
3793			break;
3794		case STMF_PS_ERROR_VERSION_MISMATCH:
3795			ret = STMF_ERROR_SERVICE_DATA_VERSION;
3796			break;
3797		default:
3798			syslog(LOG_DEBUG,
3799			    "stmfGetHostGroupList:psGetHostGroupList:error(%d)",
3800			    ret);
3801			ret = STMF_STATUS_ERROR;
3802			break;
3803	}
3804
3805	return (ret);
3806}
3807
3808/*
3809 * stmfGetHostGroupList
3810 *
3811 * Purpose: Retrieves the list of initiator group oids
3812 *
3813 * hostGroupList - pointer to pointer to hostGroupList structure
3814 *                 on success, this contains the host group list.
3815 */
3816int
3817stmfGetHostGroupList(stmfGroupList **hostGroupList)
3818{
3819	int ret = STMF_STATUS_ERROR;
3820
3821	if (hostGroupList == NULL) {
3822		return (STMF_ERROR_INVALID_ARG);
3823	}
3824
3825	ret = groupListIoctl(hostGroupList, HOST_GROUP);
3826	return (ret);
3827}
3828
3829
3830/*
3831 * Purpose: access persistent config data for host groups and target groups
3832 */
3833static int
3834iLoadGroupMembersFromPs(stmfGroupName *groupName,
3835    stmfGroupProperties **groupProp, int type)
3836{
3837	int ret;
3838
3839	if (groupName == NULL) {
3840		return (STMF_ERROR_INVALID_ARG);
3841	}
3842
3843	if (type == HOST_GROUP) {
3844		ret = psGetHostGroupMemberList((char *)groupName, groupProp);
3845	} else if (type == TARGET_GROUP) {
3846		ret = psGetTargetGroupMemberList((char *)groupName, groupProp);
3847	} else {
3848		return (STMF_ERROR_INVALID_ARG);
3849	}
3850	switch (ret) {
3851		case STMF_PS_SUCCESS:
3852			ret = STMF_STATUS_SUCCESS;
3853			break;
3854		case STMF_PS_ERROR_NOT_FOUND:
3855			ret = STMF_ERROR_NOT_FOUND;
3856			break;
3857		case STMF_PS_ERROR_BUSY:
3858			ret = STMF_ERROR_BUSY;
3859			break;
3860		case STMF_PS_ERROR_SERVICE_NOT_FOUND:
3861			ret = STMF_ERROR_SERVICE_NOT_FOUND;
3862			break;
3863		case STMF_PS_ERROR_VERSION_MISMATCH:
3864			ret = STMF_ERROR_SERVICE_DATA_VERSION;
3865			break;
3866		default:
3867			syslog(LOG_DEBUG,
3868			    "iLoadGroupMembersFromPs:psGetHostGroupList:"
3869			    "error(%d)", ret);
3870			ret = STMF_STATUS_ERROR;
3871			break;
3872	}
3873
3874	return (ret);
3875}
3876
3877/*
3878 * stmfGetHostGroupMembers
3879 *
3880 * Purpose: Retrieves the group properties for a host group
3881 *
3882 * groupName - name of group for which to retrieve host group members.
3883 * groupProp - pointer to pointer to stmfGroupProperties structure
3884 *             on success, this contains the list of group members.
3885 */
3886int
3887stmfGetHostGroupMembers(stmfGroupName *groupName,
3888    stmfGroupProperties **groupProp)
3889{
3890	int ret;
3891
3892	if (groupName == NULL || groupProp == NULL) {
3893		return (STMF_ERROR_INVALID_ARG);
3894	}
3895
3896	ret = groupMemberListIoctl(groupName, groupProp, HOST_GROUP);
3897
3898	return (ret);
3899}
3900
3901/*
3902 * stmfGetProviderData
3903 *
3904 * Purpose: Get provider data list
3905 *
3906 * providerName - name of provider for which to retrieve the data
3907 * nvl - pointer to nvlist_t pointer which will contain the nvlist data
3908 *       retrieved.
3909 * providerType - type of provider for which to retrieve data.
3910 *		    STMF_LU_PROVIDER_TYPE
3911 *		    STMF_PORT_PROVIDER_TYPE
3912 */
3913int
3914stmfGetProviderData(char *providerName, nvlist_t **nvl, int providerType)
3915{
3916	return (stmfGetProviderDataProt(providerName, nvl, providerType,
3917	    NULL));
3918}
3919
3920/*
3921 * stmfGetProviderDataProt
3922 *
3923 * Purpose: Get provider data list with token
3924 *
3925 * providerName - name of provider for which to retrieve the data
3926 * nvl - pointer to nvlist_t pointer which will contain the nvlist data
3927 *       retrieved.
3928 * providerType - type of provider for which to retrieve data.
3929 *		    STMF_LU_PROVIDER_TYPE
3930 *		    STMF_PORT_PROVIDER_TYPE
3931 * setToken - Returns the stale data token
3932 */
3933int
3934stmfGetProviderDataProt(char *providerName, nvlist_t **nvl, int providerType,
3935    uint64_t *setToken)
3936{
3937	int ret;
3938
3939	if (providerName == NULL || nvl == NULL) {
3940		return (STMF_ERROR_INVALID_ARG);
3941	}
3942	if (providerType != STMF_LU_PROVIDER_TYPE &&
3943	    providerType != STMF_PORT_PROVIDER_TYPE) {
3944		return (STMF_ERROR_INVALID_ARG);
3945	}
3946	/* call init */
3947	ret = initializeConfig();
3948	if (ret != STMF_STATUS_SUCCESS) {
3949		return (ret);
3950	}
3951	return (getProviderData(providerName, nvl, providerType, setToken));
3952}
3953
3954/*
3955 * stmfGetProviderDataList
3956 *
3957 * Purpose: Get the list of providers currently persisting data
3958 *
3959 * providerList - pointer to pointer to an stmfProviderList structure allocated
3960 *                by the caller. Will contain the list of providers on success.
3961 */
3962int
3963stmfGetProviderDataList(stmfProviderList **providerList)
3964{
3965	int ret;
3966
3967	ret = psGetProviderDataList(providerList);
3968	switch (ret) {
3969		case STMF_PS_SUCCESS:
3970			ret = STMF_STATUS_SUCCESS;
3971			break;
3972		case STMF_PS_ERROR_BUSY:
3973			ret = STMF_ERROR_BUSY;
3974			break;
3975		case STMF_PS_ERROR_SERVICE_NOT_FOUND:
3976			ret = STMF_ERROR_SERVICE_NOT_FOUND;
3977			break;
3978		case STMF_PS_ERROR_VERSION_MISMATCH:
3979			ret = STMF_ERROR_SERVICE_DATA_VERSION;
3980			break;
3981		default:
3982			syslog(LOG_DEBUG,
3983			    "stmfGetProviderDataList:psGetProviderDataList"
3984			    ":error(%d)", ret);
3985			ret = STMF_STATUS_ERROR;
3986			break;
3987	}
3988
3989	return (ret);
3990}
3991
3992
3993/*
3994 * stmfGetSessionList
3995 *
3996 * Purpose: Retrieves the session list for a target (devid)
3997 *
3998 * devid - devid of target for which to retrieve session information.
3999 * sessionList - pointer to pointer to stmfSessionList structure
4000 *             on success, this contains the list of initiator sessions.
4001 */
4002int
4003stmfGetSessionList(stmfDevid *devid, stmfSessionList **sessionList)
4004{
4005	int ret = STMF_STATUS_SUCCESS;
4006	int fd;
4007	int ioctlRet;
4008	int cmd = STMF_IOCTL_SESSION_LIST;
4009	int i;
4010	stmf_iocdata_t stmfIoctl;
4011	slist_scsi_session_t *fSessionList, *fSessionListP = NULL;
4012	uint8_t ident[260];
4013	uint32_t fSessionListSize;
4014
4015	if (sessionList == NULL || devid == NULL) {
4016		ret = STMF_ERROR_INVALID_ARG;
4017	}
4018
4019	/* call init */
4020	ret = initializeConfig();
4021	if (ret != STMF_STATUS_SUCCESS) {
4022		return (ret);
4023	}
4024
4025	/*
4026	 * Open control node for stmf
4027	 */
4028	if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
4029		return (ret);
4030
4031	/*
4032	 * Allocate ioctl input buffer
4033	 */
4034	fSessionListSize = ALLOC_SESSION;
4035	fSessionListSize = fSessionListSize * (sizeof (slist_scsi_session_t));
4036	fSessionList = (slist_scsi_session_t *)calloc(1, fSessionListSize);
4037	fSessionListP = fSessionList;
4038	if (fSessionList == NULL) {
4039		ret = STMF_ERROR_NOMEM;
4040		goto done;
4041	}
4042
4043	ident[IDENT_LENGTH_BYTE] = devid->identLength;
4044	bcopy(&(devid->ident), &ident[IDENT_LENGTH_BYTE + 1],
4045	    devid->identLength);
4046
4047	bzero(&stmfIoctl, sizeof (stmfIoctl));
4048	/*
4049	 * Issue ioctl to get the session list
4050	 */
4051	stmfIoctl.stmf_version = STMF_VERSION_1;
4052	stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&ident;
4053	stmfIoctl.stmf_ibuf_size = sizeof (ident);
4054	stmfIoctl.stmf_obuf_size = fSessionListSize;
4055	stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)fSessionList;
4056	ioctlRet = ioctl(fd, cmd, &stmfIoctl);
4057	if (ioctlRet != 0) {
4058		switch (errno) {
4059			case EBUSY:
4060				ret = STMF_ERROR_BUSY;
4061				break;
4062			case EPERM:
4063			case EACCES:
4064				ret = STMF_ERROR_PERM;
4065				break;
4066			default:
4067				syslog(LOG_DEBUG,
4068				    "stmfGetSessionList:ioctl errno(%d)",
4069				    errno);
4070				ret = STMF_STATUS_ERROR;
4071				break;
4072		}
4073		goto done;
4074	}
4075	/*
4076	 * Check whether input buffer was large enough
4077	 */
4078	if (stmfIoctl.stmf_obuf_max_nentries > ALLOC_SESSION) {
4079		fSessionListSize = stmfIoctl.stmf_obuf_max_nentries *
4080		    sizeof (slist_scsi_session_t);
4081		fSessionList = realloc(fSessionList, fSessionListSize);
4082		if (fSessionList == NULL) {
4083			ret = STMF_ERROR_NOMEM;
4084			goto done;
4085		}
4086		fSessionListP = fSessionList;
4087		stmfIoctl.stmf_obuf_size = fSessionListSize;
4088		stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)fSessionList;
4089		ioctlRet = ioctl(fd, cmd, &stmfIoctl);
4090		if (ioctlRet != 0) {
4091			switch (errno) {
4092				case EBUSY:
4093					ret = STMF_ERROR_BUSY;
4094					break;
4095				case EPERM:
4096				case EACCES:
4097					ret = STMF_ERROR_PERM;
4098					break;
4099				default:
4100					syslog(LOG_DEBUG,
4101					    "stmfGetSessionList:ioctl "
4102					    "errno(%d)", errno);
4103					ret = STMF_STATUS_ERROR;
4104					break;
4105			}
4106			goto done;
4107		}
4108	}
4109
4110	/*
4111	 * allocate caller's buffer with the final size
4112	 */
4113	*sessionList = (stmfSessionList *)calloc(1, sizeof (stmfSessionList) +
4114	    stmfIoctl.stmf_obuf_max_nentries * sizeof (stmfSession));
4115	if (*sessionList == NULL) {
4116		ret = STMF_ERROR_NOMEM;
4117		free(sessionList);
4118		goto done;
4119	}
4120
4121	(*sessionList)->cnt = stmfIoctl.stmf_obuf_max_nentries;
4122
4123	/*
4124	 * copy session info to caller's buffer
4125	 */
4126	for (i = 0; i < (*sessionList)->cnt; i++) {
4127		(*sessionList)->session[i].initiator.identLength =
4128		    fSessionList->initiator[IDENT_LENGTH_BYTE];
4129		bcopy(&(fSessionList->initiator[IDENT_LENGTH_BYTE + 1]),
4130		    (*sessionList)->session[i].initiator.ident,
4131		    STMF_IDENT_LENGTH);
4132		bcopy(&(fSessionList->alias),
4133		    &((*sessionList)->session[i].alias),
4134		    sizeof ((*sessionList)->session[i].alias));
4135		bcopy(&(fSessionList++->creation_time),
4136		    &((*sessionList)->session[i].creationTime),
4137		    sizeof (time_t));
4138	}
4139done:
4140	(void) close(fd);
4141	free(fSessionListP);
4142	return (ret);
4143}
4144
4145/*
4146 * stmfGetTargetGroupList
4147 *
4148 * Purpose: Retrieves the list of target groups
4149 *
4150 * targetGroupList - pointer to a pointer to an stmfGroupList structure. On
4151 *		     success, it contains the list of target groups.
4152 */
4153int
4154stmfGetTargetGroupList(stmfGroupList **targetGroupList)
4155{
4156	int ret;
4157
4158	if (targetGroupList == NULL) {
4159		return (STMF_ERROR_INVALID_ARG);
4160	}
4161
4162	ret = groupListIoctl(targetGroupList, TARGET_GROUP);
4163	return (ret);
4164}
4165
4166/*
4167 * stmfGetTargetGroupMembers
4168 *
4169 * Purpose: Retrieves the group members for a target group
4170 *
4171 * groupName - name of target group for which to retrieve members.
4172 * groupProp - pointer to pointer to stmfGroupProperties structure
4173 *             on success, this contains the list of group members.
4174 */
4175int
4176stmfGetTargetGroupMembers(stmfGroupName *groupName,
4177    stmfGroupProperties **groupProp)
4178{
4179	int ret;
4180
4181	if (groupName == NULL || groupProp == NULL) {
4182		return (STMF_ERROR_INVALID_ARG);
4183	}
4184
4185	ret = groupMemberListIoctl(groupName, groupProp, TARGET_GROUP);
4186
4187	return (ret);
4188}
4189
4190/*
4191 * stmfGetTargetList
4192 *
4193 * Purpose: Retrieves the list of target ports
4194 *
4195 * targetList - pointer to a pointer to an stmfDevidList structure.
4196 *		    On success, it contains the list of local ports (target).
4197 */
4198int
4199stmfGetTargetList(stmfDevidList **targetList)
4200{
4201	int ret;
4202	int fd;
4203	int ioctlRet;
4204	int i;
4205	stmf_iocdata_t stmfIoctl;
4206	/* framework target port list */
4207	slist_target_port_t *fTargetList, *fTargetListP = NULL;
4208	uint32_t fTargetListSize;
4209
4210	if (targetList == NULL) {
4211		return (STMF_ERROR_INVALID_ARG);
4212	}
4213
4214	/* call init */
4215	ret = initializeConfig();
4216	if (ret != STMF_STATUS_SUCCESS) {
4217		return (ret);
4218	}
4219
4220	/*
4221	 * Open control node for stmf
4222	 */
4223	if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
4224		return (ret);
4225
4226	/*
4227	 * Allocate ioctl input buffer
4228	 */
4229	fTargetListSize = ALLOC_TARGET_PORT * sizeof (slist_target_port_t);
4230	fTargetListP = fTargetList =
4231	    (slist_target_port_t *)calloc(1, fTargetListSize);
4232	if (fTargetList == NULL) {
4233		ret = STMF_ERROR_NOMEM;
4234		goto done;
4235	}
4236
4237	bzero(&stmfIoctl, sizeof (stmfIoctl));
4238	/*
4239	 * Issue ioctl to retrieve target list
4240	 */
4241	stmfIoctl.stmf_version = STMF_VERSION_1;
4242	stmfIoctl.stmf_obuf_size = fTargetListSize;
4243	stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)fTargetList;
4244	ioctlRet = ioctl(fd, STMF_IOCTL_TARGET_PORT_LIST, &stmfIoctl);
4245	if (ioctlRet != 0) {
4246		switch (errno) {
4247			case EBUSY:
4248				ret = STMF_ERROR_BUSY;
4249				break;
4250			case EPERM:
4251			case EACCES:
4252				ret = STMF_ERROR_PERM;
4253				break;
4254			default:
4255				syslog(LOG_DEBUG,
4256				    "stmfGetTargetList:ioctl errno(%d)", errno);
4257				ret = STMF_STATUS_ERROR;
4258				break;
4259		}
4260		goto done;
4261	}
4262	/*
4263	 * Check whether input buffer was large enough
4264	 */
4265	if (stmfIoctl.stmf_obuf_max_nentries > ALLOC_TARGET_PORT) {
4266		fTargetListSize = stmfIoctl.stmf_obuf_max_nentries *
4267		    sizeof (slist_target_port_t);
4268		fTargetListP = fTargetList =
4269		    realloc(fTargetList, fTargetListSize);
4270		if (fTargetList == NULL) {
4271			ret = STMF_ERROR_NOMEM;
4272			goto done;
4273		}
4274		stmfIoctl.stmf_obuf_size = fTargetListSize;
4275		stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)fTargetList;
4276		ioctlRet = ioctl(fd, STMF_IOCTL_TARGET_PORT_LIST,
4277		    &stmfIoctl);
4278		if (ioctlRet != 0) {
4279			switch (errno) {
4280				case EBUSY:
4281					ret = STMF_ERROR_BUSY;
4282					break;
4283				case EPERM:
4284				case EACCES:
4285					ret = STMF_ERROR_PERM;
4286					break;
4287				default:
4288					syslog(LOG_DEBUG,
4289					    "stmfGetTargetList:ioctl errno(%d)",
4290					    errno);
4291					ret = STMF_STATUS_ERROR;
4292					break;
4293			}
4294			goto done;
4295		}
4296	}
4297
4298	*targetList = (stmfDevidList *)calloc(1,
4299	    stmfIoctl.stmf_obuf_max_nentries * sizeof (stmfDevid) +
4300	    sizeof (stmfDevidList));
4301	if (*targetList == NULL) {
4302		ret = STMF_ERROR_NOMEM;
4303		goto done;
4304	}
4305
4306	(*targetList)->cnt = stmfIoctl.stmf_obuf_max_nentries;
4307	for (i = 0; i < stmfIoctl.stmf_obuf_max_nentries; i++, fTargetList++) {
4308		(*targetList)->devid[i].identLength =
4309		    fTargetList->target[IDENT_LENGTH_BYTE];
4310		bcopy(&fTargetList->target[IDENT_LENGTH_BYTE + 1],
4311		    &(*targetList)->devid[i].ident,
4312		    fTargetList->target[IDENT_LENGTH_BYTE]);
4313	}
4314
4315done:
4316	(void) close(fd);
4317	free(fTargetListP);
4318	return (ret);
4319}
4320
4321/*
4322 * stmfGetTargetProperties
4323 *
4324 * Purpose:  Retrieves the properties for a logical unit
4325 *
4326 * devid - devid of the target for which to retrieve properties
4327 * targetProps - pointer to an stmfTargetProperties structure.
4328 *		On success, it contains the target properties for
4329 *		the specified devid.
4330 */
4331int
4332stmfGetTargetProperties(stmfDevid *devid, stmfTargetProperties *targetProps)
4333{
4334	int ret = STMF_STATUS_SUCCESS;
4335	int fd;
4336	int ioctlRet;
4337	stmf_iocdata_t stmfIoctl;
4338	sioc_target_port_props_t targetProperties;
4339	scsi_devid_desc_t *scsiDevid;
4340
4341	if (devid == NULL || targetProps == NULL) {
4342		return (STMF_ERROR_INVALID_ARG);
4343	}
4344
4345	/* call init */
4346	ret = initializeConfig();
4347	if (ret != STMF_STATUS_SUCCESS) {
4348		return (ret);
4349	}
4350
4351	/*
4352	 * Open control node for stmf
4353	 */
4354	if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
4355		return (ret);
4356
4357	targetProperties.tgt_id[IDENT_LENGTH_BYTE] = devid->identLength;
4358	bcopy(&(devid->ident), &targetProperties.tgt_id[IDENT_LENGTH_BYTE + 1],
4359	    devid->identLength);
4360
4361	bzero(&stmfIoctl, sizeof (stmfIoctl));
4362	/*
4363	 * Issue ioctl to add to the host group
4364	 */
4365	stmfIoctl.stmf_version = STMF_VERSION_1;
4366	stmfIoctl.stmf_ibuf_size = sizeof (targetProperties.tgt_id);
4367	stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&targetProperties.tgt_id;
4368	stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)&targetProperties;
4369	stmfIoctl.stmf_obuf_size = sizeof (targetProperties);
4370	ioctlRet = ioctl(fd, STMF_IOCTL_GET_TARGET_PORT_PROPERTIES,
4371	    &stmfIoctl);
4372	if (ioctlRet != 0) {
4373		switch (errno) {
4374			case EBUSY:
4375				ret = STMF_ERROR_BUSY;
4376				break;
4377			case EPERM:
4378			case EACCES:
4379				ret = STMF_ERROR_PERM;
4380				break;
4381			case ENOENT:
4382				ret = STMF_ERROR_NOT_FOUND;
4383				break;
4384			default:
4385				syslog(LOG_DEBUG,
4386				    "stmfGetTargetProperties:ioctl errno(%d)",
4387				    errno);
4388				ret = STMF_STATUS_ERROR;
4389				break;
4390		}
4391		goto done;
4392	}
4393
4394	bcopy(targetProperties.tgt_provider_name, targetProps->providerName,
4395	    sizeof (targetProperties.tgt_provider_name));
4396	if (targetProperties.tgt_state == STMF_STATE_ONLINE) {
4397		targetProps->status = STMF_TARGET_PORT_ONLINE;
4398	} else if (targetProperties.tgt_state == STMF_STATE_OFFLINE) {
4399		targetProps->status = STMF_TARGET_PORT_OFFLINE;
4400	} else if (targetProperties.tgt_state == STMF_STATE_ONLINING) {
4401		targetProps->status = STMF_TARGET_PORT_ONLINING;
4402	} else if (targetProperties.tgt_state == STMF_STATE_OFFLINING) {
4403		targetProps->status = STMF_TARGET_PORT_OFFLINING;
4404	}
4405	bcopy(targetProperties.tgt_alias, targetProps->alias,
4406	    sizeof (targetProps->alias));
4407
4408	scsiDevid = (scsi_devid_desc_t *)&targetProperties.tgt_id;
4409	targetProps->protocol = scsiDevid->protocol_id;
4410
4411done:
4412	(void) close(fd);
4413	return (ret);
4414}
4415
4416/*
4417 * stmfGetLogicalUnitList
4418 *
4419 * Purpose: Retrieves list of logical unit Object IDs
4420 *
4421 * luList - pointer to a pointer to a stmfGuidList structure. On success,
4422 *          it contains the list of logical unit guids.
4423 *
4424 */
4425int
4426stmfGetLogicalUnitList(stmfGuidList **luList)
4427{
4428	int ret;
4429	int fd;
4430	int ioctlRet;
4431	int cmd = STMF_IOCTL_LU_LIST;
4432	int i;
4433	stmf_iocdata_t stmfIoctl;
4434	slist_lu_t *fLuList;
4435	uint32_t fLuListSize;
4436	uint32_t listCnt;
4437
4438	if (luList == NULL) {
4439		return (STMF_ERROR_INVALID_ARG);
4440	}
4441
4442	/* call init */
4443	ret = initializeConfig();
4444	if (ret != STMF_STATUS_SUCCESS) {
4445		return (ret);
4446	}
4447
4448	/*
4449	 * Open control node for stmf
4450	 */
4451	if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
4452		return (ret);
4453
4454	/*
4455	 * Allocate ioctl input buffer
4456	 */
4457	fLuListSize = ALLOC_LU;
4458	fLuListSize = fLuListSize * (sizeof (slist_lu_t));
4459	fLuList = (slist_lu_t *)calloc(1, fLuListSize);
4460	if (fLuList == NULL) {
4461		ret = STMF_ERROR_NOMEM;
4462		goto done;
4463	}
4464
4465	bzero(&stmfIoctl, sizeof (stmfIoctl));
4466	/*
4467	 * Issue ioctl to get the LU list
4468	 */
4469	stmfIoctl.stmf_version = STMF_VERSION_1;
4470	stmfIoctl.stmf_obuf_size = fLuListSize;
4471	stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)fLuList;
4472	ioctlRet = ioctl(fd, cmd, &stmfIoctl);
4473	if (ioctlRet != 0) {
4474		switch (errno) {
4475			case EBUSY:
4476				ret = STMF_ERROR_BUSY;
4477				break;
4478			case EPERM:
4479			case EACCES:
4480				ret = STMF_ERROR_PERM;
4481				break;
4482			default:
4483				syslog(LOG_DEBUG,
4484				    "stmfGetLogicalUnitList:ioctl errno(%d)",
4485				    errno);
4486				ret = STMF_STATUS_ERROR;
4487				break;
4488		}
4489		goto done;
4490	}
4491	/*
4492	 * Check whether input buffer was large enough
4493	 */
4494	if (stmfIoctl.stmf_obuf_max_nentries > ALLOC_LU) {
4495		fLuListSize = stmfIoctl.stmf_obuf_max_nentries *
4496		    sizeof (slist_lu_t);
4497		free(fLuList);
4498		fLuList = (slist_lu_t *)calloc(1, fLuListSize);
4499		if (fLuList == NULL) {
4500			ret = STMF_ERROR_NOMEM;
4501			goto done;
4502		}
4503		stmfIoctl.stmf_obuf_size = fLuListSize;
4504		stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)fLuList;
4505		ioctlRet = ioctl(fd, cmd, &stmfIoctl);
4506		if (ioctlRet != 0) {
4507			switch (errno) {
4508				case EBUSY:
4509					ret = STMF_ERROR_BUSY;
4510					break;
4511				case EPERM:
4512				case EACCES:
4513					ret = STMF_ERROR_PERM;
4514					break;
4515				default:
4516					syslog(LOG_DEBUG,
4517					    "stmfGetLogicalUnitList:"
4518					    "ioctl errno(%d)", errno);
4519					ret = STMF_STATUS_ERROR;
4520					break;
4521			}
4522			goto done;
4523		}
4524	}
4525
4526	if (ret != STMF_STATUS_SUCCESS) {
4527		goto done;
4528	}
4529
4530	listCnt = stmfIoctl.stmf_obuf_nentries;
4531
4532	/*
4533	 * allocate caller's buffer with the final size
4534	 */
4535	*luList = (stmfGuidList *)calloc(1, sizeof (stmfGuidList) +
4536	    listCnt * sizeof (stmfGuid));
4537	if (*luList == NULL) {
4538		ret = STMF_ERROR_NOMEM;
4539		goto done;
4540	}
4541
4542	(*luList)->cnt = listCnt;
4543
4544	/* copy to caller's buffer */
4545	for (i = 0; i < listCnt; i++) {
4546		bcopy(&fLuList[i].lu_guid, (*luList)->guid[i].guid,
4547		    sizeof (stmfGuid));
4548	}
4549
4550	/*
4551	 * sort the list. This gives a consistent view across gets
4552	 */
4553	qsort((void *)&((*luList)->guid[0]), (*luList)->cnt,
4554	    sizeof (stmfGuid), guidCompare);
4555
4556done:
4557	(void) close(fd);
4558	/*
4559	 * free internal buffers
4560	 */
4561	free(fLuList);
4562	return (ret);
4563}
4564
4565/*
4566 * stmfGetLogicalUnitProperties
4567 *
4568 * Purpose:  Retrieves the properties for a logical unit
4569 *
4570 * lu - guid of the logical unit for which to retrieve properties
4571 * stmfLuProps - pointer to an stmfLogicalUnitProperties structure. On success,
4572 *               it contains the logical unit properties for the specified guid.
4573 */
4574int
4575stmfGetLogicalUnitProperties(stmfGuid *lu, stmfLogicalUnitProperties *luProps)
4576{
4577	int ret = STMF_STATUS_SUCCESS;
4578	int stmfRet;
4579	int fd;
4580	int ioctlRet;
4581	int cmd = STMF_IOCTL_GET_LU_PROPERTIES;
4582	stmfViewEntryList *viewEntryList = NULL;
4583	stmf_iocdata_t stmfIoctl;
4584	sioc_lu_props_t fLuProps;
4585
4586	if (lu == NULL || luProps == NULL) {
4587		return (STMF_ERROR_INVALID_ARG);
4588	}
4589
4590	bzero(luProps, sizeof (stmfLogicalUnitProperties));
4591
4592	/* call init */
4593	ret = initializeConfig();
4594	if (ret != STMF_STATUS_SUCCESS) {
4595		return (ret);
4596	}
4597
4598	/*
4599	 * Open control node for stmf
4600	 */
4601	if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
4602		return (ret);
4603
4604	bzero(&stmfIoctl, sizeof (stmfIoctl));
4605	/*
4606	 * Issue ioctl to add to the host group
4607	 */
4608	stmfIoctl.stmf_version = STMF_VERSION_1;
4609	stmfIoctl.stmf_ibuf_size = sizeof (stmfGuid);
4610	stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)lu;
4611	stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)&fLuProps;
4612	stmfIoctl.stmf_obuf_size = sizeof (fLuProps);
4613	ioctlRet = ioctl(fd, cmd, &stmfIoctl);
4614	if (ioctlRet != 0) {
4615		switch (errno) {
4616			case EBUSY:
4617				ret = STMF_ERROR_BUSY;
4618				break;
4619			case EPERM:
4620			case EACCES:
4621				ret = STMF_ERROR_PERM;
4622				break;
4623			case ENOENT:
4624				stmfRet = stmfGetViewEntryList(lu,
4625				    &viewEntryList);
4626				if (stmfRet == STMF_STATUS_SUCCESS) {
4627					luProps->status =
4628					    STMF_LOGICAL_UNIT_UNREGISTERED;
4629					if (viewEntryList->cnt > 0) {
4630						ret = STMF_STATUS_SUCCESS;
4631					} else {
4632						ret = STMF_ERROR_NOT_FOUND;
4633					}
4634				} else {
4635					ret = STMF_ERROR_NOT_FOUND;
4636				}
4637				stmfFreeMemory(viewEntryList);
4638				break;
4639			default:
4640				syslog(LOG_DEBUG,
4641				    "stmfGetLogicalUnit:ioctl errno(%d)",
4642				    errno);
4643				ret = STMF_STATUS_ERROR;
4644				break;
4645		}
4646		goto done;
4647	}
4648
4649	bcopy(fLuProps.lu_provider_name, luProps->providerName,
4650	    sizeof (fLuProps.lu_provider_name));
4651	if (fLuProps.lu_state == STMF_STATE_ONLINE) {
4652		luProps->status = STMF_LOGICAL_UNIT_ONLINE;
4653	} else if (fLuProps.lu_state == STMF_STATE_OFFLINE) {
4654		luProps->status = STMF_LOGICAL_UNIT_OFFLINE;
4655	} else if (fLuProps.lu_state == STMF_STATE_ONLINING) {
4656		luProps->status = STMF_LOGICAL_UNIT_ONLINING;
4657	} else if (fLuProps.lu_state == STMF_STATE_OFFLINING) {
4658		luProps->status = STMF_LOGICAL_UNIT_OFFLINING;
4659	}
4660	bcopy(fLuProps.lu_alias, luProps->alias, sizeof (luProps->alias));
4661done:
4662	(void) close(fd);
4663	return (ret);
4664}
4665
4666/*
4667 * stmfGetState
4668 *
4669 * Purpose: retrieve the current state of the stmf module
4670 *
4671 * state - pointer to stmfState structure allocated by the caller
4672 *         On success, contains the state of stmf
4673 */
4674int
4675stmfGetState(stmfState *state)
4676{
4677	int ret;
4678	stmf_state_desc_t iState;
4679
4680	if (state == NULL) {
4681		return (STMF_ERROR_INVALID_ARG);
4682	}
4683
4684	ret = getStmfState(&iState);
4685	if (ret != STMF_STATUS_SUCCESS) {
4686		return (ret);
4687	}
4688	switch (iState.state) {
4689		case STMF_STATE_ONLINE:
4690			state->operationalState =
4691			    STMF_SERVICE_STATE_ONLINE;
4692			break;
4693		case STMF_STATE_OFFLINE:
4694			state->operationalState =
4695			    STMF_SERVICE_STATE_OFFLINE;
4696			break;
4697		case STMF_STATE_ONLINING:
4698			state->operationalState =
4699			    STMF_SERVICE_STATE_ONLINING;
4700			break;
4701		case STMF_STATE_OFFLINING:
4702			state->operationalState =
4703			    STMF_SERVICE_STATE_OFFLINING;
4704			break;
4705		default:
4706			state->operationalState =
4707			    STMF_SERVICE_STATE_UNKNOWN;
4708			break;
4709	}
4710	switch (iState.config_state) {
4711		case STMF_CONFIG_NONE:
4712			state->configState = STMF_CONFIG_STATE_NONE;
4713			break;
4714		case STMF_CONFIG_INIT:
4715			state->configState = STMF_CONFIG_STATE_INIT;
4716			break;
4717		case STMF_CONFIG_INIT_DONE:
4718			state->configState =
4719			    STMF_CONFIG_STATE_INIT_DONE;
4720			break;
4721		default:
4722			state->configState =
4723			    STMF_CONFIG_STATE_UNKNOWN;
4724			break;
4725	}
4726	return (STMF_STATUS_SUCCESS);
4727}
4728
4729/*
4730 * stmfGetViewEntryList
4731 *
4732 * Purpose: Retrieves the list of view entries for the specified
4733 *          logical unit.
4734 *
4735 * lu - the guid of the logical unit for which to retrieve the view entry list
4736 * viewEntryList - a pointer to a pointer to a stmfViewEntryList structure. On
4737 *                 success, contains the list of view entries.
4738 */
4739int
4740stmfGetViewEntryList(stmfGuid *lu, stmfViewEntryList **viewEntryList)
4741{
4742	int ret;
4743	int fd;
4744	int ioctlRet;
4745	int cmd = STMF_IOCTL_LU_VE_LIST;
4746	int i;
4747	stmf_iocdata_t stmfIoctl;
4748	stmf_view_op_entry_t *fVeList;
4749	uint32_t fVeListSize;
4750	uint32_t listCnt;
4751
4752	if (lu == NULL || viewEntryList == NULL) {
4753		return (STMF_ERROR_INVALID_ARG);
4754	}
4755
4756	/* call init */
4757	ret = initializeConfig();
4758	if (ret != STMF_STATUS_SUCCESS) {
4759		return (ret);
4760	}
4761
4762	/*
4763	 * Open control node for stmf
4764	 */
4765	if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
4766		return (ret);
4767
4768	/*
4769	 * Allocate ioctl input buffer
4770	 */
4771	fVeListSize = ALLOC_VE;
4772	fVeListSize = fVeListSize * (sizeof (stmf_view_op_entry_t));
4773	fVeList = (stmf_view_op_entry_t *)calloc(1, fVeListSize);
4774	if (fVeList == NULL) {
4775		ret = STMF_ERROR_NOMEM;
4776		goto done;
4777	}
4778
4779	bzero(&stmfIoctl, sizeof (stmfIoctl));
4780	/*
4781	 * Issue ioctl to get the LU list
4782	 */
4783	stmfIoctl.stmf_version = STMF_VERSION_1;
4784	stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)lu;
4785	stmfIoctl.stmf_ibuf_size = sizeof (stmfGuid);
4786	stmfIoctl.stmf_obuf_size = fVeListSize;
4787	stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)fVeList;
4788	ioctlRet = ioctl(fd, cmd, &stmfIoctl);
4789	if (ioctlRet != 0) {
4790		switch (errno) {
4791			case EBUSY:
4792				ret = STMF_ERROR_BUSY;
4793				break;
4794			case EPERM:
4795			case EACCES:
4796				ret = STMF_ERROR_PERM;
4797				break;
4798			default:
4799				syslog(LOG_DEBUG,
4800				    "stmfGetViewEntryList:ioctl errno(%d)",
4801				    errno);
4802				ret = STMF_STATUS_ERROR;
4803				break;
4804		}
4805		goto done;
4806	}
4807	/*
4808	 * Check whether input buffer was large enough
4809	 */
4810	if (stmfIoctl.stmf_obuf_max_nentries > ALLOC_VE) {
4811		bzero(&stmfIoctl, sizeof (stmfIoctl));
4812		fVeListSize = stmfIoctl.stmf_obuf_max_nentries *
4813		    sizeof (stmf_view_op_entry_t);
4814		free(fVeList);
4815		fVeList = (stmf_view_op_entry_t *)calloc(1, fVeListSize);
4816		if (fVeList == NULL) {
4817			return (STMF_ERROR_NOMEM);
4818		}
4819		stmfIoctl.stmf_obuf_size = fVeListSize;
4820		stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)fVeList;
4821		ioctlRet = ioctl(fd, cmd, &stmfIoctl);
4822		if (ioctlRet != 0) {
4823			switch (errno) {
4824				case EBUSY:
4825					ret = STMF_ERROR_BUSY;
4826					break;
4827				case EPERM:
4828				case EACCES:
4829					ret = STMF_ERROR_PERM;
4830					break;
4831				default:
4832					syslog(LOG_DEBUG,
4833					    "stmfGetLogicalUnitList:"
4834					    "ioctl errno(%d)", errno);
4835					ret = STMF_STATUS_ERROR;
4836					break;
4837			}
4838			goto done;
4839		}
4840	}
4841
4842	if (ret != STMF_STATUS_SUCCESS) {
4843		goto done;
4844	}
4845
4846	listCnt = stmfIoctl.stmf_obuf_nentries;
4847
4848	/*
4849	 * allocate caller's buffer with the final size
4850	 */
4851	*viewEntryList = (stmfViewEntryList *)calloc(1,
4852	    sizeof (stmfViewEntryList) + listCnt * sizeof (stmfViewEntry));
4853	if (*viewEntryList == NULL) {
4854		ret = STMF_ERROR_NOMEM;
4855		goto done;
4856	}
4857
4858	(*viewEntryList)->cnt = listCnt;
4859
4860	/* copy to caller's buffer */
4861	for (i = 0; i < listCnt; i++) {
4862		(*viewEntryList)->ve[i].veIndexValid = B_TRUE;
4863		(*viewEntryList)->ve[i].veIndex = fVeList[i].ve_ndx;
4864		if (fVeList[i].ve_all_hosts == 1) {
4865			(*viewEntryList)->ve[i].allHosts = B_TRUE;
4866		} else {
4867			bcopy(fVeList[i].ve_host_group.name,
4868			    (*viewEntryList)->ve[i].hostGroup,
4869			    fVeList[i].ve_host_group.name_size);
4870		}
4871		if (fVeList[i].ve_all_targets == 1) {
4872			(*viewEntryList)->ve[i].allTargets = B_TRUE;
4873		} else {
4874			bcopy(fVeList[i].ve_target_group.name,
4875			    (*viewEntryList)->ve[i].targetGroup,
4876			    fVeList[i].ve_target_group.name_size);
4877		}
4878		bcopy(fVeList[i].ve_lu_nbr, (*viewEntryList)->ve[i].luNbr,
4879		    sizeof ((*viewEntryList)->ve[i].luNbr));
4880		(*viewEntryList)->ve[i].luNbrValid = B_TRUE;
4881	}
4882
4883	/*
4884	 * sort the list. This gives a consistent view across gets
4885	 */
4886	qsort((void *)&((*viewEntryList)->ve[0]), (*viewEntryList)->cnt,
4887	    sizeof (stmfViewEntry), viewEntryCompare);
4888
4889done:
4890	(void) close(fd);
4891	/*
4892	 * free internal buffers
4893	 */
4894	free(fVeList);
4895	return (ret);
4896}
4897
4898
4899/*
4900 * loadHostGroups
4901 *
4902 * Purpose - issues the ioctl to load the host groups into stmf
4903 *
4904 * fd - file descriptor for the control node of stmf.
4905 * groupList - populated host group list
4906 */
4907static int
4908loadHostGroups(int fd, stmfGroupList *groupList)
4909{
4910	int i, j;
4911	int ret = STMF_STATUS_SUCCESS;
4912	stmfGroupProperties *groupProps = NULL;
4913
4914	for (i = 0; i < groupList->cnt; i++) {
4915		if ((ret = groupIoctl(fd, STMF_IOCTL_CREATE_HOST_GROUP,
4916		    &(groupList->name[i]))) != STMF_STATUS_SUCCESS) {
4917			goto out;
4918		}
4919		ret = iLoadGroupMembersFromPs(&(groupList->name[i]),
4920		    &groupProps, HOST_GROUP);
4921		for (j = 0; j < groupProps->cnt; j++) {
4922			if ((ret = groupMemberIoctl(fd, STMF_IOCTL_ADD_HG_ENTRY,
4923			    &(groupList->name[i]), &(groupProps->name[j])))
4924			    != STMF_STATUS_SUCCESS) {
4925				goto out;
4926			}
4927		}
4928	}
4929
4930
4931out:
4932	stmfFreeMemory(groupProps);
4933	return (ret);
4934}
4935
4936/*
4937 * loadTargetGroups
4938 *
4939 * Purpose - issues the ioctl to load the target groups into stmf
4940 *
4941 * fd - file descriptor for the control node of stmf.
4942 * groupList - populated target group list.
4943 */
4944static int
4945loadTargetGroups(int fd, stmfGroupList *groupList)
4946{
4947	int i, j;
4948	int ret = STMF_STATUS_SUCCESS;
4949	stmfGroupProperties *groupProps = NULL;
4950
4951	for (i = 0; i < groupList->cnt; i++) {
4952		if ((ret = groupIoctl(fd, STMF_IOCTL_CREATE_TARGET_GROUP,
4953		    &(groupList->name[i]))) != STMF_STATUS_SUCCESS) {
4954			goto out;
4955		}
4956		ret = iLoadGroupMembersFromPs(&(groupList->name[i]),
4957		    &groupProps, TARGET_GROUP);
4958		for (j = 0; j < groupProps->cnt; j++) {
4959			if ((ret = groupMemberIoctl(fd, STMF_IOCTL_ADD_TG_ENTRY,
4960			    &(groupList->name[i]), &(groupProps->name[j])))
4961			    != STMF_STATUS_SUCCESS) {
4962				goto out;
4963			}
4964		}
4965	}
4966
4967
4968out:
4969	stmfFreeMemory(groupProps);
4970	return (ret);
4971}
4972
4973
4974/*
4975 * loadStore
4976 *
4977 * Purpose: Load the configuration data from the store
4978 *
4979 * First load the host groups and target groups, then the view entries
4980 * and finally the provider data
4981 *
4982 * fd - file descriptor of control node for stmf.
4983 */
4984static int
4985loadStore(int fd)
4986{
4987	int ret;
4988	int i, j;
4989	stmfGroupList *groupList = NULL;
4990	stmfGuidList *guidList = NULL;
4991	stmfViewEntryList *viewEntryList = NULL;
4992	stmfProviderList *providerList = NULL;
4993	int providerType;
4994	nvlist_t *nvl = NULL;
4995
4996
4997
4998	/* load host groups */
4999	ret = iLoadGroupFromPs(&groupList, HOST_GROUP);
5000	if (ret != STMF_STATUS_SUCCESS) {
5001		return (ret);
5002	}
5003	ret = loadHostGroups(fd, groupList);
5004	if (ret != STMF_STATUS_SUCCESS) {
5005		goto out;
5006	}
5007
5008	stmfFreeMemory(groupList);
5009	groupList = NULL;
5010
5011	/* load target groups */
5012	ret = iLoadGroupFromPs(&groupList, TARGET_GROUP);
5013	if (ret != STMF_STATUS_SUCCESS) {
5014		goto out;
5015	}
5016	ret = loadTargetGroups(fd, groupList);
5017	if (ret != STMF_STATUS_SUCCESS) {
5018		goto out;
5019	}
5020
5021	stmfFreeMemory(groupList);
5022	groupList = NULL;
5023
5024	/* Get the guid list */
5025	ret = psGetLogicalUnitList(&guidList);
5026	switch (ret) {
5027		case STMF_PS_SUCCESS:
5028			ret = STMF_STATUS_SUCCESS;
5029			break;
5030		case STMF_PS_ERROR_NOT_FOUND:
5031			ret = STMF_ERROR_NOT_FOUND;
5032			break;
5033		case STMF_PS_ERROR_BUSY:
5034			ret = STMF_ERROR_BUSY;
5035			break;
5036		case STMF_PS_ERROR_SERVICE_NOT_FOUND:
5037			ret = STMF_ERROR_SERVICE_NOT_FOUND;
5038			break;
5039		case STMF_PS_ERROR_VERSION_MISMATCH:
5040			ret = STMF_ERROR_SERVICE_DATA_VERSION;
5041			break;
5042		default:
5043			ret = STMF_STATUS_ERROR;
5044			break;
5045	}
5046
5047	if (ret != STMF_STATUS_SUCCESS) {
5048		goto out;
5049	}
5050
5051	/*
5052	 * We have the guid list, now get the corresponding
5053	 * view entries for each guid
5054	 */
5055	for (i = 0; i < guidList->cnt; i++) {
5056		ret = psGetViewEntryList(&guidList->guid[i], &viewEntryList);
5057		switch (ret) {
5058			case STMF_PS_SUCCESS:
5059				ret = STMF_STATUS_SUCCESS;
5060				break;
5061			case STMF_PS_ERROR_NOT_FOUND:
5062				ret = STMF_ERROR_NOT_FOUND;
5063				break;
5064			case STMF_PS_ERROR_BUSY:
5065				ret = STMF_ERROR_BUSY;
5066				break;
5067			case STMF_PS_ERROR_SERVICE_NOT_FOUND:
5068				ret = STMF_ERROR_SERVICE_NOT_FOUND;
5069				break;
5070			case STMF_PS_ERROR_VERSION_MISMATCH:
5071				ret = STMF_ERROR_SERVICE_DATA_VERSION;
5072				break;
5073			default:
5074				ret = STMF_STATUS_ERROR;
5075				break;
5076		}
5077		if (ret != STMF_STATUS_SUCCESS) {
5078			goto out;
5079		}
5080		for (j = 0; j < viewEntryList->cnt; j++) {
5081			ret = addViewEntryIoctl(fd, &guidList->guid[i],
5082			    &viewEntryList->ve[j]);
5083			if (ret != STMF_STATUS_SUCCESS) {
5084				goto out;
5085			}
5086		}
5087	}
5088
5089	/* get the list of providers that have data */
5090	ret = psGetProviderDataList(&providerList);
5091	switch (ret) {
5092		case STMF_PS_SUCCESS:
5093			ret = STMF_STATUS_SUCCESS;
5094			break;
5095		case STMF_PS_ERROR_NOT_FOUND:
5096			ret = STMF_ERROR_NOT_FOUND;
5097			break;
5098		case STMF_PS_ERROR_BUSY:
5099			ret = STMF_ERROR_BUSY;
5100			break;
5101		case STMF_PS_ERROR_SERVICE_NOT_FOUND:
5102			ret = STMF_ERROR_SERVICE_NOT_FOUND;
5103			break;
5104		case STMF_PS_ERROR_VERSION_MISMATCH:
5105			ret = STMF_ERROR_SERVICE_DATA_VERSION;
5106			break;
5107		default:
5108			ret = STMF_STATUS_ERROR;
5109			break;
5110	}
5111	if (ret != STMF_STATUS_SUCCESS) {
5112		goto out;
5113	}
5114
5115	for (i = 0; i < providerList->cnt; i++) {
5116		providerType = providerList->provider[i].providerType;
5117		ret = psGetProviderData(providerList->provider[i].name,
5118		    &nvl, providerType, NULL);
5119		switch (ret) {
5120			case STMF_PS_SUCCESS:
5121				ret = STMF_STATUS_SUCCESS;
5122				break;
5123			case STMF_PS_ERROR_NOT_FOUND:
5124				ret = STMF_ERROR_NOT_FOUND;
5125				break;
5126			case STMF_PS_ERROR_BUSY:
5127				ret = STMF_ERROR_BUSY;
5128				break;
5129			case STMF_PS_ERROR_SERVICE_NOT_FOUND:
5130				ret = STMF_ERROR_SERVICE_NOT_FOUND;
5131				break;
5132			case STMF_PS_ERROR_VERSION_MISMATCH:
5133				ret = STMF_ERROR_SERVICE_DATA_VERSION;
5134				break;
5135			default:
5136				ret = STMF_STATUS_ERROR;
5137				break;
5138		}
5139		if (ret != STMF_STATUS_SUCCESS) {
5140			goto out;
5141		}
5142
5143		/* call setProviderData */
5144		ret = setProviderData(fd, providerList->provider[i].name, nvl,
5145		    providerType, NULL);
5146		switch (ret) {
5147			case STMF_PS_SUCCESS:
5148				ret = STMF_STATUS_SUCCESS;
5149				break;
5150			case STMF_PS_ERROR_NOT_FOUND:
5151				ret = STMF_ERROR_NOT_FOUND;
5152				break;
5153			case STMF_PS_ERROR_BUSY:
5154				ret = STMF_ERROR_BUSY;
5155				break;
5156			case STMF_PS_ERROR_SERVICE_NOT_FOUND:
5157				ret = STMF_ERROR_SERVICE_NOT_FOUND;
5158				break;
5159			case STMF_PS_ERROR_VERSION_MISMATCH:
5160				ret = STMF_ERROR_SERVICE_DATA_VERSION;
5161				break;
5162			default:
5163				ret = STMF_STATUS_ERROR;
5164				break;
5165		}
5166		if (ret != STMF_STATUS_SUCCESS) {
5167			goto out;
5168		}
5169
5170		nvlist_free(nvl);
5171		nvl = NULL;
5172	}
5173out:
5174	if (groupList != NULL) {
5175		free(groupList);
5176	}
5177	if (guidList != NULL) {
5178		free(guidList);
5179	}
5180	if (viewEntryList != NULL) {
5181		free(viewEntryList);
5182	}
5183	if (nvl != NULL) {
5184		nvlist_free(nvl);
5185	}
5186	return (ret);
5187}
5188
5189/*
5190 * stmfGetAluaState
5191 *
5192 * Purpose - Get the alua state
5193 *
5194 */
5195int
5196stmfGetAluaState(boolean_t *enabled, uint32_t *node)
5197{
5198	int ret = STMF_STATUS_SUCCESS;
5199	int fd;
5200	stmf_iocdata_t stmfIoctl = {0};
5201	stmf_alua_state_desc_t alua_state = {0};
5202	int ioctlRet;
5203
5204	if (enabled == NULL || node == NULL) {
5205		return (STMF_ERROR_INVALID_ARG);
5206	}
5207
5208	/*
5209	 * Open control node for stmf
5210	 */
5211	if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
5212		return (ret);
5213
5214	/*
5215	 * Issue ioctl to get the stmf state
5216	 */
5217	stmfIoctl.stmf_version = STMF_VERSION_1;
5218	stmfIoctl.stmf_obuf_size = sizeof (alua_state);
5219	stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)&alua_state;
5220	ioctlRet = ioctl(fd, STMF_IOCTL_GET_ALUA_STATE, &stmfIoctl);
5221
5222	(void) close(fd);
5223
5224	if (ioctlRet != 0) {
5225		switch (errno) {
5226			case EBUSY:
5227				ret = STMF_ERROR_BUSY;
5228				break;
5229			case EPERM:
5230			case EACCES:
5231				ret = STMF_ERROR_PERM;
5232				break;
5233			default:
5234				syslog(LOG_DEBUG,
5235				    "getStmfState:ioctl errno(%d)", errno);
5236				ret = STMF_STATUS_ERROR;
5237				break;
5238		}
5239	} else {
5240		if (alua_state.alua_state == 1) {
5241			*enabled = B_TRUE;
5242		} else {
5243			*enabled = B_FALSE;
5244		}
5245		*node = alua_state.alua_node;
5246	}
5247
5248	return (ret);
5249}
5250
5251/*
5252 * stmfSetAluaState
5253 *
5254 * Purpose - set the alua state to enabled/disabled
5255 *
5256 */
5257int
5258stmfSetAluaState(boolean_t enabled, uint32_t node)
5259{
5260	int ret = STMF_STATUS_SUCCESS;
5261	int fd;
5262	stmf_iocdata_t stmfIoctl = {0};
5263	stmf_alua_state_desc_t alua_state = {0};
5264	int ioctlRet;
5265
5266	if ((enabled != B_TRUE && enabled != B_FALSE) || (node > 1)) {
5267		return (STMF_ERROR_INVALID_ARG);
5268	}
5269
5270	if (enabled) {
5271		alua_state.alua_state = 1;
5272	}
5273
5274	alua_state.alua_node = node;
5275
5276	/*
5277	 * Open control node for stmf
5278	 */
5279	if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
5280		return (ret);
5281
5282	/*
5283	 * Issue ioctl to get the stmf state
5284	 */
5285	stmfIoctl.stmf_version = STMF_VERSION_1;
5286	stmfIoctl.stmf_ibuf_size = sizeof (alua_state);
5287	stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&alua_state;
5288	ioctlRet = ioctl(fd, STMF_IOCTL_SET_ALUA_STATE, &stmfIoctl);
5289
5290	(void) close(fd);
5291
5292	if (ioctlRet != 0) {
5293		switch (errno) {
5294			case EBUSY:
5295				ret = STMF_ERROR_BUSY;
5296				break;
5297			case EPERM:
5298			case EACCES:
5299				ret = STMF_ERROR_PERM;
5300				break;
5301			default:
5302				syslog(LOG_DEBUG,
5303				    "getStmfState:ioctl errno(%d)", errno);
5304				ret = STMF_STATUS_ERROR;
5305				break;
5306		}
5307	}
5308	if (!enabled && ret == STMF_STATUS_SUCCESS) {
5309		deleteNonActiveLus();
5310	}
5311
5312	return (ret);
5313}
5314
5315static void
5316deleteNonActiveLus()
5317{
5318	int stmfRet;
5319	int i;
5320	stmfGuidList *luList;
5321	luResource hdl = NULL;
5322	char propVal[10];
5323	size_t propValSize = sizeof (propVal);
5324
5325	stmfRet = stmfGetLogicalUnitList(&luList);
5326	if (stmfRet != STMF_STATUS_SUCCESS) {
5327		return;
5328	}
5329
5330	for (i = 0; i < luList->cnt; i++) {
5331		stmfRet = stmfGetLuResource(&luList->guid[i], &hdl);
5332		if (stmfRet != STMF_STATUS_SUCCESS) {
5333			goto err;
5334		}
5335		stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_ACCESS_STATE, propVal,
5336		    &propValSize);
5337		if (stmfRet != STMF_STATUS_SUCCESS) {
5338			goto err;
5339		}
5340		if (propVal[0] == '0') {
5341			(void) stmfFreeLuResource(hdl);
5342			hdl = NULL;
5343			continue;
5344		}
5345		(void) stmfDeleteLu(&luList->guid[i]);
5346		(void) stmfFreeLuResource(hdl);
5347		hdl = NULL;
5348	}
5349
5350err:
5351	stmfFreeMemory(luList);
5352	(void) stmfFreeLuResource(hdl);
5353}
5354
5355/*
5356 * stmfLoadConfig
5357 *
5358 * Purpose - load the configuration data from smf into stmf
5359 *
5360 */
5361int
5362stmfLoadConfig(void)
5363{
5364	int ret = STMF_STATUS_SUCCESS;
5365	int fd;
5366	stmf_state_desc_t stmfStateSet;
5367	stmfState state;
5368
5369	if (iGetPersistMethod() == STMF_PERSIST_NONE) {
5370		stmfStateSet.state = STMF_STATE_OFFLINE;
5371
5372		if ((ret = openStmf(OPEN_EXCL_STMF, &fd))
5373		    != STMF_STATUS_SUCCESS) {
5374			return (ret);
5375		}
5376		/*
5377		 * Configuration not stored persistently; nothing to
5378		 * initialize so do not set to STMF_CONFIG_INIT.
5379		 */
5380		stmfStateSet.config_state = STMF_CONFIG_INIT_DONE;
5381		goto done;
5382	}
5383
5384	/* Check to ensure service exists */
5385	if (psCheckService() != STMF_STATUS_SUCCESS) {
5386		return (STMF_ERROR_SERVICE_NOT_FOUND);
5387	}
5388
5389	ret = stmfGetState(&state);
5390	if (ret == STMF_STATUS_SUCCESS) {
5391		if (state.operationalState != STMF_SERVICE_STATE_OFFLINE) {
5392			return (STMF_ERROR_SERVICE_ONLINE);
5393		}
5394	} else {
5395		return (STMF_STATUS_ERROR);
5396	}
5397
5398
5399	stmfStateSet.state = STMF_STATE_OFFLINE;
5400	stmfStateSet.config_state = STMF_CONFIG_INIT;
5401
5402	/*
5403	 * Open control node for stmf
5404	 */
5405	if ((ret = openStmf(OPEN_EXCL_STMF, &fd)) != STMF_STATUS_SUCCESS)
5406		return (ret);
5407
5408	ret = setStmfState(fd, &stmfStateSet, STMF_SERVICE_TYPE);
5409	if (ret != STMF_STATUS_SUCCESS) {
5410		goto done;
5411	}
5412
5413	/* Load the persistent configuration data */
5414	ret = loadStore(fd);
5415	if (ret != 0) {
5416		goto done;
5417	}
5418
5419	stmfStateSet.state = STMF_STATE_OFFLINE;
5420	stmfStateSet.config_state = STMF_CONFIG_INIT_DONE;
5421
5422done:
5423	if (ret == STMF_STATUS_SUCCESS) {
5424		ret = setStmfState(fd, &stmfStateSet, STMF_SERVICE_TYPE);
5425	}
5426	(void) close(fd);
5427	return (ret);
5428}
5429
5430
5431/*
5432 * getStmfState
5433 *
5434 * stmfState - pointer to stmf_state_desc_t structure. Will contain the state
5435 *             information of the stmf service on success.
5436 */
5437static int
5438getStmfState(stmf_state_desc_t *stmfState)
5439{
5440	int ret = STMF_STATUS_SUCCESS;
5441	int fd;
5442	int ioctlRet;
5443	stmf_iocdata_t stmfIoctl;
5444
5445	/*
5446	 * Open control node for stmf
5447	 */
5448	if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
5449		return (ret);
5450
5451	bzero(&stmfIoctl, sizeof (stmfIoctl));
5452	/*
5453	 * Issue ioctl to get the stmf state
5454	 */
5455	stmfIoctl.stmf_version = STMF_VERSION_1;
5456	stmfIoctl.stmf_ibuf_size = sizeof (stmf_state_desc_t);
5457	stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)stmfState;
5458	stmfIoctl.stmf_obuf_size = sizeof (stmf_state_desc_t);
5459	stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)stmfState;
5460	ioctlRet = ioctl(fd, STMF_IOCTL_GET_STMF_STATE, &stmfIoctl);
5461
5462	(void) close(fd);
5463
5464	if (ioctlRet != 0) {
5465		switch (errno) {
5466			case EBUSY:
5467				ret = STMF_ERROR_BUSY;
5468				break;
5469			case EPERM:
5470			case EACCES:
5471				ret = STMF_ERROR_PERM;
5472				break;
5473			default:
5474				syslog(LOG_DEBUG,
5475				    "getStmfState:ioctl errno(%d)", errno);
5476				ret = STMF_STATUS_ERROR;
5477				break;
5478		}
5479	}
5480	return (ret);
5481}
5482
5483
5484/*
5485 * setStmfState
5486 *
5487 * stmfState - pointer to caller set state structure
5488 * objectType - one of:
5489 *		LOGICAL_UNIT_TYPE
5490 *		TARGET_TYPE
5491 *		STMF_SERVICE_TYPE
5492 */
5493static int
5494setStmfState(int fd, stmf_state_desc_t *stmfState, int objectType)
5495{
5496	int ret = STMF_STATUS_SUCCESS;
5497	int ioctlRet;
5498	int cmd;
5499	stmf_iocdata_t stmfIoctl;
5500
5501	switch (objectType) {
5502		case LOGICAL_UNIT_TYPE:
5503			cmd = STMF_IOCTL_SET_LU_STATE;
5504			break;
5505		case TARGET_TYPE:
5506			cmd = STMF_IOCTL_SET_TARGET_PORT_STATE;
5507			break;
5508		case STMF_SERVICE_TYPE:
5509			cmd = STMF_IOCTL_SET_STMF_STATE;
5510			break;
5511		default:
5512			ret = STMF_STATUS_ERROR;
5513			goto done;
5514	}
5515
5516	bzero(&stmfIoctl, sizeof (stmfIoctl));
5517	/*
5518	 * Issue ioctl to set the stmf state
5519	 */
5520	stmfIoctl.stmf_version = STMF_VERSION_1;
5521	stmfIoctl.stmf_ibuf_size = sizeof (stmf_state_desc_t);
5522	stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)stmfState;
5523	ioctlRet = ioctl(fd, cmd, &stmfIoctl);
5524	if (ioctlRet != 0) {
5525		switch (errno) {
5526			case EBUSY:
5527				ret = STMF_ERROR_BUSY;
5528				break;
5529			case EPERM:
5530			case EACCES:
5531				ret = STMF_ERROR_PERM;
5532				break;
5533			case ENOENT:
5534				ret = STMF_ERROR_NOT_FOUND;
5535				break;
5536			default:
5537				syslog(LOG_DEBUG,
5538				    "setStmfState:ioctl errno(%d)", errno);
5539				ret = STMF_STATUS_ERROR;
5540				break;
5541		}
5542	}
5543done:
5544	return (ret);
5545}
5546int
5547stmfSetStmfProp(uint8_t propType, char *propVal)
5548{
5549	int ret = STMF_STATUS_SUCCESS;
5550	switch (propType) {
5551		case STMF_DEFAULT_LU_STATE:
5552			break;
5553		case STMF_DEFAULT_TARGET_PORT_STATE:
5554			break;
5555		default:
5556			return (STMF_ERROR_INVALID_ARG);
5557	}
5558	ret = psSetStmfProp(propType, propVal);
5559	switch (ret) {
5560		case STMF_PS_SUCCESS:
5561			ret = STMF_STATUS_SUCCESS;
5562			break;
5563		case STMF_PS_ERROR_BUSY:
5564			ret = STMF_ERROR_BUSY;
5565			break;
5566		default:
5567			syslog(LOG_DEBUG,
5568			    "stmfSetStmfProp:psSetStmfProp:error(%d)",
5569			    ret);
5570			ret = STMF_STATUS_ERROR;
5571			break;
5572	}
5573	return (ret);
5574}
5575
5576
5577int
5578stmfGetStmfProp(uint8_t propType, char *propVal, size_t *propLen)
5579{
5580	int ret = STMF_STATUS_SUCCESS;
5581	char prop[MAXNAMELEN] = {0};
5582	size_t reqLen;
5583
5584	if (propVal == NULL || propLen == NULL) {
5585		return (STMF_ERROR_INVALID_ARG);
5586	}
5587	switch (propType) {
5588		case STMF_DEFAULT_LU_STATE:
5589			break;
5590		case STMF_DEFAULT_TARGET_PORT_STATE:
5591			break;
5592		default:
5593			return (STMF_ERROR_INVALID_ARG);
5594	}
5595	ret = psGetStmfProp(propType, prop);
5596	if ((reqLen = strlcpy(propVal, prop, *propLen)) >= *propLen) {
5597		*propLen = reqLen + 1;
5598		return (STMF_ERROR_INVALID_ARG);
5599	}
5600
5601	switch (ret) {
5602		case STMF_PS_SUCCESS:
5603			ret = STMF_STATUS_SUCCESS;
5604			break;
5605		case STMF_PS_ERROR_BUSY:
5606			ret = STMF_ERROR_BUSY;
5607			break;
5608		case STMF_PS_ERROR_NOT_FOUND:
5609			ret = STMF_ERROR_NOT_FOUND;
5610			break;
5611		default:
5612			syslog(LOG_DEBUG,
5613			    "stmfGetStmfProp:psGetStmfProp:error(%d)",
5614			    ret);
5615			ret = STMF_STATUS_ERROR;
5616			break;
5617	}
5618	return (ret);
5619}
5620
5621static int
5622setStmfProp(stmf_set_props_t *stmf_set_props)
5623{
5624	char propVal[MAXNAMELEN] = {0};
5625	int ret;
5626	if ((ret = psGetStmfProp(STMF_DEFAULT_LU_STATE, propVal)) ==
5627	    STMF_PS_SUCCESS) {
5628		if (strncmp(propVal, "offline", strlen(propVal)) == 0) {
5629			stmf_set_props->default_lu_state_value =
5630			    STMF_STATE_OFFLINE;
5631		} else {
5632			stmf_set_props->default_lu_state_value =
5633			    STMF_STATE_ONLINE;
5634		}
5635	} else {
5636		syslog(LOG_DEBUG,
5637		    "DefaultLuState:psSetStmfProp:error(%d)", ret);
5638		goto done;
5639	}
5640
5641	if ((ret = psGetStmfProp(STMF_DEFAULT_TARGET_PORT_STATE, propVal)) ==
5642	    STMF_PS_SUCCESS) {
5643		if (strncmp(propVal, "offline", strlen(propVal)) == 0) {
5644			stmf_set_props->default_target_state_value =
5645			    STMF_STATE_OFFLINE;
5646		} else {
5647			stmf_set_props->default_target_state_value =
5648			    STMF_STATE_ONLINE;
5649		}
5650	} else {
5651		syslog(LOG_DEBUG,
5652		    "DefaultTargetPortState:psSetStmfProp:error(%d)", ret);
5653		goto done;
5654	}
5655done:
5656	switch (ret) {
5657		case STMF_PS_SUCCESS:
5658			ret = STMF_STATUS_SUCCESS;
5659			break;
5660		case STMF_PS_ERROR_NOT_FOUND:
5661			ret = STMF_ERROR_NOT_FOUND;
5662			break;
5663		case STMF_PS_ERROR_BUSY:
5664			ret = STMF_ERROR_BUSY;
5665			break;
5666		default:
5667			ret = STMF_STATUS_ERROR;
5668			break;
5669	}
5670	return (ret);
5671}
5672
5673static int
5674loadStmfProp(int fd)
5675{
5676	int ret = STMF_STATUS_SUCCESS;
5677	int ioctlRet;
5678	stmf_iocdata_t stmfIoctl = {0};
5679	stmf_set_props_t *stmf_set_props = NULL;
5680
5681	stmf_set_props = (stmf_set_props_t *)
5682	    calloc(1, (sizeof (stmf_set_props_t)));
5683	if (stmf_set_props == NULL) {
5684		ret = STMF_ERROR_NOMEM;
5685		goto done;
5686	}
5687
5688	/* Loading the default property values from smf */
5689
5690	if ((ret = setStmfProp(stmf_set_props)) != STMF_STATUS_SUCCESS)
5691		goto done;
5692
5693	stmfIoctl.stmf_version = STMF_VERSION_1;
5694	stmfIoctl.stmf_ibuf_size = sizeof (stmf_set_props_t);
5695	stmfIoctl.stmf_ibuf =
5696	    (uint64_t)(unsigned long)stmf_set_props;
5697
5698	ioctlRet = ioctl(fd, STMF_IOCTL_SET_STMF_PROPS,
5699	    &stmfIoctl);
5700
5701	if (ioctlRet != 0) {
5702		switch (errno) {
5703			case EBUSY:
5704				ret = STMF_ERROR_BUSY;
5705				break;
5706			case EPERM:
5707			case EACCES:
5708				ret = STMF_ERROR_PERM;
5709				break;
5710			case ENOENT:
5711				ret = STMF_ERROR_NOT_FOUND;
5712				break;
5713			default:
5714				syslog(LOG_DEBUG,
5715				    "setDefaultStmfState:"
5716				    "ioctl errno(%d)", errno);
5717				ret = STMF_STATUS_ERROR;
5718				break;
5719		}
5720	}
5721done:
5722	if (stmf_set_props != NULL) {
5723		free(stmf_set_props);
5724	}
5725	return (ret);
5726}
5727
5728int
5729stmfLoadStmfProps(void)
5730{
5731	int ret = STMF_STATUS_SUCCESS;
5732	int fd;
5733	/* open control node for stmf */
5734	if ((ret = openStmf(OPEN_EXCL_STMF, &fd))
5735	    != STMF_STATUS_SUCCESS) {
5736		goto done;
5737	}
5738	ret = loadStmfProp(fd);
5739
5740	(void) close(fd);
5741done:
5742	if (ret != STMF_STATUS_SUCCESS) {
5743		syslog(LOG_DEBUG,
5744		    "stmfLoadStmfProps:Failed");
5745	}
5746	return (ret);
5747}
5748
5749/*
5750 * stmfOnline
5751 *
5752 * Purpose: Online stmf service
5753 *
5754 */
5755int
5756stmfOnline(void)
5757{
5758	int ret;
5759	int fd;
5760	stmfState state;
5761	stmf_state_desc_t iState;
5762
5763	ret = stmfGetState(&state);
5764	if (ret == STMF_STATUS_SUCCESS) {
5765		if (state.operationalState == STMF_SERVICE_STATE_ONLINE) {
5766			return (STMF_ERROR_SERVICE_ONLINE);
5767		}
5768	} else {
5769		return (STMF_STATUS_ERROR);
5770	}
5771	iState.state = STMF_STATE_ONLINE;
5772	iState.config_state = STMF_CONFIG_NONE;
5773	/*
5774	 * Open control node for stmf
5775	 * to make call to setStmfState()
5776	 */
5777	if ((ret = openStmf(OPEN_EXCL_STMF, &fd)) != STMF_STATUS_SUCCESS)
5778		return (ret);
5779	ret = setStmfState(fd, &iState, STMF_SERVICE_TYPE);
5780	(void) close(fd);
5781	return (ret);
5782}
5783
5784/*
5785 * stmfOffline
5786 *
5787 * Purpose: Offline stmf service
5788 *
5789 */
5790int
5791stmfOffline(void)
5792{
5793	int ret;
5794	int fd;
5795	stmfState state;
5796	stmf_state_desc_t iState;
5797
5798	ret = stmfGetState(&state);
5799	if (ret == STMF_STATUS_SUCCESS) {
5800		if (state.operationalState == STMF_SERVICE_STATE_OFFLINE) {
5801			return (STMF_ERROR_SERVICE_OFFLINE);
5802		}
5803	} else {
5804		return (STMF_STATUS_ERROR);
5805	}
5806	iState.state = STMF_STATE_OFFLINE;
5807	iState.config_state = STMF_CONFIG_NONE;
5808
5809	/*
5810	 * Open control node for stmf
5811	 * to make call to setStmfState()
5812	 */
5813	if ((ret = openStmf(OPEN_EXCL_STMF, &fd)) != STMF_STATUS_SUCCESS)
5814		return (ret);
5815	ret = setStmfState(fd, &iState, STMF_SERVICE_TYPE);
5816	(void) close(fd);
5817	return (ret);
5818}
5819
5820
5821/*
5822 * stmfOfflineTarget
5823 *
5824 * Purpose: Change state of target to offline
5825 *
5826 * devid - devid of the target to offline
5827 */
5828int
5829stmfOfflineTarget(stmfDevid *devid)
5830{
5831	stmf_state_desc_t targetState;
5832	int ret = STMF_STATUS_SUCCESS;
5833	int fd;
5834
5835	if (devid == NULL) {
5836		return (STMF_ERROR_INVALID_ARG);
5837	}
5838	bzero(&targetState, sizeof (targetState));
5839
5840	targetState.state = STMF_STATE_OFFLINE;
5841	targetState.ident[IDENT_LENGTH_BYTE] = devid->identLength;
5842	bcopy(&(devid->ident), &targetState.ident[IDENT_LENGTH_BYTE + 1],
5843	    devid->identLength);
5844	/*
5845	 * Open control node for stmf
5846	 * to make call to setStmfState()
5847	 */
5848	if ((ret = openStmf(OPEN_EXCL_STMF, &fd)) != STMF_STATUS_SUCCESS)
5849		return (ret);
5850	ret = setStmfState(fd, &targetState, TARGET_TYPE);
5851	(void) close(fd);
5852	return (ret);
5853}
5854
5855/*
5856 * stmfOfflineLogicalUnit
5857 *
5858 * Purpose: Change state of logical unit to offline
5859 *
5860 * lu - guid of the logical unit to offline
5861 */
5862int
5863stmfOfflineLogicalUnit(stmfGuid *lu)
5864{
5865	stmf_state_desc_t luState;
5866	int ret = STMF_STATUS_SUCCESS;
5867	int fd;
5868
5869	if (lu == NULL) {
5870		return (STMF_ERROR_INVALID_ARG);
5871	}
5872
5873	bzero(&luState, sizeof (luState));
5874
5875	luState.state = STMF_STATE_OFFLINE;
5876	bcopy(lu, &luState.ident, sizeof (stmfGuid));
5877	/*
5878	 * Open control node for stmf
5879	 * to make call to setStmfState()
5880	 */
5881	if ((ret = openStmf(OPEN_EXCL_STMF, &fd)) != STMF_STATUS_SUCCESS)
5882		return (ret);
5883	ret = setStmfState(fd, &luState, LOGICAL_UNIT_TYPE);
5884	(void) close(fd);
5885	return (ret);
5886}
5887
5888/*
5889 * stmfOnlineTarget
5890 *
5891 * Purpose: Change state of target to online
5892 *
5893 * devid - devid of the target to online
5894 */
5895int
5896stmfOnlineTarget(stmfDevid *devid)
5897{
5898	stmf_state_desc_t targetState;
5899	int ret = STMF_STATUS_SUCCESS;
5900	int fd;
5901
5902	if (devid == NULL) {
5903		return (STMF_ERROR_INVALID_ARG);
5904	}
5905	bzero(&targetState, sizeof (targetState));
5906
5907	targetState.state = STMF_STATE_ONLINE;
5908	targetState.ident[IDENT_LENGTH_BYTE] = devid->identLength;
5909	bcopy(&(devid->ident), &targetState.ident[IDENT_LENGTH_BYTE + 1],
5910	    devid->identLength);
5911	/*
5912	 * Open control node for stmf
5913	 * to make call to setStmfState()
5914	 */
5915	if ((ret = openStmf(OPEN_EXCL_STMF, &fd)) != STMF_STATUS_SUCCESS)
5916		return (ret);
5917	ret = setStmfState(fd, &targetState, TARGET_TYPE);
5918	(void) close(fd);
5919	return (ret);
5920}
5921
5922/*
5923 * stmfOnlineLogicalUnit
5924 *
5925 * Purpose: Change state of logical unit to online
5926 *
5927 * lu - guid of the logical unit to online
5928 */
5929int
5930stmfOnlineLogicalUnit(stmfGuid *lu)
5931{
5932	stmf_state_desc_t luState;
5933	int ret = STMF_STATUS_SUCCESS;
5934	int fd;
5935
5936	if (lu == NULL) {
5937		return (STMF_ERROR_INVALID_ARG);
5938	}
5939
5940	bzero(&luState, sizeof (luState));
5941
5942	luState.state = STMF_STATE_ONLINE;
5943	bcopy(lu, &luState.ident, sizeof (stmfGuid));
5944	/*
5945	 * Open control node for stmf
5946	 * to make call to setStmfState()
5947	 */
5948	if ((ret = openStmf(OPEN_EXCL_STMF, &fd)) != STMF_STATUS_SUCCESS)
5949		return (ret);
5950	ret = setStmfState(fd, &luState, LOGICAL_UNIT_TYPE);
5951	(void) close(fd);
5952	return (ret);
5953}
5954
5955/*
5956 * stmfRemoveFromHostGroup
5957 *
5958 * Purpose: Removes an initiator from an initiator group
5959 *
5960 * hostGroupName - name of an initiator group
5961 * hostName - name of host group member to remove
5962 */
5963int
5964stmfRemoveFromHostGroup(stmfGroupName *hostGroupName, stmfDevid *hostName)
5965{
5966	int ret;
5967	int fd;
5968
5969	if (hostGroupName == NULL ||
5970	    (strnlen((char *)hostGroupName, sizeof (stmfGroupName))
5971	    == sizeof (stmfGroupName)) || hostName == NULL) {
5972		return (STMF_ERROR_INVALID_ARG);
5973	}
5974
5975	/* call init */
5976	ret = initializeConfig();
5977	if (ret != STMF_STATUS_SUCCESS) {
5978		return (ret);
5979	}
5980
5981	/*
5982	 * Open control node for stmf
5983	 */
5984	if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
5985		return (ret);
5986
5987	if ((ret = groupMemberIoctl(fd, STMF_IOCTL_REMOVE_HG_ENTRY,
5988	    hostGroupName, hostName)) != STMF_STATUS_SUCCESS) {
5989		goto done;
5990	}
5991
5992	if (iGetPersistMethod() == STMF_PERSIST_NONE) {
5993		goto done;
5994	}
5995
5996	ret = psRemoveHostGroupMember((char *)hostGroupName,
5997	    (char *)hostName->ident);
5998	switch (ret) {
5999		case STMF_PS_SUCCESS:
6000			ret = STMF_STATUS_SUCCESS;
6001			break;
6002		case STMF_PS_ERROR_MEMBER_NOT_FOUND:
6003			ret = STMF_ERROR_MEMBER_NOT_FOUND;
6004			break;
6005		case STMF_PS_ERROR_GROUP_NOT_FOUND:
6006			ret = STMF_ERROR_GROUP_NOT_FOUND;
6007			break;
6008		case STMF_PS_ERROR_BUSY:
6009			ret = STMF_ERROR_BUSY;
6010			break;
6011		case STMF_PS_ERROR_SERVICE_NOT_FOUND:
6012			ret = STMF_ERROR_SERVICE_NOT_FOUND;
6013			break;
6014		case STMF_PS_ERROR_VERSION_MISMATCH:
6015			ret = STMF_ERROR_SERVICE_DATA_VERSION;
6016			break;
6017		default:
6018			syslog(LOG_DEBUG,
6019			    "stmfRemoveFromHostGroup"
6020			    "psRemoveHostGroupMember:error(%d)", ret);
6021			ret = STMF_STATUS_ERROR;
6022			break;
6023	}
6024
6025done:
6026	(void) close(fd);
6027	return (ret);
6028}
6029
6030/*
6031 * stmfRemoveFromTargetGroup
6032 *
6033 * Purpose: Removes a local port from a local port group
6034 *
6035 * targetGroupName - name of a target group
6036 * targetName - name of target to remove
6037 */
6038int
6039stmfRemoveFromTargetGroup(stmfGroupName *targetGroupName, stmfDevid *targetName)
6040{
6041	int ret;
6042	int fd;
6043
6044	if (targetGroupName == NULL ||
6045	    (strnlen((char *)targetGroupName, sizeof (stmfGroupName))
6046	    == sizeof (stmfGroupName)) || targetName == NULL) {
6047		return (STMF_ERROR_INVALID_ARG);
6048	}
6049
6050	/* call init */
6051	ret = initializeConfig();
6052	if (ret != STMF_STATUS_SUCCESS) {
6053		return (ret);
6054	}
6055
6056	/*
6057	 * Open control node for stmf
6058	 */
6059	if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
6060		return (ret);
6061
6062	if ((ret = groupMemberIoctl(fd, STMF_IOCTL_REMOVE_TG_ENTRY,
6063	    targetGroupName, targetName)) != STMF_STATUS_SUCCESS) {
6064		goto done;
6065	}
6066
6067	if (iGetPersistMethod() == STMF_PERSIST_NONE) {
6068		goto done;
6069	}
6070
6071	ret = psRemoveTargetGroupMember((char *)targetGroupName,
6072	    (char *)targetName->ident);
6073	switch (ret) {
6074		case STMF_PS_SUCCESS:
6075			ret = STMF_STATUS_SUCCESS;
6076			break;
6077		case STMF_PS_ERROR_MEMBER_NOT_FOUND:
6078			ret = STMF_ERROR_MEMBER_NOT_FOUND;
6079			break;
6080		case STMF_PS_ERROR_GROUP_NOT_FOUND:
6081			ret = STMF_ERROR_GROUP_NOT_FOUND;
6082			break;
6083		case STMF_PS_ERROR_BUSY:
6084			ret = STMF_ERROR_BUSY;
6085			break;
6086		case STMF_PS_ERROR_SERVICE_NOT_FOUND:
6087			ret = STMF_ERROR_SERVICE_NOT_FOUND;
6088			break;
6089		case STMF_PS_ERROR_VERSION_MISMATCH:
6090			ret = STMF_ERROR_SERVICE_DATA_VERSION;
6091			break;
6092		default:
6093			syslog(LOG_DEBUG,
6094			    "stmfRemoveFromTargetGroup"
6095			    "psRemoveTargetGroupMember:error(%d)", ret);
6096			ret = STMF_STATUS_ERROR;
6097			break;
6098	}
6099
6100done:
6101	(void) close(fd);
6102	return (ret);
6103}
6104
6105/*
6106 * stmfRemoveViewEntry
6107 *
6108 * Purpose: Removes a view entry from a logical unit
6109 *
6110 * lu - guid of lu for which view entry is being removed
6111 * viewEntryIndex - index of view entry to remove
6112 *
6113 */
6114int
6115stmfRemoveViewEntry(stmfGuid *lu, uint32_t viewEntryIndex)
6116{
6117	int ret = STMF_STATUS_SUCCESS;
6118	int fd;
6119	int ioctlRet;
6120	stmf_iocdata_t stmfIoctl;
6121	stmf_view_op_entry_t ioctlViewEntry;
6122
6123	if (lu == NULL) {
6124		return (STMF_ERROR_INVALID_ARG);
6125	}
6126
6127	/* call init */
6128	ret = initializeConfig();
6129	if (ret != STMF_STATUS_SUCCESS) {
6130		return (ret);
6131	}
6132
6133	/*
6134	 * Open control node for stmf
6135	 */
6136	if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
6137		return (ret);
6138
6139	bzero(&ioctlViewEntry, sizeof (ioctlViewEntry));
6140	ioctlViewEntry.ve_ndx_valid = B_TRUE;
6141	ioctlViewEntry.ve_ndx = viewEntryIndex;
6142	bcopy(lu, &ioctlViewEntry.ve_guid, sizeof (stmfGuid));
6143
6144	bzero(&stmfIoctl, sizeof (stmfIoctl));
6145	/*
6146	 * Issue ioctl to add to the view entry
6147	 */
6148	stmfIoctl.stmf_version = STMF_VERSION_1;
6149	stmfIoctl.stmf_ibuf_size = sizeof (ioctlViewEntry);
6150	stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&ioctlViewEntry;
6151	ioctlRet = ioctl(fd, STMF_IOCTL_REMOVE_VIEW_ENTRY, &stmfIoctl);
6152	if (ioctlRet != 0) {
6153		switch (errno) {
6154			case EBUSY:
6155				ret = STMF_ERROR_BUSY;
6156				break;
6157			case EPERM:
6158				ret = STMF_ERROR_PERM;
6159				break;
6160			case EACCES:
6161				switch (stmfIoctl.stmf_error) {
6162					case STMF_IOCERR_UPDATE_NEED_CFG_INIT:
6163						ret = STMF_ERROR_CONFIG_NONE;
6164						break;
6165					default:
6166						ret = STMF_ERROR_PERM;
6167						break;
6168				}
6169				break;
6170			case ENODEV:
6171			case ENOENT:
6172				ret = STMF_ERROR_NOT_FOUND;
6173				break;
6174			default:
6175				syslog(LOG_DEBUG,
6176				    "stmfRemoveViewEntry:ioctl errno(%d)",
6177				    errno);
6178				ret = STMF_STATUS_ERROR;
6179				break;
6180		}
6181		goto done;
6182	}
6183
6184	if (iGetPersistMethod() == STMF_PERSIST_NONE) {
6185		goto done;
6186	}
6187
6188	ret = psRemoveViewEntry(lu, viewEntryIndex);
6189	switch (ret) {
6190		case STMF_PS_SUCCESS:
6191			ret = STMF_STATUS_SUCCESS;
6192			break;
6193		case STMF_PS_ERROR_NOT_FOUND:
6194			ret = STMF_ERROR_NOT_FOUND;
6195			break;
6196		case STMF_PS_ERROR_BUSY:
6197			ret = STMF_ERROR_BUSY;
6198			break;
6199		case STMF_PS_ERROR_SERVICE_NOT_FOUND:
6200			ret = STMF_ERROR_SERVICE_NOT_FOUND;
6201			break;
6202		case STMF_PS_ERROR_VERSION_MISMATCH:
6203			ret = STMF_ERROR_SERVICE_DATA_VERSION;
6204			break;
6205		default:
6206			syslog(LOG_DEBUG,
6207			    "stmfRemoveViewEntry" "psRemoveViewEntry:error(%d)",
6208			    ret);
6209			ret = STMF_STATUS_ERROR;
6210			break;
6211	}
6212
6213done:
6214	(void) close(fd);
6215	return (ret);
6216}
6217
6218/*
6219 * stmfSetProviderData
6220 *
6221 * Purpose: set the provider data
6222 *
6223 * providerName - unique name of provider
6224 * nvl - nvlist to set
6225 * providerType - type of provider for which to set data
6226 *		STMF_LU_PROVIDER_TYPE
6227 *		STMF_PORT_PROVIDER_TYPE
6228 */
6229int
6230stmfSetProviderData(char *providerName, nvlist_t *nvl, int providerType)
6231{
6232	return (stmfSetProviderDataProt(providerName, nvl, providerType,
6233	    NULL));
6234}
6235
6236/*
6237 * stmfSetProviderDataProt
6238 *
6239 * Purpose: set the provider data
6240 *
6241 * providerName - unique name of provider
6242 * nvl - nvlist to set
6243 * providerType - type of provider for which to set data
6244 *		STMF_LU_PROVIDER_TYPE
6245 *		STMF_PORT_PROVIDER_TYPE
6246 * setToken - Stale data token returned in the stmfGetProviderDataProt()
6247 *	      call or NULL.
6248 */
6249int
6250stmfSetProviderDataProt(char *providerName, nvlist_t *nvl, int providerType,
6251    uint64_t *setToken)
6252{
6253	int ret;
6254	int fd;
6255
6256	if (providerName == NULL || nvl == NULL) {
6257		return (STMF_ERROR_INVALID_ARG);
6258	}
6259
6260	if (providerType != STMF_LU_PROVIDER_TYPE &&
6261	    providerType != STMF_PORT_PROVIDER_TYPE) {
6262		return (STMF_ERROR_INVALID_ARG);
6263	}
6264
6265	/* call init */
6266	ret = initializeConfig();
6267	if (ret != STMF_STATUS_SUCCESS) {
6268		return (ret);
6269	}
6270
6271	/*
6272	 * Open control node for stmf
6273	 */
6274	if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
6275		return (ret);
6276
6277	ret = setProviderData(fd, providerName, nvl, providerType, setToken);
6278
6279	(void) close(fd);
6280
6281	if (ret != STMF_STATUS_SUCCESS) {
6282		goto done;
6283	}
6284
6285	if (iGetPersistMethod() == STMF_PERSIST_NONE) {
6286		goto done;
6287	}
6288
6289	/* setting driver provider data successful. Now persist it */
6290	ret = psSetProviderData(providerName, nvl, providerType, NULL);
6291	switch (ret) {
6292		case STMF_PS_SUCCESS:
6293			ret = STMF_STATUS_SUCCESS;
6294			break;
6295		case STMF_PS_ERROR_EXISTS:
6296			ret = STMF_ERROR_EXISTS;
6297			break;
6298		case STMF_PS_ERROR_BUSY:
6299			ret = STMF_ERROR_BUSY;
6300			break;
6301		case STMF_PS_ERROR_SERVICE_NOT_FOUND:
6302			ret = STMF_ERROR_SERVICE_NOT_FOUND;
6303			break;
6304		case STMF_PS_ERROR_VERSION_MISMATCH:
6305			ret = STMF_ERROR_SERVICE_DATA_VERSION;
6306			break;
6307		case STMF_PS_ERROR_PROV_DATA_STALE:
6308			ret = STMF_ERROR_PROV_DATA_STALE;
6309			break;
6310		default:
6311			syslog(LOG_DEBUG,
6312			    "stmfSetProviderData"
6313			    "psSetProviderData:error(%d)", ret);
6314			ret = STMF_STATUS_ERROR;
6315			break;
6316	}
6317
6318done:
6319	return (ret);
6320}
6321
6322/*
6323 * getProviderData
6324 *
6325 * Purpose: set the provider data from stmf
6326 *
6327 * providerName - unique name of provider
6328 * nvl - nvlist to load/retrieve
6329 * providerType - logical unit or port provider
6330 * setToken - returned stale data token
6331 */
6332int
6333getProviderData(char *providerName, nvlist_t **nvl, int providerType,
6334    uint64_t *setToken)
6335{
6336	int ret = STMF_STATUS_SUCCESS;
6337	int fd;
6338	int ioctlRet;
6339	size_t nvlistSize = ALLOC_PP_DATA_SIZE;
6340	int retryCnt = 0;
6341	int retryCntMax = MAX_PROVIDER_RETRY;
6342	stmf_ppioctl_data_t ppi = {0}, *ppi_out = NULL;
6343	boolean_t retry = B_TRUE;
6344	stmf_iocdata_t stmfIoctl;
6345
6346	if (providerName == NULL) {
6347		return (STMF_ERROR_INVALID_ARG);
6348	}
6349
6350	/*
6351	 * Open control node for stmf
6352	 */
6353	if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
6354		return (ret);
6355
6356	/* set provider name and provider type */
6357	if (strlcpy(ppi.ppi_name, providerName,
6358	    sizeof (ppi.ppi_name)) >=
6359	    sizeof (ppi.ppi_name)) {
6360		ret = STMF_ERROR_INVALID_ARG;
6361		goto done;
6362	}
6363	switch (providerType) {
6364		case STMF_LU_PROVIDER_TYPE:
6365			ppi.ppi_lu_provider = 1;
6366			break;
6367		case STMF_PORT_PROVIDER_TYPE:
6368			ppi.ppi_port_provider = 1;
6369			break;
6370		default:
6371			ret = STMF_ERROR_INVALID_ARG;
6372			goto done;
6373	}
6374
6375	do {
6376		/* allocate memory for ioctl */
6377		ppi_out = (stmf_ppioctl_data_t *)calloc(1, nvlistSize +
6378		    sizeof (stmf_ppioctl_data_t));
6379		if (ppi_out == NULL) {
6380			ret = STMF_ERROR_NOMEM;
6381			goto done;
6382
6383		}
6384
6385		/* set the size of the ioctl data to allocated buffer */
6386		ppi.ppi_data_size = nvlistSize;
6387
6388		bzero(&stmfIoctl, sizeof (stmfIoctl));
6389
6390		stmfIoctl.stmf_version = STMF_VERSION_1;
6391		stmfIoctl.stmf_ibuf_size = sizeof (stmf_ppioctl_data_t);
6392		stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&ppi;
6393		stmfIoctl.stmf_obuf_size = sizeof (stmf_ppioctl_data_t) +
6394		    nvlistSize;
6395		stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)ppi_out;
6396		ioctlRet = ioctl(fd, STMF_IOCTL_GET_PP_DATA, &stmfIoctl);
6397		if (ioctlRet != 0) {
6398			switch (errno) {
6399				case EBUSY:
6400					ret = STMF_ERROR_BUSY;
6401					break;
6402				case EPERM:
6403				case EACCES:
6404					ret = STMF_ERROR_PERM;
6405					break;
6406				case EINVAL:
6407					if (stmfIoctl.stmf_error ==
6408					    STMF_IOCERR_INSUFFICIENT_BUF) {
6409						nvlistSize =
6410						    ppi_out->ppi_data_size;
6411						free(ppi_out);
6412						ppi_out = NULL;
6413						if (retryCnt++ > retryCntMax) {
6414							retry = B_FALSE;
6415							ret = STMF_ERROR_BUSY;
6416						} else {
6417							ret =
6418							    STMF_STATUS_SUCCESS;
6419						}
6420					} else {
6421						syslog(LOG_DEBUG,
6422						    "getProviderData:ioctl"
6423						    "unable to retrieve "
6424						    "nvlist");
6425						ret = STMF_STATUS_ERROR;
6426					}
6427					break;
6428				case ENOENT:
6429					ret = STMF_ERROR_NOT_FOUND;
6430					break;
6431				default:
6432					syslog(LOG_DEBUG,
6433					    "getProviderData:ioctl errno(%d)",
6434					    errno);
6435					ret = STMF_STATUS_ERROR;
6436					break;
6437			}
6438			if (ret != STMF_STATUS_SUCCESS)
6439				goto done;
6440		}
6441	} while (retry && stmfIoctl.stmf_error == STMF_IOCERR_INSUFFICIENT_BUF);
6442
6443	if ((ret = nvlist_unpack((char *)ppi_out->ppi_data,
6444	    ppi_out->ppi_data_size, nvl, 0)) != 0) {
6445		ret = STMF_STATUS_ERROR;
6446		goto done;
6447	}
6448
6449	/* caller has asked for new token */
6450	if (setToken) {
6451		*setToken = ppi_out->ppi_token;
6452	}
6453done:
6454	free(ppi_out);
6455	(void) close(fd);
6456	return (ret);
6457}
6458
6459/*
6460 * setProviderData
6461 *
6462 * Purpose: set the provider data in stmf
6463 *
6464 * providerName - unique name of provider
6465 * nvl - nvlist to set
6466 * providerType - logical unit or port provider
6467 * setToken - stale data token to check if not NULL
6468 */
6469static int
6470setProviderData(int fd, char *providerName, nvlist_t *nvl, int providerType,
6471    uint64_t *setToken)
6472{
6473	int ret = STMF_STATUS_SUCCESS;
6474	int ioctlRet;
6475	size_t nvlistEncodedSize;
6476	stmf_ppioctl_data_t *ppi = NULL;
6477	uint64_t outToken;
6478	char *allocatedNvBuffer;
6479	stmf_iocdata_t stmfIoctl;
6480
6481	if (providerName == NULL) {
6482		return (STMF_ERROR_INVALID_ARG);
6483	}
6484
6485	/* get size of encoded nvlist */
6486	if (nvlist_size(nvl, &nvlistEncodedSize, NV_ENCODE_XDR) != 0) {
6487		return (STMF_STATUS_ERROR);
6488	}
6489
6490	/* allocate memory for ioctl */
6491	ppi = (stmf_ppioctl_data_t *)calloc(1, nvlistEncodedSize +
6492	    sizeof (stmf_ppioctl_data_t));
6493	if (ppi == NULL) {
6494		return (STMF_ERROR_NOMEM);
6495	}
6496
6497	if (setToken) {
6498		ppi->ppi_token_valid = 1;
6499		ppi->ppi_token = *setToken;
6500	}
6501
6502	allocatedNvBuffer = (char *)&ppi->ppi_data;
6503	if (nvlist_pack(nvl, &allocatedNvBuffer, &nvlistEncodedSize,
6504	    NV_ENCODE_XDR, 0) != 0) {
6505		return (STMF_STATUS_ERROR);
6506	}
6507
6508	/* set provider name and provider type */
6509	(void) strncpy(ppi->ppi_name, providerName, sizeof (ppi->ppi_name));
6510	switch (providerType) {
6511		case STMF_LU_PROVIDER_TYPE:
6512			ppi->ppi_lu_provider = 1;
6513			break;
6514		case STMF_PORT_PROVIDER_TYPE:
6515			ppi->ppi_port_provider = 1;
6516			break;
6517		default:
6518			return (STMF_ERROR_INVALID_ARG);
6519	}
6520
6521	/* set the size of the ioctl data to packed data size */
6522	ppi->ppi_data_size = nvlistEncodedSize;
6523
6524	bzero(&stmfIoctl, sizeof (stmfIoctl));
6525
6526	stmfIoctl.stmf_version = STMF_VERSION_1;
6527	/*
6528	 * Subtracting 8 from the size as that is the size of the last member
6529	 * of the structure where the packed data resides
6530	 */
6531	stmfIoctl.stmf_ibuf_size = nvlistEncodedSize +
6532	    sizeof (stmf_ppioctl_data_t) - 8;
6533	stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)ppi;
6534	stmfIoctl.stmf_obuf_size = sizeof (uint64_t);
6535	stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)&outToken;
6536	ioctlRet = ioctl(fd, STMF_IOCTL_LOAD_PP_DATA, &stmfIoctl);
6537	if (ioctlRet != 0) {
6538		switch (errno) {
6539			case EBUSY:
6540				ret = STMF_ERROR_BUSY;
6541				break;
6542			case EPERM:
6543			case EACCES:
6544				ret = STMF_ERROR_PERM;
6545				break;
6546			case EINVAL:
6547				if (stmfIoctl.stmf_error ==
6548				    STMF_IOCERR_PPD_UPDATED) {
6549					ret = STMF_ERROR_PROV_DATA_STALE;
6550				} else {
6551					ret = STMF_STATUS_ERROR;
6552				}
6553				break;
6554			default:
6555				syslog(LOG_DEBUG,
6556				    "setProviderData:ioctl errno(%d)", errno);
6557				ret = STMF_STATUS_ERROR;
6558				break;
6559		}
6560		if (ret != STMF_STATUS_SUCCESS)
6561			goto done;
6562	}
6563
6564	/* caller has asked for new token */
6565	if (setToken) {
6566		*setToken = outToken;
6567	}
6568done:
6569	free(ppi);
6570	return (ret);
6571}
6572
6573/*
6574 * set the persistence method in the library only or library and service
6575 */
6576int
6577stmfSetPersistMethod(uint8_t persistType, boolean_t serviceSet)
6578{
6579	int ret = STMF_STATUS_SUCCESS;
6580	int oldPersist;
6581
6582	(void) pthread_mutex_lock(&persistenceTypeLock);
6583	oldPersist = iPersistType;
6584	if (persistType == STMF_PERSIST_NONE ||
6585	    persistType == STMF_PERSIST_SMF) {
6586		iLibSetPersist = B_TRUE;
6587		iPersistType = persistType;
6588	} else {
6589		(void) pthread_mutex_unlock(&persistenceTypeLock);
6590		return (STMF_ERROR_INVALID_ARG);
6591	}
6592	/* Is this for this library open or in SMF */
6593	if (serviceSet == B_TRUE) {
6594		ret = psSetServicePersist(persistType);
6595		if (ret != STMF_PS_SUCCESS) {
6596			ret = STMF_ERROR_PERSIST_TYPE;
6597			/* Set to old value */
6598			iPersistType = oldPersist;
6599		}
6600	}
6601	(void) pthread_mutex_unlock(&persistenceTypeLock);
6602
6603	return (ret);
6604}
6605
6606/*
6607 * Only returns internal state for persist. If unset, goes to ps. If that
6608 * fails, returns default setting
6609 */
6610static uint8_t
6611iGetPersistMethod()
6612{
6613
6614	uint8_t persistType = 0;
6615
6616	(void) pthread_mutex_lock(&persistenceTypeLock);
6617	if (iLibSetPersist) {
6618		persistType = iPersistType;
6619	} else {
6620		int ret;
6621		ret = psGetServicePersist(&persistType);
6622		if (ret != STMF_PS_SUCCESS) {
6623			/* set to default */
6624			persistType = STMF_DEFAULT_PERSIST;
6625		}
6626	}
6627	(void) pthread_mutex_unlock(&persistenceTypeLock);
6628	return (persistType);
6629}
6630
6631/*
6632 * Returns either library state or persistent config state depending on
6633 * serviceState
6634 */
6635int
6636stmfGetPersistMethod(uint8_t *persistType, boolean_t serviceState)
6637{
6638	int ret = STMF_STATUS_SUCCESS;
6639
6640	if (persistType == NULL) {
6641		return (STMF_ERROR_INVALID_ARG);
6642	}
6643	if (serviceState) {
6644		ret = psGetServicePersist(persistType);
6645		if (ret != STMF_PS_SUCCESS) {
6646			ret = STMF_ERROR_PERSIST_TYPE;
6647		}
6648	} else {
6649		(void) pthread_mutex_lock(&persistenceTypeLock);
6650		if (iLibSetPersist) {
6651			*persistType = iPersistType;
6652		} else {
6653			*persistType = STMF_DEFAULT_PERSIST;
6654		}
6655		(void) pthread_mutex_unlock(&persistenceTypeLock);
6656	}
6657
6658	return (ret);
6659}
6660
6661/*
6662 * stmfPostProxyMsg
6663 *
6664 * Purpose: Post a message to the proxy port provider
6665 *
6666 * buf - buffer containing message to post
6667 * buflen - buffer length
6668 */
6669int
6670stmfPostProxyMsg(int hdl, void *buf, uint32_t buflen)
6671{
6672	int ret = STMF_STATUS_SUCCESS;
6673	int ioctlRet;
6674	pppt_iocdata_t ppptIoctl = {0};
6675
6676	if (buf == NULL) {
6677		return (STMF_ERROR_INVALID_ARG);
6678	}
6679
6680	/*
6681	 * Issue ioctl to post the message
6682	 */
6683	ppptIoctl.pppt_version = PPPT_VERSION_1;
6684	ppptIoctl.pppt_buf_size = buflen;
6685	ppptIoctl.pppt_buf = (uint64_t)(unsigned long)buf;
6686	ioctlRet = ioctl(hdl, PPPT_MESSAGE, &ppptIoctl);
6687	if (ioctlRet != 0) {
6688		switch (errno) {
6689			case EPERM:
6690			case EACCES:
6691				ret = STMF_ERROR_PERM;
6692				break;
6693			default:
6694				ret = STMF_ERROR_POST_MSG_FAILED;
6695				break;
6696		}
6697	}
6698
6699	return (ret);
6700}
6701
6702/*
6703 * stmfInitProxyDoor
6704 *
6705 * Purpose: Install door in proxy
6706 *
6707 * hdl - pointer to returned handle
6708 * fd - door from door_create()
6709 */
6710int
6711stmfInitProxyDoor(int *hdl, int door)
6712{
6713	int ret = STMF_STATUS_SUCCESS;
6714	int ioctlRet;
6715	int fd;
6716	pppt_iocdata_t ppptIoctl = {0};
6717
6718	if (hdl == NULL) {
6719		return (STMF_ERROR_INVALID_ARG);
6720	}
6721
6722	/*
6723	 * Open control node for pppt
6724	 */
6725	if ((ret = openPppt(OPEN_PPPT, &fd)) != STMF_STATUS_SUCCESS) {
6726		return (ret);
6727	}
6728
6729	/*
6730	 * Issue ioctl to install the door
6731	 */
6732	ppptIoctl.pppt_version = PPPT_VERSION_1;
6733	ppptIoctl.pppt_door_fd = (uint32_t)door;
6734	ioctlRet = ioctl(fd, PPPT_INSTALL_DOOR, &ppptIoctl);
6735	if (ioctlRet != 0) {
6736		switch (errno) {
6737			case EPERM:
6738			case EACCES:
6739				ret = STMF_ERROR_PERM;
6740				break;
6741			case EINVAL:
6742				ret = STMF_ERROR_INVALID_ARG;
6743				break;
6744			case EBUSY:
6745				ret = STMF_ERROR_DOOR_INSTALLED;
6746				break;
6747			default:
6748				ret = STMF_STATUS_ERROR;
6749				break;
6750		}
6751	}
6752
6753	/* return driver fd to caller */
6754	*hdl = fd;
6755	return (ret);
6756}
6757
6758void
6759stmfDestroyProxyDoor(int hdl)
6760{
6761	(void) close(hdl);
6762}
6763
6764/*
6765 * validateLunNumIoctl
6766 *
6767 * Purpose: Issues ioctl to check and get available lun# in view entry
6768 *
6769 * viewEntry - view entry to use
6770 */
6771static int
6772validateLunNumIoctl(int fd, stmfViewEntry *viewEntry)
6773{
6774	int ret = STMF_STATUS_SUCCESS;
6775	int ioctlRet;
6776	stmf_iocdata_t stmfIoctl;
6777	stmf_view_op_entry_t ioctlViewEntry;
6778
6779	bzero(&ioctlViewEntry, sizeof (ioctlViewEntry));
6780	/*
6781	 * don't set ve_ndx or ve_ndx_valid as ve_ndx_valid should be
6782	 * false on input
6783	 */
6784	ioctlViewEntry.ve_lu_number_valid = viewEntry->luNbrValid;
6785	ioctlViewEntry.ve_all_hosts = viewEntry->allHosts;
6786	ioctlViewEntry.ve_all_targets = viewEntry->allTargets;
6787
6788	if (viewEntry->allHosts == B_FALSE) {
6789		bcopy(viewEntry->hostGroup, &ioctlViewEntry.ve_host_group.name,
6790		    sizeof (stmfGroupName));
6791		ioctlViewEntry.ve_host_group.name_size =
6792		    strlen((char *)viewEntry->hostGroup);
6793	}
6794	if (viewEntry->allTargets == B_FALSE) {
6795		bcopy(viewEntry->targetGroup,
6796		    &ioctlViewEntry.ve_target_group.name,
6797		    sizeof (stmfGroupName));
6798		ioctlViewEntry.ve_target_group.name_size =
6799		    strlen((char *)viewEntry->targetGroup);
6800	}
6801	/* Validating the lun number */
6802	if (viewEntry->luNbrValid) {
6803		bcopy(viewEntry->luNbr, &ioctlViewEntry.ve_lu_nbr,
6804		    sizeof (ioctlViewEntry.ve_lu_nbr));
6805	}
6806
6807	bzero(&stmfIoctl, sizeof (stmfIoctl));
6808	/*
6809	 * Issue ioctl to validate lun# in the view entry
6810	 */
6811	stmfIoctl.stmf_version = STMF_VERSION_1;
6812	stmfIoctl.stmf_ibuf_size = sizeof (ioctlViewEntry);
6813	stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&ioctlViewEntry;
6814	stmfIoctl.stmf_obuf_size = sizeof (ioctlViewEntry);
6815	stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)&ioctlViewEntry;
6816	ioctlRet = ioctl(fd, STMF_IOCTL_VALIDATE_VIEW, &stmfIoctl);
6817
6818	/* save available lun number */
6819	if (!viewEntry->luNbrValid) {
6820		bcopy(ioctlViewEntry.ve_lu_nbr, viewEntry->luNbr,
6821		    sizeof (ioctlViewEntry.ve_lu_nbr));
6822	}
6823	if (ioctlRet != 0) {
6824		switch (errno) {
6825			case EBUSY:
6826				ret = STMF_ERROR_BUSY;
6827				break;
6828			case EPERM:
6829				ret = STMF_ERROR_PERM;
6830				break;
6831			case EACCES:
6832				switch (stmfIoctl.stmf_error) {
6833					case STMF_IOCERR_UPDATE_NEED_CFG_INIT:
6834						ret = STMF_ERROR_CONFIG_NONE;
6835						break;
6836					default:
6837						ret = STMF_ERROR_PERM;
6838						break;
6839				}
6840				break;
6841			default:
6842				switch (stmfIoctl.stmf_error) {
6843					case STMF_IOCERR_LU_NUMBER_IN_USE:
6844						ret = STMF_ERROR_LUN_IN_USE;
6845						break;
6846					case STMF_IOCERR_VIEW_ENTRY_CONFLICT:
6847						ret = STMF_ERROR_VE_CONFLICT;
6848						break;
6849					case STMF_IOCERR_UPDATE_NEED_CFG_INIT:
6850						ret = STMF_ERROR_CONFIG_NONE;
6851						break;
6852					case STMF_IOCERR_INVALID_HG:
6853						ret = STMF_ERROR_INVALID_HG;
6854						break;
6855					case STMF_IOCERR_INVALID_TG:
6856						ret = STMF_ERROR_INVALID_TG;
6857						break;
6858					default:
6859						syslog(LOG_DEBUG,
6860						    "addViewEntryIoctl"
6861						    ":error(%d)",
6862						    stmfIoctl.stmf_error);
6863						ret = STMF_STATUS_ERROR;
6864						break;
6865				}
6866				break;
6867		}
6868	}
6869	return (ret);
6870}
6871
6872/*
6873 * stmfValidateView
6874 *
6875 * Purpose: Validate or get lun # base on TG, HG of view entry
6876 *
6877 * viewEntry - view entry structure to use
6878 */
6879int
6880stmfValidateView(stmfViewEntry *viewEntry)
6881{
6882	int ret;
6883	int fd;
6884	stmfViewEntry iViewEntry;
6885
6886	if (viewEntry == NULL) {
6887		return (STMF_ERROR_INVALID_ARG);
6888	}
6889
6890	/* initialize and set internal view entry */
6891	bzero(&iViewEntry, sizeof (iViewEntry));
6892
6893	if (!viewEntry->allHosts) {
6894		bcopy(viewEntry->hostGroup, iViewEntry.hostGroup,
6895		    sizeof (iViewEntry.hostGroup));
6896	} else {
6897		iViewEntry.allHosts = B_TRUE;
6898	}
6899
6900	if (!viewEntry->allTargets) {
6901		bcopy(viewEntry->targetGroup, iViewEntry.targetGroup,
6902		    sizeof (iViewEntry.targetGroup));
6903	} else {
6904		iViewEntry.allTargets = B_TRUE;
6905	}
6906
6907	if (viewEntry->luNbrValid) {
6908		iViewEntry.luNbrValid = B_TRUE;
6909		bcopy(viewEntry->luNbr, iViewEntry.luNbr,
6910		    sizeof (iViewEntry.luNbr));
6911	}
6912
6913	/*
6914	 * set users return view entry index valid flag to false
6915	 * in case of failure
6916	 */
6917	viewEntry->veIndexValid = B_FALSE;
6918
6919	/* Check to ensure service exists */
6920	if (psCheckService() != STMF_STATUS_SUCCESS) {
6921		return (STMF_ERROR_SERVICE_NOT_FOUND);
6922	}
6923
6924	/* call init */
6925	ret = initializeConfig();
6926	if (ret != STMF_STATUS_SUCCESS) {
6927		return (ret);
6928	}
6929
6930	/*
6931	 * Open control node for stmf
6932	 */
6933	if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
6934		return (ret);
6935
6936	/*
6937	 * Validate lun# in the view entry from the driver
6938	 */
6939	ret = validateLunNumIoctl(fd, &iViewEntry);
6940	(void) close(fd);
6941
6942	/* save available lun number */
6943	if (!viewEntry->luNbrValid) {
6944		bcopy(iViewEntry.luNbr, viewEntry->luNbr,
6945		    sizeof (iViewEntry.luNbr));
6946	}
6947
6948	return (ret);
6949}
6950