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