xref: /illumos-gate/usr/src/lib/libstmf/common/stmf.c (revision bbe6aa77dcdd1ff0ed28cd41788ea266c5fba962)
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 	    sizeof (stmfGroupName) * 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) +
3276 	    sizeof (stmfDevid) * stmfIoctl.stmf_obuf_nentries);
3277 	if (*groupProps == NULL) {
3278 		ret = STMF_ERROR_NOMEM;
3279 		goto done;
3280 	}
3281 	(*groupProps)->cnt = stmfIoctl.stmf_obuf_nentries;
3282 	for (i = 0; i < stmfIoctl.stmf_obuf_nentries; i++) {
3283 		(*groupProps)->name[i].identLength =
3284 		    iGroupMembers[i].ident_size;
3285 		bcopy(iGroupMembers[i].ident, (*groupProps)->name[i].ident,
3286 		    iGroupMembers[i].ident_size);
3287 	}
3288 
3289 done:
3290 	free(iGroupMembers);
3291 	(void) close(fd);
3292 	return (ret);
3293 }
3294 
3295 /*
3296  * Purpose: access persistent config data for host groups and target groups
3297  */
3298 static int
3299 iLoadGroupFromPs(stmfGroupList **groupList, int type)
3300 {
3301 	int ret;
3302 
3303 	if (groupList == NULL) {
3304 		return (STMF_ERROR_INVALID_ARG);
3305 	}
3306 
3307 	if (type == HOST_GROUP) {
3308 		ret = psGetHostGroupList(groupList);
3309 	} else if (type == TARGET_GROUP) {
3310 		ret = psGetTargetGroupList(groupList);
3311 	} else {
3312 		return (STMF_ERROR_INVALID_ARG);
3313 	}
3314 	switch (ret) {
3315 		case STMF_PS_SUCCESS:
3316 			ret = STMF_STATUS_SUCCESS;
3317 			break;
3318 		case STMF_PS_ERROR_NOT_FOUND:
3319 			ret = STMF_ERROR_NOT_FOUND;
3320 			break;
3321 		case STMF_PS_ERROR_BUSY:
3322 			ret = STMF_ERROR_BUSY;
3323 			break;
3324 		case STMF_PS_ERROR_SERVICE_NOT_FOUND:
3325 			ret = STMF_ERROR_SERVICE_NOT_FOUND;
3326 			break;
3327 		case STMF_PS_ERROR_VERSION_MISMATCH:
3328 			ret = STMF_ERROR_SERVICE_DATA_VERSION;
3329 			break;
3330 		default:
3331 			syslog(LOG_DEBUG,
3332 			    "stmfGetHostGroupList:psGetHostGroupList:error(%d)",
3333 			    ret);
3334 			ret = STMF_STATUS_ERROR;
3335 			break;
3336 	}
3337 
3338 	return (ret);
3339 }
3340 
3341 /*
3342  * stmfGetHostGroupList
3343  *
3344  * Purpose: Retrieves the list of initiator group oids
3345  *
3346  * hostGroupList - pointer to pointer to hostGroupList structure
3347  *                 on success, this contains the host group list.
3348  */
3349 int
3350 stmfGetHostGroupList(stmfGroupList **hostGroupList)
3351 {
3352 	int ret = STMF_STATUS_ERROR;
3353 
3354 	if (hostGroupList == NULL) {
3355 		return (STMF_ERROR_INVALID_ARG);
3356 	}
3357 
3358 	ret = groupListIoctl(hostGroupList, HOST_GROUP);
3359 	return (ret);
3360 }
3361 
3362 
3363 /*
3364  * Purpose: access persistent config data for host groups and target groups
3365  */
3366 static int
3367 iLoadGroupMembersFromPs(stmfGroupName *groupName,
3368     stmfGroupProperties **groupProp, int type)
3369 {
3370 	int ret;
3371 
3372 	if (groupName == NULL) {
3373 		return (STMF_ERROR_INVALID_ARG);
3374 	}
3375 
3376 	if (type == HOST_GROUP) {
3377 		ret = psGetHostGroupMemberList((char *)groupName, groupProp);
3378 	} else if (type == TARGET_GROUP) {
3379 		ret = psGetTargetGroupMemberList((char *)groupName, groupProp);
3380 	} else {
3381 		return (STMF_ERROR_INVALID_ARG);
3382 	}
3383 	switch (ret) {
3384 		case STMF_PS_SUCCESS:
3385 			ret = STMF_STATUS_SUCCESS;
3386 			break;
3387 		case STMF_PS_ERROR_NOT_FOUND:
3388 			ret = STMF_ERROR_NOT_FOUND;
3389 			break;
3390 		case STMF_PS_ERROR_BUSY:
3391 			ret = STMF_ERROR_BUSY;
3392 			break;
3393 		case STMF_PS_ERROR_SERVICE_NOT_FOUND:
3394 			ret = STMF_ERROR_SERVICE_NOT_FOUND;
3395 			break;
3396 		case STMF_PS_ERROR_VERSION_MISMATCH:
3397 			ret = STMF_ERROR_SERVICE_DATA_VERSION;
3398 			break;
3399 		default:
3400 			syslog(LOG_DEBUG,
3401 			    "iLoadGroupMembersFromPs:psGetHostGroupList:"
3402 			    "error(%d)", ret);
3403 			ret = STMF_STATUS_ERROR;
3404 			break;
3405 	}
3406 
3407 	return (ret);
3408 }
3409 
3410 /*
3411  * stmfGetHostGroupMembers
3412  *
3413  * Purpose: Retrieves the group properties for a host group
3414  *
3415  * groupName - name of group for which to retrieve host group members.
3416  * groupProp - pointer to pointer to stmfGroupProperties structure
3417  *             on success, this contains the list of group members.
3418  */
3419 int
3420 stmfGetHostGroupMembers(stmfGroupName *groupName,
3421     stmfGroupProperties **groupProp)
3422 {
3423 	int ret;
3424 
3425 	if (groupName == NULL || groupProp == NULL) {
3426 		return (STMF_ERROR_INVALID_ARG);
3427 	}
3428 
3429 	ret = groupMemberListIoctl(groupName, groupProp, HOST_GROUP);
3430 
3431 	return (ret);
3432 }
3433 
3434 /*
3435  * stmfGetProviderData
3436  *
3437  * Purpose: Get provider data list
3438  *
3439  * providerName - name of provider for which to retrieve the data
3440  * nvl - pointer to nvlist_t pointer which will contain the nvlist data
3441  *       retrieved.
3442  * providerType - type of provider for which to retrieve data.
3443  *		    STMF_LU_PROVIDER_TYPE
3444  *		    STMF_PORT_PROVIDER_TYPE
3445  */
3446 int
3447 stmfGetProviderData(char *providerName, nvlist_t **nvl, int providerType)
3448 {
3449 	return (stmfGetProviderDataProt(providerName, nvl, providerType,
3450 	    NULL));
3451 }
3452 
3453 /*
3454  * stmfGetProviderDataProt
3455  *
3456  * Purpose: Get provider data list with token
3457  *
3458  * providerName - name of provider for which to retrieve the data
3459  * nvl - pointer to nvlist_t pointer which will contain the nvlist data
3460  *       retrieved.
3461  * providerType - type of provider for which to retrieve data.
3462  *		    STMF_LU_PROVIDER_TYPE
3463  *		    STMF_PORT_PROVIDER_TYPE
3464  * setToken - Returns the stale data token
3465  */
3466 int
3467 stmfGetProviderDataProt(char *providerName, nvlist_t **nvl, int providerType,
3468     uint64_t *setToken)
3469 {
3470 	int ret;
3471 
3472 	if (providerName == NULL || nvl == NULL) {
3473 		return (STMF_ERROR_INVALID_ARG);
3474 	}
3475 	if (providerType != STMF_LU_PROVIDER_TYPE &&
3476 	    providerType != STMF_PORT_PROVIDER_TYPE) {
3477 		return (STMF_ERROR_INVALID_ARG);
3478 	}
3479 	/* call init */
3480 	ret = initializeConfig();
3481 	if (ret != STMF_STATUS_SUCCESS) {
3482 		return (ret);
3483 	}
3484 	return (getProviderData(providerName, nvl, providerType, setToken));
3485 }
3486 
3487 /*
3488  * stmfGetProviderDataList
3489  *
3490  * Purpose: Get the list of providers currently persisting data
3491  *
3492  * providerList - pointer to pointer to an stmfProviderList structure allocated
3493  *                by the caller. Will contain the list of providers on success.
3494  */
3495 int
3496 stmfGetProviderDataList(stmfProviderList **providerList)
3497 {
3498 	int ret;
3499 
3500 	ret = psGetProviderDataList(providerList);
3501 	switch (ret) {
3502 		case STMF_PS_SUCCESS:
3503 			ret = STMF_STATUS_SUCCESS;
3504 			break;
3505 		case STMF_PS_ERROR_BUSY:
3506 			ret = STMF_ERROR_BUSY;
3507 			break;
3508 		case STMF_PS_ERROR_SERVICE_NOT_FOUND:
3509 			ret = STMF_ERROR_SERVICE_NOT_FOUND;
3510 			break;
3511 		case STMF_PS_ERROR_VERSION_MISMATCH:
3512 			ret = STMF_ERROR_SERVICE_DATA_VERSION;
3513 			break;
3514 		default:
3515 			syslog(LOG_DEBUG,
3516 			    "stmfGetProviderDataList:psGetProviderDataList"
3517 			    ":error(%d)", ret);
3518 			ret = STMF_STATUS_ERROR;
3519 			break;
3520 	}
3521 
3522 	return (ret);
3523 }
3524 
3525 
3526 /*
3527  * stmfGetSessionList
3528  *
3529  * Purpose: Retrieves the session list for a target (devid)
3530  *
3531  * devid - devid of target for which to retrieve session information.
3532  * sessionList - pointer to pointer to stmfSessionList structure
3533  *             on success, this contains the list of initiator sessions.
3534  */
3535 int
3536 stmfGetSessionList(stmfDevid *devid, stmfSessionList **sessionList)
3537 {
3538 	int ret = STMF_STATUS_SUCCESS;
3539 	int fd;
3540 	int ioctlRet;
3541 	int cmd = STMF_IOCTL_SESSION_LIST;
3542 	int i;
3543 	stmf_iocdata_t stmfIoctl;
3544 	slist_scsi_session_t *fSessionList;
3545 	uint8_t ident[260];
3546 	uint32_t fSessionListSize;
3547 
3548 	if (sessionList == NULL || devid == NULL) {
3549 		ret = STMF_ERROR_INVALID_ARG;
3550 	}
3551 
3552 	/* call init */
3553 	ret = initializeConfig();
3554 	if (ret != STMF_STATUS_SUCCESS) {
3555 		return (ret);
3556 	}
3557 
3558 	/*
3559 	 * Open control node for stmf
3560 	 */
3561 	if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
3562 		return (ret);
3563 
3564 	/*
3565 	 * Allocate ioctl input buffer
3566 	 */
3567 	fSessionListSize = ALLOC_SESSION;
3568 	fSessionListSize = fSessionListSize * (sizeof (slist_scsi_session_t));
3569 	fSessionList = (slist_scsi_session_t *)calloc(1, fSessionListSize);
3570 	if (fSessionList == NULL) {
3571 		return (STMF_ERROR_NOMEM);
3572 	}
3573 
3574 	ident[IDENT_LENGTH_BYTE] = devid->identLength;
3575 	bcopy(&(devid->ident), &ident[IDENT_LENGTH_BYTE + 1],
3576 	    devid->identLength);
3577 
3578 	bzero(&stmfIoctl, sizeof (stmfIoctl));
3579 	/*
3580 	 * Issue ioctl to get the session list
3581 	 */
3582 	stmfIoctl.stmf_version = STMF_VERSION_1;
3583 	stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&ident;
3584 	stmfIoctl.stmf_ibuf_size = sizeof (ident);
3585 	stmfIoctl.stmf_obuf_size = fSessionListSize;
3586 	stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)fSessionList;
3587 	ioctlRet = ioctl(fd, cmd, &stmfIoctl);
3588 	if (ioctlRet != 0) {
3589 		switch (errno) {
3590 			case EBUSY:
3591 				ret = STMF_ERROR_BUSY;
3592 				break;
3593 			case EPERM:
3594 			case EACCES:
3595 				ret = STMF_ERROR_PERM;
3596 				break;
3597 			default:
3598 				syslog(LOG_DEBUG,
3599 				    "stmfGetSessionList:ioctl errno(%d)",
3600 				    errno);
3601 				ret = STMF_STATUS_ERROR;
3602 				break;
3603 		}
3604 		goto done;
3605 	}
3606 	/*
3607 	 * Check whether input buffer was large enough
3608 	 */
3609 	if (stmfIoctl.stmf_obuf_max_nentries > ALLOC_SESSION) {
3610 		fSessionListSize = stmfIoctl.stmf_obuf_max_nentries *
3611 		    sizeof (slist_scsi_session_t);
3612 		fSessionList = realloc(fSessionList, fSessionListSize);
3613 		if (fSessionList == NULL) {
3614 			return (STMF_ERROR_NOMEM);
3615 		}
3616 		stmfIoctl.stmf_obuf_size = fSessionListSize;
3617 		stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)fSessionList;
3618 		ioctlRet = ioctl(fd, cmd, &stmfIoctl);
3619 		if (ioctlRet != 0) {
3620 			switch (errno) {
3621 				case EBUSY:
3622 					ret = STMF_ERROR_BUSY;
3623 					break;
3624 				case EPERM:
3625 				case EACCES:
3626 					ret = STMF_ERROR_PERM;
3627 					break;
3628 				default:
3629 					syslog(LOG_DEBUG,
3630 					    "stmfGetSessionList:ioctl "
3631 					    "errno(%d)", errno);
3632 					ret = STMF_STATUS_ERROR;
3633 					break;
3634 			}
3635 			goto done;
3636 		}
3637 	}
3638 
3639 	/*
3640 	 * allocate caller's buffer with the final size
3641 	 */
3642 	*sessionList = (stmfSessionList *)calloc(1, sizeof (stmfSessionList) +
3643 	    stmfIoctl.stmf_obuf_max_nentries * sizeof (stmfSession));
3644 	if (*sessionList == NULL) {
3645 		ret = STMF_ERROR_NOMEM;
3646 		free(sessionList);
3647 		goto done;
3648 	}
3649 
3650 	(*sessionList)->cnt = stmfIoctl.stmf_obuf_max_nentries;
3651 
3652 	/*
3653 	 * copy session info to caller's buffer
3654 	 */
3655 	for (i = 0; i < (*sessionList)->cnt; i++) {
3656 		(*sessionList)->session[i].initiator.identLength =
3657 		    fSessionList->initiator[IDENT_LENGTH_BYTE];
3658 		bcopy(&(fSessionList->initiator[IDENT_LENGTH_BYTE + 1]),
3659 		    (*sessionList)->session[i].initiator.ident,
3660 		    STMF_IDENT_LENGTH);
3661 		bcopy(&(fSessionList->alias),
3662 		    &((*sessionList)->session[i].alias),
3663 		    sizeof ((*sessionList)->session[i].alias));
3664 		bcopy(&(fSessionList++->creation_time),
3665 		    &((*sessionList)->session[i].creationTime),
3666 		    sizeof (time_t));
3667 	}
3668 done:
3669 	(void) close(fd);
3670 	return (ret);
3671 }
3672 
3673 /*
3674  * stmfGetTargetGroupList
3675  *
3676  * Purpose: Retrieves the list of target groups
3677  *
3678  * targetGroupList - pointer to a pointer to an stmfGroupList structure. On
3679  *		     success, it contains the list of target groups.
3680  */
3681 int
3682 stmfGetTargetGroupList(stmfGroupList **targetGroupList)
3683 {
3684 	int ret;
3685 
3686 	if (targetGroupList == NULL) {
3687 		return (STMF_ERROR_INVALID_ARG);
3688 	}
3689 
3690 	ret = groupListIoctl(targetGroupList, TARGET_GROUP);
3691 	return (ret);
3692 }
3693 
3694 /*
3695  * stmfGetTargetGroupMembers
3696  *
3697  * Purpose: Retrieves the group members for a target group
3698  *
3699  * groupName - name of target group for which to retrieve members.
3700  * groupProp - pointer to pointer to stmfGroupProperties structure
3701  *             on success, this contains the list of group members.
3702  */
3703 int
3704 stmfGetTargetGroupMembers(stmfGroupName *groupName,
3705     stmfGroupProperties **groupProp)
3706 {
3707 	int ret;
3708 
3709 	if (groupName == NULL || groupProp == NULL) {
3710 		return (STMF_ERROR_INVALID_ARG);
3711 	}
3712 
3713 	ret = groupMemberListIoctl(groupName, groupProp, TARGET_GROUP);
3714 
3715 	return (ret);
3716 }
3717 
3718 /*
3719  * stmfGetTargetList
3720  *
3721  * Purpose: Retrieves the list of target ports
3722  *
3723  * targetList - pointer to a pointer to an stmfDevidList structure.
3724  *		    On success, it contains the list of local ports (target).
3725  */
3726 int
3727 stmfGetTargetList(stmfDevidList **targetList)
3728 {
3729 	int ret;
3730 	int fd;
3731 	int ioctlRet;
3732 	int i;
3733 	stmf_iocdata_t stmfIoctl;
3734 	/* framework target port list */
3735 	slist_target_port_t *fTargetList, *fTargetListP = NULL;
3736 	uint32_t fTargetListSize;
3737 
3738 	if (targetList == NULL) {
3739 		return (STMF_ERROR_INVALID_ARG);
3740 	}
3741 
3742 	/* call init */
3743 	ret = initializeConfig();
3744 	if (ret != STMF_STATUS_SUCCESS) {
3745 		return (ret);
3746 	}
3747 
3748 	/*
3749 	 * Open control node for stmf
3750 	 */
3751 	if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
3752 		return (ret);
3753 
3754 	/*
3755 	 * Allocate ioctl input buffer
3756 	 */
3757 	fTargetListSize = ALLOC_TARGET_PORT * sizeof (slist_target_port_t);
3758 	fTargetListP = fTargetList =
3759 	    (slist_target_port_t *)calloc(1, fTargetListSize);
3760 	if (fTargetList == NULL) {
3761 		ret = STMF_ERROR_NOMEM;
3762 		goto done;
3763 	}
3764 
3765 	bzero(&stmfIoctl, sizeof (stmfIoctl));
3766 	/*
3767 	 * Issue ioctl to retrieve target list
3768 	 */
3769 	stmfIoctl.stmf_version = STMF_VERSION_1;
3770 	stmfIoctl.stmf_obuf_size = fTargetListSize;
3771 	stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)fTargetList;
3772 	ioctlRet = ioctl(fd, STMF_IOCTL_TARGET_PORT_LIST, &stmfIoctl);
3773 	if (ioctlRet != 0) {
3774 		switch (errno) {
3775 			case EBUSY:
3776 				ret = STMF_ERROR_BUSY;
3777 				break;
3778 			case EPERM:
3779 			case EACCES:
3780 				ret = STMF_ERROR_PERM;
3781 				break;
3782 			default:
3783 				syslog(LOG_DEBUG,
3784 				    "stmfGetTargetList:ioctl errno(%d)", errno);
3785 				ret = STMF_STATUS_ERROR;
3786 				break;
3787 		}
3788 		goto done;
3789 	}
3790 	/*
3791 	 * Check whether input buffer was large enough
3792 	 */
3793 	if (stmfIoctl.stmf_obuf_max_nentries > ALLOC_TARGET_PORT) {
3794 		fTargetListSize = stmfIoctl.stmf_obuf_max_nentries *
3795 		    sizeof (slist_target_port_t);
3796 		fTargetListP = fTargetList =
3797 		    realloc(fTargetList, fTargetListSize);
3798 		if (fTargetList == NULL) {
3799 			ret = STMF_ERROR_NOMEM;
3800 			goto done;
3801 		}
3802 		stmfIoctl.stmf_obuf_size = fTargetListSize;
3803 		stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)fTargetList;
3804 		ioctlRet = ioctl(fd, STMF_IOCTL_TARGET_PORT_LIST,
3805 		    &stmfIoctl);
3806 		if (ioctlRet != 0) {
3807 			switch (errno) {
3808 				case EBUSY:
3809 					ret = STMF_ERROR_BUSY;
3810 					break;
3811 				case EPERM:
3812 				case EACCES:
3813 					ret = STMF_ERROR_PERM;
3814 					break;
3815 				default:
3816 					syslog(LOG_DEBUG,
3817 					    "stmfGetTargetList:ioctl errno(%d)",
3818 					    errno);
3819 					ret = STMF_STATUS_ERROR;
3820 					break;
3821 			}
3822 			goto done;
3823 		}
3824 	}
3825 
3826 	*targetList = (stmfDevidList *)calloc(1,
3827 	    stmfIoctl.stmf_obuf_max_nentries * sizeof (stmfDevid) +
3828 	    sizeof (stmfDevidList));
3829 	if (*targetList == NULL) {
3830 		ret = STMF_ERROR_NOMEM;
3831 		goto done;
3832 	}
3833 
3834 	(*targetList)->cnt = stmfIoctl.stmf_obuf_max_nentries;
3835 	for (i = 0; i < stmfIoctl.stmf_obuf_max_nentries; i++, fTargetList++) {
3836 		(*targetList)->devid[i].identLength =
3837 		    fTargetList->target[IDENT_LENGTH_BYTE];
3838 		bcopy(&fTargetList->target[IDENT_LENGTH_BYTE + 1],
3839 		    &(*targetList)->devid[i].ident,
3840 		    fTargetList->target[IDENT_LENGTH_BYTE]);
3841 	}
3842 
3843 done:
3844 	(void) close(fd);
3845 	free(fTargetListP);
3846 	return (ret);
3847 }
3848 
3849 /*
3850  * stmfGetTargetProperties
3851  *
3852  * Purpose:  Retrieves the properties for a logical unit
3853  *
3854  * devid - devid of the target for which to retrieve properties
3855  * targetProps - pointer to an stmfTargetProperties structure.
3856  *		On success, it contains the target properties for
3857  *		the specified devid.
3858  */
3859 int
3860 stmfGetTargetProperties(stmfDevid *devid, stmfTargetProperties *targetProps)
3861 {
3862 	int ret = STMF_STATUS_SUCCESS;
3863 	int fd;
3864 	int ioctlRet;
3865 	stmf_iocdata_t stmfIoctl;
3866 	sioc_target_port_props_t targetProperties;
3867 
3868 	if (devid == NULL || targetProps == NULL) {
3869 		return (STMF_ERROR_INVALID_ARG);
3870 	}
3871 
3872 	/* call init */
3873 	ret = initializeConfig();
3874 	if (ret != STMF_STATUS_SUCCESS) {
3875 		return (ret);
3876 	}
3877 
3878 	/*
3879 	 * Open control node for stmf
3880 	 */
3881 	if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
3882 		return (ret);
3883 
3884 	targetProperties.tgt_id[IDENT_LENGTH_BYTE] = devid->identLength;
3885 	bcopy(&(devid->ident), &targetProperties.tgt_id[IDENT_LENGTH_BYTE + 1],
3886 	    devid->identLength);
3887 
3888 	bzero(&stmfIoctl, sizeof (stmfIoctl));
3889 	/*
3890 	 * Issue ioctl to add to the host group
3891 	 */
3892 	stmfIoctl.stmf_version = STMF_VERSION_1;
3893 	stmfIoctl.stmf_ibuf_size = sizeof (targetProperties.tgt_id);
3894 	stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&targetProperties.tgt_id;
3895 	stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)&targetProperties;
3896 	stmfIoctl.stmf_obuf_size = sizeof (targetProperties);
3897 	ioctlRet = ioctl(fd, STMF_IOCTL_GET_TARGET_PORT_PROPERTIES,
3898 	    &stmfIoctl);
3899 	if (ioctlRet != 0) {
3900 		switch (errno) {
3901 			case EBUSY:
3902 				ret = STMF_ERROR_BUSY;
3903 				break;
3904 			case EPERM:
3905 			case EACCES:
3906 				ret = STMF_ERROR_PERM;
3907 				break;
3908 			case ENOENT:
3909 				ret = STMF_ERROR_NOT_FOUND;
3910 				break;
3911 			default:
3912 				syslog(LOG_DEBUG,
3913 				    "stmfGetTargetProperties:ioctl errno(%d)",
3914 				    errno);
3915 				ret = STMF_STATUS_ERROR;
3916 				break;
3917 		}
3918 		goto done;
3919 	}
3920 
3921 	bcopy(targetProperties.tgt_provider_name, targetProps->providerName,
3922 	    sizeof (targetProperties.tgt_provider_name));
3923 	if (targetProperties.tgt_state == STMF_STATE_ONLINE) {
3924 		targetProps->status = STMF_TARGET_PORT_ONLINE;
3925 	} else if (targetProperties.tgt_state == STMF_STATE_OFFLINE) {
3926 		targetProps->status = STMF_TARGET_PORT_OFFLINE;
3927 	} else if (targetProperties.tgt_state == STMF_STATE_ONLINING) {
3928 		targetProps->status = STMF_TARGET_PORT_ONLINING;
3929 	} else if (targetProperties.tgt_state == STMF_STATE_OFFLINING) {
3930 		targetProps->status = STMF_TARGET_PORT_OFFLINING;
3931 	}
3932 	bcopy(targetProperties.tgt_alias, targetProps->alias,
3933 	    sizeof (targetProps->alias));
3934 done:
3935 	(void) close(fd);
3936 	return (ret);
3937 }
3938 
3939 /*
3940  * stmfGetLogicalUnitList
3941  *
3942  * Purpose: Retrieves list of logical unit Object IDs
3943  *
3944  * luList - pointer to a pointer to a stmfGuidList structure. On success,
3945  *          it contains the list of logical unit guids.
3946  *
3947  */
3948 int
3949 stmfGetLogicalUnitList(stmfGuidList **luList)
3950 {
3951 	int ret;
3952 	int fd;
3953 	int ioctlRet;
3954 	int cmd = STMF_IOCTL_LU_LIST;
3955 	int i;
3956 	stmf_iocdata_t stmfIoctl;
3957 	slist_lu_t *fLuList;
3958 	uint32_t fLuListSize;
3959 	uint32_t listCnt;
3960 
3961 	if (luList == NULL) {
3962 		return (STMF_ERROR_INVALID_ARG);
3963 	}
3964 
3965 	/* call init */
3966 	ret = initializeConfig();
3967 	if (ret != STMF_STATUS_SUCCESS) {
3968 		return (ret);
3969 	}
3970 
3971 	/*
3972 	 * Open control node for stmf
3973 	 */
3974 	if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
3975 		return (ret);
3976 
3977 	/*
3978 	 * Allocate ioctl input buffer
3979 	 */
3980 	fLuListSize = ALLOC_LU;
3981 	fLuListSize = fLuListSize * (sizeof (slist_lu_t));
3982 	fLuList = (slist_lu_t *)calloc(1, fLuListSize);
3983 	if (fLuList == NULL) {
3984 		ret = STMF_ERROR_NOMEM;
3985 		goto done;
3986 	}
3987 
3988 	bzero(&stmfIoctl, sizeof (stmfIoctl));
3989 	/*
3990 	 * Issue ioctl to get the LU list
3991 	 */
3992 	stmfIoctl.stmf_version = STMF_VERSION_1;
3993 	stmfIoctl.stmf_obuf_size = fLuListSize;
3994 	stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)fLuList;
3995 	ioctlRet = ioctl(fd, cmd, &stmfIoctl);
3996 	if (ioctlRet != 0) {
3997 		switch (errno) {
3998 			case EBUSY:
3999 				ret = STMF_ERROR_BUSY;
4000 				break;
4001 			case EPERM:
4002 			case EACCES:
4003 				ret = STMF_ERROR_PERM;
4004 				break;
4005 			default:
4006 				syslog(LOG_DEBUG,
4007 				    "stmfGetLogicalUnitList:ioctl errno(%d)",
4008 				    errno);
4009 				ret = STMF_STATUS_ERROR;
4010 				break;
4011 		}
4012 		goto done;
4013 	}
4014 	/*
4015 	 * Check whether input buffer was large enough
4016 	 */
4017 	if (stmfIoctl.stmf_obuf_max_nentries > ALLOC_LU) {
4018 		fLuListSize = stmfIoctl.stmf_obuf_max_nentries *
4019 		    sizeof (slist_lu_t);
4020 		free(fLuList);
4021 		fLuList = (slist_lu_t *)calloc(1, fLuListSize);
4022 		if (fLuList == NULL) {
4023 			ret = STMF_ERROR_NOMEM;
4024 			goto done;
4025 		}
4026 		stmfIoctl.stmf_obuf_size = fLuListSize;
4027 		stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)fLuList;
4028 		ioctlRet = ioctl(fd, cmd, &stmfIoctl);
4029 		if (ioctlRet != 0) {
4030 			switch (errno) {
4031 				case EBUSY:
4032 					ret = STMF_ERROR_BUSY;
4033 					break;
4034 				case EPERM:
4035 				case EACCES:
4036 					ret = STMF_ERROR_PERM;
4037 					break;
4038 				default:
4039 					syslog(LOG_DEBUG,
4040 					    "stmfGetLogicalUnitList:"
4041 					    "ioctl errno(%d)", errno);
4042 					ret = STMF_STATUS_ERROR;
4043 					break;
4044 			}
4045 			goto done;
4046 		}
4047 	}
4048 
4049 	if (ret != STMF_STATUS_SUCCESS) {
4050 		goto done;
4051 	}
4052 
4053 	listCnt = stmfIoctl.stmf_obuf_nentries;
4054 
4055 	/*
4056 	 * allocate caller's buffer with the final size
4057 	 */
4058 	*luList = (stmfGuidList *)calloc(1, sizeof (stmfGuidList) +
4059 	    listCnt * sizeof (stmfGuid));
4060 	if (*luList == NULL) {
4061 		ret = STMF_ERROR_NOMEM;
4062 		goto done;
4063 	}
4064 
4065 	(*luList)->cnt = listCnt;
4066 
4067 	/* copy to caller's buffer */
4068 	for (i = 0; i < listCnt; i++) {
4069 		bcopy(&fLuList[i].lu_guid, (*luList)->guid[i].guid,
4070 		    sizeof (stmfGuid));
4071 	}
4072 
4073 	/*
4074 	 * sort the list. This gives a consistent view across gets
4075 	 */
4076 	qsort((void *)&((*luList)->guid[0]), (*luList)->cnt,
4077 	    sizeof (stmfGuid), guidCompare);
4078 
4079 done:
4080 	(void) close(fd);
4081 	/*
4082 	 * free internal buffers
4083 	 */
4084 	free(fLuList);
4085 	return (ret);
4086 }
4087 
4088 /*
4089  * stmfGetLogicalUnitProperties
4090  *
4091  * Purpose:  Retrieves the properties for a logical unit
4092  *
4093  * lu - guid of the logical unit for which to retrieve properties
4094  * stmfLuProps - pointer to an stmfLogicalUnitProperties structure. On success,
4095  *               it contains the logical unit properties for the specified guid.
4096  */
4097 int
4098 stmfGetLogicalUnitProperties(stmfGuid *lu, stmfLogicalUnitProperties *luProps)
4099 {
4100 	int ret = STMF_STATUS_SUCCESS;
4101 	int stmfRet;
4102 	int fd;
4103 	int ioctlRet;
4104 	int cmd = STMF_IOCTL_GET_LU_PROPERTIES;
4105 	stmfViewEntryList *viewEntryList = NULL;
4106 	stmf_iocdata_t stmfIoctl;
4107 	sioc_lu_props_t fLuProps;
4108 
4109 	if (lu == NULL || luProps == NULL) {
4110 		return (STMF_ERROR_INVALID_ARG);
4111 	}
4112 
4113 	bzero(luProps, sizeof (stmfLogicalUnitProperties));
4114 
4115 	/* call init */
4116 	ret = initializeConfig();
4117 	if (ret != STMF_STATUS_SUCCESS) {
4118 		return (ret);
4119 	}
4120 
4121 	/*
4122 	 * Open control node for stmf
4123 	 */
4124 	if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
4125 		return (ret);
4126 
4127 	bzero(&stmfIoctl, sizeof (stmfIoctl));
4128 	/*
4129 	 * Issue ioctl to add to the host group
4130 	 */
4131 	stmfIoctl.stmf_version = STMF_VERSION_1;
4132 	stmfIoctl.stmf_ibuf_size = sizeof (stmfGuid);
4133 	stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)lu;
4134 	stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)&fLuProps;
4135 	stmfIoctl.stmf_obuf_size = sizeof (fLuProps);
4136 	ioctlRet = ioctl(fd, cmd, &stmfIoctl);
4137 	if (ioctlRet != 0) {
4138 		switch (errno) {
4139 			case EBUSY:
4140 				ret = STMF_ERROR_BUSY;
4141 				break;
4142 			case EPERM:
4143 			case EACCES:
4144 				ret = STMF_ERROR_PERM;
4145 				break;
4146 			case ENOENT:
4147 				stmfRet = stmfGetViewEntryList(lu,
4148 				    &viewEntryList);
4149 				if (stmfRet == STMF_STATUS_SUCCESS) {
4150 					luProps->status =
4151 					    STMF_LOGICAL_UNIT_UNREGISTERED;
4152 					if (viewEntryList->cnt > 0) {
4153 						ret = STMF_STATUS_SUCCESS;
4154 					} else {
4155 						ret = STMF_ERROR_NOT_FOUND;
4156 					}
4157 				} else {
4158 					ret = STMF_ERROR_NOT_FOUND;
4159 				}
4160 				stmfFreeMemory(viewEntryList);
4161 				break;
4162 			default:
4163 				syslog(LOG_DEBUG,
4164 				    "stmfGetLogicalUnit:ioctl errno(%d)",
4165 				    errno);
4166 				ret = STMF_STATUS_ERROR;
4167 				break;
4168 		}
4169 		goto done;
4170 	}
4171 
4172 	bcopy(fLuProps.lu_provider_name, luProps->providerName,
4173 	    sizeof (fLuProps.lu_provider_name));
4174 	if (fLuProps.lu_state == STMF_STATE_ONLINE) {
4175 		luProps->status = STMF_LOGICAL_UNIT_ONLINE;
4176 	} else if (fLuProps.lu_state == STMF_STATE_OFFLINE) {
4177 		luProps->status = STMF_LOGICAL_UNIT_OFFLINE;
4178 	} else if (fLuProps.lu_state == STMF_STATE_ONLINING) {
4179 		luProps->status = STMF_LOGICAL_UNIT_ONLINING;
4180 	} else if (fLuProps.lu_state == STMF_STATE_OFFLINING) {
4181 		luProps->status = STMF_LOGICAL_UNIT_OFFLINING;
4182 	}
4183 	bcopy(fLuProps.lu_alias, luProps->alias, sizeof (luProps->alias));
4184 done:
4185 	(void) close(fd);
4186 	return (ret);
4187 }
4188 
4189 /*
4190  * stmfGetState
4191  *
4192  * Purpose: retrieve the current state of the stmf module
4193  *
4194  * state - pointer to stmfState structure allocated by the caller
4195  *         On success, contains the state of stmf
4196  */
4197 int
4198 stmfGetState(stmfState *state)
4199 {
4200 	int ret;
4201 	stmf_state_desc_t iState;
4202 
4203 	if (state == NULL) {
4204 		return (STMF_ERROR_INVALID_ARG);
4205 	}
4206 
4207 	ret = getStmfState(&iState);
4208 	if (ret != STMF_STATUS_SUCCESS) {
4209 		return (ret);
4210 	}
4211 	switch (iState.state) {
4212 		case STMF_STATE_ONLINE:
4213 			state->operationalState =
4214 			    STMF_SERVICE_STATE_ONLINE;
4215 			break;
4216 		case STMF_STATE_OFFLINE:
4217 			state->operationalState =
4218 			    STMF_SERVICE_STATE_OFFLINE;
4219 			break;
4220 		case STMF_STATE_ONLINING:
4221 			state->operationalState =
4222 			    STMF_SERVICE_STATE_ONLINING;
4223 			break;
4224 		case STMF_STATE_OFFLINING:
4225 			state->operationalState =
4226 			    STMF_SERVICE_STATE_OFFLINING;
4227 			break;
4228 		default:
4229 			state->operationalState =
4230 			    STMF_SERVICE_STATE_UNKNOWN;
4231 			break;
4232 	}
4233 	switch (iState.config_state) {
4234 		case STMF_CONFIG_NONE:
4235 			state->configState = STMF_CONFIG_STATE_NONE;
4236 			break;
4237 		case STMF_CONFIG_INIT:
4238 			state->configState = STMF_CONFIG_STATE_INIT;
4239 			break;
4240 		case STMF_CONFIG_INIT_DONE:
4241 			state->configState =
4242 			    STMF_CONFIG_STATE_INIT_DONE;
4243 			break;
4244 		default:
4245 			state->configState =
4246 			    STMF_CONFIG_STATE_UNKNOWN;
4247 			break;
4248 	}
4249 	return (STMF_STATUS_SUCCESS);
4250 }
4251 
4252 /*
4253  * stmfGetViewEntryList
4254  *
4255  * Purpose: Retrieves the list of view entries for the specified
4256  *          logical unit.
4257  *
4258  * lu - the guid of the logical unit for which to retrieve the view entry list
4259  * viewEntryList - a pointer to a pointer to a stmfViewEntryList structure. On
4260  *                 success, contains the list of view entries.
4261  */
4262 int
4263 stmfGetViewEntryList(stmfGuid *lu, stmfViewEntryList **viewEntryList)
4264 {
4265 	int ret;
4266 	int fd;
4267 	int ioctlRet;
4268 	int cmd = STMF_IOCTL_LU_VE_LIST;
4269 	int i;
4270 	stmf_iocdata_t stmfIoctl;
4271 	stmf_view_op_entry_t *fVeList;
4272 	uint32_t fVeListSize;
4273 	uint32_t listCnt;
4274 
4275 	if (lu == NULL || viewEntryList == NULL) {
4276 		return (STMF_ERROR_INVALID_ARG);
4277 	}
4278 
4279 	/* call init */
4280 	ret = initializeConfig();
4281 	if (ret != STMF_STATUS_SUCCESS) {
4282 		return (ret);
4283 	}
4284 
4285 	/*
4286 	 * Open control node for stmf
4287 	 */
4288 	if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
4289 		return (ret);
4290 
4291 	/*
4292 	 * Allocate ioctl input buffer
4293 	 */
4294 	fVeListSize = ALLOC_VE;
4295 	fVeListSize = fVeListSize * (sizeof (stmf_view_op_entry_t));
4296 	fVeList = (stmf_view_op_entry_t *)calloc(1, fVeListSize);
4297 	if (fVeList == NULL) {
4298 		ret = STMF_ERROR_NOMEM;
4299 		goto done;
4300 	}
4301 
4302 	bzero(&stmfIoctl, sizeof (stmfIoctl));
4303 	/*
4304 	 * Issue ioctl to get the LU list
4305 	 */
4306 	stmfIoctl.stmf_version = STMF_VERSION_1;
4307 	stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)lu;
4308 	stmfIoctl.stmf_ibuf_size = sizeof (stmfGuid);
4309 	stmfIoctl.stmf_obuf_size = fVeListSize;
4310 	stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)fVeList;
4311 	ioctlRet = ioctl(fd, cmd, &stmfIoctl);
4312 	if (ioctlRet != 0) {
4313 		switch (errno) {
4314 			case EBUSY:
4315 				ret = STMF_ERROR_BUSY;
4316 				break;
4317 			case EPERM:
4318 			case EACCES:
4319 				ret = STMF_ERROR_PERM;
4320 				break;
4321 			default:
4322 				syslog(LOG_DEBUG,
4323 				    "stmfGetViewEntryList:ioctl errno(%d)",
4324 				    errno);
4325 				ret = STMF_STATUS_ERROR;
4326 				break;
4327 		}
4328 		goto done;
4329 	}
4330 	/*
4331 	 * Check whether input buffer was large enough
4332 	 */
4333 	if (stmfIoctl.stmf_obuf_max_nentries > ALLOC_VE) {
4334 		bzero(&stmfIoctl, sizeof (stmfIoctl));
4335 		fVeListSize = stmfIoctl.stmf_obuf_max_nentries *
4336 		    sizeof (stmf_view_op_entry_t);
4337 		free(fVeList);
4338 		fVeList = (stmf_view_op_entry_t *)calloc(1, fVeListSize);
4339 		if (fVeList == NULL) {
4340 			return (STMF_ERROR_NOMEM);
4341 		}
4342 		stmfIoctl.stmf_obuf_size = fVeListSize;
4343 		stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)fVeList;
4344 		ioctlRet = ioctl(fd, cmd, &stmfIoctl);
4345 		if (ioctlRet != 0) {
4346 			switch (errno) {
4347 				case EBUSY:
4348 					ret = STMF_ERROR_BUSY;
4349 					break;
4350 				case EPERM:
4351 				case EACCES:
4352 					ret = STMF_ERROR_PERM;
4353 					break;
4354 				default:
4355 					syslog(LOG_DEBUG,
4356 					    "stmfGetLogicalUnitList:"
4357 					    "ioctl errno(%d)", errno);
4358 					ret = STMF_STATUS_ERROR;
4359 					break;
4360 			}
4361 			goto done;
4362 		}
4363 	}
4364 
4365 	if (ret != STMF_STATUS_SUCCESS) {
4366 		goto done;
4367 	}
4368 
4369 	if (stmfIoctl.stmf_obuf_nentries == 0) {
4370 		ret = STMF_ERROR_NOT_FOUND;
4371 		goto done;
4372 	}
4373 
4374 	listCnt = stmfIoctl.stmf_obuf_nentries;
4375 
4376 	/*
4377 	 * allocate caller's buffer with the final size
4378 	 */
4379 	*viewEntryList = (stmfViewEntryList *)calloc(1,
4380 	    sizeof (stmfViewEntryList) + listCnt * sizeof (stmfViewEntry));
4381 	if (*viewEntryList == NULL) {
4382 		ret = STMF_ERROR_NOMEM;
4383 		goto done;
4384 	}
4385 
4386 	(*viewEntryList)->cnt = listCnt;
4387 
4388 	/* copy to caller's buffer */
4389 	for (i = 0; i < listCnt; i++) {
4390 		(*viewEntryList)->ve[i].veIndexValid = B_TRUE;
4391 		(*viewEntryList)->ve[i].veIndex = fVeList[i].ve_ndx;
4392 		if (fVeList[i].ve_all_hosts == 1) {
4393 			(*viewEntryList)->ve[i].allHosts = B_TRUE;
4394 		} else {
4395 			bcopy(fVeList[i].ve_host_group.name,
4396 			    (*viewEntryList)->ve[i].hostGroup,
4397 			    fVeList[i].ve_host_group.name_size);
4398 		}
4399 		if (fVeList[i].ve_all_targets == 1) {
4400 			(*viewEntryList)->ve[i].allTargets = B_TRUE;
4401 		} else {
4402 			bcopy(fVeList[i].ve_target_group.name,
4403 			    (*viewEntryList)->ve[i].targetGroup,
4404 			    fVeList[i].ve_target_group.name_size);
4405 		}
4406 		bcopy(fVeList[i].ve_lu_nbr, (*viewEntryList)->ve[i].luNbr,
4407 		    sizeof ((*viewEntryList)->ve[i].luNbr));
4408 		(*viewEntryList)->ve[i].luNbrValid = B_TRUE;
4409 	}
4410 
4411 	/*
4412 	 * sort the list. This gives a consistent view across gets
4413 	 */
4414 	qsort((void *)&((*viewEntryList)->ve[0]), (*viewEntryList)->cnt,
4415 	    sizeof (stmfViewEntry), viewEntryCompare);
4416 
4417 done:
4418 	(void) close(fd);
4419 	/*
4420 	 * free internal buffers
4421 	 */
4422 	free(fVeList);
4423 	return (ret);
4424 }
4425 
4426 
4427 /*
4428  * loadHostGroups
4429  *
4430  * Purpose - issues the ioctl to load the host groups into stmf
4431  *
4432  * fd - file descriptor for the control node of stmf.
4433  * groupList - populated host group list
4434  */
4435 static int
4436 loadHostGroups(int fd, stmfGroupList *groupList)
4437 {
4438 	int i, j;
4439 	int ret = STMF_STATUS_SUCCESS;
4440 	stmfGroupProperties *groupProps = NULL;
4441 
4442 	for (i = 0; i < groupList->cnt; i++) {
4443 		if ((ret = groupIoctl(fd, STMF_IOCTL_CREATE_HOST_GROUP,
4444 		    &(groupList->name[i]))) != STMF_STATUS_SUCCESS) {
4445 			goto out;
4446 		}
4447 		ret = iLoadGroupMembersFromPs(&(groupList->name[i]),
4448 		    &groupProps, HOST_GROUP);
4449 		for (j = 0; j < groupProps->cnt; j++) {
4450 			if ((ret = groupMemberIoctl(fd, STMF_IOCTL_ADD_HG_ENTRY,
4451 			    &(groupList->name[i]), &(groupProps->name[j])))
4452 			    != STMF_STATUS_SUCCESS) {
4453 				goto out;
4454 			}
4455 		}
4456 	}
4457 
4458 
4459 out:
4460 	stmfFreeMemory(groupProps);
4461 	return (ret);
4462 }
4463 
4464 /*
4465  * loadTargetGroups
4466  *
4467  * Purpose - issues the ioctl to load the target groups into stmf
4468  *
4469  * fd - file descriptor for the control node of stmf.
4470  * groupList - populated target group list.
4471  */
4472 static int
4473 loadTargetGroups(int fd, stmfGroupList *groupList)
4474 {
4475 	int i, j;
4476 	int ret = STMF_STATUS_SUCCESS;
4477 	stmfGroupProperties *groupProps = NULL;
4478 
4479 	for (i = 0; i < groupList->cnt; i++) {
4480 		if ((ret = groupIoctl(fd, STMF_IOCTL_CREATE_TARGET_GROUP,
4481 		    &(groupList->name[i]))) != STMF_STATUS_SUCCESS) {
4482 			goto out;
4483 		}
4484 		ret = iLoadGroupMembersFromPs(&(groupList->name[i]),
4485 		    &groupProps, TARGET_GROUP);
4486 		for (j = 0; j < groupProps->cnt; j++) {
4487 			if ((ret = groupMemberIoctl(fd, STMF_IOCTL_ADD_TG_ENTRY,
4488 			    &(groupList->name[i]), &(groupProps->name[j])))
4489 			    != STMF_STATUS_SUCCESS) {
4490 				goto out;
4491 			}
4492 		}
4493 	}
4494 
4495 
4496 out:
4497 	stmfFreeMemory(groupProps);
4498 	return (ret);
4499 }
4500 
4501 
4502 /*
4503  * loadStore
4504  *
4505  * Purpose: Load the configuration data from the store
4506  *
4507  * First load the host groups and target groups, then the view entries
4508  * and finally the provider data
4509  *
4510  * fd - file descriptor of control node for stmf.
4511  */
4512 static int
4513 loadStore(int fd)
4514 {
4515 	int ret;
4516 	int i, j;
4517 	stmfGroupList *groupList = NULL;
4518 	stmfGuidList *guidList = NULL;
4519 	stmfViewEntryList *viewEntryList = NULL;
4520 	stmfProviderList *providerList = NULL;
4521 	int providerType;
4522 	nvlist_t *nvl = NULL;
4523 
4524 
4525 
4526 	/* load host groups */
4527 	ret = iLoadGroupFromPs(&groupList, HOST_GROUP);
4528 	if (ret != STMF_STATUS_SUCCESS) {
4529 		return (ret);
4530 	}
4531 	ret = loadHostGroups(fd, groupList);
4532 	if (ret != STMF_STATUS_SUCCESS) {
4533 		goto out;
4534 	}
4535 
4536 	stmfFreeMemory(groupList);
4537 	groupList = NULL;
4538 
4539 	/* load target groups */
4540 	ret = iLoadGroupFromPs(&groupList, TARGET_GROUP);
4541 	if (ret != STMF_STATUS_SUCCESS) {
4542 		goto out;
4543 	}
4544 	ret = loadTargetGroups(fd, groupList);
4545 	if (ret != STMF_STATUS_SUCCESS) {
4546 		goto out;
4547 	}
4548 
4549 	stmfFreeMemory(groupList);
4550 	groupList = NULL;
4551 
4552 	/* Get the guid list */
4553 	ret = psGetLogicalUnitList(&guidList);
4554 	switch (ret) {
4555 		case STMF_PS_SUCCESS:
4556 			ret = STMF_STATUS_SUCCESS;
4557 			break;
4558 		case STMF_PS_ERROR_NOT_FOUND:
4559 			ret = STMF_ERROR_NOT_FOUND;
4560 			break;
4561 		case STMF_PS_ERROR_BUSY:
4562 			ret = STMF_ERROR_BUSY;
4563 			break;
4564 		case STMF_PS_ERROR_SERVICE_NOT_FOUND:
4565 			ret = STMF_ERROR_SERVICE_NOT_FOUND;
4566 			break;
4567 		case STMF_PS_ERROR_VERSION_MISMATCH:
4568 			ret = STMF_ERROR_SERVICE_DATA_VERSION;
4569 			break;
4570 		default:
4571 			ret = STMF_STATUS_ERROR;
4572 			break;
4573 	}
4574 
4575 	if (ret != STMF_STATUS_SUCCESS) {
4576 		goto out;
4577 	}
4578 
4579 	/*
4580 	 * We have the guid list, now get the corresponding
4581 	 * view entries for each guid
4582 	 */
4583 	for (i = 0; i < guidList->cnt; i++) {
4584 		ret = psGetViewEntryList(&guidList->guid[i], &viewEntryList);
4585 		switch (ret) {
4586 			case STMF_PS_SUCCESS:
4587 				ret = STMF_STATUS_SUCCESS;
4588 				break;
4589 			case STMF_PS_ERROR_NOT_FOUND:
4590 				ret = STMF_ERROR_NOT_FOUND;
4591 				break;
4592 			case STMF_PS_ERROR_BUSY:
4593 				ret = STMF_ERROR_BUSY;
4594 				break;
4595 			case STMF_PS_ERROR_SERVICE_NOT_FOUND:
4596 				ret = STMF_ERROR_SERVICE_NOT_FOUND;
4597 				break;
4598 			case STMF_PS_ERROR_VERSION_MISMATCH:
4599 				ret = STMF_ERROR_SERVICE_DATA_VERSION;
4600 				break;
4601 			default:
4602 				ret = STMF_STATUS_ERROR;
4603 				break;
4604 		}
4605 		if (ret != STMF_STATUS_SUCCESS) {
4606 			goto out;
4607 		}
4608 		for (j = 0; j < viewEntryList->cnt; j++) {
4609 			ret = addViewEntryIoctl(fd, &guidList->guid[i],
4610 			    &viewEntryList->ve[j]);
4611 			if (ret != STMF_STATUS_SUCCESS) {
4612 				goto out;
4613 			}
4614 		}
4615 	}
4616 
4617 	/* get the list of providers that have data */
4618 	ret = psGetProviderDataList(&providerList);
4619 	switch (ret) {
4620 		case STMF_PS_SUCCESS:
4621 			ret = STMF_STATUS_SUCCESS;
4622 			break;
4623 		case STMF_PS_ERROR_NOT_FOUND:
4624 			ret = STMF_ERROR_NOT_FOUND;
4625 			break;
4626 		case STMF_PS_ERROR_BUSY:
4627 			ret = STMF_ERROR_BUSY;
4628 			break;
4629 		case STMF_PS_ERROR_SERVICE_NOT_FOUND:
4630 			ret = STMF_ERROR_SERVICE_NOT_FOUND;
4631 			break;
4632 		case STMF_PS_ERROR_VERSION_MISMATCH:
4633 			ret = STMF_ERROR_SERVICE_DATA_VERSION;
4634 			break;
4635 		default:
4636 			ret = STMF_STATUS_ERROR;
4637 			break;
4638 	}
4639 	if (ret != STMF_STATUS_SUCCESS) {
4640 		goto out;
4641 	}
4642 
4643 	for (i = 0; i < providerList->cnt; i++) {
4644 		providerType = providerList->provider[i].providerType;
4645 		ret = psGetProviderData(providerList->provider[i].name,
4646 		    &nvl, providerType, NULL);
4647 		switch (ret) {
4648 			case STMF_PS_SUCCESS:
4649 				ret = STMF_STATUS_SUCCESS;
4650 				break;
4651 			case STMF_PS_ERROR_NOT_FOUND:
4652 				ret = STMF_ERROR_NOT_FOUND;
4653 				break;
4654 			case STMF_PS_ERROR_BUSY:
4655 				ret = STMF_ERROR_BUSY;
4656 				break;
4657 			case STMF_PS_ERROR_SERVICE_NOT_FOUND:
4658 				ret = STMF_ERROR_SERVICE_NOT_FOUND;
4659 				break;
4660 			case STMF_PS_ERROR_VERSION_MISMATCH:
4661 				ret = STMF_ERROR_SERVICE_DATA_VERSION;
4662 				break;
4663 			default:
4664 				ret = STMF_STATUS_ERROR;
4665 				break;
4666 		}
4667 		if (ret != STMF_STATUS_SUCCESS) {
4668 			goto out;
4669 		}
4670 
4671 		/* call setProviderData */
4672 		ret = setProviderData(fd, providerList->provider[i].name, nvl,
4673 		    providerType, NULL);
4674 		switch (ret) {
4675 			case STMF_PS_SUCCESS:
4676 				ret = STMF_STATUS_SUCCESS;
4677 				break;
4678 			case STMF_PS_ERROR_NOT_FOUND:
4679 				ret = STMF_ERROR_NOT_FOUND;
4680 				break;
4681 			case STMF_PS_ERROR_BUSY:
4682 				ret = STMF_ERROR_BUSY;
4683 				break;
4684 			case STMF_PS_ERROR_SERVICE_NOT_FOUND:
4685 				ret = STMF_ERROR_SERVICE_NOT_FOUND;
4686 				break;
4687 			case STMF_PS_ERROR_VERSION_MISMATCH:
4688 				ret = STMF_ERROR_SERVICE_DATA_VERSION;
4689 				break;
4690 			default:
4691 				ret = STMF_STATUS_ERROR;
4692 				break;
4693 		}
4694 		if (ret != STMF_STATUS_SUCCESS) {
4695 			goto out;
4696 		}
4697 
4698 		nvlist_free(nvl);
4699 		nvl = NULL;
4700 	}
4701 out:
4702 	if (groupList != NULL) {
4703 		free(groupList);
4704 	}
4705 	if (guidList != NULL) {
4706 		free(guidList);
4707 	}
4708 	if (viewEntryList != NULL) {
4709 		free(viewEntryList);
4710 	}
4711 	if (nvl != NULL) {
4712 		nvlist_free(nvl);
4713 	}
4714 	return (ret);
4715 }
4716 
4717 /*
4718  * stmfLoadConfig
4719  *
4720  * Purpose - load the configuration data from smf into stmf
4721  *
4722  */
4723 int
4724 stmfLoadConfig(void)
4725 {
4726 	int ret = STMF_STATUS_SUCCESS;
4727 	int fd;
4728 	stmf_state_desc_t stmfStateSet;
4729 	stmfState state;
4730 
4731 	if (iGetPersistMethod() == STMF_PERSIST_NONE) {
4732 		stmfStateSet.state = STMF_STATE_OFFLINE;
4733 		stmfStateSet.config_state = STMF_CONFIG_INIT;
4734 		if ((ret = openStmf(OPEN_EXCL_STMF, &fd))
4735 		    != STMF_STATUS_SUCCESS) {
4736 			return (ret);
4737 		}
4738 		ret = setStmfState(fd, &stmfStateSet, STMF_SERVICE_TYPE);
4739 		if (ret != STMF_STATUS_SUCCESS) {
4740 			goto done;
4741 		}
4742 		stmfStateSet.config_state = STMF_CONFIG_INIT_DONE;
4743 		goto done;
4744 	}
4745 
4746 	/* Check to ensure service exists */
4747 	if (psCheckService() != STMF_STATUS_SUCCESS) {
4748 		return (STMF_ERROR_SERVICE_NOT_FOUND);
4749 	}
4750 
4751 	ret = stmfGetState(&state);
4752 	if (ret == STMF_STATUS_SUCCESS) {
4753 		if (state.operationalState != STMF_SERVICE_STATE_OFFLINE) {
4754 			return (STMF_ERROR_SERVICE_ONLINE);
4755 		}
4756 	} else {
4757 		return (STMF_STATUS_ERROR);
4758 	}
4759 
4760 
4761 	stmfStateSet.state = STMF_STATE_OFFLINE;
4762 	stmfStateSet.config_state = STMF_CONFIG_INIT;
4763 
4764 	/*
4765 	 * Open control node for stmf
4766 	 */
4767 	if ((ret = openStmf(OPEN_EXCL_STMF, &fd)) != STMF_STATUS_SUCCESS)
4768 		return (ret);
4769 
4770 	ret = setStmfState(fd, &stmfStateSet, STMF_SERVICE_TYPE);
4771 	if (ret != STMF_STATUS_SUCCESS) {
4772 		goto done;
4773 	}
4774 
4775 	/* Load the persistent configuration data */
4776 	ret = loadStore(fd);
4777 	if (ret != 0) {
4778 		goto done;
4779 	}
4780 
4781 	stmfStateSet.state = STMF_STATE_OFFLINE;
4782 	stmfStateSet.config_state = STMF_CONFIG_INIT_DONE;
4783 
4784 done:
4785 	if (ret == STMF_STATUS_SUCCESS) {
4786 		ret = setStmfState(fd, &stmfStateSet, STMF_SERVICE_TYPE);
4787 	}
4788 	(void) close(fd);
4789 	return (ret);
4790 }
4791 
4792 
4793 /*
4794  * getStmfState
4795  *
4796  * stmfState - pointer to stmf_state_desc_t structure. Will contain the state
4797  *             information of the stmf service on success.
4798  */
4799 static int
4800 getStmfState(stmf_state_desc_t *stmfState)
4801 {
4802 	int ret = STMF_STATUS_SUCCESS;
4803 	int fd;
4804 	int ioctlRet;
4805 	stmf_iocdata_t stmfIoctl;
4806 
4807 	/*
4808 	 * Open control node for stmf
4809 	 */
4810 	if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
4811 		return (ret);
4812 
4813 	bzero(&stmfIoctl, sizeof (stmfIoctl));
4814 	/*
4815 	 * Issue ioctl to get the stmf state
4816 	 */
4817 	stmfIoctl.stmf_version = STMF_VERSION_1;
4818 	stmfIoctl.stmf_ibuf_size = sizeof (stmf_state_desc_t);
4819 	stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)stmfState;
4820 	stmfIoctl.stmf_obuf_size = sizeof (stmf_state_desc_t);
4821 	stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)stmfState;
4822 	ioctlRet = ioctl(fd, STMF_IOCTL_GET_STMF_STATE, &stmfIoctl);
4823 
4824 	(void) close(fd);
4825 
4826 	if (ioctlRet != 0) {
4827 		switch (errno) {
4828 			case EBUSY:
4829 				ret = STMF_ERROR_BUSY;
4830 				break;
4831 			case EPERM:
4832 			case EACCES:
4833 				ret = STMF_ERROR_PERM;
4834 				break;
4835 			default:
4836 				syslog(LOG_DEBUG,
4837 				    "getStmfState:ioctl errno(%d)", errno);
4838 				ret = STMF_STATUS_ERROR;
4839 				break;
4840 		}
4841 	}
4842 	return (ret);
4843 }
4844 
4845 
4846 /*
4847  * setStmfState
4848  *
4849  * stmfState - pointer to caller set state structure
4850  * objectType - one of:
4851  *		LOGICAL_UNIT_TYPE
4852  *		TARGET_TYPE
4853  *		STMF_SERVICE_TYPE
4854  */
4855 static int
4856 setStmfState(int fd, stmf_state_desc_t *stmfState, int objectType)
4857 {
4858 	int ret = STMF_STATUS_SUCCESS;
4859 	int ioctlRet;
4860 	int cmd;
4861 	stmf_iocdata_t stmfIoctl;
4862 
4863 	switch (objectType) {
4864 		case LOGICAL_UNIT_TYPE:
4865 			cmd = STMF_IOCTL_SET_LU_STATE;
4866 			break;
4867 		case TARGET_TYPE:
4868 			cmd = STMF_IOCTL_SET_TARGET_PORT_STATE;
4869 			break;
4870 		case STMF_SERVICE_TYPE:
4871 			cmd = STMF_IOCTL_SET_STMF_STATE;
4872 			break;
4873 		default:
4874 			ret = STMF_STATUS_ERROR;
4875 			goto done;
4876 	}
4877 
4878 	bzero(&stmfIoctl, sizeof (stmfIoctl));
4879 	/*
4880 	 * Issue ioctl to set the stmf state
4881 	 */
4882 	stmfIoctl.stmf_version = STMF_VERSION_1;
4883 	stmfIoctl.stmf_ibuf_size = sizeof (stmf_state_desc_t);
4884 	stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)stmfState;
4885 	ioctlRet = ioctl(fd, cmd, &stmfIoctl);
4886 	if (ioctlRet != 0) {
4887 		switch (errno) {
4888 			case EBUSY:
4889 				ret = STMF_ERROR_BUSY;
4890 				break;
4891 			case EPERM:
4892 			case EACCES:
4893 				ret = STMF_ERROR_PERM;
4894 				break;
4895 			case ENOENT:
4896 				ret = STMF_ERROR_NOT_FOUND;
4897 				break;
4898 			default:
4899 				syslog(LOG_DEBUG,
4900 				    "setStmfState:ioctl errno(%d)", errno);
4901 				ret = STMF_STATUS_ERROR;
4902 				break;
4903 		}
4904 	}
4905 done:
4906 	return (ret);
4907 }
4908 
4909 /*
4910  * stmfOnline
4911  *
4912  * Purpose: Online stmf service
4913  *
4914  */
4915 int
4916 stmfOnline(void)
4917 {
4918 	int ret;
4919 	int fd;
4920 	stmfState state;
4921 	stmf_state_desc_t iState;
4922 
4923 	ret = stmfGetState(&state);
4924 	if (ret == STMF_STATUS_SUCCESS) {
4925 		if (state.operationalState == STMF_SERVICE_STATE_ONLINE) {
4926 			return (STMF_ERROR_SERVICE_ONLINE);
4927 		}
4928 	} else {
4929 		return (STMF_STATUS_ERROR);
4930 	}
4931 	iState.state = STMF_STATE_ONLINE;
4932 	iState.config_state = STMF_CONFIG_NONE;
4933 	/*
4934 	 * Open control node for stmf
4935 	 * to make call to setStmfState()
4936 	 */
4937 	if ((ret = openStmf(OPEN_EXCL_STMF, &fd)) != STMF_STATUS_SUCCESS)
4938 		return (ret);
4939 	ret = setStmfState(fd, &iState, STMF_SERVICE_TYPE);
4940 	(void) close(fd);
4941 	return (ret);
4942 }
4943 
4944 /*
4945  * stmfOffline
4946  *
4947  * Purpose: Offline stmf service
4948  *
4949  */
4950 int
4951 stmfOffline(void)
4952 {
4953 	int ret;
4954 	int fd;
4955 	stmfState state;
4956 	stmf_state_desc_t iState;
4957 
4958 	ret = stmfGetState(&state);
4959 	if (ret == STMF_STATUS_SUCCESS) {
4960 		if (state.operationalState == STMF_SERVICE_STATE_OFFLINE) {
4961 			return (STMF_ERROR_SERVICE_OFFLINE);
4962 		}
4963 	} else {
4964 		return (STMF_STATUS_ERROR);
4965 	}
4966 	iState.state = STMF_STATE_OFFLINE;
4967 	iState.config_state = STMF_CONFIG_NONE;
4968 
4969 	/*
4970 	 * Open control node for stmf
4971 	 * to make call to setStmfState()
4972 	 */
4973 	if ((ret = openStmf(OPEN_EXCL_STMF, &fd)) != STMF_STATUS_SUCCESS)
4974 		return (ret);
4975 	ret = setStmfState(fd, &iState, STMF_SERVICE_TYPE);
4976 	(void) close(fd);
4977 	return (ret);
4978 }
4979 
4980 
4981 /*
4982  * stmfOfflineTarget
4983  *
4984  * Purpose: Change state of target to offline
4985  *
4986  * devid - devid of the target to offline
4987  */
4988 int
4989 stmfOfflineTarget(stmfDevid *devid)
4990 {
4991 	stmf_state_desc_t targetState;
4992 	int ret = STMF_STATUS_SUCCESS;
4993 	int fd;
4994 
4995 	if (devid == NULL) {
4996 		return (STMF_ERROR_INVALID_ARG);
4997 	}
4998 	bzero(&targetState, sizeof (targetState));
4999 
5000 	targetState.state = STMF_STATE_OFFLINE;
5001 	targetState.ident[IDENT_LENGTH_BYTE] = devid->identLength;
5002 	bcopy(&(devid->ident), &targetState.ident[IDENT_LENGTH_BYTE + 1],
5003 	    devid->identLength);
5004 	/*
5005 	 * Open control node for stmf
5006 	 * to make call to setStmfState()
5007 	 */
5008 	if ((ret = openStmf(OPEN_EXCL_STMF, &fd)) != STMF_STATUS_SUCCESS)
5009 		return (ret);
5010 	ret = setStmfState(fd, &targetState, TARGET_TYPE);
5011 	(void) close(fd);
5012 	return (ret);
5013 }
5014 
5015 /*
5016  * stmfOfflineLogicalUnit
5017  *
5018  * Purpose: Change state of logical unit to offline
5019  *
5020  * lu - guid of the logical unit to offline
5021  */
5022 int
5023 stmfOfflineLogicalUnit(stmfGuid *lu)
5024 {
5025 	stmf_state_desc_t luState;
5026 	int ret = STMF_STATUS_SUCCESS;
5027 	int fd;
5028 
5029 	if (lu == NULL) {
5030 		return (STMF_ERROR_INVALID_ARG);
5031 	}
5032 
5033 	bzero(&luState, sizeof (luState));
5034 
5035 	luState.state = STMF_STATE_OFFLINE;
5036 	bcopy(lu, &luState.ident, sizeof (stmfGuid));
5037 	/*
5038 	 * Open control node for stmf
5039 	 * to make call to setStmfState()
5040 	 */
5041 	if ((ret = openStmf(OPEN_EXCL_STMF, &fd)) != STMF_STATUS_SUCCESS)
5042 		return (ret);
5043 	ret = setStmfState(fd, &luState, LOGICAL_UNIT_TYPE);
5044 	(void) close(fd);
5045 	return (ret);
5046 }
5047 
5048 /*
5049  * stmfOnlineTarget
5050  *
5051  * Purpose: Change state of target to online
5052  *
5053  * devid - devid of the target to online
5054  */
5055 int
5056 stmfOnlineTarget(stmfDevid *devid)
5057 {
5058 	stmf_state_desc_t targetState;
5059 	int ret = STMF_STATUS_SUCCESS;
5060 	int fd;
5061 
5062 	if (devid == NULL) {
5063 		return (STMF_ERROR_INVALID_ARG);
5064 	}
5065 	bzero(&targetState, sizeof (targetState));
5066 
5067 	targetState.state = STMF_STATE_ONLINE;
5068 	targetState.ident[IDENT_LENGTH_BYTE] = devid->identLength;
5069 	bcopy(&(devid->ident), &targetState.ident[IDENT_LENGTH_BYTE + 1],
5070 	    devid->identLength);
5071 	/*
5072 	 * Open control node for stmf
5073 	 * to make call to setStmfState()
5074 	 */
5075 	if ((ret = openStmf(OPEN_EXCL_STMF, &fd)) != STMF_STATUS_SUCCESS)
5076 		return (ret);
5077 	ret = setStmfState(fd, &targetState, TARGET_TYPE);
5078 	(void) close(fd);
5079 	return (ret);
5080 }
5081 
5082 /*
5083  * stmfOnlineLogicalUnit
5084  *
5085  * Purpose: Change state of logical unit to online
5086  *
5087  * lu - guid of the logical unit to online
5088  */
5089 int
5090 stmfOnlineLogicalUnit(stmfGuid *lu)
5091 {
5092 	stmf_state_desc_t luState;
5093 	int ret = STMF_STATUS_SUCCESS;
5094 	int fd;
5095 
5096 	if (lu == NULL) {
5097 		return (STMF_ERROR_INVALID_ARG);
5098 	}
5099 
5100 	bzero(&luState, sizeof (luState));
5101 
5102 	luState.state = STMF_STATE_ONLINE;
5103 	bcopy(lu, &luState.ident, sizeof (stmfGuid));
5104 	/*
5105 	 * Open control node for stmf
5106 	 * to make call to setStmfState()
5107 	 */
5108 	if ((ret = openStmf(OPEN_EXCL_STMF, &fd)) != STMF_STATUS_SUCCESS)
5109 		return (ret);
5110 	ret = setStmfState(fd, &luState, LOGICAL_UNIT_TYPE);
5111 	(void) close(fd);
5112 	return (ret);
5113 }
5114 
5115 /*
5116  * stmfRemoveFromHostGroup
5117  *
5118  * Purpose: Removes an initiator from an initiator group
5119  *
5120  * hostGroupName - name of an initiator group
5121  * hostName - name of host group member to remove
5122  */
5123 int
5124 stmfRemoveFromHostGroup(stmfGroupName *hostGroupName, stmfDevid *hostName)
5125 {
5126 	int ret;
5127 	int fd;
5128 
5129 	if (hostGroupName == NULL ||
5130 	    (strnlen((char *)hostGroupName, sizeof (stmfGroupName))
5131 	    == sizeof (stmfGroupName)) || hostName == NULL) {
5132 		return (STMF_ERROR_INVALID_ARG);
5133 	}
5134 
5135 	/* call init */
5136 	ret = initializeConfig();
5137 	if (ret != STMF_STATUS_SUCCESS) {
5138 		return (ret);
5139 	}
5140 
5141 	/*
5142 	 * Open control node for stmf
5143 	 */
5144 	if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
5145 		return (ret);
5146 
5147 	if ((ret = groupMemberIoctl(fd, STMF_IOCTL_REMOVE_HG_ENTRY,
5148 	    hostGroupName, hostName)) != STMF_STATUS_SUCCESS) {
5149 		goto done;
5150 	}
5151 
5152 	if (iGetPersistMethod() == STMF_PERSIST_NONE) {
5153 		goto done;
5154 	}
5155 
5156 	ret = psRemoveHostGroupMember((char *)hostGroupName,
5157 	    (char *)hostName->ident);
5158 	switch (ret) {
5159 		case STMF_PS_SUCCESS:
5160 			ret = STMF_STATUS_SUCCESS;
5161 			break;
5162 		case STMF_PS_ERROR_MEMBER_NOT_FOUND:
5163 			ret = STMF_ERROR_MEMBER_NOT_FOUND;
5164 			break;
5165 		case STMF_PS_ERROR_GROUP_NOT_FOUND:
5166 			ret = STMF_ERROR_GROUP_NOT_FOUND;
5167 			break;
5168 		case STMF_PS_ERROR_BUSY:
5169 			ret = STMF_ERROR_BUSY;
5170 			break;
5171 		case STMF_PS_ERROR_SERVICE_NOT_FOUND:
5172 			ret = STMF_ERROR_SERVICE_NOT_FOUND;
5173 			break;
5174 		case STMF_PS_ERROR_VERSION_MISMATCH:
5175 			ret = STMF_ERROR_SERVICE_DATA_VERSION;
5176 			break;
5177 		default:
5178 			syslog(LOG_DEBUG,
5179 			    "stmfRemoveFromHostGroup"
5180 			    "psRemoveHostGroupMember:error(%d)", ret);
5181 			ret = STMF_STATUS_ERROR;
5182 			break;
5183 	}
5184 
5185 done:
5186 	(void) close(fd);
5187 	return (ret);
5188 }
5189 
5190 /*
5191  * stmfRemoveFromTargetGroup
5192  *
5193  * Purpose: Removes a local port from a local port group
5194  *
5195  * targetGroupName - name of a target group
5196  * targetName - name of target to remove
5197  */
5198 int
5199 stmfRemoveFromTargetGroup(stmfGroupName *targetGroupName, stmfDevid *targetName)
5200 {
5201 	int ret;
5202 	int fd;
5203 
5204 	if (targetGroupName == NULL ||
5205 	    (strnlen((char *)targetGroupName, sizeof (stmfGroupName))
5206 	    == sizeof (stmfGroupName)) || targetName == NULL) {
5207 		return (STMF_ERROR_INVALID_ARG);
5208 	}
5209 
5210 	/* call init */
5211 	ret = initializeConfig();
5212 	if (ret != STMF_STATUS_SUCCESS) {
5213 		return (ret);
5214 	}
5215 
5216 	/*
5217 	 * Open control node for stmf
5218 	 */
5219 	if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
5220 		return (ret);
5221 
5222 	if ((ret = groupMemberIoctl(fd, STMF_IOCTL_REMOVE_TG_ENTRY,
5223 	    targetGroupName, targetName)) != STMF_STATUS_SUCCESS) {
5224 		goto done;
5225 	}
5226 
5227 	if (iGetPersistMethod() == STMF_PERSIST_NONE) {
5228 		goto done;
5229 	}
5230 
5231 	ret = psRemoveTargetGroupMember((char *)targetGroupName,
5232 	    (char *)targetName->ident);
5233 	switch (ret) {
5234 		case STMF_PS_SUCCESS:
5235 			ret = STMF_STATUS_SUCCESS;
5236 			break;
5237 		case STMF_PS_ERROR_MEMBER_NOT_FOUND:
5238 			ret = STMF_ERROR_MEMBER_NOT_FOUND;
5239 			break;
5240 		case STMF_PS_ERROR_GROUP_NOT_FOUND:
5241 			ret = STMF_ERROR_GROUP_NOT_FOUND;
5242 			break;
5243 		case STMF_PS_ERROR_BUSY:
5244 			ret = STMF_ERROR_BUSY;
5245 			break;
5246 		case STMF_PS_ERROR_SERVICE_NOT_FOUND:
5247 			ret = STMF_ERROR_SERVICE_NOT_FOUND;
5248 			break;
5249 		case STMF_PS_ERROR_VERSION_MISMATCH:
5250 			ret = STMF_ERROR_SERVICE_DATA_VERSION;
5251 			break;
5252 		default:
5253 			syslog(LOG_DEBUG,
5254 			    "stmfRemoveFromTargetGroup"
5255 			    "psRemoveTargetGroupMember:error(%d)", ret);
5256 			ret = STMF_STATUS_ERROR;
5257 			break;
5258 	}
5259 
5260 done:
5261 	(void) close(fd);
5262 	return (ret);
5263 }
5264 
5265 /*
5266  * stmfRemoveViewEntry
5267  *
5268  * Purpose: Removes a view entry from a logical unit
5269  *
5270  * lu - guid of lu for which view entry is being removed
5271  * viewEntryIndex - index of view entry to remove
5272  *
5273  */
5274 int
5275 stmfRemoveViewEntry(stmfGuid *lu, uint32_t viewEntryIndex)
5276 {
5277 	int ret = STMF_STATUS_SUCCESS;
5278 	int fd;
5279 	int ioctlRet;
5280 	stmf_iocdata_t stmfIoctl;
5281 	stmf_view_op_entry_t ioctlViewEntry;
5282 
5283 	if (lu == NULL) {
5284 		return (STMF_ERROR_INVALID_ARG);
5285 	}
5286 
5287 	/* call init */
5288 	ret = initializeConfig();
5289 	if (ret != STMF_STATUS_SUCCESS) {
5290 		return (ret);
5291 	}
5292 
5293 	/*
5294 	 * Open control node for stmf
5295 	 */
5296 	if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
5297 		return (ret);
5298 
5299 	bzero(&ioctlViewEntry, sizeof (ioctlViewEntry));
5300 	ioctlViewEntry.ve_ndx_valid = B_TRUE;
5301 	ioctlViewEntry.ve_ndx = viewEntryIndex;
5302 	bcopy(lu, &ioctlViewEntry.ve_guid, sizeof (stmfGuid));
5303 
5304 	bzero(&stmfIoctl, sizeof (stmfIoctl));
5305 	/*
5306 	 * Issue ioctl to add to the view entry
5307 	 */
5308 	stmfIoctl.stmf_version = STMF_VERSION_1;
5309 	stmfIoctl.stmf_ibuf_size = sizeof (ioctlViewEntry);
5310 	stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&ioctlViewEntry;
5311 	ioctlRet = ioctl(fd, STMF_IOCTL_REMOVE_VIEW_ENTRY, &stmfIoctl);
5312 	if (ioctlRet != 0) {
5313 		switch (errno) {
5314 			case EBUSY:
5315 				ret = STMF_ERROR_BUSY;
5316 				break;
5317 			case EPERM:
5318 				ret = STMF_ERROR_PERM;
5319 				break;
5320 			case EACCES:
5321 				switch (stmfIoctl.stmf_error) {
5322 					case STMF_IOCERR_UPDATE_NEED_CFG_INIT:
5323 						ret = STMF_ERROR_CONFIG_NONE;
5324 						break;
5325 					default:
5326 						ret = STMF_ERROR_PERM;
5327 						break;
5328 				}
5329 				break;
5330 			case ENODEV:
5331 			case ENOENT:
5332 				ret = STMF_ERROR_NOT_FOUND;
5333 				break;
5334 			default:
5335 				syslog(LOG_DEBUG,
5336 				    "stmfRemoveViewEntry:ioctl errno(%d)",
5337 				    errno);
5338 				ret = STMF_STATUS_ERROR;
5339 				break;
5340 		}
5341 		goto done;
5342 	}
5343 
5344 	if (iGetPersistMethod() == STMF_PERSIST_NONE) {
5345 		goto done;
5346 	}
5347 
5348 	ret = psRemoveViewEntry(lu, viewEntryIndex);
5349 	switch (ret) {
5350 		case STMF_PS_SUCCESS:
5351 			ret = STMF_STATUS_SUCCESS;
5352 			break;
5353 		case STMF_PS_ERROR_NOT_FOUND:
5354 			ret = STMF_ERROR_NOT_FOUND;
5355 			break;
5356 		case STMF_PS_ERROR_BUSY:
5357 			ret = STMF_ERROR_BUSY;
5358 			break;
5359 		case STMF_PS_ERROR_SERVICE_NOT_FOUND:
5360 			ret = STMF_ERROR_SERVICE_NOT_FOUND;
5361 			break;
5362 		case STMF_PS_ERROR_VERSION_MISMATCH:
5363 			ret = STMF_ERROR_SERVICE_DATA_VERSION;
5364 			break;
5365 		default:
5366 			syslog(LOG_DEBUG,
5367 			    "stmfRemoveViewEntry" "psRemoveViewEntry:error(%d)",
5368 			    ret);
5369 			ret = STMF_STATUS_ERROR;
5370 			break;
5371 	}
5372 
5373 done:
5374 	(void) close(fd);
5375 	return (ret);
5376 }
5377 
5378 /*
5379  * stmfSetProviderData
5380  *
5381  * Purpose: set the provider data
5382  *
5383  * providerName - unique name of provider
5384  * nvl - nvlist to set
5385  * providerType - type of provider for which to set data
5386  *		STMF_LU_PROVIDER_TYPE
5387  *		STMF_PORT_PROVIDER_TYPE
5388  */
5389 int
5390 stmfSetProviderData(char *providerName, nvlist_t *nvl, int providerType)
5391 {
5392 	return (stmfSetProviderDataProt(providerName, nvl, providerType,
5393 	    NULL));
5394 }
5395 
5396 /*
5397  * stmfSetProviderDataProt
5398  *
5399  * Purpose: set the provider data
5400  *
5401  * providerName - unique name of provider
5402  * nvl - nvlist to set
5403  * providerType - type of provider for which to set data
5404  *		STMF_LU_PROVIDER_TYPE
5405  *		STMF_PORT_PROVIDER_TYPE
5406  * setToken - Stale data token returned in the stmfGetProviderDataProt()
5407  *	      call or NULL.
5408  */
5409 int
5410 stmfSetProviderDataProt(char *providerName, nvlist_t *nvl, int providerType,
5411     uint64_t *setToken)
5412 {
5413 	int ret;
5414 	int fd;
5415 
5416 	if (providerName == NULL || nvl == NULL) {
5417 		return (STMF_ERROR_INVALID_ARG);
5418 	}
5419 
5420 	if (providerType != STMF_LU_PROVIDER_TYPE &&
5421 	    providerType != STMF_PORT_PROVIDER_TYPE) {
5422 		return (STMF_ERROR_INVALID_ARG);
5423 	}
5424 
5425 	/* call init */
5426 	ret = initializeConfig();
5427 	if (ret != STMF_STATUS_SUCCESS) {
5428 		return (ret);
5429 	}
5430 
5431 	/*
5432 	 * Open control node for stmf
5433 	 */
5434 	if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
5435 		return (ret);
5436 
5437 	ret = setProviderData(fd, providerName, nvl, providerType, setToken);
5438 
5439 	(void) close(fd);
5440 
5441 	if (ret != STMF_STATUS_SUCCESS) {
5442 		goto done;
5443 	}
5444 
5445 	if (iGetPersistMethod() == STMF_PERSIST_NONE) {
5446 		goto done;
5447 	}
5448 
5449 	/* setting driver provider data successful. Now persist it */
5450 	ret = psSetProviderData(providerName, nvl, providerType, NULL);
5451 	switch (ret) {
5452 		case STMF_PS_SUCCESS:
5453 			ret = STMF_STATUS_SUCCESS;
5454 			break;
5455 		case STMF_PS_ERROR_EXISTS:
5456 			ret = STMF_ERROR_EXISTS;
5457 			break;
5458 		case STMF_PS_ERROR_BUSY:
5459 			ret = STMF_ERROR_BUSY;
5460 			break;
5461 		case STMF_PS_ERROR_SERVICE_NOT_FOUND:
5462 			ret = STMF_ERROR_SERVICE_NOT_FOUND;
5463 			break;
5464 		case STMF_PS_ERROR_VERSION_MISMATCH:
5465 			ret = STMF_ERROR_SERVICE_DATA_VERSION;
5466 			break;
5467 		case STMF_PS_ERROR_PROV_DATA_STALE:
5468 			ret = STMF_ERROR_PROV_DATA_STALE;
5469 			break;
5470 		default:
5471 			syslog(LOG_DEBUG,
5472 			    "stmfSetProviderData"
5473 			    "psSetProviderData:error(%d)", ret);
5474 			ret = STMF_STATUS_ERROR;
5475 			break;
5476 	}
5477 
5478 done:
5479 	return (ret);
5480 }
5481 
5482 /*
5483  * getProviderData
5484  *
5485  * Purpose: set the provider data from stmf
5486  *
5487  * providerName - unique name of provider
5488  * nvl - nvlist to load/retrieve
5489  * providerType - logical unit or port provider
5490  * setToken - returned stale data token
5491  */
5492 int
5493 getProviderData(char *providerName, nvlist_t **nvl, int providerType,
5494     uint64_t *setToken)
5495 {
5496 	int ret = STMF_STATUS_SUCCESS;
5497 	int fd;
5498 	int ioctlRet;
5499 	size_t nvlistSize = ALLOC_PP_DATA_SIZE;
5500 	int retryCnt = 0;
5501 	int retryCntMax = MAX_PROVIDER_RETRY;
5502 	stmf_ppioctl_data_t ppi = {0}, *ppi_out = NULL;
5503 	boolean_t retry = B_TRUE;
5504 	stmf_iocdata_t stmfIoctl;
5505 
5506 	if (providerName == NULL) {
5507 		return (STMF_ERROR_INVALID_ARG);
5508 	}
5509 
5510 	/*
5511 	 * Open control node for stmf
5512 	 */
5513 	if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
5514 		return (ret);
5515 
5516 	/* set provider name and provider type */
5517 	if (strlcpy(ppi.ppi_name, providerName,
5518 	    sizeof (ppi.ppi_name)) >=
5519 	    sizeof (ppi.ppi_name)) {
5520 		ret = STMF_ERROR_INVALID_ARG;
5521 		goto done;
5522 	}
5523 	switch (providerType) {
5524 		case STMF_LU_PROVIDER_TYPE:
5525 			ppi.ppi_lu_provider = 1;
5526 			break;
5527 		case STMF_PORT_PROVIDER_TYPE:
5528 			ppi.ppi_port_provider = 1;
5529 			break;
5530 		default:
5531 			ret = STMF_ERROR_INVALID_ARG;
5532 			goto done;
5533 	}
5534 
5535 	do {
5536 		/* allocate memory for ioctl */
5537 		ppi_out = (stmf_ppioctl_data_t *)calloc(1, nvlistSize +
5538 		    sizeof (stmf_ppioctl_data_t));
5539 		if (ppi_out == NULL) {
5540 			ret = STMF_ERROR_NOMEM;
5541 			goto done;
5542 
5543 		}
5544 
5545 		/* set the size of the ioctl data to allocated buffer */
5546 		ppi.ppi_data_size = nvlistSize;
5547 
5548 		bzero(&stmfIoctl, sizeof (stmfIoctl));
5549 
5550 		stmfIoctl.stmf_version = STMF_VERSION_1;
5551 		stmfIoctl.stmf_ibuf_size = sizeof (stmf_ppioctl_data_t);
5552 		stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&ppi;
5553 		stmfIoctl.stmf_obuf_size = sizeof (stmf_ppioctl_data_t) +
5554 		    nvlistSize;
5555 		stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)ppi_out;
5556 		ioctlRet = ioctl(fd, STMF_IOCTL_GET_PP_DATA, &stmfIoctl);
5557 		if (ioctlRet != 0) {
5558 			switch (errno) {
5559 				case EBUSY:
5560 					ret = STMF_ERROR_BUSY;
5561 					break;
5562 				case EPERM:
5563 				case EACCES:
5564 					ret = STMF_ERROR_PERM;
5565 					break;
5566 				case EINVAL:
5567 					if (stmfIoctl.stmf_error ==
5568 					    STMF_IOCERR_INSUFFICIENT_BUF) {
5569 						nvlistSize =
5570 						    ppi_out->ppi_data_size;
5571 						free(ppi_out);
5572 						ppi_out = NULL;
5573 						if (retryCnt++ > retryCntMax) {
5574 							retry = B_FALSE;
5575 							ret = STMF_ERROR_BUSY;
5576 						} else {
5577 							ret =
5578 							    STMF_STATUS_SUCCESS;
5579 						}
5580 					} else {
5581 						syslog(LOG_DEBUG,
5582 						    "getProviderData:ioctl"
5583 						    "unable to retrieve "
5584 						    "nvlist");
5585 						ret = STMF_STATUS_ERROR;
5586 					}
5587 					break;
5588 				case ENOENT:
5589 					ret = STMF_ERROR_NOT_FOUND;
5590 					break;
5591 				default:
5592 					syslog(LOG_DEBUG,
5593 					    "getProviderData:ioctl errno(%d)",
5594 					    errno);
5595 					ret = STMF_STATUS_ERROR;
5596 					break;
5597 			}
5598 			if (ret != STMF_STATUS_SUCCESS)
5599 				goto done;
5600 		}
5601 	} while (retry && stmfIoctl.stmf_error == STMF_IOCERR_INSUFFICIENT_BUF);
5602 
5603 	if ((ret = nvlist_unpack((char *)ppi_out->ppi_data,
5604 	    ppi_out->ppi_data_size, nvl, 0)) != 0) {
5605 		ret = STMF_STATUS_ERROR;
5606 		goto done;
5607 	}
5608 
5609 	/* caller has asked for new token */
5610 	if (setToken) {
5611 		*setToken = ppi_out->ppi_token;
5612 	}
5613 done:
5614 	free(ppi_out);
5615 	(void) close(fd);
5616 	return (ret);
5617 }
5618 
5619 /*
5620  * setProviderData
5621  *
5622  * Purpose: set the provider data in stmf
5623  *
5624  * providerName - unique name of provider
5625  * nvl - nvlist to set
5626  * providerType - logical unit or port provider
5627  * setToken - stale data token to check if not NULL
5628  */
5629 static int
5630 setProviderData(int fd, char *providerName, nvlist_t *nvl, int providerType,
5631     uint64_t *setToken)
5632 {
5633 	int ret = STMF_STATUS_SUCCESS;
5634 	int ioctlRet;
5635 	size_t nvlistEncodedSize;
5636 	stmf_ppioctl_data_t *ppi = NULL;
5637 	uint64_t outToken;
5638 	char *allocatedNvBuffer;
5639 	stmf_iocdata_t stmfIoctl;
5640 
5641 	if (providerName == NULL) {
5642 		return (STMF_ERROR_INVALID_ARG);
5643 	}
5644 
5645 	/* get size of encoded nvlist */
5646 	if (nvlist_size(nvl, &nvlistEncodedSize, NV_ENCODE_XDR) != 0) {
5647 		return (STMF_STATUS_ERROR);
5648 	}
5649 
5650 	/* allocate memory for ioctl */
5651 	ppi = (stmf_ppioctl_data_t *)calloc(1, nvlistEncodedSize +
5652 	    sizeof (stmf_ppioctl_data_t));
5653 	if (ppi == NULL) {
5654 		return (STMF_ERROR_NOMEM);
5655 	}
5656 
5657 	if (setToken) {
5658 		ppi->ppi_token_valid = 1;
5659 		ppi->ppi_token = *setToken;
5660 	}
5661 
5662 	allocatedNvBuffer = (char *)&ppi->ppi_data;
5663 	if (nvlist_pack(nvl, &allocatedNvBuffer, &nvlistEncodedSize,
5664 	    NV_ENCODE_XDR, 0) != 0) {
5665 		return (STMF_STATUS_ERROR);
5666 	}
5667 
5668 	/* set provider name and provider type */
5669 	(void) strncpy(ppi->ppi_name, providerName, sizeof (ppi->ppi_name));
5670 	switch (providerType) {
5671 		case STMF_LU_PROVIDER_TYPE:
5672 			ppi->ppi_lu_provider = 1;
5673 			break;
5674 		case STMF_PORT_PROVIDER_TYPE:
5675 			ppi->ppi_port_provider = 1;
5676 			break;
5677 		default:
5678 			return (STMF_ERROR_INVALID_ARG);
5679 	}
5680 
5681 	/* set the size of the ioctl data to packed data size */
5682 	ppi->ppi_data_size = nvlistEncodedSize;
5683 
5684 	bzero(&stmfIoctl, sizeof (stmfIoctl));
5685 
5686 	stmfIoctl.stmf_version = STMF_VERSION_1;
5687 	/*
5688 	 * Subtracting 8 from the size as that is the size of the last member
5689 	 * of the structure where the packed data resides
5690 	 */
5691 	stmfIoctl.stmf_ibuf_size = nvlistEncodedSize +
5692 	    sizeof (stmf_ppioctl_data_t) - 8;
5693 	stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)ppi;
5694 	stmfIoctl.stmf_obuf_size = sizeof (uint64_t);
5695 	stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)&outToken;
5696 	ioctlRet = ioctl(fd, STMF_IOCTL_LOAD_PP_DATA, &stmfIoctl);
5697 	if (ioctlRet != 0) {
5698 		switch (errno) {
5699 			case EBUSY:
5700 				ret = STMF_ERROR_BUSY;
5701 				break;
5702 			case EPERM:
5703 			case EACCES:
5704 				ret = STMF_ERROR_PERM;
5705 				break;
5706 			case EINVAL:
5707 				if (stmfIoctl.stmf_error ==
5708 				    STMF_IOCERR_PPD_UPDATED) {
5709 					ret = STMF_ERROR_PROV_DATA_STALE;
5710 				} else {
5711 					ret = STMF_STATUS_ERROR;
5712 				}
5713 				break;
5714 			default:
5715 				syslog(LOG_DEBUG,
5716 				    "setProviderData:ioctl errno(%d)", errno);
5717 				ret = STMF_STATUS_ERROR;
5718 				break;
5719 		}
5720 		if (ret != STMF_STATUS_SUCCESS)
5721 			goto done;
5722 	}
5723 
5724 	/* caller has asked for new token */
5725 	if (setToken) {
5726 		*setToken = outToken;
5727 	}
5728 done:
5729 	free(ppi);
5730 	return (ret);
5731 }
5732 
5733 /*
5734  * set the persistence method in the library only or library and service
5735  */
5736 int
5737 stmfSetPersistMethod(uint8_t persistType, boolean_t serviceSet)
5738 {
5739 	int ret = STMF_STATUS_SUCCESS;
5740 	int oldPersist;
5741 
5742 	(void) pthread_mutex_lock(&persistenceTypeLock);
5743 	oldPersist = iPersistType;
5744 	if (persistType == STMF_PERSIST_NONE ||
5745 	    persistType == STMF_PERSIST_SMF) {
5746 		iLibSetPersist = B_TRUE;
5747 		iPersistType = persistType;
5748 	} else {
5749 		(void) pthread_mutex_unlock(&persistenceTypeLock);
5750 		return (STMF_ERROR_INVALID_ARG);
5751 	}
5752 	/* Is this for this library open or in SMF */
5753 	if (serviceSet == B_TRUE) {
5754 		ret = psSetServicePersist(persistType);
5755 		if (ret != STMF_PS_SUCCESS) {
5756 			ret = STMF_ERROR_PERSIST_TYPE;
5757 			/* Set to old value */
5758 			iPersistType = oldPersist;
5759 		}
5760 	}
5761 	(void) pthread_mutex_unlock(&persistenceTypeLock);
5762 
5763 	return (ret);
5764 }
5765 
5766 /*
5767  * Only returns internal state for persist. If unset, goes to ps. If that
5768  * fails, returns default setting
5769  */
5770 static uint8_t
5771 iGetPersistMethod()
5772 {
5773 
5774 	uint8_t persistType = 0;
5775 
5776 	(void) pthread_mutex_lock(&persistenceTypeLock);
5777 	if (iLibSetPersist) {
5778 		persistType = iPersistType;
5779 	} else {
5780 		int ret;
5781 		ret = psGetServicePersist(&persistType);
5782 		if (ret != STMF_PS_SUCCESS) {
5783 			/* set to default */
5784 			persistType = STMF_DEFAULT_PERSIST;
5785 		}
5786 	}
5787 	(void) pthread_mutex_unlock(&persistenceTypeLock);
5788 	return (persistType);
5789 }
5790 
5791 /*
5792  * Returns either library state or persistent config state depending on
5793  * serviceState
5794  */
5795 int
5796 stmfGetPersistMethod(uint8_t *persistType, boolean_t serviceState)
5797 {
5798 	int ret = STMF_STATUS_SUCCESS;
5799 
5800 	if (persistType == NULL) {
5801 		return (STMF_ERROR_INVALID_ARG);
5802 	}
5803 	if (serviceState) {
5804 		ret = psGetServicePersist(persistType);
5805 		if (ret != STMF_PS_SUCCESS) {
5806 			ret = STMF_ERROR_PERSIST_TYPE;
5807 		}
5808 	} else {
5809 		(void) pthread_mutex_lock(&persistenceTypeLock);
5810 		if (iLibSetPersist) {
5811 			*persistType = iPersistType;
5812 		} else {
5813 			*persistType = STMF_DEFAULT_PERSIST;
5814 		}
5815 		(void) pthread_mutex_unlock(&persistenceTypeLock);
5816 	}
5817 
5818 	return (ret);
5819 }
5820