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