xref: /illumos-gate/usr/src/lib/libstmf/common/store.c (revision 66582b606a8194f7f3ba5b3a3a6dca5b0d346361)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
23  * Copyright 2012 Milan Jurik. All rights reserved.
24  */
25 
26 #include <libscf.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <errno.h>
30 #include <assert.h>
31 #include <strings.h>
32 #include <libstmf.h>
33 #include <store.h>
34 #include <syslog.h>
35 #include <signal.h>
36 #include <pthread.h>
37 #include <libnvpair.h>
38 #include <limits.h>
39 #include <unistd.h>
40 
41 /*
42  * This file's functions are responsible for all store and retrieve operations
43  * against the STMF smf(5) database. The following shows the currently defined
44  * schema for the STMF database:
45  *
46  * Description of property groups for service: svc:/system/stmf
47  *
48  * Stability: Volatile
49  *
50  * 1. Property Group: host_groups
51  *        Properties: group_name-<N> where <N> is an unsigned integer
52  *                        type: ustring
53  *                        contains: group name
54  *                    group_name-<N>-member_list where <N> is an unsigned
55  *                            integer matching a group_name-<N> property.
56  *                        type: ustring
57  *                        contains: list of members
58  *
59  *        Description:
60  *             Contains the host group names as well as the host group members
61  *             for each host group.
62  *
63  * 2. Property Group: target_groups
64  *        Properties: group_name-<N> where <N> is an unsigned integer
65  *                        type: ustring
66  *                        contains: group name
67  *                    group_name-<N>-member_list where <N> is an unsigned
68  *                            integer matching a group_name-<N> property.
69  *                        type: ustring
70  *                        contains: list of members
71  *
72  *        Description:
73  *             Contains the target group names as well as the target group
74  *             members for each target group.
75  *
76  * 3. Property Group: lu-<GUID>
77  *                        where <GUID> is a 32 character hexadecimal string.
78  *        Properties: ve_cnt
79  *                        type: count
80  *                        contains: the number of current view entries
81  *                    view-entry-<N>-<GUID> where <N> is an unsigned integer
82  *                        type: ustring
83  *                        contains: nothing. Used as reference to the view
84  *                                  entry property group
85  *
86  *        Description:
87  *             Contains the references to each view entry. One lu-<GUID>
88  *             property group will exist for each logical unit with 1 or more
89  *             view entries.
90  *             Potentially can hold any other data that can be managed on a per
91  *             logical unit basis.
92  *
93  * 4. Property Group: view_entry-<N>-<GUID> (matches property in lu-<GUID>
94  *                    property group)
95  *        Properties: all_hosts
96  *                        type: boolean
97  *                        contains: when true, the value of host_group is
98  *                                  ignored
99  *                    all_targets
100  *                        type: boolean
101  *                        contains: when true, the value of target_group is
102  *                                  ignored
103  *                    host_group
104  *                        type: ustring
105  *                        contains: host group for logical unit mapping and
106  *                                  masking purposes
107  *                    target_group
108  *                        type: ustring
109  *                        contains: target group for logical unit mapping and
110  *                                  masking purposes
111  *                    lu_nbr
112  *                        type: opaque
113  *                        contains: the 8-byte SCSI logical unit number for
114  *                                  mapping and masking purposes
115  *        Description:
116  *             One "view_entry-<N>-<GUID>" property group will exist for each
117  *             view entry in the system. This property group name maps
118  *             directly to the "lu-<GUID>" property group with a matching
119  *             <GUID>.
120  *
121  * 5. Property Group: provider_data_pg_<provider-name>
122  *                        where <provider-name> is the name of the provider
123  *                           registered with stmf.
124  *        Properties: provider_data_prop-<N>
125  *                        where <N> is a sequential identifier for the data
126  *                           chunk.
127  *                        type: opaque
128  *                        contains: up to STMF_PROVIDER_DATA_PROP_SIZE bytes
129  *                                  of nvlist packed data.
130  *                    provider_data_count
131  *                        type: count
132  *                        contains: the number of provider data chunks
133  *                    provider_data_type
134  *                        type: integer
135  *                        contains: STMF_PORT_PROVIDER_TYPE or
136  *                                  STMF_LU_PROVIDER_TYPE
137  *
138  *        Description:
139  *             Holds the nvlist packed provider data set via
140  *             stmfSetProviderData and retrieved via stmfGetProviderData. Data
141  *             is stored in STMF_PROVIDER_DATA_PROP_SIZE chunks. On retrieve,
142  *             these chunks are reassembled and unpacked.
143  *
144  */
145 
146 static int iPsInit(scf_handle_t **, scf_service_t **);
147 static int iPsCreateDeleteGroup(char *, char *, int);
148 static int iPsAddRemoveGroupMember(char *, char *, char *, int);
149 static int iPsGetGroupList(char *, stmfGroupList **);
150 static int iPsGetGroupMemberList(char *, char *, stmfGroupProperties **);
151 static int iPsAddViewEntry(char *, char *, stmfViewEntry *);
152 static int iPsAddRemoveLuViewEntry(char *, char *, int);
153 static int iPsGetViewEntry(char *, stmfViewEntry *);
154 static int iPsGetActualGroupName(char *, char *, char *);
155 static int iPsGetServiceVersion(uint64_t *, scf_handle_t *, scf_service_t *);
156 static int iPsGetSetPersistType(uint8_t *, scf_handle_t *, scf_service_t *,
157     int);
158 static int iPsGetSetStmfProp(int, char *, int);
159 static int viewEntryCompare(const void *, const void *);
160 static int holdSignal(sigset_t *);
161 static int releaseSignal(sigset_t *);
162 static void sigHandler();
163 
164 static pthread_mutex_t sigSetLock = PTHREAD_MUTEX_INITIALIZER;
165 
166 sigset_t sigSet;
167 sigset_t signalsCaught;
168 
169 struct sigaction currentActionQuit;
170 struct sigaction currentActionTerm;
171 struct sigaction currentActionInt;
172 
173 boolean_t actionSet = B_FALSE;
174 
175 /*
176  * Version info for the SMF schema
177  */
178 #define	STMF_SMF_VERSION    1
179 
180 /*
181  * Note: Do not change these property names and size values.
182  * They represent fields in the persistent config and once modified
183  * will have a nasty side effect of invalidating the existing store.
184  * If you do need to change them, you'll need to use the versioning above
185  * to retain backward compatiblity with the previous configuration schema.
186  */
187 
188 /* BEGIN STORE PROPERTY DEFINITIONS */
189 /*
190  * Property Group Names and prefixes
191  */
192 #define	STMF_HOST_GROUPS	"host_groups"
193 #define	STMF_TARGET_GROUPS	"target_groups"
194 #define	STMF_VE_PREFIX		"view_entry"
195 #define	STMF_LU_PREFIX		"lu"
196 #define	STMF_DATA_GROUP		"stmf_data"
197 
198 /*
199  * Property names and prefix for logical unit property group
200  */
201 #define	STMF_VE_CNT		"ve_cnt"
202 #define	STMF_GROUP_PREFIX	"group_name"
203 #define	STMF_MEMBER_LIST_SUFFIX	"member_list"
204 #define	STMF_VERSION_NAME	"version_name"
205 #define	STMF_PERSIST_TYPE	"persist_method"
206 
207 /* Property names for stmf properties */
208 
209 #define	DEFAULT_LU_STATE		"default_lu_state"
210 #define	DEFAULT_TARGET_PORT_STATE	"default_target_state"
211 
212 /*
213  * Property names for view entry
214  */
215 #define	STMF_VE_ALLHOSTS	    "all_hosts"
216 #define	STMF_VE_HOSTGROUP	    "host_group"
217 #define	STMF_VE_ALLTARGETS	    "all_targets"
218 #define	STMF_VE_TARGETGROUP	    "target_group"
219 #define	STMF_VE_LUNBR		    "lu_nbr"
220 
221 /* Property group suffix for provider data */
222 #define	STMF_PROVIDER_DATA_PREFIX "provider_data_pg_"
223 #define	STMF_PROVIDER_DATA_PROP_PREFIX "provider_data_prop"
224 #define	STMF_PROVIDER_DATA_PROP_NAME_SIZE 256
225 #define	STMF_PROVIDER_DATA_PROP_TYPE "provider_type"
226 #define	STMF_PROVIDER_DATA_PROP_SET_COUNT "provider_data_set_cnt"
227 #define	STMF_PROVIDER_DATA_PROP_COUNT "provider_data_cnt"
228 
229 
230 #define	STMF_SMF_READ_ATTR	"solaris.smf.read.stmf"
231 
232 #define	STMF_PS_PERSIST_NONE	"none"
233 #define	STMF_PS_PERSIST_SMF	"smf"
234 #define	STMF_PROVIDER_DATA_PROP_SIZE 4000
235 
236 #define	STMF_PS_LU_ONLINE		"default_lu_online"
237 #define	STMF_PS_LU_OFFLINE		"default_lu_offline"
238 #define	STMF_PS_TARGET_PORT_ONLINE	"default_target_online"
239 #define	STMF_PS_TARGET_PORT_OFFLINE	"default_target_offline"
240 
241 /* END STORE PROPERTY DEFINITIONS */
242 
243 /* service name */
244 #define	STMF_SERVICE	"system/stmf"
245 
246 /* limits and flag values */
247 #define	GROUP_MEMBER_ALLOC 100
248 #define	VIEW_ENTRY_STRUCT_CNT 6
249 #define	VIEW_ENTRY_PG_SIZE 256
250 #define	LOGICAL_UNIT_PG_SIZE 256
251 #define	VIEW_ENTRY_MAX UINT32_MAX
252 #define	GROUP_MAX UINT64_MAX
253 #define	ADD 0
254 #define	REMOVE 1
255 #define	GET 0
256 #define	SET 1
257 
258 /*
259  * sigHandler
260  *
261  * Catch the signal and set the global signalsCaught to the signal received
262  *
263  * signalsCaught will be used by releaseSignal to raise this signal when
264  * we're done processing our critical code.
265  *
266  */
267 static void
268 sigHandler(int sig)
269 {
270 	(void) sigaddset(&signalsCaught, sig);
271 }
272 
273 /*
274  * iPsAddRemoveGroupMember
275  *
276  * Add or remove a member for a given group
277  *
278  * pgName - Property group name
279  * groupName - group name to which the member is added/removed
280  * memberName - member to be added/removed
281  * addRemoveFlag - ADD/REMOVE
282  *
283  * returns:
284  *  STMF_PS_SUCCESS on success
285  *  STMF_PS_ERROR_* on failure
286  */
287 static int
288 iPsAddRemoveGroupMember(char *pgName, char *groupName, char *memberName,
289     int addRemoveFlag)
290 {
291 	scf_handle_t *handle = NULL;
292 	scf_service_t *svc = NULL;
293 	scf_propertygroup_t *pg = NULL;
294 	scf_property_t *prop = NULL;
295 	scf_value_t *valueLookup = NULL;
296 	scf_value_t **valueSet = NULL;
297 	scf_iter_t *valueIter = NULL;
298 	scf_transaction_t *tran = NULL;
299 	scf_transaction_entry_t *entry = NULL;
300 	int i = 0;
301 	int lastAlloc;
302 	int valueArraySize = 0;
303 	int ret = STMF_PS_SUCCESS;
304 	char buf[STMF_IDENT_LENGTH];
305 	int commitRet;
306 	boolean_t found = B_FALSE;
307 
308 	assert(pgName != NULL && groupName != NULL && memberName != NULL);
309 
310 	/*
311 	 * Init the service handle
312 	 */
313 	ret = iPsInit(&handle, &svc);
314 	if (ret != STMF_PS_SUCCESS) {
315 		goto out;
316 	}
317 
318 	/*
319 	 * Allocate scf resources
320 	 */
321 	if (((pg = scf_pg_create(handle)) == NULL) ||
322 	    ((tran = scf_transaction_create(handle)) == NULL) ||
323 	    ((entry = scf_entry_create(handle)) == NULL) ||
324 	    ((prop = scf_property_create(handle)) == NULL) ||
325 	    ((valueIter = scf_iter_create(handle)) == NULL)) {
326 		syslog(LOG_ERR, "scf alloc resource failed - %s",
327 		    scf_strerror(scf_error()));
328 		ret = STMF_PS_ERROR;
329 		goto out;
330 	}
331 
332 	/*
333 	 * Get the service property group handle
334 	 */
335 	if (scf_service_get_pg(svc, pgName, pg) == -1) {
336 		if (scf_error() == SCF_ERROR_NOT_FOUND) {
337 			ret = STMF_PS_ERROR_NOT_FOUND;
338 		} else {
339 			ret = STMF_PS_ERROR;
340 		}
341 		syslog(LOG_ERR, "get pg %s failed - %s",
342 		    pgName, scf_strerror(scf_error()));
343 
344 		goto out;
345 	}
346 
347 	/*
348 	 * Begin the transaction
349 	 */
350 	if (scf_transaction_start(tran, pg) == -1) {
351 		syslog(LOG_ERR, "start transaction for %s failed - %s",
352 		    pgName, scf_strerror(scf_error()));
353 		ret = STMF_PS_ERROR;
354 		goto out;
355 	}
356 
357 	/*
358 	 * We're changing an existing property by adding a propval
359 	 * There are no add semantics in libscf for a property value. We'll
360 	 * need to read in the current properties and apply them all to the
361 	 * set and then add the one we were asked to add or omit the one
362 	 * we were asked to remove.
363 	 */
364 	if (scf_transaction_property_change(tran, entry, groupName,
365 	    SCF_TYPE_USTRING) == -1) {
366 		if (scf_error() == SCF_ERROR_NOT_FOUND) {
367 			ret = STMF_PS_ERROR_GROUP_NOT_FOUND;
368 		} else {
369 			ret = STMF_PS_ERROR;
370 			syslog(LOG_ERR, "tran property change %s/%s "
371 			    "failed - %s", pgName, groupName,
372 			    scf_strerror(scf_error()));
373 		}
374 		goto out;
375 	}
376 
377 	/*
378 	 * Get the property handle
379 	 */
380 	if (scf_pg_get_property(pg, groupName, prop) == -1) {
381 		syslog(LOG_ERR, "get property %s/%s failed - %s",
382 		    pgName, groupName, scf_strerror(scf_error()));
383 		ret = STMF_PS_ERROR;
384 		goto out;
385 	}
386 
387 	/*
388 	 * Value lookup is used to lookup the existing values
389 	 */
390 	valueLookup = scf_value_create(handle);
391 	if (valueLookup == NULL) {
392 		syslog(LOG_ERR, "scf value alloc for %s failed - %s",
393 		    pgName, scf_strerror(scf_error()));
394 		ret = STMF_PS_ERROR;
395 		goto out;
396 	}
397 
398 	/*
399 	 * valueIter is the iterator handle, create the resource
400 	 */
401 	if (scf_iter_property_values(valueIter, prop) == -1) {
402 		syslog(LOG_ERR, "iter values for %s/%s failed - %s",
403 		    pgName, groupName, scf_strerror(scf_error()));
404 		ret = STMF_PS_ERROR;
405 		goto out;
406 	}
407 
408 	/*
409 	 * Allocate value resource pointers.
410 	 * We need a value resource for each value as value pointers passed
411 	 * to libscf cannot be destroyed until the commit or destroy on the
412 	 * transaction is done.
413 	 *
414 	 * We're using GROUP_MEMBER_ALLOC initially. If it's not large
415 	 * enough, we'll realloc on the fly
416 	 */
417 	valueSet = (scf_value_t **)calloc(1, sizeof (*valueSet)
418 	    * (lastAlloc = GROUP_MEMBER_ALLOC));
419 	if (valueSet == NULL) {
420 		ret = STMF_PS_ERROR_NOMEM;
421 		goto out;
422 	}
423 
424 	/*
425 	 * Iterate through the existing values
426 	 */
427 	while (scf_iter_next_value(valueIter, valueLookup) == 1) {
428 		bzero(buf, sizeof (buf));
429 		if (scf_value_get_ustring(valueLookup, buf, MAXNAMELEN) == -1) {
430 			syslog(LOG_ERR, "iter %s/%s value failed - %s",
431 			    pgName, groupName, scf_strerror(scf_error()));
432 			ret = STMF_PS_ERROR;
433 			break;
434 		}
435 
436 		/*
437 		 * Check for existing
438 		 * If we're adding, it's an error
439 		 * If we're removing, we skip it and simply not
440 		 * add it to the set. Subtraction by omission.
441 		 */
442 		if ((strlen(buf) == strlen(memberName)) &&
443 		    bcmp(buf, memberName, strlen(buf)) == 0) {
444 			if (addRemoveFlag == ADD) {
445 				ret = STMF_PS_ERROR_EXISTS;
446 				break;
447 			} else {
448 				found = B_TRUE;
449 				continue;
450 			}
451 		}
452 
453 		/*
454 		 * Create the value resource for this iteration
455 		 */
456 		valueSet[i] = scf_value_create(handle);
457 		if (valueSet[i] == NULL) {
458 			syslog(LOG_ERR, "scf value alloc for %s failed - %s",
459 			    pgName, scf_strerror(scf_error()));
460 			ret = STMF_PS_ERROR;
461 			break;
462 		}
463 
464 		/*
465 		 * Set the value
466 		 */
467 		if (scf_value_set_ustring(valueSet[i], buf) == -1) {
468 			syslog(LOG_ERR, "set value for %s/%s failed - %s",
469 			    pgName, groupName, scf_strerror(scf_error()));
470 			ret = STMF_PS_ERROR;
471 			break;
472 		}
473 
474 		/*
475 		 * Now add the value
476 		 */
477 		if (scf_entry_add_value(entry, valueSet[i]) == -1) {
478 			syslog(LOG_ERR, "add value for %s/%s failed - %s",
479 			    pgName, groupName, scf_strerror(scf_error()));
480 			ret = STMF_PS_ERROR;
481 			break;
482 		}
483 
484 		i++;
485 
486 		/*
487 		 * realloc if we've hit the previous alloc size
488 		 */
489 		if (i >= lastAlloc) {
490 			lastAlloc += GROUP_MEMBER_ALLOC;
491 			valueSet = realloc(valueSet,
492 			    sizeof (*valueSet) * lastAlloc);
493 			if (valueSet == NULL) {
494 				ret = STMF_PS_ERROR;
495 				break;
496 			}
497 		}
498 	}
499 
500 	/*
501 	 * set valueArraySize to final allocated length
502 	 * so we can use it to destroy the resources correctly
503 	 */
504 	valueArraySize = i;
505 
506 	if (!found && (addRemoveFlag == REMOVE)) {
507 		ret = STMF_PS_ERROR_MEMBER_NOT_FOUND;
508 	}
509 
510 	if (ret != STMF_PS_SUCCESS) {
511 		goto out;
512 	}
513 
514 	/*
515 	 * If we're adding, we have one more step. Add the member to the
516 	 * propval list
517 	 */
518 	if (addRemoveFlag == ADD) {
519 		/*
520 		 * Now create the new entry
521 		 */
522 		valueSet[i] = scf_value_create(handle);
523 		if (valueSet[i] == NULL) {
524 			syslog(LOG_ERR, "scf value alloc for %s/%s failed - %s",
525 			    pgName, groupName, scf_strerror(scf_error()));
526 			ret = STMF_PS_ERROR;
527 			goto out;
528 		} else {
529 			valueArraySize++;
530 		}
531 
532 		/*
533 		 * Set the new member name
534 		 */
535 		if (scf_value_set_ustring(valueSet[i], memberName) == -1) {
536 			syslog(LOG_ERR, "set value for %s/%s failed - %s",
537 			    pgName, groupName, scf_strerror(scf_error()));
538 			ret = STMF_PS_ERROR;
539 			goto out;
540 		}
541 
542 		/*
543 		 * Add the new member
544 		 */
545 		if (scf_entry_add_value(entry, valueSet[i]) == -1) {
546 			syslog(LOG_ERR, "add value for %s/%s failed - %s",
547 			    pgName, groupName, scf_strerror(scf_error()));
548 			ret = STMF_PS_ERROR;
549 			goto out;
550 		}
551 	}
552 
553 	/*
554 	 * Yes, we're finally done. We actually added or removed one entry
555 	 * from the list.
556 	 * Woohoo!
557 	 */
558 	if ((commitRet = scf_transaction_commit(tran)) != 1) {
559 		syslog(LOG_ERR, "transaction commit for %s failed - %s",
560 		    pgName, scf_strerror(scf_error()));
561 		if (commitRet == 0) {
562 			ret = STMF_PS_ERROR_BUSY;
563 		} else {
564 			ret = STMF_PS_ERROR;
565 		}
566 		goto out;
567 	}
568 
569 out:
570 	/*
571 	 * Free resources
572 	 */
573 	if (handle != NULL) {
574 		scf_handle_destroy(handle);
575 	}
576 	if (svc != NULL) {
577 		scf_service_destroy(svc);
578 	}
579 	if (pg != NULL) {
580 		scf_pg_destroy(pg);
581 	}
582 	if (tran != NULL) {
583 		scf_transaction_destroy(tran);
584 	}
585 	if (entry != NULL) {
586 		scf_entry_destroy(entry);
587 	}
588 	if (prop != NULL) {
589 		scf_property_destroy(prop);
590 	}
591 	if (valueLookup != NULL) {
592 		scf_value_destroy(valueLookup);
593 	}
594 	if (valueIter != NULL) {
595 		scf_iter_destroy(valueIter);
596 	}
597 
598 	/*
599 	 * Free valueSet scf resources
600 	 */
601 	if (valueArraySize > 0) {
602 		for (i = 0; i < valueArraySize; i++) {
603 			scf_value_destroy(valueSet[i]);
604 		}
605 	}
606 	/*
607 	 * Now free the pointer array to the resources
608 	 */
609 	if (valueSet != NULL) {
610 		free(valueSet);
611 	}
612 
613 	return (ret);
614 }
615 
616 /*
617  * iPsAddRemoveLuViewEntry
618  *
619  * Adds or removes a view entry name property for a given logical unit
620  * property group. There is one logical unit property group for every logical
621  * unit that has one or more associated view entries.
622  *
623  * luPgName - Property group name of logical unit
624  * viewEntryPgName - Property group name of view entry
625  * addRemoveFlag - ADD_VE/REMOVE_VE
626  *
627  * returns:
628  *  STMF_PS_SUCCESS on success
629  *  STMF_PS_ERROR_* on failure
630  */
631 static int
632 iPsAddRemoveLuViewEntry(char *luPgName, char *viewEntryPgName,
633     int addRemoveFlag)
634 {
635 	scf_handle_t	*handle = NULL;
636 	scf_service_t	*svc = NULL;
637 	scf_propertygroup_t	*pg = NULL;
638 	scf_property_t	*prop = NULL;
639 	scf_value_t	*value = NULL;
640 	scf_transaction_t   *tran = NULL;
641 	scf_transaction_entry_t *entry = NULL;
642 	scf_transaction_entry_t *entryVeName = NULL;
643 	boolean_t createVeCnt = B_FALSE;
644 	uint64_t veCnt = 0;
645 	int ret = STMF_PS_SUCCESS;
646 	int commitRet;
647 
648 	assert(luPgName != NULL || viewEntryPgName != NULL);
649 	assert(!(addRemoveFlag != ADD && addRemoveFlag != REMOVE));
650 
651 	/*
652 	 * Init the service handle
653 	 */
654 	ret = iPsInit(&handle, &svc);
655 	if (ret != STMF_PS_SUCCESS) {
656 		goto out;
657 	}
658 
659 	/*
660 	 * Allocate scf resources
661 	 */
662 	if (((pg = scf_pg_create(handle)) == NULL) ||
663 	    ((tran = scf_transaction_create(handle)) == NULL) ||
664 	    ((entry = scf_entry_create(handle)) == NULL) ||
665 	    ((prop = scf_property_create(handle)) == NULL) ||
666 	    ((value = scf_value_create(handle)) == NULL)) {
667 		syslog(LOG_ERR, "scf alloc resource failed - %s",
668 		    scf_strerror(scf_error()));
669 		ret = STMF_PS_ERROR;
670 		goto out;
671 	}
672 
673 	/* get the LU property group */
674 	if (scf_service_get_pg(svc, luPgName, pg) == -1) {
675 		if (scf_error() == SCF_ERROR_NOT_FOUND &&
676 		    addRemoveFlag == ADD) {
677 			/* if it doesn't exist, create it */
678 			if (scf_service_add_pg(svc, luPgName,
679 			    SCF_GROUP_APPLICATION, 0, pg) == -1) {
680 				syslog(LOG_ERR, "add pg %s failed - %s",
681 				    luPgName, scf_strerror(scf_error()));
682 				ret = STMF_PS_ERROR;
683 			} else {
684 				/* we need to create the VE_CNT property */
685 				createVeCnt = B_TRUE;
686 				ret = STMF_PS_SUCCESS;
687 			}
688 		} else if (scf_error() == SCF_ERROR_NOT_FOUND) {
689 			ret = STMF_PS_ERROR_NOT_FOUND;
690 		} else {
691 			syslog(LOG_ERR, "get lu pg %s failed - %s",
692 			    luPgName, scf_strerror(scf_error()));
693 			ret = STMF_PS_ERROR;
694 		}
695 		if (ret != STMF_PS_SUCCESS) {
696 			goto out;
697 		}
698 	}
699 
700 
701 	/*
702 	 * Begin the transaction
703 	 */
704 	if (scf_transaction_start(tran, pg) == -1) {
705 		syslog(LOG_ERR, "start transaction for %s failed - %s",
706 		    luPgName, scf_strerror(scf_error()));
707 		ret = STMF_PS_ERROR;
708 		goto out;
709 	}
710 
711 
712 	if (createVeCnt) {
713 		/*
714 		 * Create the STMF_VE_CNT property. This will keep the current
715 		 * total view entries for this logical unit.
716 		 */
717 		if (scf_transaction_property_new(tran, entry, STMF_VE_CNT,
718 		    SCF_TYPE_COUNT) == -1) {
719 			if (scf_error() == SCF_ERROR_EXISTS) {
720 				ret = STMF_PS_ERROR_EXISTS;
721 			} else {
722 				syslog(LOG_ERR,
723 				    "transaction property new %s/%s "
724 				    "failed - %s", luPgName, STMF_VE_CNT,
725 				    scf_strerror(scf_error()));
726 				ret = STMF_PS_ERROR;
727 			}
728 			goto out;
729 		}
730 	} else {
731 		/*
732 		 * The STMF_VE_CNT property already exists. Just update
733 		 * it.
734 		 */
735 		if (scf_transaction_property_change(tran, entry,
736 		    STMF_VE_CNT, SCF_TYPE_COUNT) == -1) {
737 			syslog(LOG_ERR, "transaction property %s/%s change "
738 			    "failed - %s", luPgName, STMF_VE_CNT,
739 			    scf_strerror(scf_error()));
740 			ret = STMF_PS_ERROR;
741 			goto out;
742 		}
743 
744 		/*
745 		 * Get the STMF_VE_CNT property
746 		 */
747 		if (scf_pg_get_property(pg, STMF_VE_CNT, prop) == -1) {
748 			syslog(LOG_ERR, "get property %s/%s failed - %s",
749 			    luPgName, STMF_VE_CNT, scf_strerror(scf_error()));
750 			ret = STMF_PS_ERROR;
751 			goto out;
752 		}
753 
754 		/*
755 		 * Get the STMF_VE_CNT value
756 		 */
757 		if (scf_property_get_value(prop, value) == -1) {
758 			syslog(LOG_ERR, "get property %s/%s value failed - %s",
759 			    luPgName, STMF_VE_CNT, scf_strerror(scf_error()));
760 			ret = STMF_PS_ERROR;
761 			goto out;
762 		}
763 
764 		/*
765 		 * Now get the actual value from the value handle
766 		 */
767 		if (scf_value_get_count(value, &veCnt) == -1) {
768 			syslog(LOG_ERR, "get count value %s/%s failed - %s",
769 			    luPgName, STMF_VE_CNT, scf_strerror(scf_error()));
770 			ret = STMF_PS_ERROR;
771 			goto out;
772 		}
773 
774 		/*
775 		 * Reset the value resource as it is used below
776 		 */
777 		scf_value_reset(value);
778 	}
779 
780 	if (addRemoveFlag == ADD) {
781 		veCnt++;
782 	} else {
783 		/* Check if this is the last one being removed */
784 		if (veCnt == 1) {
785 			/*
786 			 * Delete the pg and get out if this is the last
787 			 * view entry
788 			 */
789 			if (scf_pg_delete(pg) == -1) {
790 				syslog(LOG_ERR, "delete pg %s failed - %s",
791 				    luPgName, scf_strerror(scf_error()));
792 
793 				ret = STMF_PS_ERROR;
794 			}
795 			goto out;
796 		} else {
797 			veCnt--;
798 		}
799 	}
800 
801 
802 	/*
803 	 * Set the view entry count
804 	 */
805 	scf_value_set_count(value, veCnt);
806 
807 	/*
808 	 * Add the value to the transaction entry
809 	 */
810 	if (scf_entry_add_value(entry, value) == -1) {
811 		syslog(LOG_ERR, "add value %s/%s failed - %s",
812 		    luPgName, STMF_VE_CNT, scf_strerror(scf_error()));
813 		ret = STMF_PS_ERROR;
814 		goto out;
815 	}
816 
817 	/*
818 	 * Create a transaction entry resource for the view entry name
819 	 */
820 	entryVeName = scf_entry_create(handle);
821 	if (entryVeName == NULL) {
822 		syslog(LOG_ERR, "scf transaction entry alloc %s/%s failed - %s",
823 		    luPgName, viewEntryPgName, scf_strerror(scf_error()));
824 		ret = STMF_PS_ERROR;
825 		goto out;
826 	}
827 
828 	if (addRemoveFlag == ADD) {
829 		/*
830 		 * If adding, create a property with the view entry name
831 		 */
832 		if (scf_transaction_property_new(tran, entryVeName,
833 		    viewEntryPgName, SCF_TYPE_USTRING) == -1) {
834 			if (scf_error() == SCF_ERROR_EXISTS) {
835 				ret = STMF_PS_ERROR_EXISTS;
836 			} else {
837 				syslog(LOG_ERR,
838 				    "transaction property new %s/%s "
839 				    "failed - %s", luPgName, viewEntryPgName,
840 				    scf_strerror(scf_error()));
841 				ret = STMF_PS_ERROR;
842 			}
843 			goto out;
844 		}
845 	} else {
846 		/*
847 		 * If removing, delete the existing property with the view
848 		 * entry name
849 		 */
850 		if (scf_transaction_property_delete(tran, entryVeName,
851 		    viewEntryPgName) == -1) {
852 			if (scf_error() == SCF_ERROR_NOT_FOUND) {
853 				ret = STMF_PS_ERROR_NOT_FOUND;
854 			} else {
855 				syslog(LOG_ERR,
856 				    "transaction property delete %s/%s "
857 				    "failed - %s", luPgName, viewEntryPgName,
858 				    scf_strerror(scf_error()));
859 				ret = STMF_PS_ERROR;
860 			}
861 			goto out;
862 		}
863 	}
864 
865 	/*
866 	 * Commit property transaction
867 	 */
868 	if ((commitRet = scf_transaction_commit(tran)) != 1) {
869 		syslog(LOG_ERR, "transaction commit for %s failed - %s",
870 		    luPgName, scf_strerror(scf_error()));
871 		if (commitRet == 0) {
872 			ret = STMF_PS_ERROR_BUSY;
873 		} else {
874 			ret = STMF_PS_ERROR;
875 		}
876 		goto out;
877 	}
878 
879 out:
880 	/*
881 	 * Free resources
882 	 */
883 	if (handle != NULL) {
884 		scf_handle_destroy(handle);
885 	}
886 	if (svc != NULL) {
887 		scf_service_destroy(svc);
888 	}
889 	if (pg != NULL) {
890 		scf_pg_destroy(pg);
891 	}
892 	if (tran != NULL) {
893 		scf_transaction_destroy(tran);
894 	}
895 	if (entry != NULL) {
896 		scf_entry_destroy(entry);
897 	}
898 	if (entryVeName != NULL) {
899 		scf_entry_destroy(entryVeName);
900 	}
901 	if (prop != NULL) {
902 		scf_property_destroy(prop);
903 	}
904 	if (value != NULL) {
905 		scf_value_destroy(value);
906 	}
907 
908 	return (ret);
909 }
910 
911 /*
912  * iPsAddViewEntry
913  *
914  * Add a view entry property group and optionally, a logical unit property
915  * group if it does not exist.
916  *
917  * luName - ascii hexadecimal logical unit identifier
918  * viewEntryName - name of view entry (VIEW_ENTRY_nn)
919  * viewEntry - pointer to stmfViewEntry structure
920  */
921 static int
922 iPsAddViewEntry(char *luPgName, char *viewEntryPgName, stmfViewEntry *viewEntry)
923 {
924 	scf_handle_t	*handle = NULL;
925 	scf_service_t	*svc = NULL;
926 	scf_propertygroup_t	*pg = NULL;
927 	scf_value_t	*value[VIEW_ENTRY_STRUCT_CNT];
928 	scf_transaction_t   *tran = NULL;
929 	scf_transaction_entry_t *entry[VIEW_ENTRY_STRUCT_CNT];
930 	int i = 0;
931 	int j = 0;
932 	int ret;
933 	uint8_t scfBool;
934 	boolean_t createdVePg = B_FALSE;
935 	int backoutRet;
936 	int commitRet;
937 
938 	assert(luPgName != NULL || viewEntryPgName != NULL ||
939 	    viewEntry == NULL);
940 
941 	bzero(value, sizeof (value));
942 	bzero(entry, sizeof (entry));
943 
944 	/*
945 	 * Init the service handle
946 	 */
947 	ret = iPsInit(&handle, &svc);
948 	if (ret != STMF_PS_SUCCESS) {
949 		goto out;
950 	}
951 
952 	/*
953 	 * Allocate scf resources
954 	 */
955 	if (((pg = scf_pg_create(handle)) == NULL) ||
956 	    ((tran = scf_transaction_create(handle)) == NULL)) {
957 		syslog(LOG_ERR, "scf alloc resource failed - %s",
958 		    scf_strerror(scf_error()));
959 		ret = STMF_PS_ERROR;
960 		goto out;
961 	}
962 
963 	/*
964 	 * allocate value and entry resources for scf
965 	 */
966 	for (i = 0; i < VIEW_ENTRY_STRUCT_CNT; i++) {
967 		if (((value[i] = scf_value_create(handle)) == NULL) ||
968 		    ((entry[i] = scf_entry_create(handle)) == NULL)) {
969 			syslog(LOG_ERR, "scf alloc resource failed - %s",
970 			    scf_strerror(scf_error()));
971 			ret = STMF_PS_ERROR;
972 			goto out;
973 		}
974 	}
975 
976 	i = 0;
977 
978 	/*
979 	 * Create the View Entry property group
980 	 */
981 	if (scf_service_add_pg(svc, viewEntryPgName, SCF_GROUP_APPLICATION,
982 	    0, pg) == -1) {
983 		if (scf_error() == SCF_ERROR_EXISTS) {
984 			ret = STMF_PS_ERROR_EXISTS;
985 		} else {
986 			syslog(LOG_ERR, "add pg %s failed - %s",
987 			    viewEntryPgName, scf_strerror(scf_error()));
988 			ret = STMF_PS_ERROR;
989 		}
990 		goto out;
991 	}
992 
993 	createdVePg = B_TRUE;
994 
995 	/*
996 	 * Add the view entry as properties on the view entry group
997 	 */
998 
999 	/*
1000 	 * Begin property update transaction
1001 	 */
1002 	if (scf_transaction_start(tran, pg) == -1) {
1003 		syslog(LOG_ERR, "start transaction for add %s failed - %s",
1004 		    viewEntryPgName, scf_strerror(scf_error()));
1005 		ret = STMF_PS_ERROR;
1006 		goto out;
1007 	}
1008 
1009 	/*
1010 	 * Add allHosts property
1011 	 */
1012 	if (scf_transaction_property_new(tran, entry[i],
1013 	    STMF_VE_ALLHOSTS, SCF_TYPE_BOOLEAN) == -1) {
1014 		if (scf_error() == SCF_ERROR_EXISTS) {
1015 			ret = STMF_PS_ERROR_EXISTS;
1016 		} else {
1017 			syslog(LOG_ERR, "transaction property new %s/%s "
1018 			    "failed - %s", viewEntryPgName, STMF_VE_ALLHOSTS,
1019 			    scf_strerror(scf_error()));
1020 			ret = STMF_PS_ERROR;
1021 		}
1022 		goto out;
1023 	}
1024 
1025 	/* Set the allHosts value */
1026 	scfBool = viewEntry->allHosts;
1027 	scf_value_set_boolean(value[i], scfBool);
1028 
1029 	/*
1030 	 * Add the allHosts value to the transaction
1031 	 */
1032 	if (scf_entry_add_value(entry[i], value[i]) == -1) {
1033 		syslog(LOG_ERR, "add value %s/%s failed - %s",
1034 		    viewEntryPgName, STMF_VE_ALLHOSTS,
1035 		    scf_strerror(scf_error()));
1036 		ret = STMF_PS_ERROR;
1037 		goto out;
1038 	}
1039 
1040 	i++;
1041 
1042 	/*
1043 	 * Create hostGroup property
1044 	 */
1045 	if (scf_transaction_property_new(tran, entry[i],
1046 	    STMF_VE_HOSTGROUP, SCF_TYPE_USTRING) == -1) {
1047 		if (scf_error() == SCF_ERROR_EXISTS) {
1048 			ret = STMF_PS_ERROR_EXISTS;
1049 		} else {
1050 			syslog(LOG_ERR, "transaction property new %s/%s "
1051 			    "failed - %s", viewEntryPgName, STMF_VE_HOSTGROUP,
1052 			    scf_strerror(scf_error()));
1053 			ret = STMF_PS_ERROR;
1054 		}
1055 		goto out;
1056 	}
1057 
1058 	/*
1059 	 * Set the value for hostGroup
1060 	 */
1061 	if (scf_value_set_ustring(value[i], viewEntry->hostGroup) == -1) {
1062 		syslog(LOG_ERR, "set value %s/%s failed - %s",
1063 		    viewEntryPgName, STMF_VE_HOSTGROUP,
1064 		    scf_strerror(scf_error()));
1065 		ret = STMF_PS_ERROR;
1066 		goto out;
1067 	}
1068 
1069 	/*
1070 	 * Add the hostGroup value to the transaction entry
1071 	 */
1072 	if (scf_entry_add_value(entry[i], value[i]) == -1) {
1073 		syslog(LOG_ERR, "add value %s/%s failed - %s",
1074 		    viewEntryPgName, STMF_VE_HOSTGROUP,
1075 		    scf_strerror(scf_error()));
1076 		ret = STMF_PS_ERROR;
1077 		goto out;
1078 	}
1079 
1080 	i++;
1081 
1082 	/*
1083 	 * Create the allTargets property
1084 	 */
1085 	if (scf_transaction_property_new(tran, entry[i],
1086 	    STMF_VE_ALLTARGETS, SCF_TYPE_BOOLEAN) == -1) {
1087 		if (scf_error() == SCF_ERROR_EXISTS) {
1088 			ret = STMF_PS_ERROR_EXISTS;
1089 		} else {
1090 			syslog(LOG_ERR, "transaction property new %s/%s "
1091 			    "failed - %s", viewEntryPgName, STMF_VE_ALLTARGETS,
1092 			    scf_strerror(scf_error()));
1093 			ret = STMF_PS_ERROR;
1094 		}
1095 		goto out;
1096 	}
1097 
1098 	/*
1099 	 * Set the allTargets value
1100 	 */
1101 	scfBool = viewEntry->allTargets;
1102 	scf_value_set_boolean(value[i], scfBool);
1103 
1104 	/*
1105 	 * Add the allTargets value to the transaction
1106 	 */
1107 	if (scf_entry_add_value(entry[i], value[i]) == -1) {
1108 		syslog(LOG_ERR, "add value %s/%s failed - %s",
1109 		    viewEntryPgName, STMF_VE_ALLTARGETS,
1110 		    scf_strerror(scf_error()));
1111 		ret = STMF_PS_ERROR;
1112 		goto out;
1113 	}
1114 
1115 	i++;
1116 
1117 	/*
1118 	 * Create targetGroup property
1119 	 */
1120 	if (scf_transaction_property_new(tran, entry[i],
1121 	    STMF_VE_TARGETGROUP, SCF_TYPE_USTRING) == -1) {
1122 		if (scf_error() == SCF_ERROR_EXISTS) {
1123 			ret = STMF_PS_ERROR_EXISTS;
1124 		} else {
1125 			syslog(LOG_ERR, "transaction property new %s/%s "
1126 			    "failed - %s", viewEntryPgName,
1127 			    STMF_VE_TARGETGROUP, scf_strerror(scf_error()));
1128 			ret = STMF_PS_ERROR;
1129 		}
1130 		goto out;
1131 	}
1132 
1133 	/*
1134 	 * Set the value for targetGroup
1135 	 */
1136 	if (scf_value_set_ustring(value[i], viewEntry->targetGroup) == -1) {
1137 		syslog(LOG_ERR, "set value %s/%s failed - %s",
1138 		    viewEntryPgName, STMF_VE_TARGETGROUP,
1139 		    scf_strerror(scf_error()));
1140 		ret = STMF_PS_ERROR;
1141 		goto out;
1142 	}
1143 
1144 	/*
1145 	 * Add targetGroup value to the transaction
1146 	 */
1147 	if (scf_entry_add_value(entry[i], value[i]) == -1) {
1148 		syslog(LOG_ERR, "add value %s/%s failed - %s",
1149 		    viewEntryPgName, STMF_VE_TARGETGROUP,
1150 		    scf_strerror(scf_error()));
1151 		ret = STMF_PS_ERROR;
1152 		goto out;
1153 	}
1154 
1155 	i++;
1156 
1157 	/*
1158 	 * Create the luNbr property
1159 	 */
1160 	if (scf_transaction_property_new(tran, entry[i], STMF_VE_LUNBR,
1161 	    SCF_TYPE_OPAQUE) == -1) {
1162 		if (scf_error() == SCF_ERROR_EXISTS) {
1163 			ret = STMF_PS_ERROR_EXISTS;
1164 		} else {
1165 			syslog(LOG_ERR, "transaction property new %s/%s "
1166 			    "failed - %s", viewEntryPgName, STMF_VE_LUNBR,
1167 			    scf_strerror(scf_error()));
1168 			ret = STMF_PS_ERROR;
1169 		}
1170 		goto out;
1171 	}
1172 
1173 	/*
1174 	 * Set the luNbr
1175 	 */
1176 	if (scf_value_set_opaque(value[i], (char *)viewEntry->luNbr,
1177 	    sizeof (viewEntry->luNbr)) == -1) {
1178 		syslog(LOG_ERR, "set value %s/%s failed - %s",
1179 		    viewEntryPgName, STMF_VE_LUNBR, scf_strerror(scf_error()));
1180 		ret = STMF_PS_ERROR;
1181 		goto out;
1182 	}
1183 
1184 	/*
1185 	 * Add luNbr to the transaction entry
1186 	 */
1187 	if (scf_entry_add_value(entry[i], value[i]) == -1) {
1188 		syslog(LOG_ERR, "add value %s/%s failed - %s",
1189 		    viewEntryPgName, STMF_VE_LUNBR, scf_strerror(scf_error()));
1190 		ret = STMF_PS_ERROR;
1191 		goto out;
1192 	}
1193 
1194 	/*
1195 	 * Now that we've successfully added the view entry,
1196 	 * update the logical unit property group or create
1197 	 * it if it does not exist
1198 	 */
1199 	ret = iPsAddRemoveLuViewEntry(luPgName, viewEntryPgName, ADD);
1200 
1201 	/*
1202 	 * If we did not add the view entry name to the logical unit,
1203 	 * make sure we do not commit the transaction
1204 	 */
1205 	if (ret != STMF_PS_SUCCESS) {
1206 		goto out;
1207 	}
1208 
1209 	/*
1210 	 * Commit property transaction
1211 	 */
1212 	if ((commitRet = scf_transaction_commit(tran)) != 1) {
1213 		syslog(LOG_ERR, "transaction commit for add %s failed - %s",
1214 		    viewEntryPgName, scf_strerror(scf_error()));
1215 		if (commitRet == 0) {
1216 			ret = STMF_PS_ERROR_BUSY;
1217 		} else {
1218 			ret = STMF_PS_ERROR;
1219 		}
1220 	}
1221 
1222 	if (ret != STMF_PS_SUCCESS) {
1223 		/*
1224 		 * If we did not commit, try to remove the view entry name
1225 		 * from the logical unit.
1226 		 * If that fails, we're now inconsistent.
1227 		 */
1228 		backoutRet = iPsAddRemoveLuViewEntry(luPgName, viewEntryPgName,
1229 		    REMOVE);
1230 
1231 		if (backoutRet != STMF_PS_SUCCESS) {
1232 			syslog(LOG_ERR, "remove lu view entry %s failed"
1233 			    "possible inconsistency - %s", luPgName,
1234 			    scf_strerror(scf_error()));
1235 		}
1236 		/*
1237 		 * We are still in an error scenario even though the remove
1238 		 * lu view entry succeeded.
1239 		 */
1240 		goto out;
1241 	}
1242 
1243 out:
1244 	/*
1245 	 * Free resources
1246 	 */
1247 	if (handle != NULL) {
1248 		scf_handle_destroy(handle);
1249 	}
1250 	if (svc != NULL) {
1251 		scf_service_destroy(svc);
1252 	}
1253 	/* if there was an error, delete the created pg if one was created */
1254 	if ((ret != STMF_PS_SUCCESS) && createdVePg) {
1255 		if (scf_pg_delete(pg) == -1) {
1256 			syslog(LOG_ERR, "delete VE pg %s failed - %s",
1257 			    viewEntryPgName, scf_strerror(scf_error()));
1258 		}
1259 	}
1260 	if (pg != NULL) {
1261 		scf_pg_destroy(pg);
1262 	}
1263 	if (tran != NULL) {
1264 		scf_transaction_destroy(tran);
1265 	}
1266 	/*
1267 	 * Free value and entry scf resources
1268 	 */
1269 	if (i > 0) {
1270 		for (j = 0; j < VIEW_ENTRY_STRUCT_CNT; j++) {
1271 			if (value[j] != NULL)
1272 				scf_value_destroy(value[j]);
1273 			if (entry[j] != NULL)
1274 				scf_entry_destroy(entry[j]);
1275 		}
1276 	}
1277 
1278 	return (ret);
1279 }
1280 /*
1281  * psClearProviderData
1282  *
1283  * providerName - name of provider data to clear
1284  */
1285 int
1286 psClearProviderData(char *providerName, int providerType)
1287 {
1288 	scf_handle_t	*handle = NULL;
1289 	scf_service_t	*svc = NULL;
1290 	scf_propertygroup_t	*pg = NULL;
1291 	char pgName[MAXPATHLEN];
1292 	int ret = STMF_PS_SUCCESS;
1293 	boolean_t pgNotFound = B_FALSE;
1294 
1295 	if (providerName == NULL || (providerType != STMF_LU_PROVIDER_TYPE &&
1296 	    providerType != STMF_PORT_PROVIDER_TYPE)) {
1297 		ret = STMF_PS_ERROR_INVALID_ARG;
1298 		goto out;
1299 	}
1300 
1301 	ret = iPsInit(&handle, &svc);
1302 	if (ret != STMF_PS_SUCCESS) {
1303 		goto out;
1304 	}
1305 
1306 	/*
1307 	 * Allocate scf resources
1308 	 */
1309 	if ((pg = scf_pg_create(handle)) == NULL) {
1310 		syslog(LOG_ERR, "scf alloc resource failed - %s",
1311 		    scf_strerror(scf_error()));
1312 		ret = STMF_PS_ERROR;
1313 		goto out;
1314 	}
1315 
1316 	/*
1317 	 * create the property group name
1318 	 */
1319 	(void) snprintf(pgName, sizeof (pgName), "%s%s",
1320 	    STMF_PROVIDER_DATA_PREFIX, providerName);
1321 
1322 	/*
1323 	 * delete provider property group
1324 	 */
1325 	if (scf_service_get_pg(svc, pgName, pg) == -1) {
1326 		if (scf_error() != SCF_ERROR_NOT_FOUND) {
1327 			syslog(LOG_ERR, "get pg %s failed - %s",
1328 			    pgName, scf_strerror(scf_error()));
1329 			ret = STMF_PS_ERROR;
1330 			goto out;
1331 		} else {
1332 			pgNotFound = B_TRUE;
1333 		}
1334 	}
1335 
1336 	if (!pgNotFound && (scf_pg_delete(pg) == -1)) {
1337 		syslog(LOG_ERR, "delete pg %s failed - %s",
1338 		    pgName, scf_strerror(scf_error()));
1339 		ret = STMF_PS_ERROR;
1340 		goto out;
1341 	}
1342 
1343 	if (pgNotFound) {
1344 		ret = STMF_PS_ERROR_NOT_FOUND;
1345 	}
1346 
1347 out:
1348 	/*
1349 	 * Free resources
1350 	 */
1351 	if (handle != NULL) {
1352 		scf_handle_destroy(handle);
1353 	}
1354 	if (svc != NULL) {
1355 		scf_service_destroy(svc);
1356 	}
1357 	if (pg != NULL) {
1358 		scf_pg_destroy(pg);
1359 	}
1360 
1361 	return (ret);
1362 }
1363 
1364 /*
1365  * iPsCreateDeleteGroup
1366  *
1367  * Creates or deletes a group (target or host)
1368  *
1369  * When creating a group, two properties are created. One to hold the group
1370  * name and the other to hold the group members.
1371  *
1372  * pgName - Property group name
1373  * groupName - group name to create
1374  * addRemoveFlag - ADD_GROUP/REMOVE_GROUP
1375  *
1376  * returns:
1377  *  STMF_PS_SUCCESS on success
1378  *  STMF_PS_ERROR_* on failure
1379  */
1380 static int
1381 iPsCreateDeleteGroup(char *pgRefName, char *groupName, int addRemoveFlag)
1382 {
1383 	scf_handle_t	*handle = NULL;
1384 	scf_service_t	*svc = NULL;
1385 	scf_propertygroup_t	*pg = NULL;
1386 	scf_property_t	*prop = NULL;
1387 	scf_iter_t	*propIter = NULL;
1388 	scf_transaction_t   *tran = NULL;
1389 	scf_transaction_entry_t *entry1 = NULL;
1390 	scf_transaction_entry_t *entry2 = NULL;
1391 	scf_value_t *value = NULL;
1392 	uint64_t groupIdx;
1393 	char buf1[MAXNAMELEN];
1394 	char buf2[MAXNAMELEN];
1395 	char tmpbuf[MAXNAMELEN];
1396 	boolean_t found = B_FALSE;
1397 	int ret = STMF_PS_SUCCESS;
1398 	int commitRet;
1399 
1400 	assert(groupName != NULL);
1401 
1402 	ret = iPsInit(&handle, &svc);
1403 	if (ret != STMF_PS_SUCCESS) {
1404 		goto out;
1405 	}
1406 
1407 	/*
1408 	 * Allocate scf resources
1409 	 */
1410 	if (((pg = scf_pg_create(handle)) == NULL) ||
1411 	    ((tran = scf_transaction_create(handle)) == NULL) ||
1412 	    ((entry1 = scf_entry_create(handle)) == NULL) ||
1413 	    ((entry2 = scf_entry_create(handle)) == NULL) ||
1414 	    ((prop = scf_property_create(handle)) == NULL) ||
1415 	    ((propIter = scf_iter_create(handle)) == NULL) ||
1416 	    ((value = scf_value_create(handle)) == NULL)) {
1417 		syslog(LOG_ERR, "scf alloc resource failed - %s",
1418 		    scf_strerror(scf_error()));
1419 		ret = STMF_PS_ERROR;
1420 		goto out;
1421 	}
1422 
1423 	/*
1424 	 * Get the property group being modified
1425 	 */
1426 	if (scf_service_get_pg(svc, pgRefName, pg) == -1) {
1427 		if (scf_error() == SCF_ERROR_NOT_FOUND &&
1428 		    addRemoveFlag == ADD) {
1429 			if (scf_service_add_pg(svc, pgRefName,
1430 			    SCF_GROUP_APPLICATION, 0, pg) == -1) {
1431 				syslog(LOG_ERR, "add pg %s failed - %s",
1432 				    pgRefName, scf_strerror(scf_error()));
1433 				ret = STMF_PS_ERROR;
1434 			}
1435 		} else if (scf_error() == SCF_ERROR_NOT_FOUND) {
1436 			syslog(LOG_ERR, "get pg %s failed - %s",
1437 			    pgRefName, scf_strerror(scf_error()));
1438 			ret = STMF_PS_ERROR_NOT_FOUND;
1439 		} else {
1440 			syslog(LOG_ERR, "get pg %s failed - %s",
1441 			    pgRefName, scf_strerror(scf_error()));
1442 			ret = STMF_PS_ERROR;
1443 		}
1444 		if (ret != STMF_PS_SUCCESS) {
1445 			goto out;
1446 		}
1447 	}
1448 
1449 	/*
1450 	 * propIter is the iterator handle
1451 	 */
1452 	if (scf_iter_pg_properties(propIter, pg) == -1) {
1453 		syslog(LOG_ERR, "iter properties for %s failed - %s",
1454 		    pgRefName, scf_strerror(scf_error()));
1455 		ret = STMF_PS_ERROR;
1456 		goto out;
1457 	}
1458 
1459 	/*
1460 	 * Iterate through the group names.
1461 	 * If we find it in the list, it's an error when addRemoveFlag == ADD.
1462 	 */
1463 	while (scf_iter_next_property(propIter, prop) == 1) {
1464 		if (scf_property_get_name(prop, buf1, sizeof (buf1)) == -1) {
1465 			syslog(LOG_ERR, "get name from %s iter failed - %s",
1466 			    pgRefName, scf_strerror(scf_error()));
1467 			ret = STMF_PS_ERROR;
1468 			break;
1469 		}
1470 		/*
1471 		 * Skip over member list properties
1472 		 */
1473 		if (strstr(buf1, STMF_MEMBER_LIST_SUFFIX)) {
1474 			continue;
1475 		}
1476 		if (scf_property_get_value(prop, value) == -1) {
1477 			syslog(LOG_ERR, "get property value %s/%s failed - %s",
1478 			    pgRefName, buf1, scf_strerror(scf_error()));
1479 			ret = STMF_PS_ERROR;
1480 			break;
1481 		}
1482 		if (scf_value_get_ustring(value, tmpbuf,
1483 		    sizeof (tmpbuf)) == -1) {
1484 			syslog(LOG_ERR, "get ustring %s/%s failed - %s",
1485 			    pgRefName, buf1, scf_strerror(scf_error()));
1486 			ret = STMF_PS_ERROR;
1487 			break;
1488 		}
1489 
1490 		if ((strlen(tmpbuf) == strlen(groupName)) &&
1491 		    bcmp(tmpbuf, groupName, strlen(tmpbuf)) == 0) {
1492 			if (addRemoveFlag == ADD) {
1493 				ret = STMF_PS_ERROR_EXISTS;
1494 			}
1495 			found = B_TRUE;
1496 			/*
1497 			 * buf1 contains the name for REMOVE
1498 			 */
1499 			break;
1500 		}
1501 	}
1502 
1503 	if (ret != STMF_PS_SUCCESS) {
1504 		goto out;
1505 	}
1506 
1507 	scf_value_reset(value);
1508 
1509 	if (!found && addRemoveFlag == REMOVE) {
1510 		ret = STMF_PS_ERROR_NOT_FOUND;
1511 		goto out;
1512 	}
1513 
1514 	/*
1515 	 * If we're adding, we need to create a new property name for the
1516 	 * new group
1517 	 */
1518 	if (addRemoveFlag == ADD) {
1519 		for (groupIdx = 0; groupIdx < GROUP_MAX; groupIdx++) {
1520 			if (snprintf(buf1, sizeof (buf1), "%s-%lld",
1521 			    STMF_GROUP_PREFIX, groupIdx) > sizeof (buf1)) {
1522 				syslog(LOG_ERR,
1523 				    "buffer overflow on property name %s",
1524 				    buf1);
1525 				ret = STMF_PS_ERROR;
1526 				break;
1527 			}
1528 			if (scf_pg_get_property(pg, buf1, prop) == -1) {
1529 				if (scf_error() != SCF_ERROR_NOT_FOUND) {
1530 					syslog(LOG_ERR, "get property %s/%s "
1531 					    "failed - %s", pgRefName, buf1,
1532 					    scf_strerror(scf_error()));
1533 					ret = STMF_PS_ERROR;
1534 				}
1535 				break;
1536 			}
1537 		}
1538 	}
1539 
1540 	/*
1541 	 * Now create the new member list property for the new group
1542 	 */
1543 	if (snprintf(buf2, sizeof (buf2), "%s-%s", buf1,
1544 	    STMF_MEMBER_LIST_SUFFIX) > sizeof (buf2)) {
1545 		syslog(LOG_ERR, "buffer overflow on property name %s",
1546 		    buf1);
1547 		ret = STMF_PS_ERROR;
1548 		goto out;
1549 	}
1550 
1551 	/*
1552 	 * buf1 now contains the name of the property if it was found in the
1553 	 * list in the case of delete or the next available property name
1554 	 * in the case of create
1555 	 *
1556 	 * buf2 now contains the member list property name
1557 	 */
1558 	if (scf_transaction_start(tran, pg) == -1) {
1559 		syslog(LOG_ERR, "start transaction for %s failed - %s",
1560 		    pgRefName, scf_strerror(scf_error()));
1561 		ret = STMF_PS_ERROR;
1562 		goto out;
1563 	}
1564 
1565 	if (addRemoveFlag == ADD) {
1566 		/*
1567 		 * Create the property 'group name'
1568 		 * This is the container for the group name
1569 		 */
1570 		if (scf_transaction_property_new(tran, entry1, buf1,
1571 		    SCF_TYPE_USTRING) == -1) {
1572 			syslog(LOG_ERR, "transaction property new %s/%s "
1573 			    "failed - %s", pgRefName, buf1,
1574 			    scf_strerror(scf_error()));
1575 			ret = STMF_PS_ERROR;
1576 			goto out;
1577 		}
1578 		if (scf_value_set_ustring(value, groupName) == -1) {
1579 			syslog(LOG_ERR, "set ustring %s/%s failed - %s",
1580 			    pgRefName, buf1, scf_strerror(scf_error()));
1581 			ret = STMF_PS_ERROR;
1582 			goto out;
1583 		}
1584 		if (scf_entry_add_value(entry1, value) == -1) {
1585 			syslog(LOG_ERR, "add value %s/%s failed - %s",
1586 			    pgRefName, buf1, scf_strerror(scf_error()));
1587 			ret = STMF_PS_ERROR;
1588 			goto out;
1589 		}
1590 		/*
1591 		 * Create the property 'group list'
1592 		 * This is the container for the group members
1593 		 */
1594 		if (scf_transaction_property_new(tran, entry2, buf2,
1595 		    SCF_TYPE_USTRING) == -1) {
1596 			syslog(LOG_ERR, "transaction property new %s/%s "
1597 			    "failed - %s", pgRefName, buf2,
1598 			    scf_strerror(scf_error()));
1599 			ret = STMF_PS_ERROR;
1600 			goto out;
1601 		}
1602 	} else {
1603 		/*
1604 		 * Delete the property 'group name'
1605 		 */
1606 		if (scf_transaction_property_delete(tran, entry1, buf1)
1607 		    == -1) {
1608 			syslog(LOG_ERR,
1609 			    "transaction property delete %s/%s failed - %s",
1610 			    pgRefName, buf1, scf_strerror(scf_error()));
1611 			ret = STMF_PS_ERROR;
1612 			goto out;
1613 		}
1614 		/*
1615 		 * Delete the property 'group list'
1616 		 */
1617 		if (scf_transaction_property_delete(tran, entry2, buf2)
1618 		    == -1) {
1619 			syslog(LOG_ERR, "transaction property delete %s/%s "
1620 			    "failed - %s", pgRefName, buf2,
1621 			    scf_strerror(scf_error()));
1622 			ret = STMF_PS_ERROR;
1623 			goto out;
1624 		}
1625 	}
1626 
1627 	if (ret != STMF_PS_SUCCESS) {
1628 		goto out;
1629 	}
1630 
1631 	if ((commitRet = scf_transaction_commit(tran)) != 1) {
1632 		syslog(LOG_ERR, "transaction commit for %s failed - %s",
1633 		    pgRefName, scf_strerror(scf_error()));
1634 		if (commitRet == 0) {
1635 			ret = STMF_PS_ERROR_BUSY;
1636 		} else {
1637 			ret = STMF_PS_ERROR;
1638 		}
1639 	}
1640 
1641 out:
1642 	/*
1643 	 * Free resources
1644 	 */
1645 	if (handle != NULL) {
1646 		scf_handle_destroy(handle);
1647 	}
1648 	if (svc != NULL) {
1649 		scf_service_destroy(svc);
1650 	}
1651 	if (pg != NULL) {
1652 		scf_pg_destroy(pg);
1653 	}
1654 	if (tran != NULL) {
1655 		scf_transaction_destroy(tran);
1656 	}
1657 	if (entry1 != NULL) {
1658 		scf_entry_destroy(entry1);
1659 	}
1660 	if (entry2 != NULL) {
1661 		scf_entry_destroy(entry2);
1662 	}
1663 	if (prop != NULL) {
1664 		scf_property_destroy(prop);
1665 	}
1666 	if (propIter != NULL) {
1667 		scf_iter_destroy(propIter);
1668 	}
1669 	if (value != NULL) {
1670 		scf_value_destroy(value);
1671 	}
1672 
1673 	return (ret);
1674 }
1675 
1676 /*
1677  * iPsGetGroupList
1678  *
1679  * pgName - Property group name
1680  * groupList - pointer to pointer to stmfGroupList structure. On success,
1681  * contains the list of groups
1682  *
1683  * returns:
1684  *  STMF_PS_SUCCESS on success
1685  *  STMF_PS_ERROR_* on failure
1686  */
1687 static int
1688 iPsGetGroupList(char *pgName, stmfGroupList **groupList)
1689 {
1690 	scf_handle_t	*handle = NULL;
1691 	scf_service_t	*svc = NULL;
1692 	scf_propertygroup_t	*pg = NULL;
1693 	scf_property_t	*prop = NULL;
1694 	scf_iter_t	*propIter = NULL;
1695 	scf_value_t	*value = NULL;
1696 	char buf[MAXNAMELEN];
1697 	int memberCnt = 0;
1698 	int i = 0;
1699 	int ret = STMF_PS_SUCCESS;
1700 
1701 	assert(groupList != NULL);
1702 
1703 	ret = iPsInit(&handle, &svc);
1704 	if (ret != STMF_PS_SUCCESS) {
1705 		goto out;
1706 	}
1707 
1708 	/*
1709 	 * Allocate scf resources
1710 	 */
1711 	if (((pg = scf_pg_create(handle)) == NULL) ||
1712 	    ((prop = scf_property_create(handle)) == NULL) ||
1713 	    ((propIter = scf_iter_create(handle)) == NULL) ||
1714 	    ((value = scf_value_create(handle)) == NULL)) {
1715 		syslog(LOG_ERR, "scf alloc resource failed - %s",
1716 		    scf_strerror(scf_error()));
1717 		ret = STMF_PS_ERROR;
1718 		goto out;
1719 	}
1720 
1721 	if (scf_service_get_pg(svc, pgName, pg) == -1) {
1722 		if (scf_error() == SCF_ERROR_NOT_FOUND) {
1723 			syslog(LOG_ERR, "get pg %s failed - %s",
1724 			    pgName, scf_strerror(scf_error()));
1725 			ret = STMF_PS_ERROR_NOT_FOUND;
1726 		} else {
1727 			syslog(LOG_ERR, "get pg %s failed - %s",
1728 			    pgName, scf_strerror(scf_error()));
1729 			ret = STMF_PS_ERROR;
1730 		}
1731 		goto out;
1732 	}
1733 
1734 	/*
1735 	 * propIter is the iterator handle
1736 	 */
1737 	if (scf_iter_pg_properties(propIter, pg) == -1) {
1738 		syslog(LOG_ERR, "iter properties for %s failed - %s",
1739 		    pgName, scf_strerror(scf_error()));
1740 		ret = STMF_PS_ERROR;
1741 		goto out;
1742 	}
1743 
1744 	while (scf_iter_next_property(propIter, prop) == 1) {
1745 		if (scf_property_get_name(prop, buf, sizeof (buf)) == -1) {
1746 			syslog(LOG_ERR, "get name from %s iter failed - %s",
1747 			    pgName, scf_strerror(scf_error()));
1748 			ret = STMF_PS_ERROR;
1749 			break;
1750 		}
1751 		/*
1752 		 * Skip over member list properties
1753 		 */
1754 		if (strstr(buf, STMF_MEMBER_LIST_SUFFIX)) {
1755 			continue;
1756 		}
1757 		memberCnt++;
1758 	}
1759 
1760 	/*
1761 	 * propIter is the iterator handle
1762 	 */
1763 	if (scf_iter_pg_properties(propIter, pg) == -1) {
1764 		syslog(LOG_ERR, "iter properties for %s failed - %s",
1765 		    pgName, scf_strerror(scf_error()));
1766 		ret = STMF_PS_ERROR;
1767 		goto out;
1768 	}
1769 
1770 	*groupList = (stmfGroupList *)calloc(1, sizeof (stmfGroupList) +
1771 	    memberCnt * sizeof (stmfGroupName));
1772 
1773 	if (*groupList == NULL) {
1774 		ret = STMF_PS_ERROR_NOMEM;
1775 		goto out;
1776 	}
1777 
1778 	/*
1779 	 * In order to get a list of groups, simply get all of the
1780 	 * properties that are not member list properties, i.e. the group
1781 	 * name properties.
1782 	 * It's possible for this list to grow beyond what was originally
1783 	 * read so just ensure we're not writing beyond our allocated buffer
1784 	 * by ensuring i < memberCnt
1785 	 */
1786 	while ((scf_iter_next_property(propIter, prop) == 1) &&
1787 	    (i < memberCnt)) {
1788 		if (scf_property_get_name(prop, buf, sizeof (buf)) == -1) {
1789 			syslog(LOG_ERR, "get name from %s iter failed - %s",
1790 			    pgName, scf_strerror(scf_error()));
1791 			ret = STMF_PS_ERROR;
1792 			break;
1793 		}
1794 		/*
1795 		 * Skip over member list properties
1796 		 */
1797 		if (strstr(buf, STMF_MEMBER_LIST_SUFFIX)) {
1798 			continue;
1799 		}
1800 		if (scf_property_get_value(prop, value) == -1) {
1801 			syslog(LOG_ERR, "get property value %s/%s failed - %s",
1802 			    pgName, buf, scf_strerror(scf_error()));
1803 			ret = STMF_PS_ERROR;
1804 			break;
1805 		}
1806 		if (scf_value_get_ustring(value, buf, sizeof (buf)) == -1) {
1807 			syslog(LOG_ERR, "get ustring %s/%s failed - %s",
1808 			    pgName, buf, scf_strerror(scf_error()));
1809 			ret = STMF_PS_ERROR;
1810 			break;
1811 		}
1812 		bcopy(buf, (*groupList)->name[i++], strlen(buf));
1813 		(*groupList)->cnt++;
1814 	}
1815 
1816 	if (ret != STMF_PS_SUCCESS) {
1817 		free(*groupList);
1818 		goto out;
1819 	}
1820 
1821 out:
1822 	/*
1823 	 * Free resources
1824 	 */
1825 	if (handle != NULL) {
1826 		scf_handle_destroy(handle);
1827 	}
1828 	if (svc != NULL) {
1829 		scf_service_destroy(svc);
1830 	}
1831 	if (pg != NULL) {
1832 		scf_pg_destroy(pg);
1833 	}
1834 	if (propIter != NULL) {
1835 		scf_iter_destroy(propIter);
1836 	}
1837 	if (prop != NULL) {
1838 		scf_property_destroy(prop);
1839 	}
1840 	if (value != NULL) {
1841 		scf_value_destroy(value);
1842 	}
1843 
1844 	return (ret);
1845 }
1846 
1847 /*
1848  * iPsGetGroupMemberList
1849  *
1850  * pgName - Property group name
1851  * groupName - group name (host group or target group)
1852  * groupMemberList - pointer to pointer to stmfGroupProperties structure. On
1853  * success, contains the list of group members
1854  *
1855  * returns:
1856  *  STMF_PS_SUCCESS on success
1857  *  STMF_PS_ERROR_* on failure
1858  */
1859 static int
1860 iPsGetGroupMemberList(char *pgName, char *groupName,
1861     stmfGroupProperties **groupMemberList)
1862 {
1863 	scf_handle_t	*handle = NULL;
1864 	scf_service_t	*svc = NULL;
1865 	scf_propertygroup_t	*pg = NULL;
1866 	scf_property_t	*prop = NULL;
1867 	scf_value_t	*valueLookup = NULL;
1868 	scf_iter_t	*valueIter = NULL;
1869 	int i = 0;
1870 	int memberCnt;
1871 	int len;
1872 	int ret = STMF_PS_SUCCESS;
1873 	char buf[MAXNAMELEN];
1874 
1875 	assert(pgName != NULL && groupName != NULL);
1876 
1877 	/*
1878 	 * init the service handle
1879 	 */
1880 	ret = iPsInit(&handle, &svc);
1881 	if (ret != STMF_PS_SUCCESS) {
1882 		goto out;
1883 	}
1884 
1885 	/*
1886 	 * Allocate scf resources
1887 	 */
1888 	if (((pg = scf_pg_create(handle)) == NULL) ||
1889 	    ((prop = scf_property_create(handle)) == NULL) ||
1890 	    ((valueIter = scf_iter_create(handle)) == NULL) ||
1891 	    ((valueLookup = scf_value_create(handle)) == NULL)) {
1892 		syslog(LOG_ERR, "scf alloc resource failed - %s",
1893 		    scf_strerror(scf_error()));
1894 		ret = STMF_PS_ERROR;
1895 		goto out;
1896 	}
1897 
1898 	/*
1899 	 * get the service property group handle
1900 	 */
1901 	if (scf_service_get_pg(svc, pgName, pg) == -1) {
1902 		if (scf_error() == SCF_ERROR_NOT_FOUND) {
1903 			ret = STMF_PS_ERROR_NOT_FOUND;
1904 		} else {
1905 			ret = STMF_PS_ERROR;
1906 		}
1907 		syslog(LOG_ERR, "get pg %s failed - %s",
1908 		    pgName, scf_strerror(scf_error()));
1909 		goto out;
1910 	}
1911 
1912 	/*
1913 	 * Get the property handle
1914 	 * based on the target or host group name
1915 	 */
1916 	if (scf_pg_get_property(pg, groupName, prop) == -1) {
1917 		syslog(LOG_ERR, "get property %s/%s failed - %s",
1918 		    pgName, groupName, scf_strerror(scf_error()));
1919 		ret = STMF_PS_ERROR;
1920 		goto out;
1921 	}
1922 
1923 	/*
1924 	 * valueIter is the iterator handle
1925 	 */
1926 	if (scf_iter_property_values(valueIter, prop) == -1) {
1927 		syslog(LOG_ERR, "iter value %s/%s failed - %s",
1928 		    pgName, groupName, scf_strerror(scf_error()));
1929 		ret = STMF_PS_ERROR;
1930 		goto out;
1931 	}
1932 
1933 	while (scf_iter_next_value(valueIter, valueLookup) == 1) {
1934 		if (scf_value_get_ustring(valueLookup, buf, MAXNAMELEN) == -1) {
1935 			syslog(LOG_ERR, "iter value %s/%s failed - %s",
1936 			    pgName, groupName, scf_strerror(scf_error()));
1937 			ret = STMF_PS_ERROR;
1938 			break;
1939 		}
1940 		i++;
1941 	}
1942 
1943 	/*
1944 	 * valueIter is the iterator handle
1945 	 */
1946 	if (scf_iter_property_values(valueIter, prop) == -1) {
1947 		syslog(LOG_ERR, "iter value %s/%s failed - %s",
1948 		    pgName, groupName, scf_strerror(scf_error()));
1949 		ret = STMF_PS_ERROR;
1950 		goto out;
1951 	}
1952 
1953 	memberCnt = i;
1954 
1955 	*groupMemberList = (stmfGroupProperties *)calloc(1,
1956 	    sizeof (stmfGroupProperties) + memberCnt * sizeof (stmfDevid));
1957 	if (*groupMemberList == NULL) {
1958 		ret = STMF_PS_ERROR_NOMEM;
1959 		goto out;
1960 	}
1961 
1962 	i = 0;
1963 	while ((scf_iter_next_value(valueIter, valueLookup) == 1) &&
1964 	    (i < memberCnt)) {
1965 		if ((len = scf_value_get_ustring(valueLookup, buf, MAXNAMELEN))
1966 		    == -1) {
1967 			syslog(LOG_ERR, "iter value %s/%s failed - %s",
1968 			    pgName, groupName, scf_strerror(scf_error()));
1969 			ret = STMF_PS_ERROR;
1970 			break;
1971 		}
1972 		if (len < sizeof (stmfDevid) - 1) {
1973 			(*groupMemberList)->name[i].identLength = len;
1974 			bcopy(buf,
1975 			    (*groupMemberList)->name[i++].ident, len);
1976 			(*groupMemberList)->cnt++;
1977 		} else {
1978 			ret = STMF_PS_ERROR;
1979 			break;
1980 		}
1981 	}
1982 
1983 	if (ret != STMF_PS_SUCCESS) {
1984 		free(*groupMemberList);
1985 		goto out;
1986 	}
1987 
1988 out:
1989 	/*
1990 	 * Free resources
1991 	 */
1992 	if (handle != NULL) {
1993 		scf_handle_destroy(handle);
1994 	}
1995 	if (svc != NULL) {
1996 		scf_service_destroy(svc);
1997 	}
1998 	if (pg != NULL) {
1999 		scf_pg_destroy(pg);
2000 	}
2001 	if (prop != NULL) {
2002 		scf_property_destroy(prop);
2003 	}
2004 	if (valueLookup != NULL) {
2005 		scf_value_destroy(valueLookup);
2006 	}
2007 	if (valueIter != NULL) {
2008 		scf_iter_destroy(valueIter);
2009 	}
2010 
2011 	return (ret);
2012 }
2013 
2014 int
2015 psGetServicePersist(uint8_t *persistType)
2016 {
2017 	scf_handle_t	*handle = NULL;
2018 	scf_service_t	*svc = NULL;
2019 	int ret;
2020 
2021 
2022 	ret = iPsInit(&handle, &svc);
2023 	if (ret != STMF_PS_SUCCESS) {
2024 		return (STMF_PS_ERROR);
2025 	}
2026 
2027 	ret = iPsGetSetPersistType(persistType, handle, svc, GET);
2028 
2029 	/*
2030 	 * Free resources
2031 	 */
2032 	if (handle != NULL) {
2033 		scf_handle_destroy(handle);
2034 	}
2035 	if (svc != NULL) {
2036 		scf_service_destroy(svc);
2037 	}
2038 	return (ret);
2039 }
2040 
2041 int
2042 psSetServicePersist(uint8_t persistType)
2043 {
2044 	scf_handle_t	*handle = NULL;
2045 	scf_service_t	*svc = NULL;
2046 	int ret;
2047 
2048 
2049 	ret = iPsInit(&handle, &svc);
2050 	if (ret != STMF_PS_SUCCESS) {
2051 		return (STMF_PS_ERROR);
2052 	}
2053 
2054 	ret = iPsGetSetPersistType(&persistType, handle, svc, SET);
2055 
2056 	/*
2057 	 * Free resources
2058 	 */
2059 	if (handle != NULL) {
2060 		scf_handle_destroy(handle);
2061 	}
2062 	if (svc != NULL) {
2063 		scf_service_destroy(svc);
2064 	}
2065 	return (ret);
2066 }
2067 
2068 static int
2069 iPsGetSetPersistType(uint8_t *persistType, scf_handle_t *handle,
2070     scf_service_t *svc, int getSet)
2071 {
2072 	scf_propertygroup_t	*pg = NULL;
2073 	scf_property_t	*prop = NULL;
2074 	scf_value_t	*value = NULL;
2075 	scf_transaction_t *tran = NULL;
2076 	scf_transaction_entry_t *entry = NULL;
2077 	char iPersistTypeGet[MAXNAMELEN] = {0};
2078 	char *iPersistType;
2079 	int ret = STMF_PS_SUCCESS;
2080 	int commitRet;
2081 
2082 	if (((pg = scf_pg_create(handle)) == NULL) ||
2083 	    ((prop = scf_property_create(handle)) == NULL) ||
2084 	    ((entry = scf_entry_create(handle)) == NULL) ||
2085 	    ((tran = scf_transaction_create(handle)) == NULL) ||
2086 	    ((value = scf_value_create(handle)) == NULL)) {
2087 		syslog(LOG_ERR, "scf alloc resource failed - %s",
2088 		    scf_strerror(scf_error()));
2089 		ret = STMF_PS_ERROR;
2090 		goto out;
2091 	}
2092 
2093 	if (getSet == GET) {
2094 		/* set to default */
2095 		*persistType = STMF_PERSIST_SMF;
2096 		iPersistType = STMF_PS_PERSIST_SMF;
2097 	}
2098 
2099 	if (getSet == SET) {
2100 		if (*persistType == STMF_PERSIST_SMF) {
2101 			iPersistType = STMF_PS_PERSIST_SMF;
2102 		} else if (*persistType == STMF_PERSIST_NONE) {
2103 			iPersistType = STMF_PS_PERSIST_NONE;
2104 		} else {
2105 			ret = STMF_PS_ERROR;
2106 			goto out;
2107 		}
2108 	}
2109 
2110 	/*
2111 	 * get stmf data property group
2112 	 */
2113 	if (scf_service_get_pg(svc, STMF_DATA_GROUP, pg) == -1) {
2114 		if (scf_error() == SCF_ERROR_NOT_FOUND) {
2115 			ret = STMF_PS_ERROR_NOT_FOUND;
2116 		} else {
2117 			ret = STMF_PS_ERROR;
2118 		}
2119 		syslog(LOG_ERR, "get pg %s failed - %s",
2120 		    STMF_DATA_GROUP, scf_strerror(scf_error()));
2121 
2122 		goto out;
2123 	}
2124 
2125 	/* find persistence property */
2126 	/*
2127 	 * Get the persistence property
2128 	 */
2129 	if (scf_pg_get_property(pg, STMF_PERSIST_TYPE, prop) == -1) {
2130 		if (scf_error() == SCF_ERROR_NOT_FOUND) {
2131 			ret = STMF_PS_ERROR_NOT_FOUND;
2132 		} else {
2133 			syslog(LOG_ERR, "get property %s/%s failed - %s",
2134 			    STMF_DATA_GROUP, STMF_PERSIST_TYPE,
2135 			    scf_strerror(scf_error()));
2136 			ret = STMF_PS_ERROR;
2137 			goto out;
2138 		}
2139 	}
2140 
2141 	/* no persist property found */
2142 	if (ret == STMF_PS_ERROR_NOT_FOUND || getSet == SET) {
2143 		/*
2144 		 * If we have no persistType property, go ahead
2145 		 * and create it with the user specified value or
2146 		 * the default value.
2147 		 */
2148 		/*
2149 		 * Begin the transaction
2150 		 */
2151 		if (scf_transaction_start(tran, pg) == -1) {
2152 			syslog(LOG_ERR, "start transaction for %s failed - %s",
2153 			    STMF_DATA_GROUP, scf_strerror(scf_error()));
2154 			ret = STMF_PS_ERROR;
2155 			goto out;
2156 		}
2157 
2158 		/* is this a SET or GET w/error? */
2159 		if (ret) {
2160 			if (scf_transaction_property_new(tran, entry,
2161 			    STMF_PERSIST_TYPE, SCF_TYPE_ASTRING) == -1) {
2162 				syslog(LOG_ERR, "transaction property new "
2163 				    "%s/%s failed - %s", STMF_DATA_GROUP,
2164 				    STMF_PERSIST_TYPE,
2165 				    scf_strerror(scf_error()));
2166 				ret = STMF_PS_ERROR;
2167 				goto out;
2168 			}
2169 		} else {
2170 			if (scf_transaction_property_change(tran, entry,
2171 			    STMF_PERSIST_TYPE, SCF_TYPE_ASTRING) == -1) {
2172 				syslog(LOG_ERR, "transaction property change "
2173 				    "%s/%s failed - %s", STMF_DATA_GROUP,
2174 				    STMF_PERSIST_TYPE,
2175 				    scf_strerror(scf_error()));
2176 				ret = STMF_PS_ERROR;
2177 				goto out;
2178 			}
2179 		}
2180 
2181 		/*
2182 		 * set the persist type
2183 		 */
2184 		if (scf_value_set_astring(value, iPersistType) == -1) {
2185 			syslog(LOG_ERR, "set value %s/%s failed - %s",
2186 			    STMF_DATA_GROUP, STMF_PERSIST_TYPE,
2187 			    scf_strerror(scf_error()));
2188 			ret = STMF_PS_ERROR;
2189 			goto out;
2190 		}
2191 
2192 		/*
2193 		 * add the value to the transaction
2194 		 */
2195 		if (scf_entry_add_value(entry, value) == -1) {
2196 			syslog(LOG_ERR, "add value %s/%s failed - %s",
2197 			    STMF_DATA_GROUP, STMF_PERSIST_TYPE,
2198 			    scf_strerror(scf_error()));
2199 			ret = STMF_PS_ERROR;
2200 			goto out;
2201 		}
2202 		if ((commitRet = scf_transaction_commit(tran)) != 1) {
2203 			syslog(LOG_ERR, "transaction commit for %s failed - %s",
2204 			    STMF_DATA_GROUP, scf_strerror(scf_error()));
2205 			if (commitRet == 0) {
2206 				ret = STMF_PS_ERROR_BUSY;
2207 			} else {
2208 				ret = STMF_PS_ERROR;
2209 			}
2210 			goto out;
2211 		}
2212 		/* reset return value */
2213 		ret = STMF_PS_SUCCESS;
2214 	} else if (getSet == GET) {
2215 		/* get the persist property */
2216 		if (scf_property_get_value(prop, value) == -1) {
2217 			syslog(LOG_ERR, "get property value %s/%s failed - %s",
2218 			    STMF_DATA_GROUP, STMF_PERSIST_TYPE,
2219 			    scf_strerror(scf_error()));
2220 			ret = STMF_PS_ERROR;
2221 			goto out;
2222 		}
2223 
2224 		/*
2225 		 * Get the value of the persist property
2226 		 */
2227 		if (scf_value_get_astring(value, iPersistTypeGet, MAXNAMELEN)
2228 		    == -1) {
2229 			syslog(LOG_ERR, "get string value %s/%s failed - %s",
2230 			    STMF_DATA_GROUP, STMF_PERSIST_TYPE,
2231 			    scf_strerror(scf_error()));
2232 			ret = STMF_PS_ERROR;
2233 			goto out;
2234 		}
2235 	}
2236 
2237 	if (getSet == GET) {
2238 		if (strcmp(iPersistTypeGet, STMF_PS_PERSIST_NONE) == 0) {
2239 			*persistType = STMF_PERSIST_NONE;
2240 		} else if (strcmp(iPersistTypeGet, STMF_PS_PERSIST_SMF) == 0) {
2241 			*persistType = STMF_PERSIST_SMF;
2242 		} else {
2243 			ret = STMF_PS_ERROR;
2244 			goto out;
2245 		}
2246 	}
2247 out:
2248 	/*
2249 	 * Free resources.
2250 	 * handle and svc should not be free'd here. They're
2251 	 * free'd elsewhere
2252 	 */
2253 	if (pg != NULL) {
2254 		scf_pg_destroy(pg);
2255 	}
2256 	if (prop != NULL) {
2257 		scf_property_destroy(prop);
2258 	}
2259 	if (entry != NULL) {
2260 		scf_entry_destroy(entry);
2261 	}
2262 	if (tran != NULL) {
2263 		scf_transaction_destroy(tran);
2264 	}
2265 	if (value != NULL) {
2266 		scf_value_destroy(value);
2267 	}
2268 	return (ret);
2269 }
2270 
2271 int
2272 psSetStmfProp(int propType, char *propVal)
2273 {
2274 	return (iPsGetSetStmfProp(propType, propVal, SET));
2275 }
2276 
2277 int
2278 psGetStmfProp(int propType, char *propVal)
2279 {
2280 	return (iPsGetSetStmfProp(propType, propVal, GET));
2281 }
2282 
2283 static int
2284 iPsGetSetStmfProp(int propType, char *propVal, int getSet)
2285 {
2286 	scf_handle_t	*handle = NULL;
2287 	scf_service_t	*svc = NULL;
2288 	scf_property_t *prop = NULL;
2289 	scf_propertygroup_t	*pg = NULL;
2290 	scf_transaction_t *tran = NULL;
2291 	scf_transaction_entry_t *entry = NULL;
2292 	scf_value_t	*value = NULL;
2293 	char *psStmfPropVal = NULL;
2294 	char *psStmfProp = NULL;
2295 	char stmfPropGet[MAXNAMELEN] = {0};
2296 	int ret = STMF_PS_SUCCESS;
2297 	int commitRet;
2298 
2299 	if (propVal == NULL || (getSet != GET && getSet != SET)) {
2300 		ret = STMF_PS_ERROR;
2301 		goto out;
2302 	}
2303 
2304 	/*
2305 	 * Init the service handle
2306 	 */
2307 
2308 	ret = iPsInit(&handle, &svc);
2309 	if (ret != STMF_PS_SUCCESS) {
2310 		goto out;
2311 	}
2312 
2313 	/*
2314 	 * Allocate scf resources
2315 	 */
2316 
2317 	if (((pg = scf_pg_create(handle)) == NULL) ||
2318 	    ((prop = scf_property_create(handle)) == NULL) ||
2319 	    ((entry = scf_entry_create(handle)) == NULL) ||
2320 	    ((tran = scf_transaction_create(handle)) == NULL) ||
2321 	    ((value = scf_value_create(handle)) == NULL)) {
2322 		syslog(LOG_ERR, "scf alloc resource failed - %s",
2323 		    scf_strerror(scf_error()));
2324 		ret = STMF_PS_ERROR;
2325 		goto out;
2326 	}
2327 	if (getSet == GET) {
2328 		switch (propType) {
2329 			case STMF_DEFAULT_LU_STATE :
2330 				psStmfProp = DEFAULT_LU_STATE;
2331 				psStmfPropVal = STMF_PS_LU_ONLINE;
2332 				(void) strcpy(stmfPropGet, psStmfPropVal);
2333 				break;
2334 			case STMF_DEFAULT_TARGET_PORT_STATE :
2335 				psStmfProp = DEFAULT_TARGET_PORT_STATE;
2336 				psStmfPropVal = STMF_PS_TARGET_PORT_ONLINE;
2337 				(void) strcpy(stmfPropGet, psStmfPropVal);
2338 				break;
2339 			default :
2340 				ret = STMF_PS_ERROR;
2341 				goto out;
2342 		}
2343 	}
2344 	if (getSet == SET) {
2345 		switch (propType) {
2346 			case STMF_DEFAULT_LU_STATE :
2347 				psStmfProp = DEFAULT_LU_STATE;
2348 				if (strcasecmp(propVal, "online") == 0) {
2349 					psStmfPropVal = STMF_PS_LU_ONLINE;
2350 				} else if (strcasecmp(propVal,
2351 				    "offline") == 0) {
2352 					psStmfPropVal = STMF_PS_LU_OFFLINE;
2353 				} else {
2354 					ret = STMF_PS_ERROR;
2355 					goto out;
2356 				}
2357 				break;
2358 			case STMF_DEFAULT_TARGET_PORT_STATE :
2359 				psStmfProp = DEFAULT_TARGET_PORT_STATE;
2360 				if (strcasecmp(propVal, "online") == 0) {
2361 					psStmfPropVal =
2362 					    STMF_PS_TARGET_PORT_ONLINE;
2363 				} else if (strcasecmp(propVal,
2364 				    "offline") == 0) {
2365 					psStmfPropVal =
2366 					    STMF_PS_TARGET_PORT_OFFLINE;
2367 				} else {
2368 					ret = STMF_PS_ERROR;
2369 					goto out;
2370 				}
2371 				break;
2372 			default :
2373 				ret = STMF_PS_ERROR;
2374 				goto out;
2375 		}
2376 	}
2377 
2378 	/*
2379 	 * get stmf data property group
2380 	 */
2381 
2382 	if (scf_service_get_pg(svc, STMF_DATA_GROUP, pg) == -1) {
2383 		if (scf_error() == SCF_ERROR_NOT_FOUND) {
2384 			ret = STMF_PS_ERROR_NOT_FOUND;
2385 		} else {
2386 			ret = STMF_PS_ERROR;
2387 		}
2388 		syslog(LOG_ERR, "get pg %s failed - %s",
2389 		    STMF_DATA_GROUP, scf_strerror(scf_error()));
2390 		goto out;
2391 	}
2392 
2393 	/*
2394 	 * get the stmf props property, if exists
2395 	 */
2396 
2397 	if (scf_pg_get_property(pg, psStmfProp, prop) == -1) {
2398 		if (scf_error() == SCF_ERROR_NOT_FOUND) {
2399 			ret = STMF_PS_ERROR_NOT_FOUND;
2400 		} else {
2401 			syslog(LOG_ERR, "start transaction for %s/%s "
2402 			    "failed - %s", STMF_DATA_GROUP, psStmfProp,
2403 			    scf_strerror(scf_error()));
2404 			ret = STMF_PS_ERROR;
2405 			goto out;
2406 		}
2407 	}
2408 
2409 	/* if stmf prop is not found or while setting the prop */
2410 
2411 	if (ret == STMF_PS_ERROR_NOT_FOUND || getSet == SET) {
2412 		/*
2413 		 * Begin the transaction
2414 		 */
2415 		if (scf_transaction_start(tran, pg) == -1) {
2416 			syslog(LOG_ERR, "start transaction for %s failed - %s",
2417 			    STMF_DATA_GROUP, scf_strerror(scf_error()));
2418 			ret = STMF_PS_ERROR;
2419 			goto out;
2420 		}
2421 		if (ret) {
2422 			if (scf_transaction_property_new(tran, entry,
2423 			    psStmfProp, SCF_TYPE_ASTRING) == -1) {
2424 				syslog(LOG_ERR, "transaction property new "
2425 				    "%s/%s failed - %s", STMF_DATA_GROUP,
2426 				    psStmfProp, scf_strerror(scf_error()));
2427 				ret = STMF_PS_ERROR;
2428 				goto out;
2429 			}
2430 		} else {
2431 			if (scf_transaction_property_change(tran, entry,
2432 			    psStmfProp, SCF_TYPE_ASTRING) == -1) {
2433 					syslog(LOG_ERR,
2434 					    "transaction property change "
2435 					    "%s/%s failed - %s",
2436 					    STMF_DATA_GROUP, psStmfProp,
2437 					    scf_strerror(scf_error()));
2438 					ret = STMF_PS_ERROR;
2439 					goto out;
2440 			}
2441 		}
2442 
2443 		/*
2444 		 * set stmf prop value
2445 		 */
2446 
2447 		if (scf_value_set_astring(value, psStmfPropVal) == -1) {
2448 			syslog(LOG_ERR, "set value %s/%s failed - %s",
2449 			    STMF_DATA_GROUP, psStmfProp,
2450 			    scf_strerror(scf_error()));
2451 			ret = STMF_PS_ERROR;
2452 			goto out;
2453 		}
2454 
2455 		/*
2456 		 * add the value to the transaction
2457 		 */
2458 
2459 		if (scf_entry_add_value(entry, value) == -1) {
2460 			syslog(LOG_ERR, "add value %s/%s failed - %s",
2461 			    STMF_DATA_GROUP, psStmfProp,
2462 			    scf_strerror(scf_error()));
2463 			ret = STMF_PS_ERROR;
2464 			goto out;
2465 		}
2466 		if ((commitRet = scf_transaction_commit(tran)) != 1) {
2467 			syslog(LOG_ERR, "transaction commit for %s"
2468 			    "failed - %s", STMF_DATA_GROUP,
2469 			    scf_strerror(scf_error()));
2470 			if (commitRet == 0) {
2471 				ret = STMF_PS_ERROR_BUSY;
2472 			} else {
2473 				ret = STMF_PS_ERROR;
2474 			}
2475 			goto out;
2476 		}
2477 		ret = STMF_PS_SUCCESS;
2478 	} else if (getSet == GET) {
2479 		if (scf_property_get_value(prop, value) == -1) {
2480 			syslog(LOG_ERR, "get property value "
2481 			    "%s/%s failed - %s",
2482 			    STMF_DATA_GROUP, psStmfProp,
2483 			    scf_strerror(scf_error()));
2484 			ret = STMF_PS_ERROR;
2485 			goto out;
2486 		}
2487 
2488 		/* get stmfProp */
2489 
2490 		if (scf_value_get_astring(value, stmfPropGet, MAXNAMELEN)
2491 		    == -1) {
2492 			syslog(LOG_ERR, "get string value %s/%s failed - %s",
2493 			    STMF_DATA_GROUP, psStmfProp,
2494 			    scf_strerror(scf_error()));
2495 			ret = STMF_PS_ERROR;
2496 			goto out;
2497 		}
2498 	}
2499 	if (getSet == GET) {
2500 		if (strcmp(stmfPropGet, STMF_PS_LU_ONLINE) == 0) {
2501 			(void) strcpy(propVal, "online");
2502 		} else if (strcmp(stmfPropGet, STMF_PS_LU_OFFLINE) == 0) {
2503 			(void) strcpy(propVal, "offline");
2504 		} else if (strcmp(stmfPropGet, STMF_PS_TARGET_PORT_ONLINE)
2505 		    == 0) {
2506 			(void) strcpy(propVal, "online");
2507 		} else if (strcmp(stmfPropGet, STMF_PS_TARGET_PORT_OFFLINE)
2508 		    == 0) {
2509 			(void) strcpy(propVal, "offline");
2510 		} else {
2511 			ret = STMF_PS_ERROR;
2512 			goto out;
2513 		}
2514 	}
2515 out:
2516 	/*
2517 	 * Free resources.
2518 	 */
2519 
2520 	if (handle != NULL) {
2521 		scf_handle_destroy(handle);
2522 	}
2523 	if (svc != NULL) {
2524 		scf_service_destroy(svc);
2525 	}
2526 	if (pg != NULL) {
2527 		scf_pg_destroy(pg);
2528 	}
2529 	if (prop != NULL) {
2530 		scf_property_destroy(prop);
2531 	}
2532 	if (entry != NULL) {
2533 		scf_entry_destroy(entry);
2534 	}
2535 	if (tran != NULL) {
2536 		scf_transaction_destroy(tran);
2537 	}
2538 	if (value != NULL) {
2539 		scf_value_destroy(value);
2540 	}
2541 	return (ret);
2542 }
2543 
2544 /*
2545  * Initialize scf stmf service access
2546  * handle - returned handle
2547  * service - returned service handle
2548  *
2549  * Both handle and service must be destroyed by the caller
2550  */
2551 static int
2552 iPsInit(scf_handle_t **handle, scf_service_t **service)
2553 {
2554 	scf_scope_t	*scope = NULL;
2555 	uint64_t version;
2556 	int ret;
2557 
2558 	assert(handle != NULL && service != NULL);
2559 
2560 	if ((*handle = scf_handle_create(SCF_VERSION)) == NULL) {
2561 		syslog(LOG_ERR, "scf_handle_create failed - %s",
2562 		    scf_strerror(scf_error()));
2563 		ret = STMF_PS_ERROR;
2564 		goto err;
2565 	}
2566 
2567 	if (scf_handle_bind(*handle) == -1) {
2568 		syslog(LOG_ERR, "scf_handle_bind failed - %s",
2569 		    scf_strerror(scf_error()));
2570 		ret = STMF_PS_ERROR;
2571 		goto err;
2572 	}
2573 
2574 	if ((*service = scf_service_create(*handle)) == NULL) {
2575 		syslog(LOG_ERR, "scf_service_create failed - %s",
2576 		    scf_strerror(scf_error()));
2577 		ret = STMF_PS_ERROR;
2578 		goto err;
2579 	}
2580 
2581 	if ((scope = scf_scope_create(*handle)) == NULL) {
2582 		syslog(LOG_ERR, "scf_scope_create failed - %s",
2583 		    scf_strerror(scf_error()));
2584 		ret = STMF_PS_ERROR;
2585 		goto err;
2586 	}
2587 
2588 	if (scf_handle_get_scope(*handle, SCF_SCOPE_LOCAL, scope) == -1) {
2589 		syslog(LOG_ERR, "scf_handle_get_scope failed - %s",
2590 		    scf_strerror(scf_error()));
2591 		ret = STMF_PS_ERROR;
2592 		goto err;
2593 	}
2594 
2595 	if (scf_scope_get_service(scope, STMF_SERVICE, *service) == -1) {
2596 		syslog(LOG_ERR, "scf_scope_get_service failed - %s",
2597 		    scf_strerror(scf_error()));
2598 		ret = STMF_PS_ERROR_SERVICE_NOT_FOUND;
2599 		goto err;
2600 	}
2601 
2602 
2603 	/*
2604 	 * Get and check the version number
2605 	 */
2606 	ret = iPsGetServiceVersion(&version, *handle, *service);
2607 	if (ret != STMF_PS_SUCCESS) {
2608 		goto err;
2609 	}
2610 
2611 	if (version != STMF_SMF_VERSION) {
2612 		ret = STMF_PS_ERROR_VERSION_MISMATCH;
2613 		goto err;
2614 	}
2615 
2616 	/* we only need destroy the scope here */
2617 	scf_scope_destroy(scope);
2618 
2619 	return (STMF_PS_SUCCESS);
2620 
2621 err:
2622 	if (*handle != NULL) {
2623 		scf_handle_destroy(*handle);
2624 	}
2625 	if (*service != NULL) {
2626 		scf_service_destroy(*service);
2627 		*service = NULL;
2628 	}
2629 	if (scope != NULL) {
2630 		scf_scope_destroy(scope);
2631 	}
2632 	return (ret);
2633 }
2634 
2635 
2636 /*
2637  * called by iPsInit only
2638  * iPsGetServiceVersion
2639  */
2640 static int
2641 iPsGetServiceVersion(uint64_t *version, scf_handle_t *handle,
2642     scf_service_t *svc)
2643 {
2644 	scf_propertygroup_t	*pg = NULL;
2645 	scf_property_t	*prop = NULL;
2646 	scf_value_t	*value = NULL;
2647 	scf_transaction_t *tran = NULL;
2648 	scf_transaction_entry_t *entry = NULL;
2649 	int ret = STMF_PS_SUCCESS;
2650 	int commitRet;
2651 
2652 	if (((pg = scf_pg_create(handle)) == NULL) ||
2653 	    ((prop = scf_property_create(handle)) == NULL) ||
2654 	    ((entry = scf_entry_create(handle)) == NULL) ||
2655 	    ((tran = scf_transaction_create(handle)) == NULL) ||
2656 	    ((value = scf_value_create(handle)) == NULL)) {
2657 		syslog(LOG_ERR, "scf alloc resource failed - %s",
2658 		    scf_strerror(scf_error()));
2659 		ret = STMF_PS_ERROR;
2660 		goto out;
2661 	}
2662 
2663 	*version = STMF_SMF_VERSION;
2664 
2665 	/*
2666 	 * get stmf data property group
2667 	 */
2668 	if (scf_service_get_pg(svc, STMF_DATA_GROUP, pg) == -1) {
2669 		if (scf_error() == SCF_ERROR_NOT_FOUND) {
2670 			ret = STMF_PS_ERROR_NOT_FOUND;
2671 		} else {
2672 			syslog(LOG_ERR, "get pg %s failed - %s",
2673 			    STMF_DATA_GROUP, scf_strerror(scf_error()));
2674 			ret = STMF_PS_ERROR;
2675 			goto out;
2676 		}
2677 	}
2678 
2679 	/* create the group */
2680 	if (ret == STMF_PS_ERROR_NOT_FOUND) {
2681 		/*
2682 		 * create the property group.
2683 		 */
2684 		if (scf_service_add_pg(svc, STMF_DATA_GROUP,
2685 		    SCF_GROUP_APPLICATION, 0, pg) == -1) {
2686 			syslog(LOG_ERR, "add pg %s failed - %s",
2687 			    STMF_DATA_GROUP, scf_strerror(scf_error()));
2688 			ret = STMF_PS_ERROR;
2689 			goto out;
2690 		}
2691 		/* reset return value */
2692 		ret = STMF_PS_SUCCESS;
2693 	}
2694 
2695 	/* find version property */
2696 	/*
2697 	 * Get the version property
2698 	 */
2699 	if (scf_pg_get_property(pg, STMF_VERSION_NAME, prop) == -1) {
2700 		if (scf_error() == SCF_ERROR_NOT_FOUND) {
2701 			ret = STMF_PS_ERROR_NOT_FOUND;
2702 		} else {
2703 			syslog(LOG_ERR, "get property %s/%s failed - %s",
2704 			    STMF_DATA_GROUP, STMF_VERSION_NAME,
2705 			    scf_strerror(scf_error()));
2706 			ret = STMF_PS_ERROR;
2707 			goto out;
2708 		}
2709 	}
2710 
2711 	/* no version property found */
2712 	if (ret == STMF_PS_ERROR_NOT_FOUND) {
2713 		/*
2714 		 * If we have no version property, go ahead
2715 		 * and create it. We're obviously making an assumption
2716 		 * here that someone did not delete the existing property
2717 		 * and that this is the initial set and the initial call
2718 		 * to iPsInit.
2719 		 * If they did delete it, this will simply plant this
2720 		 * library's version on this service. That may or may not be
2721 		 * correct and we have no way of determining that.
2722 		 */
2723 		/*
2724 		 * Begin the transaction
2725 		 */
2726 		if (scf_transaction_start(tran, pg) == -1) {
2727 			syslog(LOG_ERR, "start transaction for %s failed - %s",
2728 			    STMF_DATA_GROUP, scf_strerror(scf_error()));
2729 			ret = STMF_PS_ERROR;
2730 			goto out;
2731 		}
2732 
2733 		if (scf_transaction_property_new(tran, entry,
2734 		    STMF_VERSION_NAME, SCF_TYPE_COUNT) == -1) {
2735 			syslog(LOG_ERR,
2736 			    "transaction property new %s/%s failed - %s",
2737 			    STMF_DATA_GROUP, STMF_VERSION_NAME,
2738 			    scf_strerror(scf_error()));
2739 			ret = STMF_PS_ERROR;
2740 			goto out;
2741 		}
2742 
2743 		/*
2744 		 * set the version number
2745 		 */
2746 		scf_value_set_count(value, *version);
2747 
2748 		/*
2749 		 * add the value to the transaction
2750 		 */
2751 		if (scf_entry_add_value(entry, value) == -1) {
2752 			syslog(LOG_ERR, "add value %s/%s failed - %s",
2753 			    STMF_DATA_GROUP, STMF_VERSION_NAME,
2754 			    scf_strerror(scf_error()));
2755 			ret = STMF_PS_ERROR;
2756 			goto out;
2757 		}
2758 		if ((commitRet = scf_transaction_commit(tran)) != 1) {
2759 			syslog(LOG_ERR, "transaction commit for %s failed - %s",
2760 			    STMF_DATA_GROUP, scf_strerror(scf_error()));
2761 			if (commitRet == 0) {
2762 				ret = STMF_PS_ERROR_BUSY;
2763 			} else {
2764 				ret = STMF_PS_ERROR;
2765 			}
2766 			goto out;
2767 		}
2768 		/* reset return value */
2769 		ret = STMF_PS_SUCCESS;
2770 	} else {
2771 		/* get the version property */
2772 		if (scf_pg_get_property(pg, STMF_VERSION_NAME, prop) == -1) {
2773 			syslog(LOG_ERR, "get property %s/%s failed - %s",
2774 			    STMF_DATA_GROUP, STMF_VERSION_NAME,
2775 			    scf_strerror(scf_error()));
2776 			ret = STMF_PS_ERROR;
2777 			goto out;
2778 		}
2779 
2780 		if (scf_property_get_value(prop, value) == -1) {
2781 			syslog(LOG_ERR, "get property value %s/%s failed - %s",
2782 			    STMF_DATA_GROUP, STMF_VERSION_NAME,
2783 			    scf_strerror(scf_error()));
2784 			ret = STMF_PS_ERROR;
2785 			goto out;
2786 		}
2787 
2788 		/*
2789 		 * Get the actual value of the view entry count property
2790 		 */
2791 		if (scf_value_get_count(value, version) == -1) {
2792 			syslog(LOG_ERR, "get count value %s/%s failed - %s",
2793 			    STMF_DATA_GROUP, STMF_VERSION_NAME,
2794 			    scf_strerror(scf_error()));
2795 			ret = STMF_PS_ERROR;
2796 			goto out;
2797 		}
2798 	}
2799 
2800 out:
2801 	/*
2802 	 * Free resources.
2803 	 * handle and svc should not be free'd here. They're
2804 	 * free'd elsewhere
2805 	 */
2806 	if (pg != NULL) {
2807 		scf_pg_destroy(pg);
2808 	}
2809 	if (prop != NULL) {
2810 		scf_property_destroy(prop);
2811 	}
2812 	if (entry != NULL) {
2813 		scf_entry_destroy(entry);
2814 	}
2815 	if (tran != NULL) {
2816 		scf_transaction_destroy(tran);
2817 	}
2818 	if (value != NULL) {
2819 		scf_value_destroy(value);
2820 	}
2821 	return (ret);
2822 }
2823 
2824 
2825 
2826 /*
2827  * iPsGetActualGroupName
2828  *
2829  * pgName - Property group name
2830  * groupName - requested group name
2831  * actualName - actual group name to reference (len must be >= MAXNAMELEN)
2832  *
2833  * returns:
2834  *  STMF_PS_SUCCESS on success
2835  *  STMF_PS_ERROR_* on failure
2836  */
2837 static int
2838 iPsGetActualGroupName(char *pgName, char *groupName, char *actualName)
2839 {
2840 	scf_handle_t	*handle = NULL;
2841 	scf_service_t	*svc = NULL;
2842 	scf_propertygroup_t	*pg = NULL;
2843 	scf_property_t	*prop = NULL;
2844 	scf_iter_t	*propIter = NULL;
2845 	scf_value_t	*value = NULL;
2846 	char buf[MAXNAMELEN];
2847 	int ret;
2848 
2849 	ret = iPsInit(&handle, &svc);
2850 	if (ret != STMF_PS_SUCCESS) {
2851 		goto out;
2852 	}
2853 
2854 	/*
2855 	 * Allocate scf resources
2856 	 */
2857 	if (((pg = scf_pg_create(handle)) == NULL) ||
2858 	    ((prop = scf_property_create(handle)) == NULL) ||
2859 	    ((propIter = scf_iter_create(handle)) == NULL) ||
2860 	    ((value = scf_value_create(handle)) == NULL)) {
2861 		syslog(LOG_ERR, "scf alloc resource failed - %s",
2862 		    scf_strerror(scf_error()));
2863 		ret = STMF_PS_ERROR;
2864 		goto out;
2865 	}
2866 
2867 	/*
2868 	 * get group list property group
2869 	 */
2870 	if (scf_service_get_pg(svc, pgName, pg) == -1) {
2871 		if (scf_error() == SCF_ERROR_NOT_FOUND) {
2872 			ret = STMF_PS_ERROR_GROUP_NOT_FOUND;
2873 		} else {
2874 			syslog(LOG_ERR, "get pg %s failed - %s",
2875 			    pgName, scf_strerror(scf_error()));
2876 			ret = STMF_PS_ERROR;
2877 		}
2878 		goto out;
2879 	}
2880 
2881 	/*
2882 	 * propIter is the iterator handle
2883 	 */
2884 	if (scf_iter_pg_properties(propIter, pg) == -1) {
2885 		syslog(LOG_ERR, "iter properties for %s failed - %s",
2886 		    pgName, scf_strerror(scf_error()));
2887 		ret = STMF_PS_ERROR;
2888 		goto out;
2889 	}
2890 
2891 	/*
2892 	 * Iterate through group properties searching for the requested
2893 	 * group name. When we find it, we need to get the property name
2894 	 * since it refers to the actual group name.
2895 	 */
2896 
2897 	/* initialize to not found */
2898 	ret = STMF_PS_ERROR_GROUP_NOT_FOUND;
2899 	while (scf_iter_next_property(propIter, prop) == 1) {
2900 		if (scf_property_get_name(prop, actualName, MAXNAMELEN) == -1) {
2901 			syslog(LOG_ERR, "get name from %s iter failed - %s",
2902 			    pgName, scf_strerror(scf_error()));
2903 			ret = STMF_PS_ERROR;
2904 			break;
2905 		}
2906 		/*
2907 		 * Skip over non-member list properties
2908 		 */
2909 		if (strstr(actualName, STMF_MEMBER_LIST_SUFFIX)) {
2910 			continue;
2911 		}
2912 		if (scf_property_get_value(prop, value) == -1) {
2913 			syslog(LOG_ERR, "get property value %s/%s failed - %s",
2914 			    pgName, actualName, scf_strerror(scf_error()));
2915 			ret = STMF_PS_ERROR;
2916 			break;
2917 		}
2918 		if (scf_value_get_ustring(value, buf, sizeof (buf)) == -1) {
2919 			syslog(LOG_ERR, "get ustring %s/%s failed - %s",
2920 			    pgName, actualName, scf_strerror(scf_error()));
2921 			ret = STMF_PS_ERROR;
2922 			break;
2923 		}
2924 
2925 		/*
2926 		 * When we find a match, set success and break
2927 		 */
2928 		if ((strlen(buf) == strlen(groupName)) &&
2929 		    bcmp(buf, groupName, strlen(buf)) == 0) {
2930 			ret = STMF_PS_SUCCESS;
2931 			break;
2932 		}
2933 	}
2934 
2935 	/*
2936 	 * if we didn't find it, ret is set to STMF_PS_ERROR_GROUP_NOT_FOUND
2937 	 */
2938 
2939 out:
2940 	/*
2941 	 * Free resources
2942 	 */
2943 	if (handle != NULL) {
2944 		scf_handle_destroy(handle);
2945 	}
2946 	if (svc != NULL) {
2947 		scf_service_destroy(svc);
2948 	}
2949 	if (pg != NULL) {
2950 		scf_pg_destroy(pg);
2951 	}
2952 	if (propIter != NULL) {
2953 		scf_iter_destroy(propIter);
2954 	}
2955 	if (prop != NULL) {
2956 		scf_property_destroy(prop);
2957 	}
2958 	if (value != NULL) {
2959 		scf_value_destroy(value);
2960 	}
2961 
2962 	return (ret);
2963 }
2964 
2965 /*
2966  * psAddHostGroupMember
2967  *
2968  * Add a host group member to a host group,
2969  *
2970  * Input: groupName - name of group to which the member is added
2971  *        memberName - name of group member to add
2972  */
2973 int
2974 psAddHostGroupMember(char *groupName, char *memberName)
2975 {
2976 	int ret;
2977 	char groupPropListName[MAXNAMELEN];
2978 	char groupPropName[MAXNAMELEN];
2979 
2980 	ret = iPsGetActualGroupName(STMF_HOST_GROUPS, groupName,
2981 	    groupPropName);
2982 	if (ret != STMF_PS_SUCCESS) {
2983 		return (ret);
2984 	}
2985 
2986 	if (snprintf(groupPropListName, sizeof (groupPropListName),
2987 	    "%s-%s", groupPropName, STMF_MEMBER_LIST_SUFFIX) >
2988 	    sizeof (groupPropListName)) {
2989 		syslog(LOG_ERR, "buffer overflow on property name %s",
2990 		    groupPropName);
2991 		return (STMF_PS_ERROR);
2992 	}
2993 
2994 	return (iPsAddRemoveGroupMember(STMF_HOST_GROUPS, groupPropListName,
2995 	    memberName, ADD));
2996 }
2997 
2998 /*
2999  * psAddTargetGroupMember
3000  *
3001  * Add a target port group member to a target group
3002  *
3003  * Input: groupName - name of group to which the member is added
3004  *        memberName - name of group member to add. Must be nul terminated.
3005  */
3006 int
3007 psAddTargetGroupMember(char *groupName, char *memberName)
3008 {
3009 	int ret;
3010 	char groupPropListName[MAXNAMELEN];
3011 	char groupPropName[MAXNAMELEN];
3012 
3013 	ret = iPsGetActualGroupName(STMF_TARGET_GROUPS, groupName,
3014 	    groupPropName);
3015 	if (ret != STMF_PS_SUCCESS) {
3016 		return (ret);
3017 	}
3018 
3019 	if (snprintf(groupPropListName, sizeof (groupPropListName),
3020 	    "%s-%s", groupPropName, STMF_MEMBER_LIST_SUFFIX) >
3021 	    sizeof (groupPropListName)) {
3022 		syslog(LOG_ERR, "buffer overflow on property name %s",
3023 		    groupPropName);
3024 		return (STMF_PS_ERROR);
3025 	}
3026 
3027 	return (iPsAddRemoveGroupMember(STMF_TARGET_GROUPS, groupPropListName,
3028 	    memberName, ADD));
3029 }
3030 
3031 
3032 /*
3033  * psAddViewEntry
3034  *
3035  * luGuid - logical unit identifier
3036  * viewEntry - pointer to viewEntry allocated by the caller that contains
3037  *             the values to set for this view entry
3038  *
3039  * returns:
3040  *  STMF_PS_SUCCESS on success
3041  *  STMF_PS_ERROR_* on failure
3042  */
3043 int
3044 psAddViewEntry(stmfGuid *lu, stmfViewEntry *viewEntry)
3045 {
3046 	scf_handle_t	*handle = NULL;
3047 	scf_service_t	*svc = NULL;
3048 	scf_propertygroup_t	*pg = NULL;
3049 	char guidAsciiBuf[33]; /* size of ascii hex 16 byte guid with NULL */
3050 	char viewEntryPgName[VIEW_ENTRY_PG_SIZE];
3051 	char scfLuPgName[LOGICAL_UNIT_PG_SIZE];
3052 	int ret = STMF_PS_SUCCESS;
3053 	sigset_t sigmaskRestore;
3054 
3055 	/* grab the signal hold lock */
3056 	(void) pthread_mutex_lock(&sigSetLock);
3057 
3058 	/*
3059 	 * hold signals until we're done
3060 	 */
3061 	if (holdSignal(&sigmaskRestore) != 0) {
3062 		(void) pthread_mutex_unlock(&sigSetLock);
3063 		return (STMF_PS_ERROR);
3064 	}
3065 
3066 	ret = iPsInit(&handle, &svc);
3067 	if (ret != STMF_PS_SUCCESS) {
3068 		goto out;
3069 	}
3070 
3071 	pg = scf_pg_create(handle);
3072 	if (pg == NULL) {
3073 		syslog(LOG_ERR, "scf pg alloc failed - %s",
3074 		    scf_strerror(scf_error()));
3075 		ret = STMF_PS_ERROR;
3076 		goto out;
3077 	}
3078 
3079 	/* Convert to ASCII uppercase hexadecimal string */
3080 	(void) snprintf(guidAsciiBuf, sizeof (guidAsciiBuf),
3081 	    "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
3082 	    lu->guid[0], lu->guid[1], lu->guid[2], lu->guid[3], lu->guid[4],
3083 	    lu->guid[5], lu->guid[6], lu->guid[7], lu->guid[8], lu->guid[9],
3084 	    lu->guid[10], lu->guid[11], lu->guid[12], lu->guid[13],
3085 	    lu->guid[14], lu->guid[15]);
3086 
3087 	(void) snprintf(scfLuPgName, sizeof (scfLuPgName), "%s-%s",
3088 	    STMF_LU_PREFIX, guidAsciiBuf);
3089 
3090 	bzero(viewEntryPgName, sizeof (viewEntryPgName));
3091 	/*
3092 	 * Format of view entry property group name:
3093 	 *	VE-<view_entry_name>-<lu_name>
3094 	 */
3095 	(void) snprintf(viewEntryPgName, sizeof (viewEntryPgName),
3096 	    "%s-%d-%s", STMF_VE_PREFIX, viewEntry->veIndex, guidAsciiBuf);
3097 
3098 	ret = iPsAddViewEntry(scfLuPgName, viewEntryPgName, viewEntry);
3099 
3100 out:
3101 	/*
3102 	 * Okay, we're done. Release the signals
3103 	 */
3104 	if (releaseSignal(&sigmaskRestore) != 0) {
3105 		/*
3106 		 * Don't set this as an STMF_PS_ERROR_*. We succeeded
3107 		 * the requested operation. But we do need to log it.
3108 		 */
3109 		syslog(LOG_ERR, "Unable to release one or more signals - %s",
3110 		    strerror(errno));
3111 	}
3112 
3113 	/*
3114 	 * Free resources
3115 	 */
3116 	if (handle != NULL) {
3117 		scf_handle_destroy(handle);
3118 	}
3119 	if (svc != NULL) {
3120 		scf_service_destroy(svc);
3121 	}
3122 	if (pg != NULL) {
3123 		scf_pg_destroy(pg);
3124 	}
3125 
3126 	/* release the signal hold lock */
3127 	(void) pthread_mutex_unlock(&sigSetLock);
3128 
3129 	return (ret);
3130 }
3131 
3132 /*
3133  * psCheckService
3134  *
3135  * Purpose: Checks whether service exists
3136  *
3137  */
3138 int
3139 psCheckService()
3140 {
3141 	int ret;
3142 	scf_handle_t	*handle = NULL;
3143 	scf_service_t	*svc = NULL;
3144 
3145 	ret = iPsInit(&handle, &svc);
3146 
3147 	/*
3148 	 * Free resources
3149 	 */
3150 	if (handle != NULL) {
3151 		scf_handle_destroy(handle);
3152 	}
3153 	if (svc != NULL) {
3154 		scf_service_destroy(svc);
3155 	}
3156 
3157 	return (ret);
3158 }
3159 
3160 /*
3161  * psCreateHostGroup
3162  *
3163  * groupName - name of group to create
3164  *
3165  * returns:
3166  *  STMF_PS_SUCCESS on success
3167  *  STMF_PS_ERROR_* on failure
3168  */
3169 int
3170 psCreateHostGroup(char *groupName)
3171 {
3172 	return (iPsCreateDeleteGroup(STMF_HOST_GROUPS, groupName, ADD));
3173 }
3174 
3175 /*
3176  * psCreateTargetGroup
3177  *
3178  * groupName - name of group to create
3179  *
3180  * returns:
3181  *  STMF_PS_SUCCESS on success
3182  *  STMF_PS_ERROR_* on failure
3183  */
3184 int
3185 psCreateTargetGroup(char *groupName)
3186 {
3187 	return (iPsCreateDeleteGroup(STMF_TARGET_GROUPS, groupName, ADD));
3188 }
3189 
3190 /*
3191  * psDeleteHostGroup
3192  *
3193  * groupName - name of group to delete
3194  *
3195  * returns:
3196  *  STMF_PS_SUCCESS on success
3197  *  STMF_PS_ERROR_* on failure
3198  */
3199 int
3200 psDeleteHostGroup(char *groupName)
3201 {
3202 	return (iPsCreateDeleteGroup(STMF_HOST_GROUPS, groupName, REMOVE));
3203 }
3204 
3205 /*
3206  * psDeleteTargetGroup
3207  *
3208  * groupName - name of group to delete
3209  *
3210  * returns:
3211  *  STMF_PS_SUCCESS on success
3212  *  STMF_PS_ERROR_* on failure
3213  */
3214 int
3215 psDeleteTargetGroup(char *groupName)
3216 {
3217 	return (iPsCreateDeleteGroup(STMF_TARGET_GROUPS, groupName,
3218 	    REMOVE));
3219 }
3220 
3221 /*
3222  * psGetHostGroupList
3223  *
3224  * groupList - pointer to pointer to stmfGroupList. Contains the list
3225  *             of host groups on successful return.
3226  *
3227  * returns:
3228  *  STMF_PS_SUCCESS on success
3229  *  STMF_PS_ERROR_* on failure
3230  */
3231 int
3232 psGetHostGroupList(stmfGroupList **groupList)
3233 {
3234 	return (iPsGetGroupList(STMF_HOST_GROUPS, groupList));
3235 }
3236 
3237 /*
3238  * psGetLogicalUnitList
3239  *
3240  *
3241  */
3242 int
3243 psGetLogicalUnitList(stmfGuidList **guidList)
3244 {
3245 	scf_handle_t	*handle = NULL;
3246 	scf_service_t	*svc = NULL;
3247 	scf_propertygroup_t	*pg = NULL;
3248 	scf_iter_t	*pgIter = NULL;
3249 	char buf[MAXNAMELEN];
3250 	int guidCnt = 0;
3251 	int i = 0, j;
3252 	int ret = STMF_PS_SUCCESS;
3253 	unsigned int guid[sizeof (stmfGuid)];
3254 	stmfGuid outGuid;
3255 
3256 	assert(guidList != NULL);
3257 
3258 	ret = iPsInit(&handle, &svc);
3259 	if (ret != STMF_PS_SUCCESS) {
3260 		goto out;
3261 	}
3262 
3263 	/*
3264 	 * Allocate scf resources
3265 	 */
3266 	if (((pg = scf_pg_create(handle)) == NULL) ||
3267 	    ((pgIter = scf_iter_create(handle)) == NULL)) {
3268 		syslog(LOG_ERR, "scf alloc resource failed - %s",
3269 		    scf_strerror(scf_error()));
3270 		ret = STMF_PS_ERROR;
3271 		goto out;
3272 	}
3273 
3274 	/*
3275 	 * pgIter is the iterator handle
3276 	 */
3277 	if (scf_iter_service_pgs(pgIter, svc) == -1) {
3278 		syslog(LOG_ERR, "iter property groups failed - %s",
3279 		    scf_strerror(scf_error()));
3280 		ret = STMF_PS_ERROR;
3281 		goto out;
3282 	}
3283 
3284 	while (scf_iter_next_pg(pgIter, pg) == 1) {
3285 		if (scf_pg_get_name(pg, buf, sizeof (buf)) == -1) {
3286 			syslog(LOG_ERR, "get pg name failed - %s",
3287 			    scf_strerror(scf_error()));
3288 			ret = STMF_PS_ERROR;
3289 			break;
3290 		}
3291 		/*
3292 		 * Only count LU property groups
3293 		 */
3294 		if (strncmp(buf, STMF_LU_PREFIX, strlen(STMF_LU_PREFIX)) == 0) {
3295 			guidCnt++;
3296 		}
3297 	}
3298 
3299 	/*
3300 	 * pgIter is the iterator handle
3301 	 */
3302 	if (scf_iter_service_pgs(pgIter, svc) == -1) {
3303 		syslog(LOG_ERR, "iter property groups failed - %s",
3304 		    scf_strerror(scf_error()));
3305 		ret = STMF_PS_ERROR;
3306 		goto out;
3307 	}
3308 
3309 	*guidList = (stmfGuidList *)calloc(1, sizeof (stmfGuidList) +
3310 	    guidCnt * sizeof (stmfGuid));
3311 	if (*guidList == NULL) {
3312 		ret = STMF_PS_ERROR_NOMEM;
3313 		goto out;
3314 	}
3315 
3316 	/*
3317 	 * it's possible for entries to be added/removed while we're retrieving
3318 	 * the property groups. Just make sure we don't write beyond our
3319 	 * allocated buffer by checking to ensure i < guidCnt.
3320 	 */
3321 	while ((scf_iter_next_pg(pgIter, pg) == 1) && (i < guidCnt)) {
3322 		if (scf_pg_get_name(pg, buf, sizeof (buf)) == -1) {
3323 			syslog(LOG_ERR, "get pg name failed - %s",
3324 			    scf_strerror(scf_error()));
3325 			ret = STMF_PS_ERROR;
3326 			break;
3327 		}
3328 		/*
3329 		 * Only use LU property groups
3330 		 */
3331 		if (strncmp(buf, STMF_LU_PREFIX, strlen(STMF_LU_PREFIX)) != 0) {
3332 			continue;
3333 		}
3334 
3335 		j = strlen(STMF_LU_PREFIX) + strlen("-");
3336 
3337 		(void) sscanf(buf + j,
3338 		    "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
3339 		    &guid[0], &guid[1], &guid[2], &guid[3], &guid[4], &guid[5],
3340 		    &guid[6], &guid[7], &guid[8], &guid[9], &guid[10],
3341 		    &guid[11], &guid[12], &guid[13], &guid[14], &guid[15]);
3342 
3343 		for (j = 0; j < sizeof (stmfGuid); j++) {
3344 			outGuid.guid[j] = guid[j];
3345 		}
3346 
3347 		bcopy(&outGuid, (*guidList)->guid[i++].guid, sizeof (stmfGuid));
3348 		(*guidList)->cnt++;
3349 	}
3350 
3351 	if (ret != STMF_PS_SUCCESS) {
3352 		free(*guidList);
3353 		goto out;
3354 	}
3355 
3356 out:
3357 	/*
3358 	 * Free resources
3359 	 */
3360 	if (handle != NULL) {
3361 		scf_handle_destroy(handle);
3362 	}
3363 	if (svc != NULL) {
3364 		scf_service_destroy(svc);
3365 	}
3366 	if (pg != NULL) {
3367 		scf_pg_destroy(pg);
3368 	}
3369 	if (pgIter != NULL) {
3370 		scf_iter_destroy(pgIter);
3371 	}
3372 
3373 	return (ret);
3374 }
3375 
3376 /*
3377  * psGetTargetGroupList
3378  *
3379  * groupList - pointer to pointer to stmfGroupList. Contains the list
3380  *             of target groups on successful return.
3381  *
3382  * returns:
3383  *  STMF_PS_SUCCESS on success
3384  *  STMF_PS_ERROR_* on failure
3385  */
3386 int
3387 psGetTargetGroupList(stmfGroupList **groupList)
3388 {
3389 	return (iPsGetGroupList(STMF_TARGET_GROUPS, groupList));
3390 }
3391 
3392 /*
3393  * psGetHostGroupMemberList
3394  *
3395  * groupName - group name for which to retrieve a member list
3396  * groupMemberList - pointer to pointer to stmfGroupProperties list
3397  *
3398  * returns:
3399  *  STMF_PS_SUCCESS on success
3400  *  STMF_PS_ERROR_* on failure
3401  */
3402 int
3403 psGetHostGroupMemberList(char *groupName, stmfGroupProperties **groupMemberList)
3404 {
3405 	int ret;
3406 	char groupPropListName[MAXNAMELEN];
3407 	char groupPropName[MAXNAMELEN];
3408 
3409 	ret = iPsGetActualGroupName(STMF_HOST_GROUPS, groupName,
3410 	    groupPropName);
3411 	if (ret != STMF_PS_SUCCESS) {
3412 		return (ret);
3413 	}
3414 
3415 	if (snprintf(groupPropListName, sizeof (groupPropListName),
3416 	    "%s-%s", groupPropName, STMF_MEMBER_LIST_SUFFIX) >
3417 	    sizeof (groupPropListName)) {
3418 		syslog(LOG_ERR, "buffer overflow on property name %s",
3419 		    groupPropName);
3420 		return (STMF_PS_ERROR);
3421 	}
3422 
3423 	return (iPsGetGroupMemberList(STMF_HOST_GROUPS, groupPropListName,
3424 	    groupMemberList));
3425 }
3426 
3427 /*
3428  * psGetTargetGroupMemberList
3429  *
3430  * groupName - group name for which to retrieve a member list
3431  * groupMemberList - pointer to pointer to stmfGroupProperties list
3432  *
3433  * returns:
3434  *  STMF_PS_SUCCESS on success
3435  *  STMF_PS_ERROR_* on failure
3436  */
3437 int
3438 psGetTargetGroupMemberList(char *groupName,
3439     stmfGroupProperties **groupMemberList)
3440 {
3441 	int ret;
3442 	char groupPropListName[MAXNAMELEN];
3443 	char groupPropName[MAXNAMELEN];
3444 
3445 	ret = iPsGetActualGroupName(STMF_TARGET_GROUPS, groupName,
3446 	    groupPropName);
3447 	if (ret != STMF_PS_SUCCESS) {
3448 		return (ret);
3449 	}
3450 
3451 	if (snprintf(groupPropListName, sizeof (groupPropListName),
3452 	    "%s-%s", groupPropName, STMF_MEMBER_LIST_SUFFIX) >
3453 	    sizeof (groupPropListName)) {
3454 		syslog(LOG_ERR, "buffer overflow on property name %s",
3455 		    groupPropName);
3456 		return (STMF_PS_ERROR);
3457 	}
3458 
3459 	return (iPsGetGroupMemberList(STMF_TARGET_GROUPS,
3460 	    groupPropListName, groupMemberList));
3461 }
3462 
3463 /*
3464  * qsort function
3465  * sort on veIndex
3466  */
3467 static int
3468 viewEntryCompare(const void *p1, const void *p2)
3469 {
3470 
3471 	stmfViewEntry *v1 = (stmfViewEntry *)p1, *v2 = (stmfViewEntry *)p2;
3472 	if (v1->veIndex > v2->veIndex)
3473 		return (1);
3474 	if (v1->veIndex < v2->veIndex)
3475 		return (-1);
3476 	return (0);
3477 }
3478 
3479 /*
3480  * psGetViewEntryList
3481  *
3482  * luGuid - identifier of logical unit for which to retrieve a view entry list
3483  * viewEntryList - pointer to pointer to stmfViewEntryList. It will be allocated
3484  *                 on successful return.
3485  *
3486  * returns:
3487  *  STMF_PS_SUCCESS on success
3488  *  STMF_PS_ERROR_* on failure
3489  */
3490 int
3491 psGetViewEntryList(stmfGuid *lu, stmfViewEntryList **viewEntryList)
3492 {
3493 	scf_handle_t	*handle = NULL;
3494 	scf_service_t	*svc = NULL;
3495 	scf_propertygroup_t	*pg = NULL;
3496 	scf_property_t	*prop = NULL;
3497 	scf_value_t *value = NULL;
3498 	scf_iter_t  *propIter = NULL;
3499 	char guidAsciiBuf[33]; /* size of ascii hex 16 byte guid with NULL */
3500 	char viewEntryPgName[VIEW_ENTRY_PG_SIZE];
3501 	char luPgName[LOGICAL_UNIT_PG_SIZE];
3502 	int ret = STMF_PS_SUCCESS;
3503 	uint64_t i = 0;
3504 	uint64_t veCnt;
3505 
3506 
3507 	ret = iPsInit(&handle, &svc);
3508 	if (ret != STMF_PS_SUCCESS) {
3509 		goto out;
3510 	}
3511 
3512 	/*
3513 	 * Allocate scf resources
3514 	 */
3515 	if (((pg = scf_pg_create(handle)) == NULL) ||
3516 	    ((prop = scf_property_create(handle)) == NULL) ||
3517 	    ((propIter = scf_iter_create(handle)) == NULL) ||
3518 	    ((value = scf_value_create(handle)) == NULL)) {
3519 		syslog(LOG_ERR, "scf alloc resource failed - %s",
3520 		    scf_strerror(scf_error()));
3521 		ret = STMF_PS_ERROR;
3522 		goto out;
3523 	}
3524 
3525 	/* Convert to ASCII uppercase hexadecimal string */
3526 	(void) snprintf(guidAsciiBuf, sizeof (guidAsciiBuf),
3527 	    "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
3528 	    lu->guid[0], lu->guid[1], lu->guid[2], lu->guid[3], lu->guid[4],
3529 	    lu->guid[5], lu->guid[6], lu->guid[7], lu->guid[8], lu->guid[9],
3530 	    lu->guid[10], lu->guid[11], lu->guid[12], lu->guid[13],
3531 	    lu->guid[14], lu->guid[15]);
3532 
3533 	/* form the LU property group name (LU-<guid>) */
3534 	(void) snprintf(luPgName, sizeof (luPgName), "%s-%s",
3535 	    STMF_LU_PREFIX, guidAsciiBuf);
3536 
3537 	/* get the property group associated with this LU */
3538 	if (scf_service_get_pg(svc, luPgName, pg) == -1) {
3539 		if (scf_error() == SCF_ERROR_NOT_FOUND) {
3540 			ret = STMF_PS_ERROR_NOT_FOUND;
3541 		} else {
3542 			syslog(LOG_ERR, "get pg %s failed - %s",
3543 			    luPgName, scf_strerror(scf_error()));
3544 			ret = STMF_PS_ERROR;
3545 		}
3546 		goto out;
3547 	}
3548 
3549 	/* get the view entry count property */
3550 	if (scf_pg_get_property(pg, STMF_VE_CNT, prop) == -1) {
3551 		syslog(LOG_ERR, "get property %s/%s failed - %s",
3552 		    luPgName, STMF_VE_CNT, scf_strerror(scf_error()));
3553 		ret = STMF_PS_ERROR;
3554 		goto out;
3555 	}
3556 
3557 	if (scf_property_get_value(prop, value) == -1) {
3558 		syslog(LOG_ERR, "get property value %s/%s failed - %s",
3559 		    luPgName, STMF_VE_CNT, scf_strerror(scf_error()));
3560 		ret = STMF_PS_ERROR;
3561 		goto out;
3562 	}
3563 
3564 	/*
3565 	 * Get the actual value of the view entry count property
3566 	 */
3567 	if (scf_value_get_count(value, &veCnt) == -1) {
3568 		syslog(LOG_ERR, "get integer value %s/%s failed - %s",
3569 		    luPgName, STMF_VE_CNT, scf_strerror(scf_error()));
3570 		ret = STMF_PS_ERROR;
3571 		goto out;
3572 	}
3573 
3574 	/*
3575 	 * propIter is the iterator handle
3576 	 */
3577 	if (scf_iter_pg_properties(propIter, pg) == -1) {
3578 		syslog(LOG_ERR, "iter properties for %s failed - %s",
3579 		    luPgName, scf_strerror(scf_error()));
3580 		ret = STMF_PS_ERROR;
3581 		goto out;
3582 	}
3583 
3584 	/*
3585 	 * alloc the list based on the view entry count
3586 	 */
3587 	*viewEntryList = (stmfViewEntryList *)calloc(1,
3588 	    sizeof (stmfViewEntryList) + veCnt * sizeof (stmfViewEntry));
3589 	if (*viewEntryList == NULL) {
3590 		ret = STMF_PS_ERROR_NOMEM;
3591 		goto out;
3592 	}
3593 
3594 	i = 0;
3595 	/*
3596 	 * iterate through the view entry properties to find the
3597 	 * view entries
3598 	 */
3599 	while (scf_iter_next_property(propIter, prop) == 1) {
3600 		/* find match for view entry property */
3601 		if (scf_property_get_name(prop, viewEntryPgName,
3602 		    sizeof (viewEntryPgName)) != -1) {
3603 			if (strncmp(viewEntryPgName, STMF_VE_PREFIX,
3604 			    strlen(STMF_VE_PREFIX)) != 0) {
3605 				continue;
3606 			}
3607 			/*
3608 			 * We've exceeded our alloc limit
3609 			 * break with error
3610 			 */
3611 			if (i == veCnt) {
3612 				ret = STMF_PS_ERROR;
3613 				break;
3614 			}
3615 
3616 			if ((ret = iPsGetViewEntry(viewEntryPgName,
3617 			    &((*viewEntryList)->ve[i]))) != STMF_PS_SUCCESS) {
3618 				break;
3619 			}
3620 
3621 			i++;
3622 
3623 			/* set the list count */
3624 			(*viewEntryList)->cnt++;
3625 		} else {
3626 			syslog(LOG_ERR, "scf iter %s properties failed - %s",
3627 			    luPgName, scf_strerror(scf_error()));
3628 			ret = STMF_PS_ERROR;
3629 			break;
3630 		}
3631 
3632 	}
3633 
3634 	if (ret != STMF_PS_SUCCESS) {
3635 		free(*viewEntryList);
3636 		goto out;
3637 	}
3638 
3639 	/*
3640 	 * We're sorting the final list here based on the veIndex
3641 	 * If we don't, the caller is going to have to do it to reap
3642 	 * some intelligent output.
3643 	 */
3644 	qsort((void *)&((*viewEntryList)->ve[0]), (*viewEntryList)->cnt,
3645 	    sizeof (stmfViewEntry), viewEntryCompare);
3646 
3647 out:
3648 	/*
3649 	 * Free resources
3650 	 */
3651 	if (handle != NULL) {
3652 		scf_handle_destroy(handle);
3653 	}
3654 	if (svc != NULL) {
3655 		scf_service_destroy(svc);
3656 	}
3657 	if (pg != NULL) {
3658 		scf_pg_destroy(pg);
3659 	}
3660 	if (prop != NULL) {
3661 		scf_property_destroy(prop);
3662 	}
3663 	if (value != NULL) {
3664 		scf_value_destroy(value);
3665 	}
3666 	if (propIter != NULL) {
3667 		scf_iter_destroy(propIter);
3668 	}
3669 
3670 	return (ret);
3671 }
3672 
3673 /*
3674  * iPsGetViewEntry
3675  *
3676  * viewEntryPgName - view entry property group name to retrieve
3677  * viewEntry - pointer to stmfViewEntry structure allocated by the caller
3678  *
3679  * returns:
3680  *  STMF_PS_SUCCESS on success
3681  *  STMF_PS_ERROR_* on failure
3682  */
3683 static int
3684 iPsGetViewEntry(char *viewEntryPgName, stmfViewEntry *viewEntry)
3685 {
3686 	scf_handle_t	*handle = NULL;
3687 	scf_service_t	*svc = NULL;
3688 	scf_propertygroup_t	*pg = NULL;
3689 	scf_property_t	*prop = NULL;
3690 	scf_value_t *value = NULL;
3691 	uint8_t scfBool;
3692 	char *indexPtr;
3693 	char groupName[sizeof (stmfGroupName)];
3694 	int ret = STMF_PS_SUCCESS;
3695 
3696 
3697 	ret = iPsInit(&handle, &svc);
3698 	if (ret != STMF_PS_SUCCESS) {
3699 		goto out;
3700 	}
3701 
3702 	/*
3703 	 * Allocate scf resources
3704 	 */
3705 	if (((pg = scf_pg_create(handle)) == NULL) ||
3706 	    ((prop = scf_property_create(handle)) == NULL) ||
3707 	    ((value = scf_value_create(handle)) == NULL)) {
3708 		syslog(LOG_ERR, "scf alloc resource failed - %s",
3709 		    scf_strerror(scf_error()));
3710 		ret = STMF_PS_ERROR;
3711 		goto out;
3712 	}
3713 
3714 	bzero(viewEntry, sizeof (stmfViewEntry));
3715 
3716 	/*
3717 	 * get the service property group view entry handle
3718 	 */
3719 	if (scf_service_get_pg(svc, viewEntryPgName, pg) == -1) {
3720 		if (scf_error() == SCF_ERROR_NOT_FOUND) {
3721 			ret = STMF_PS_ERROR_NOT_FOUND;
3722 		} else {
3723 			syslog(LOG_ERR, "get pg %s failed - %s",
3724 			    viewEntryPgName, scf_strerror(scf_error()));
3725 			ret = STMF_PS_ERROR;
3726 		}
3727 		goto out;
3728 	}
3729 
3730 
3731 	/*
3732 	 * get index
3733 	 * format is: VE-<veIndex>-GUID
3734 	 */
3735 	indexPtr = strchr(viewEntryPgName, '-');
3736 	if (!indexPtr) {
3737 		ret = STMF_PS_ERROR;
3738 		goto out;
3739 	}
3740 
3741 	/* Set the index */
3742 	viewEntry->veIndex = atoi(strtok(++indexPtr, "-"));
3743 
3744 	viewEntry->veIndexValid = B_TRUE;
3745 
3746 	/* get allHosts property */
3747 	if (scf_pg_get_property(pg, STMF_VE_ALLHOSTS,
3748 	    prop) == -1) {
3749 		syslog(LOG_ERR, "get property %s/%s failed - %s",
3750 		    viewEntryPgName, STMF_VE_ALLHOSTS,
3751 		    scf_strerror(scf_error()));
3752 		ret = STMF_PS_ERROR;
3753 		goto out;
3754 	}
3755 
3756 	if (scf_property_get_value(prop, value) == -1) {
3757 		syslog(LOG_ERR, "get property %s/%s failed - %s",
3758 		    viewEntryPgName, STMF_VE_ALLHOSTS,
3759 		    scf_strerror(scf_error()));
3760 		ret = STMF_PS_ERROR;
3761 		goto out;
3762 	}
3763 
3764 	/* set allHosts */
3765 	if (scf_value_get_boolean(value, (uint8_t *)&scfBool) == -1) {
3766 		syslog(LOG_ERR, "get property %s/%s failed - %s",
3767 		    viewEntryPgName, STMF_VE_ALLHOSTS,
3768 		    scf_strerror(scf_error()));
3769 		ret = STMF_PS_ERROR;
3770 		goto out;
3771 	}
3772 	viewEntry->allHosts = scfBool;
3773 
3774 	/* get hostGroup property */
3775 	if (scf_pg_get_property(pg, STMF_VE_HOSTGROUP,
3776 	    prop) == -1) {
3777 		syslog(LOG_ERR, "get property %s/%s failed - %s",
3778 		    viewEntryPgName, STMF_VE_HOSTGROUP,
3779 		    scf_strerror(scf_error()));
3780 		ret = STMF_PS_ERROR;
3781 		goto out;
3782 	}
3783 
3784 	if (scf_property_get_value(prop, value) == -1) {
3785 		syslog(LOG_ERR, "get property %s/%s failed - %s",
3786 		    viewEntryPgName, STMF_VE_HOSTGROUP,
3787 		    scf_strerror(scf_error()));
3788 		ret = STMF_PS_ERROR;
3789 		goto out;
3790 	}
3791 
3792 	if (scf_value_get_ustring(value, groupName,
3793 	    sizeof (groupName)) == -1) {
3794 		syslog(LOG_ERR, "get value %s/%s failed - %s",
3795 		    viewEntryPgName, STMF_VE_HOSTGROUP,
3796 		    scf_strerror(scf_error()));
3797 		ret = STMF_PS_ERROR;
3798 		goto out;
3799 	}
3800 	/* set hostGroup */
3801 	bcopy(groupName, viewEntry->hostGroup, strlen(groupName));
3802 
3803 	/* get allTargets property */
3804 	if (scf_pg_get_property(pg, STMF_VE_ALLTARGETS,
3805 	    prop) == -1) {
3806 		syslog(LOG_ERR, "get property %s/%s failed - %s",
3807 		    viewEntryPgName, STMF_VE_ALLTARGETS,
3808 		    scf_strerror(scf_error()));
3809 		ret = STMF_PS_ERROR;
3810 		goto out;
3811 	}
3812 
3813 	if (scf_property_get_value(prop, value) == -1) {
3814 		syslog(LOG_ERR, "get property value %s/%s failed - %s",
3815 		    viewEntryPgName, STMF_VE_ALLTARGETS,
3816 		    scf_strerror(scf_error()));
3817 		ret = STMF_PS_ERROR;
3818 		goto out;
3819 	}
3820 
3821 	/* set allTargets */
3822 	if (scf_value_get_boolean(value, (uint8_t *)&scfBool) == -1) {
3823 		syslog(LOG_ERR, "get value %s/%s failed - %s",
3824 		    viewEntryPgName, STMF_VE_ALLTARGETS,
3825 		    scf_strerror(scf_error()));
3826 		ret = STMF_PS_ERROR;
3827 		goto out;
3828 	}
3829 	viewEntry->allTargets = scfBool;
3830 
3831 	/* get targetGroup property */
3832 	if (scf_pg_get_property(pg, STMF_VE_TARGETGROUP, prop) == -1) {
3833 		syslog(LOG_ERR, "get property %s/%s failed - %s",
3834 		    viewEntryPgName, STMF_VE_TARGETGROUP,
3835 		    scf_strerror(scf_error()));
3836 		ret = STMF_PS_ERROR;
3837 		goto out;
3838 	}
3839 
3840 	if (scf_property_get_value(prop, value) == -1) {
3841 		syslog(LOG_ERR, "get property value %s/%s failed - %s",
3842 		    viewEntryPgName, STMF_VE_TARGETGROUP,
3843 		    scf_strerror(scf_error()));
3844 		ret = STMF_PS_ERROR;
3845 		goto out;
3846 	}
3847 
3848 	if (scf_value_get_ustring(value, groupName,
3849 	    sizeof (groupName)) == -1) {
3850 		syslog(LOG_ERR, "get value %s/%s failed - %s",
3851 		    viewEntryPgName, STMF_VE_TARGETGROUP,
3852 		    scf_strerror(scf_error()));
3853 		ret = STMF_PS_ERROR;
3854 		goto out;
3855 	}
3856 	/* set targetGroup */
3857 	bcopy(groupName, viewEntry->targetGroup, strlen(groupName));
3858 
3859 	/* get luNbr property */
3860 	if (scf_pg_get_property(pg, STMF_VE_LUNBR,
3861 	    prop) == -1) {
3862 		syslog(LOG_ERR, "get property %s/%s failed - %s",
3863 		    viewEntryPgName, STMF_VE_LUNBR,
3864 		    scf_strerror(scf_error()));
3865 		ret = STMF_PS_ERROR;
3866 		goto out;
3867 	}
3868 
3869 	if (scf_property_get_value(prop, value) == -1) {
3870 		syslog(LOG_ERR, "get property value %s/%s failed - %s",
3871 		    viewEntryPgName, STMF_VE_LUNBR,
3872 		    scf_strerror(scf_error()));
3873 		ret = STMF_PS_ERROR;
3874 		goto out;
3875 	}
3876 
3877 	/* set luNbr */
3878 	if (scf_value_get_opaque(value, (char *)viewEntry->luNbr,
3879 	    sizeof (viewEntry->luNbr)) == -1) {
3880 		syslog(LOG_ERR, "get opaque value %s/%s failed - %s",
3881 		    viewEntryPgName, STMF_VE_LUNBR,
3882 		    scf_strerror(scf_error()));
3883 		ret = STMF_PS_ERROR;
3884 		goto out;
3885 	}
3886 	/* set luNbrValid to true since we just got it */
3887 	viewEntry->luNbrValid = B_TRUE;
3888 
3889 out:
3890 	/*
3891 	 * Free resources
3892 	 */
3893 	if (handle != NULL) {
3894 		scf_handle_destroy(handle);
3895 	}
3896 	if (svc != NULL) {
3897 		scf_service_destroy(svc);
3898 	}
3899 	if (pg != NULL) {
3900 		scf_pg_destroy(pg);
3901 	}
3902 	if (value != NULL) {
3903 		scf_value_destroy(value);
3904 	}
3905 	if (prop != NULL) {
3906 		scf_property_destroy(prop);
3907 	}
3908 
3909 	return (ret);
3910 }
3911 
3912 
3913 /*
3914  * psRemoveHostGroupMember
3915  *
3916  * Remove a host group member from a host group,
3917  *
3918  * groupName - name of group from which the member is removed
3919  * memberName - name of group member to remove
3920  *
3921  * returns:
3922  *  STMF_PS_SUCCESS on success
3923  *  STMF_PS_ERROR_* on failure
3924  */
3925 int
3926 psRemoveHostGroupMember(char *groupName, char *memberName)
3927 {
3928 	int ret;
3929 	char groupPropListName[MAXNAMELEN];
3930 	char groupPropName[MAXNAMELEN];
3931 
3932 	ret = iPsGetActualGroupName(STMF_HOST_GROUPS, groupName,
3933 	    groupPropName);
3934 	if (ret != STMF_PS_SUCCESS) {
3935 		return (ret);
3936 	}
3937 
3938 	if (snprintf(groupPropListName, sizeof (groupPropListName),
3939 	    "%s-%s", groupPropName, STMF_MEMBER_LIST_SUFFIX) >
3940 	    sizeof (groupPropListName)) {
3941 		syslog(LOG_ERR, "buffer overflow on property name %s",
3942 		    groupPropName);
3943 		return (STMF_PS_ERROR);
3944 	}
3945 
3946 	return (iPsAddRemoveGroupMember(STMF_HOST_GROUPS, groupPropListName,
3947 	    memberName, REMOVE));
3948 }
3949 
3950 /*
3951  * psRemoveTargetGroupMember
3952  *
3953  * Remove a target port group member from an target port group,
3954  *
3955  * groupName - name of group from which the member is removed
3956  * memberName - name of group member to remove
3957  *
3958  * returns:
3959  *  STMF_PS_SUCCESS on success
3960  *  STMF_PS_ERROR_* on failure
3961  */
3962 int
3963 psRemoveTargetGroupMember(char *groupName, char *memberName)
3964 {
3965 	int ret;
3966 	char groupPropListName[MAXNAMELEN];
3967 	char groupPropName[MAXNAMELEN];
3968 
3969 	ret = iPsGetActualGroupName(STMF_TARGET_GROUPS, groupName,
3970 	    groupPropName);
3971 	if (ret != STMF_PS_SUCCESS) {
3972 		return (ret);
3973 	}
3974 
3975 	if (snprintf(groupPropListName, sizeof (groupPropListName),
3976 	    "%s-%s", groupPropName, STMF_MEMBER_LIST_SUFFIX) >
3977 	    sizeof (groupPropListName)) {
3978 		syslog(LOG_ERR, "buffer overflow on property name %s",
3979 		    groupPropName);
3980 		return (STMF_PS_ERROR);
3981 	}
3982 
3983 	return (iPsAddRemoveGroupMember(STMF_TARGET_GROUPS, groupPropListName,
3984 	    memberName, REMOVE));
3985 }
3986 
3987 /*
3988  * psGetProviderData
3989  *
3990  * Retrieves an nvlist on a per provider basis
3991  *
3992  * providerName - property group name to use
3993  * nvl - nvlist to retrieve
3994  *
3995  */
3996 int
3997 psGetProviderData(char *providerName, nvlist_t **nvl, int providerType,
3998     uint64_t *setToken)
3999 {
4000 	scf_handle_t	*handle = NULL;
4001 	scf_service_t	*svc = NULL;
4002 	scf_propertygroup_t	*pg = NULL;
4003 	scf_property_t	*prop = NULL;
4004 	scf_value_t	*value = NULL;
4005 	uint64_t blockCnt = 0;
4006 	ssize_t blockOffset = 0;
4007 	ssize_t actualBlockSize = 0;
4008 	char pgName[MAXPATHLEN];
4009 	char dataPropertyName[STMF_PROVIDER_DATA_PROP_NAME_SIZE];
4010 	char *nvlistEncoded = NULL;
4011 	ssize_t nvlistEncodedSize = 0;
4012 	boolean_t foundSetCnt = B_TRUE;
4013 	int i;
4014 	int ret = STMF_PS_SUCCESS;
4015 
4016 	if (providerName == NULL || (providerType != STMF_LU_PROVIDER_TYPE &&
4017 	    providerType != STMF_PORT_PROVIDER_TYPE)) {
4018 		ret = STMF_PS_ERROR_INVALID_ARG;
4019 		goto out;
4020 	}
4021 
4022 	ret = iPsInit(&handle, &svc);
4023 	if (ret != STMF_PS_SUCCESS) {
4024 		goto out;
4025 	}
4026 
4027 	/*
4028 	 * create the property group name
4029 	 */
4030 	(void) snprintf(pgName, sizeof (pgName), "%s%s",
4031 	    STMF_PROVIDER_DATA_PREFIX, providerName);
4032 
4033 	/*
4034 	 * Allocate scf resources
4035 	 */
4036 	if (((pg = scf_pg_create(handle)) == NULL) ||
4037 	    ((value = scf_value_create(handle)) == NULL) ||
4038 	    ((prop = scf_property_create(handle)) == NULL)) {
4039 		syslog(LOG_ERR, "scf alloc resource failed - %s",
4040 		    scf_strerror(scf_error()));
4041 		ret = STMF_PS_ERROR;
4042 		goto out;
4043 	}
4044 
4045 	/*
4046 	 * Retrieve the existing property group.
4047 	 */
4048 	if (scf_service_get_pg(svc, pgName, pg) == -1) {
4049 		if (scf_error() != SCF_ERROR_NOT_FOUND) {
4050 			syslog(LOG_ERR, "get pg %s failed - %s", pgName,
4051 			    scf_strerror(scf_error()));
4052 			ret = STMF_PS_ERROR;
4053 			goto out;
4054 		} else {
4055 			ret = STMF_PS_ERROR_NOT_FOUND;
4056 			goto out;
4057 		}
4058 	}
4059 
4060 	/*
4061 	 * Get the STMF_PROVIDER_DATA_PROP_COUNT property
4062 	 */
4063 	if (scf_pg_get_property(pg, STMF_PROVIDER_DATA_PROP_COUNT,
4064 	    prop) == -1) {
4065 		syslog(LOG_ERR, "get property %s/%s failed - %s",
4066 		    pgName, STMF_PROVIDER_DATA_PROP_COUNT,
4067 		    scf_strerror(scf_error()));
4068 		ret = STMF_PS_ERROR;
4069 		goto out;
4070 	}
4071 
4072 	/*
4073 	 * Get the STMF_PROVIDER_DATA_PROP_COUNT value
4074 	 */
4075 	if (scf_property_get_value(prop, value) == -1) {
4076 		syslog(LOG_ERR, "get property value %s/%s failed - %s",
4077 		    pgName, STMF_PROVIDER_DATA_PROP_COUNT,
4078 		    scf_strerror(scf_error()));
4079 		ret = STMF_PS_ERROR;
4080 		goto out;
4081 	}
4082 
4083 	/*
4084 	 * Now get the actual value from the value handle
4085 	 */
4086 	if (scf_value_get_count(value, &blockCnt) == -1) {
4087 		syslog(LOG_ERR, "get integer value %s/%s failed - %s",
4088 		    pgName, STMF_PROVIDER_DATA_PROP_COUNT,
4089 		    scf_strerror(scf_error()));
4090 		ret = STMF_PS_ERROR;
4091 		goto out;
4092 	}
4093 
4094 	/* Has the caller requested the token to be set? */
4095 	if (setToken) {
4096 		/*
4097 		 * Get the STMF_PROVIDER_DATA_PROP_SET_COUNT property
4098 		 * If it doesn't exist, we assume it to be zero.
4099 		 */
4100 		*setToken = 0;
4101 		if (scf_pg_get_property(pg, STMF_PROVIDER_DATA_PROP_SET_COUNT,
4102 		    prop) == -1) {
4103 			if (scf_error() == SCF_ERROR_NOT_FOUND) {
4104 				foundSetCnt = B_FALSE;
4105 			} else {
4106 				syslog(LOG_ERR, "get property %s/%s "
4107 				    "failed - %s", pgName,
4108 				    STMF_PROVIDER_DATA_PROP_SET_COUNT,
4109 				    scf_strerror(scf_error()));
4110 				ret = STMF_PS_ERROR;
4111 				goto out;
4112 			}
4113 		}
4114 
4115 		if (foundSetCnt) {
4116 			/*
4117 			 * Get the STMF_PROVIDER_DATA_PROP_SET_COUNT value
4118 			 */
4119 			if (scf_property_get_value(prop, value) == -1) {
4120 				syslog(LOG_ERR,
4121 				    "get property value %s/%s failed - %s",
4122 				    pgName, STMF_PROVIDER_DATA_PROP_SET_COUNT,
4123 				    scf_strerror(scf_error()));
4124 				ret = STMF_PS_ERROR;
4125 				goto out;
4126 			}
4127 
4128 			/*
4129 			 * Now get the actual value from the value handle
4130 			 * and set the caller's token
4131 			 */
4132 			if (scf_value_get_count(value, setToken) == -1) {
4133 				syslog(LOG_ERR,
4134 				    "get integer value %s/%s failed - %s",
4135 				    pgName, STMF_PROVIDER_DATA_PROP_SET_COUNT,
4136 				    scf_strerror(scf_error()));
4137 				ret = STMF_PS_ERROR;
4138 				goto out;
4139 			}
4140 		}
4141 	}
4142 
4143 	nvlistEncoded = (char *)calloc(1,
4144 	    blockCnt * STMF_PROVIDER_DATA_PROP_SIZE);
4145 	if (nvlistEncoded == NULL) {
4146 		syslog(LOG_ERR, "nvlistEncoded alloc failed");
4147 		ret = STMF_PS_ERROR_NOMEM;
4148 		goto out;
4149 	}
4150 
4151 	for (i = 0; i < blockCnt; i++) {
4152 		bzero(dataPropertyName, sizeof (dataPropertyName));
4153 		/*
4154 		 * create the name to use for the property
4155 		 */
4156 		(void) snprintf(dataPropertyName, sizeof (dataPropertyName),
4157 		    "%s-%d", STMF_PROVIDER_DATA_PROP_PREFIX, i);
4158 
4159 		if (scf_pg_get_property(pg, dataPropertyName, prop) == -1) {
4160 			syslog(LOG_ERR, "get property %s/%s failed - %s",
4161 			    pgName, dataPropertyName,
4162 			    scf_strerror(scf_error()));
4163 			ret = STMF_PS_ERROR;
4164 			goto out;
4165 		}
4166 
4167 		if (scf_property_get_value(prop, value) == -1) {
4168 			syslog(LOG_ERR, "get property value %s/%s failed - %s",
4169 			    pgName, dataPropertyName,
4170 			    scf_strerror(scf_error()));
4171 			ret = STMF_PS_ERROR;
4172 			goto out;
4173 		}
4174 
4175 		/*
4176 		 * Set the data block offset
4177 		 */
4178 		blockOffset = STMF_PROVIDER_DATA_PROP_SIZE * i;
4179 		actualBlockSize = scf_value_get_opaque(value,
4180 		    &nvlistEncoded[blockOffset], STMF_PROVIDER_DATA_PROP_SIZE);
4181 		if (actualBlockSize == -1) {
4182 			syslog(LOG_ERR, "get opaque property value %s/%s "
4183 			    "failed - %s", pgName, dataPropertyName,
4184 			    scf_strerror(scf_error()));
4185 			ret = STMF_PS_ERROR;
4186 			goto out;
4187 		}
4188 		nvlistEncodedSize += actualBlockSize;
4189 	}
4190 
4191 	if (nvlist_unpack(nvlistEncoded, nvlistEncodedSize, nvl, 0) != 0) {
4192 		syslog(LOG_ERR, "unable to unpack nvlist");
4193 		ret = STMF_PS_ERROR;
4194 		goto out;
4195 	}
4196 
4197 
4198 out:
4199 	/*
4200 	 * Free resources
4201 	 */
4202 	if (handle != NULL) {
4203 		scf_handle_destroy(handle);
4204 	}
4205 	if (svc != NULL) {
4206 		scf_service_destroy(svc);
4207 	}
4208 	if (pg != NULL) {
4209 		scf_pg_destroy(pg);
4210 	}
4211 	if (prop != NULL) {
4212 		scf_property_destroy(prop);
4213 	}
4214 	if (value != NULL) {
4215 		scf_value_destroy(value);
4216 	}
4217 	if (nvlistEncoded != NULL) {
4218 		free(nvlistEncoded);
4219 	}
4220 
4221 	return (ret);
4222 
4223 }
4224 /*
4225  * psGetProviderDataList
4226  *
4227  * Retrieves the list of providers that currently store persistent data
4228  *
4229  * providerList - pointer to a pointer to an stmfProviderList structure
4230  *                On success, this will contain the list of providers
4231  *                currently storing persistent data.
4232  */
4233 int
4234 psGetProviderDataList(stmfProviderList **providerList)
4235 {
4236 	scf_handle_t *handle = NULL;
4237 	scf_service_t *svc = NULL;
4238 	scf_propertygroup_t *pg = NULL;
4239 	scf_property_t *prop = NULL;
4240 	scf_value_t *value = NULL;
4241 	scf_iter_t *pgIter = NULL;
4242 	char buf[MAXNAMELEN];
4243 	int providerCnt = 0;
4244 	int64_t providerType;
4245 	int i = 0, j;
4246 	int ret = STMF_PS_SUCCESS;
4247 
4248 	ret = iPsInit(&handle, &svc);
4249 	if (ret != STMF_PS_SUCCESS) {
4250 		goto out;
4251 	}
4252 
4253 	*providerList = NULL;
4254 
4255 	/*
4256 	 * Allocate scf resources
4257 	 */
4258 	if (((pg = scf_pg_create(handle)) == NULL) ||
4259 	    ((value = scf_value_create(handle)) == NULL) ||
4260 	    ((prop = scf_property_create(handle)) == NULL) ||
4261 	    ((pgIter = scf_iter_create(handle)) == NULL)) {
4262 		syslog(LOG_ERR, "scf alloc resource failed - %s",
4263 		    scf_strerror(scf_error()));
4264 		ret = STMF_PS_ERROR;
4265 		goto out;
4266 	}
4267 
4268 	/*
4269 	 * pgIter is the iterator handle
4270 	 */
4271 	if (scf_iter_service_pgs(pgIter, svc) == -1) {
4272 		syslog(LOG_ERR, "iter property groups failed - %s",
4273 		    scf_strerror(scf_error()));
4274 		ret = STMF_PS_ERROR;
4275 		goto out;
4276 	}
4277 
4278 	while (scf_iter_next_pg(pgIter, pg) == 1) {
4279 		if (scf_pg_get_name(pg, buf, sizeof (buf)) == -1) {
4280 			syslog(LOG_ERR, "get name failed - %s",
4281 			    scf_strerror(scf_error()));
4282 			ret = STMF_PS_ERROR;
4283 			break;
4284 		}
4285 		/*
4286 		 * Only count LU property groups
4287 		 */
4288 		if (strncmp(buf, STMF_PROVIDER_DATA_PREFIX,
4289 		    strlen(STMF_PROVIDER_DATA_PREFIX)) == 0) {
4290 			providerCnt++;
4291 		}
4292 	}
4293 
4294 	/*
4295 	 * pgIter is the iterator handle
4296 	 */
4297 	if (scf_iter_service_pgs(pgIter, svc) == -1) {
4298 		syslog(LOG_ERR, "iter property groups failed - %s",
4299 		    scf_strerror(scf_error()));
4300 		ret = STMF_PS_ERROR;
4301 		goto out;
4302 	}
4303 
4304 	*providerList = (stmfProviderList *)calloc(1,
4305 	    sizeof (stmfProviderList) + providerCnt * sizeof (stmfProvider));
4306 	if (*providerList == NULL) {
4307 		ret = STMF_PS_ERROR_NOMEM;
4308 		goto out;
4309 	}
4310 
4311 	/*
4312 	 * it's possible for entries to be added/removed while we're retrieving
4313 	 * the property groups. Just make sure we don't write beyond our
4314 	 * allocated buffer by checking to ensure i < providerCnt.
4315 	 */
4316 	while ((scf_iter_next_pg(pgIter, pg) == 1) && (i < providerCnt)) {
4317 		if (scf_pg_get_name(pg, buf, sizeof (buf)) == -1) {
4318 			syslog(LOG_ERR, "get name failed - %s",
4319 			    scf_strerror(scf_error()));
4320 			ret = STMF_PS_ERROR;
4321 			break;
4322 		}
4323 		/*
4324 		 * Only use provider data property groups
4325 		 */
4326 		if (strncmp(buf, STMF_PROVIDER_DATA_PREFIX,
4327 		    strlen(STMF_PROVIDER_DATA_PREFIX)) != 0) {
4328 			continue;
4329 		}
4330 
4331 		/*
4332 		 * Get the STMF_PROVIDER_DATA_PROP_TYPE property
4333 		 */
4334 		if (scf_pg_get_property(pg, STMF_PROVIDER_DATA_PROP_TYPE,
4335 		    prop) == -1) {
4336 			syslog(LOG_ERR, "get property %s/%s failed - %s",
4337 			    buf, STMF_PROVIDER_DATA_PROP_TYPE,
4338 			    scf_strerror(scf_error()));
4339 			ret = STMF_PS_ERROR;
4340 			break;
4341 		}
4342 
4343 		/*
4344 		 * Get the STMF_PROVIDER_DATA_PROP_TYPE value
4345 		 */
4346 		if (scf_property_get_value(prop, value) == -1) {
4347 			syslog(LOG_ERR, "get property value %s/%s failed - %s",
4348 			    buf, STMF_PROVIDER_DATA_PROP_TYPE,
4349 			    scf_strerror(scf_error()));
4350 			ret = STMF_PS_ERROR;
4351 			break;
4352 		}
4353 
4354 		/*
4355 		 * Now get the actual value from the value handle
4356 		 */
4357 		if (scf_value_get_integer(value, &providerType) == -1) {
4358 			syslog(LOG_ERR, "get integer value %s/%s failed - %s",
4359 			    buf, STMF_PROVIDER_DATA_PROP_TYPE,
4360 			    scf_strerror(scf_error()));
4361 			ret = STMF_PS_ERROR;
4362 			break;
4363 		}
4364 
4365 		(*providerList)->provider[i].providerType = providerType;
4366 
4367 		/* determine offset for copy of provider name */
4368 		j = strlen(STMF_PROVIDER_DATA_PREFIX);
4369 
4370 		/* copy provider name to caller's list */
4371 		(void) strncpy((*providerList)->provider[i].name, buf + j,
4372 		    sizeof ((*providerList)->provider[i].name));
4373 		i++;
4374 		(*providerList)->cnt++;
4375 	}
4376 
4377 	if (ret != STMF_PS_SUCCESS) {
4378 		free(*providerList);
4379 		goto out;
4380 	}
4381 
4382 out:
4383 	/*
4384 	 * Free resources
4385 	 */
4386 	if (handle != NULL) {
4387 		scf_handle_destroy(handle);
4388 	}
4389 	if (svc != NULL) {
4390 		scf_service_destroy(svc);
4391 	}
4392 	if (pg != NULL) {
4393 		scf_pg_destroy(pg);
4394 	}
4395 	if (value != NULL) {
4396 		scf_value_destroy(value);
4397 	}
4398 	if (prop != NULL) {
4399 		scf_property_destroy(prop);
4400 	}
4401 	if (pgIter != NULL) {
4402 		scf_iter_destroy(pgIter);
4403 	}
4404 
4405 	return (ret);
4406 }
4407 
4408 
4409 /*
4410  * psSetProviderData
4411  *
4412  * Stores a packed nvlist on a per provider basis
4413  *
4414  * providerName - property group name to use
4415  * nvl - nvlist to store
4416  * providerType - type of provider (logical unit or port)
4417  *
4418  */
4419 int
4420 psSetProviderData(char *providerName, nvlist_t *nvl, int providerType,
4421     uint64_t *setToken)
4422 {
4423 	scf_handle_t	*handle = NULL;
4424 	scf_service_t	*svc = NULL;
4425 	scf_propertygroup_t	*pg = NULL;
4426 	scf_property_t	*prop = NULL;
4427 	scf_transaction_t *tran = NULL;
4428 	/* represents arrays of entry and value pointers for scf */
4429 	scf_transaction_entry_t	**addEntry = NULL;
4430 	scf_transaction_entry_t	**deleteEntry = NULL;
4431 	scf_value_t **addValue = NULL;
4432 
4433 	/*
4434 	 * These declarations are for known entry and value set/get
4435 	 * operations
4436 	 */
4437 	scf_transaction_entry_t *entry1 = NULL;
4438 	scf_transaction_entry_t *entry2 = NULL;
4439 	scf_transaction_entry_t *entry3 = NULL;
4440 	scf_transaction_entry_t *entry5 = NULL;
4441 	scf_value_t *value1 = NULL;
4442 	scf_value_t *value2 = NULL;
4443 	scf_value_t *value3 = NULL;
4444 	scf_value_t *value4 = NULL;
4445 	scf_value_t *value5 = NULL;
4446 
4447 	boolean_t newPg = B_FALSE;
4448 	char pgName[MAXPATHLEN];
4449 	char dataPropertyName[STMF_PROVIDER_DATA_PROP_NAME_SIZE];
4450 	char *nvlistEncoded = NULL;
4451 	size_t nvlistEncodedSize;
4452 	size_t blockSize;
4453 	int i, j = 0;
4454 	int addEntryAlloc = 0, deleteEntryAlloc = 0, addValueAlloc = 0;
4455 	int blockOffset;
4456 	uint64_t oldBlockCnt = 0;
4457 	uint64_t blockCnt = 0;
4458 	uint64_t setCnt = 0;
4459 	boolean_t foundSetCnt = B_TRUE;
4460 	int ret = STMF_PS_SUCCESS;
4461 	int commitRet;
4462 
4463 	if (providerName == NULL || (providerType != STMF_LU_PROVIDER_TYPE &&
4464 	    providerType != STMF_PORT_PROVIDER_TYPE)) {
4465 		ret = STMF_PS_ERROR_INVALID_ARG;
4466 		goto out;
4467 	}
4468 
4469 	ret = iPsInit(&handle, &svc);
4470 	if (ret != STMF_PS_SUCCESS) {
4471 		goto out;
4472 	}
4473 
4474 	bzero(pgName, sizeof (pgName));
4475 	/*
4476 	 * create the property group name
4477 	 */
4478 	(void) snprintf(pgName, sizeof (pgName), "%s%s",
4479 	    STMF_PROVIDER_DATA_PREFIX, providerName);
4480 
4481 	/*
4482 	 * Allocate scf resources
4483 	 */
4484 	if (((pg = scf_pg_create(handle)) == NULL) ||
4485 	    ((entry1 = scf_entry_create(handle)) == NULL) ||
4486 	    ((entry2 = scf_entry_create(handle)) == NULL) ||
4487 	    ((entry3 = scf_entry_create(handle)) == NULL) ||
4488 	    ((entry5 = scf_entry_create(handle)) == NULL) ||
4489 	    ((value1 = scf_value_create(handle)) == NULL) ||
4490 	    ((value2 = scf_value_create(handle)) == NULL) ||
4491 	    ((value3 = scf_value_create(handle)) == NULL) ||
4492 	    ((value4 = scf_value_create(handle)) == NULL) ||
4493 	    ((value5 = scf_value_create(handle)) == NULL) ||
4494 	    ((prop = scf_property_create(handle)) == NULL) ||
4495 	    ((tran = scf_transaction_create(handle)) == NULL)) {
4496 		syslog(LOG_ERR, "scf alloc resource failed - %s",
4497 		    scf_strerror(scf_error()));
4498 		ret = STMF_PS_ERROR;
4499 		goto out;
4500 	}
4501 
4502 	/*
4503 	 * Get the existing property group
4504 	 */
4505 	if (scf_service_get_pg(svc, pgName, pg) == -1) {
4506 		if (scf_error() != SCF_ERROR_NOT_FOUND) {
4507 			syslog(LOG_ERR, "get pg %s failed - %s",
4508 			    pgName, scf_strerror(scf_error()));
4509 			ret = STMF_PS_ERROR;
4510 			goto out;
4511 		} else {
4512 			/*
4513 			 * create the property group.
4514 			 */
4515 			if (scf_service_add_pg(svc, pgName,
4516 			    SCF_GROUP_APPLICATION, 0, pg) == -1) {
4517 				syslog(LOG_ERR, "add pg %s failed - %s",
4518 				    pgName, scf_strerror(scf_error()));
4519 				ret = STMF_PS_ERROR;
4520 				goto out;
4521 			}
4522 			newPg = B_TRUE;
4523 		}
4524 	}
4525 
4526 	/*
4527 	 * Begin the transaction
4528 	 */
4529 	if (scf_transaction_start(tran, pg) == -1) {
4530 		syslog(LOG_ERR, "start transaction for %s failed - %s",
4531 		    pgName, scf_strerror(scf_error()));
4532 		ret = STMF_PS_ERROR;
4533 		goto out;
4534 	}
4535 
4536 	if (!newPg) {
4537 		/*
4538 		 * Get the STMF_PROVIDER_DATA_PROP_COUNT property
4539 		 */
4540 		if (scf_pg_get_property(pg, STMF_PROVIDER_DATA_PROP_COUNT,
4541 		    prop) == -1) {
4542 			syslog(LOG_ERR, "get property %s/%s failed - %s",
4543 			    pgName, STMF_PROVIDER_DATA_PROP_COUNT,
4544 			    scf_strerror(scf_error()));
4545 			ret = STMF_PS_ERROR;
4546 			goto out;
4547 		}
4548 
4549 		/*
4550 		 * Get the STMF_PROVIDER_DATA_PROP_COUNT value
4551 		 */
4552 		if (scf_property_get_value(prop, value4) == -1) {
4553 			syslog(LOG_ERR, "get property value %s/%s failed - %s",
4554 			    pgName, STMF_PROVIDER_DATA_PROP_COUNT,
4555 			    scf_strerror(scf_error()));
4556 			ret = STMF_PS_ERROR;
4557 			goto out;
4558 		}
4559 
4560 		/*
4561 		 * Now get the actual value from the value handle
4562 		 */
4563 		if (scf_value_get_count(value4, &oldBlockCnt) == -1) {
4564 			syslog(LOG_ERR, "get integer value %s/%s failed - %s",
4565 			    pgName, STMF_PROVIDER_DATA_PROP_COUNT,
4566 			    scf_strerror(scf_error()));
4567 			ret = STMF_PS_ERROR;
4568 			goto out;
4569 		}
4570 	}
4571 
4572 	/*
4573 	 * Get the STMF_PROVIDER_DATA_PROP_SET_COUNT property
4574 	 * If it doesn't exist, we'll create it later after successfully
4575 	 * setting the data.
4576 	 */
4577 	if (scf_pg_get_property(pg, STMF_PROVIDER_DATA_PROP_SET_COUNT,
4578 	    prop) == -1) {
4579 		if (scf_error() == SCF_ERROR_NOT_FOUND) {
4580 			foundSetCnt = B_FALSE;
4581 		} else {
4582 			syslog(LOG_ERR, "get property %s/%s failed - %s",
4583 			    pgName, STMF_PROVIDER_DATA_PROP_SET_COUNT,
4584 			    scf_strerror(scf_error()));
4585 			ret = STMF_PS_ERROR;
4586 			goto out;
4587 		}
4588 	}
4589 
4590 	if (foundSetCnt) {
4591 		/*
4592 		 * Get the STMF_PROVIDER_DATA_PROP_SET_COUNT value
4593 		 */
4594 		if (scf_property_get_value(prop, value5) == -1) {
4595 			syslog(LOG_ERR, "get property value %s/%s failed - %s",
4596 			    pgName, STMF_PROVIDER_DATA_PROP_SET_COUNT,
4597 			    scf_strerror(scf_error()));
4598 			ret = STMF_PS_ERROR;
4599 			goto out;
4600 		}
4601 
4602 		/*
4603 		 * Now get the actual value from the value handle
4604 		 */
4605 		if (scf_value_get_count(value5, &setCnt) == -1) {
4606 			syslog(LOG_ERR, "get integer value %s/%s failed - %s",
4607 			    pgName, STMF_PROVIDER_DATA_PROP_SET_COUNT,
4608 			    scf_strerror(scf_error()));
4609 			ret = STMF_PS_ERROR;
4610 			goto out;
4611 		}
4612 
4613 		/*
4614 		 * Compare the setCnt prop to the caller's.
4615 		 */
4616 		if (setToken && (*setToken != setCnt)) {
4617 			ret = STMF_PS_ERROR_PROV_DATA_STALE;
4618 			goto out;
4619 		}
4620 	}
4621 
4622 	setCnt++;
4623 
4624 	/*
4625 	 * prepare the list for writing
4626 	 */
4627 	if (nvlist_pack(nvl, &nvlistEncoded, &nvlistEncodedSize,
4628 	    NV_ENCODE_XDR, 0) != 0) {
4629 		syslog(LOG_ERR, "nvlist_pack for %s failed",
4630 		    pgName);
4631 		ret = STMF_PS_ERROR_NOMEM;
4632 		goto out;
4633 	}
4634 
4635 	/* Determine how many chunks we need to write */
4636 	blockCnt = nvlistEncodedSize/STMF_PROVIDER_DATA_PROP_SIZE;
4637 	if (nvlistEncodedSize % STMF_PROVIDER_DATA_PROP_SIZE)
4638 		blockCnt++;
4639 
4640 	/* allocate entry and value resources for writing those chunks */
4641 	addEntry = (scf_transaction_entry_t **)calloc(1, sizeof (*addEntry)
4642 	    * blockCnt);
4643 	if (addEntry == NULL) {
4644 		syslog(LOG_ERR, "addEntry alloc for %s failed", pgName);
4645 		ret = STMF_PS_ERROR_NOMEM;
4646 		goto out;
4647 	}
4648 
4649 	addValue = (scf_value_t **)calloc(1, sizeof (*addValue)
4650 	    * blockCnt);
4651 	if (addValue == NULL) {
4652 		syslog(LOG_ERR, "value alloc for %s failed", pgName);
4653 		ret = STMF_PS_ERROR_NOMEM;
4654 		goto out;
4655 	}
4656 
4657 	/*
4658 	 * allocate entry delete resources for deleting anything existing
4659 	 * that is more than the new block count. We could leave them around
4660 	 * without suffering any ill effects but it will be cleaner to look at
4661 	 * in smf tools if they are deleted.
4662 	 */
4663 	if (oldBlockCnt > blockCnt) {
4664 		deleteEntry = (scf_transaction_entry_t **)calloc(1,
4665 		    sizeof (*deleteEntry) * (oldBlockCnt - blockCnt));
4666 		if (deleteEntry == NULL) {
4667 			syslog(LOG_ERR, "deleteEntry alloc for %s failed",
4668 			    pgName);
4669 			ret = STMF_PS_ERROR_NOMEM;
4670 			goto out;
4671 		}
4672 		deleteEntryAlloc = oldBlockCnt - blockCnt;
4673 	}
4674 
4675 
4676 	for (i = 0; i < blockCnt; i++) {
4677 		/*
4678 		 * Create the entry resource for the prop
4679 		 */
4680 		addEntry[i] = scf_entry_create(handle);
4681 		if (addEntry[i] == NULL) {
4682 			syslog(LOG_ERR, "scf value alloc for %s failed - %s",
4683 			    pgName, scf_strerror(scf_error()));
4684 			ret = STMF_PS_ERROR;
4685 			goto out;
4686 		}
4687 
4688 		/* bump alloc count for addEntry allocation */
4689 		addEntryAlloc++;
4690 
4691 		/*
4692 		 * create the name to use for the property
4693 		 */
4694 		(void) snprintf(dataPropertyName, sizeof (dataPropertyName),
4695 		    "%s-%d", STMF_PROVIDER_DATA_PROP_PREFIX, i);
4696 
4697 		/*
4698 		 * Create the new property
4699 		 */
4700 		if (scf_transaction_property_new(tran, addEntry[i],
4701 		    dataPropertyName, SCF_TYPE_OPAQUE) == -1) {
4702 			if (scf_error() == SCF_ERROR_EXISTS) {
4703 				if (scf_transaction_property_change(tran,
4704 				    addEntry[i], dataPropertyName,
4705 				    SCF_TYPE_OPAQUE) == -1) {
4706 					syslog(LOG_ERR, "transaction property "
4707 					    "change %s/%s failed - %s",
4708 					    pgName, dataPropertyName,
4709 					    scf_strerror(scf_error()));
4710 					ret = STMF_PS_ERROR;
4711 					goto out;
4712 				}
4713 			} else {
4714 				syslog(LOG_ERR,
4715 				    "transaction property new %s/%s "
4716 				    "failed - %s", pgName, dataPropertyName,
4717 				    scf_strerror(scf_error()));
4718 				ret = STMF_PS_ERROR;
4719 				goto out;
4720 			}
4721 		}
4722 		/*
4723 		 * Create the value resource for the prop
4724 		 */
4725 		addValue[i] = scf_value_create(handle);
4726 		if (addValue[i] == NULL) {
4727 			syslog(LOG_ERR, "scf value alloc for %s failed - %s",
4728 			    pgName, scf_strerror(scf_error()));
4729 			ret = STMF_PS_ERROR;
4730 			goto out;
4731 		}
4732 
4733 		/* bump alloc count for addValue allocation */
4734 		addValueAlloc++;
4735 
4736 		/*
4737 		 * Set the data block offset and size
4738 		 */
4739 		if ((STMF_PROVIDER_DATA_PROP_SIZE * (i + 1))
4740 		    > nvlistEncodedSize) {
4741 			blockSize = nvlistEncodedSize
4742 			    - STMF_PROVIDER_DATA_PROP_SIZE * i;
4743 		} else {
4744 			blockSize = STMF_PROVIDER_DATA_PROP_SIZE;
4745 		}
4746 
4747 		blockOffset = STMF_PROVIDER_DATA_PROP_SIZE * i;
4748 		if (scf_value_set_opaque(addValue[i],
4749 		    &nvlistEncoded[blockOffset], blockSize) == -1) {
4750 			syslog(LOG_ERR, "set value for %s failed - %s",
4751 			    pgName, scf_strerror(scf_error()));
4752 			ret = STMF_PS_ERROR;
4753 			goto out;
4754 		}
4755 
4756 		/*
4757 		 * Add the data block to the transaction entry
4758 		 */
4759 		if (scf_entry_add_value(addEntry[i], addValue[i]) == -1) {
4760 			syslog(LOG_ERR, "add value for %s failed - %s",
4761 			    pgName, scf_strerror(scf_error()));
4762 			ret = STMF_PS_ERROR;
4763 			goto out;
4764 		}
4765 	}
4766 
4767 	/*
4768 	 * Now we need to delete any chunks (properties) that are no longer
4769 	 * needed. Iterate through the rest of the chunks deleting each.
4770 	 */
4771 	for (i = blockCnt; i < oldBlockCnt; i++) {
4772 		/*
4773 		 * Create the entry resource for the prop
4774 		 */
4775 		deleteEntry[j] = scf_entry_create(handle);
4776 		if (deleteEntry[j] == NULL) {
4777 			syslog(LOG_ERR, "scf value alloc for %s failed - %s",
4778 			    pgName, scf_strerror(scf_error()));
4779 			ret = STMF_PS_ERROR;
4780 			goto out;
4781 		}
4782 
4783 		/*
4784 		 * create the name to use for the property
4785 		 */
4786 		(void) snprintf(dataPropertyName, sizeof (dataPropertyName),
4787 		    "%s-%d", STMF_PROVIDER_DATA_PROP_PREFIX, i);
4788 
4789 		/*
4790 		 * Delete the existing property
4791 		 */
4792 		if (scf_transaction_property_delete(tran, deleteEntry[j++],
4793 		    dataPropertyName) == -1) {
4794 			syslog(LOG_ERR, "delete property %s/%s failed - %s",
4795 			    pgName, dataPropertyName,
4796 			    scf_strerror(scf_error()));
4797 			ret = STMF_PS_ERROR;
4798 			goto out;
4799 		}
4800 	}
4801 
4802 	if (newPg) {
4803 		/*
4804 		 * Ensure the read_authorization property is set
4805 		 * for the group
4806 		 */
4807 		if (scf_transaction_property_new(tran, entry1,
4808 		    "read_authorization", SCF_TYPE_ASTRING) == -1) {
4809 			syslog(LOG_ERR, "transaction property %s/%s new "
4810 			    "failed - %s", pgName, "read_authorization",
4811 			    scf_strerror(scf_error()));
4812 			ret = STMF_PS_ERROR;
4813 			goto out;
4814 		}
4815 
4816 		if (scf_value_set_astring(value1, STMF_SMF_READ_ATTR) == -1) {
4817 			syslog(LOG_ERR, "set value %s/%s failed - %s",
4818 			    pgName, "read_authorization",
4819 			    scf_strerror(scf_error()));
4820 			ret = STMF_PS_ERROR;
4821 			goto out;
4822 		}
4823 
4824 		if (scf_entry_add_value(entry1, value1) == -1) {
4825 			syslog(LOG_ERR, "add value %s/%s failed - %s",
4826 			    pgName, "read_authorization",
4827 			    scf_strerror(scf_error()));
4828 			ret = STMF_PS_ERROR;
4829 			goto out;
4830 		}
4831 	}
4832 
4833 	/* create or change the count property */
4834 	if (scf_transaction_property_new(tran, entry2,
4835 	    STMF_PROVIDER_DATA_PROP_COUNT, SCF_TYPE_COUNT) == -1) {
4836 		if (scf_error() == SCF_ERROR_EXISTS) {
4837 			if (scf_transaction_property_change(tran, entry2,
4838 			    STMF_PROVIDER_DATA_PROP_COUNT,
4839 			    SCF_TYPE_COUNT) == -1) {
4840 				syslog(LOG_ERR, "transaction property change "
4841 				    "%s/%s failed - %s", pgName,
4842 				    STMF_PROVIDER_DATA_PROP_COUNT,
4843 				    scf_strerror(scf_error()));
4844 				ret = STMF_PS_ERROR;
4845 				goto out;
4846 			}
4847 		} else {
4848 			syslog(LOG_ERR, "transaction property %s/%s new "
4849 			    "failed - %s", pgName,
4850 			    STMF_PROVIDER_DATA_PROP_COUNT,
4851 			    scf_strerror(scf_error()));
4852 			ret = STMF_PS_ERROR;
4853 			goto out;
4854 		}
4855 	}
4856 
4857 	scf_value_set_count(value2, blockCnt);
4858 
4859 	if (scf_entry_add_value(entry2, value2) == -1) {
4860 		syslog(LOG_ERR, "add value %s/%s failed - %s",
4861 		    pgName, STMF_PROVIDER_DATA_PROP_COUNT,
4862 		    scf_strerror(scf_error()));
4863 		ret = STMF_PS_ERROR;
4864 		goto out;
4865 	}
4866 
4867 	/* create or change the set count property */
4868 	if (scf_transaction_property_new(tran, entry5,
4869 	    STMF_PROVIDER_DATA_PROP_SET_COUNT, SCF_TYPE_COUNT) == -1) {
4870 		if (scf_error() == SCF_ERROR_EXISTS) {
4871 			if (scf_transaction_property_change(tran, entry5,
4872 			    STMF_PROVIDER_DATA_PROP_SET_COUNT,
4873 			    SCF_TYPE_COUNT) == -1) {
4874 				syslog(LOG_ERR,
4875 				    "transaction property change %s/%s "
4876 				    "failed - %s", pgName,
4877 				    STMF_PROVIDER_DATA_PROP_SET_COUNT,
4878 				    scf_strerror(scf_error()));
4879 				ret = STMF_PS_ERROR;
4880 				goto out;
4881 			}
4882 		} else {
4883 			syslog(LOG_ERR, "transaction property new %s/%s "
4884 			    "failed - %s", pgName,
4885 			    STMF_PROVIDER_DATA_PROP_SET_COUNT,
4886 			    scf_strerror(scf_error()));
4887 			ret = STMF_PS_ERROR;
4888 			goto out;
4889 		}
4890 	}
4891 
4892 
4893 
4894 	scf_value_set_count(value5, setCnt);
4895 
4896 	if (scf_entry_add_value(entry5, value5) == -1) {
4897 		syslog(LOG_ERR, "add value %s/%s failed - %s",
4898 		    pgName, STMF_PROVIDER_DATA_PROP_SET_COUNT,
4899 		    scf_strerror(scf_error()));
4900 		ret = STMF_PS_ERROR;
4901 		goto out;
4902 	}
4903 
4904 	/* create or change the provider type property */
4905 	if (scf_transaction_property_new(tran, entry3,
4906 	    STMF_PROVIDER_DATA_PROP_TYPE, SCF_TYPE_INTEGER) == -1) {
4907 		if (scf_error() == SCF_ERROR_EXISTS) {
4908 			if (scf_transaction_property_change(tran, entry3,
4909 			    STMF_PROVIDER_DATA_PROP_TYPE,
4910 			    SCF_TYPE_INTEGER) == -1) {
4911 				syslog(LOG_ERR,
4912 				    "transaction property change %s/%s "
4913 				    "failed - %s", pgName,
4914 				    STMF_PROVIDER_DATA_PROP_TYPE,
4915 				    scf_strerror(scf_error()));
4916 				ret = STMF_PS_ERROR;
4917 				goto out;
4918 			}
4919 		} else {
4920 			syslog(LOG_ERR, "transaction property new %s/%s "
4921 			    "failed - %s", pgName, STMF_PROVIDER_DATA_PROP_TYPE,
4922 			    scf_strerror(scf_error()));
4923 			ret = STMF_PS_ERROR;
4924 			goto out;
4925 		}
4926 	}
4927 
4928 	switch (providerType) {
4929 		case STMF_PORT_PROVIDER_TYPE:
4930 		case STMF_LU_PROVIDER_TYPE:
4931 			scf_value_set_integer(value3, providerType);
4932 			break;
4933 		default:
4934 			ret = STMF_PS_ERROR;
4935 			goto out;
4936 	}
4937 
4938 	if (scf_entry_add_value(entry3, value3) == -1) {
4939 		syslog(LOG_ERR, "add value %s/%s failed - %s", pgName,
4940 		    STMF_PROVIDER_DATA_PROP_TYPE, scf_strerror(scf_error()));
4941 		ret = STMF_PS_ERROR;
4942 		goto out;
4943 	}
4944 
4945 
4946 	if ((commitRet = scf_transaction_commit(tran)) != 1) {
4947 		syslog(LOG_ERR, "transaction commit for %s failed - %s",
4948 		    pgName, scf_strerror(scf_error()));
4949 		if (commitRet == 0) {
4950 			ret = STMF_PS_ERROR_BUSY;
4951 		} else {
4952 			ret = STMF_PS_ERROR;
4953 		}
4954 		goto out;
4955 	}
4956 
4957 	/* pass the new token back to the caller if requested */
4958 	if (ret == STMF_PS_SUCCESS && setToken) {
4959 		*setToken = setCnt;
4960 	}
4961 
4962 out:
4963 	/*
4964 	 * Free resources
4965 	 */
4966 	if (handle != NULL) {
4967 		scf_handle_destroy(handle);
4968 	}
4969 	if (svc != NULL) {
4970 		scf_service_destroy(svc);
4971 	}
4972 	if (pg != NULL) {
4973 		scf_pg_destroy(pg);
4974 	}
4975 	if (prop != NULL) {
4976 		scf_property_destroy(prop);
4977 	}
4978 	if (tran != NULL) {
4979 		scf_transaction_destroy(tran);
4980 	}
4981 	for (i = 0; i < addEntryAlloc; i++) {
4982 		scf_entry_destroy(addEntry[i]);
4983 	}
4984 	for (i = 0; i < addValueAlloc; i++) {
4985 		scf_value_destroy(addValue[i]);
4986 	}
4987 	free(addValue);
4988 	free(addEntry);
4989 	for (i = 0; i < deleteEntryAlloc; i++) {
4990 		scf_entry_destroy(deleteEntry[i]);
4991 	}
4992 	free(deleteEntry);
4993 	if (entry1 != NULL) {
4994 		scf_entry_destroy(entry1);
4995 	}
4996 	if (entry2 != NULL) {
4997 		scf_entry_destroy(entry2);
4998 	}
4999 	if (entry3 != NULL) {
5000 		scf_entry_destroy(entry3);
5001 	}
5002 	if (entry5 != NULL) {
5003 		scf_entry_destroy(entry5);
5004 	}
5005 	if (value1 != NULL) {
5006 		scf_value_destroy(value1);
5007 	}
5008 	if (value2 != NULL) {
5009 		scf_value_destroy(value2);
5010 	}
5011 	if (value3 != NULL) {
5012 		scf_value_destroy(value3);
5013 	}
5014 	if (value4 != NULL) {
5015 		scf_value_destroy(value4);
5016 	}
5017 	if (value5 != NULL) {
5018 		scf_value_destroy(value5);
5019 	}
5020 	if (nvlistEncoded != NULL) {
5021 		free(nvlistEncoded);
5022 	}
5023 
5024 	return (ret);
5025 }
5026 
5027 /*
5028  * psGetViewEntry
5029  *
5030  * Purpose: Get a single view entry based on the logical unit identifier and
5031  *          view entry index
5032  *
5033  * lu - logical unit identifier
5034  * viewEntryIndex - index of view entry
5035  * ve - caller allocated stmfViewEntry structure. On success, this will
5036  *      contain the retrieved view entry
5037  */
5038 int
5039 psGetViewEntry(stmfGuid *lu, uint32_t viewEntryIndex, stmfViewEntry *ve)
5040 {
5041 	scf_handle_t	*handle = NULL;
5042 	scf_service_t	*svc = NULL;
5043 	scf_propertygroup_t	*pg = NULL;
5044 	char guidAsciiBuf[33]; /* size of ascii hex 16 byte guid with NULL */
5045 	char viewEntryPgName[VIEW_ENTRY_PG_SIZE];
5046 	char luPgName[LOGICAL_UNIT_PG_SIZE];
5047 	int ret = STMF_PS_SUCCESS;
5048 
5049 	ret = iPsInit(&handle, &svc);
5050 	if (ret != STMF_PS_SUCCESS) {
5051 		goto out;
5052 	}
5053 
5054 	pg = scf_pg_create(handle);
5055 	if (pg == NULL) {
5056 		syslog(LOG_ERR, "scf pg alloc failed - %s",
5057 		    scf_strerror(scf_error()));
5058 		ret = STMF_PS_ERROR;
5059 		goto out;
5060 	}
5061 
5062 	/* Convert to ASCII uppercase hexadecimal string */
5063 	(void) snprintf(guidAsciiBuf, sizeof (guidAsciiBuf),
5064 	    "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
5065 	    lu->guid[0], lu->guid[1], lu->guid[2], lu->guid[3], lu->guid[4],
5066 	    lu->guid[5], lu->guid[6], lu->guid[7], lu->guid[8], lu->guid[9],
5067 	    lu->guid[10], lu->guid[11], lu->guid[12], lu->guid[13],
5068 	    lu->guid[14], lu->guid[15]);
5069 
5070 	(void) snprintf(luPgName, sizeof (luPgName), "%s-%s",
5071 	    STMF_LU_PREFIX, guidAsciiBuf);
5072 
5073 	/*
5074 	 * Format of view entry property group name:
5075 	 *	VE-<view_entry_index>-<lu_name>
5076 	 */
5077 	(void) snprintf(viewEntryPgName, sizeof (viewEntryPgName),
5078 	    "%s-%d-%s", STMF_VE_PREFIX, viewEntryIndex, guidAsciiBuf);
5079 
5080 	if (scf_service_get_pg(svc, viewEntryPgName, pg) == -1) {
5081 		if (scf_error() == SCF_ERROR_NOT_FOUND) {
5082 			ret = STMF_PS_ERROR_NOT_FOUND;
5083 		} else {
5084 			syslog(LOG_ERR, "get pg %s failed - %s",
5085 			    viewEntryPgName, scf_strerror(scf_error()));
5086 			ret = STMF_PS_ERROR;
5087 		}
5088 		goto out;
5089 	}
5090 
5091 
5092 	if ((ret = iPsGetViewEntry(viewEntryPgName, ve)) != STMF_PS_SUCCESS) {
5093 		ret = STMF_PS_ERROR;
5094 		goto out;
5095 	}
5096 
5097 out:
5098 	/*
5099 	 * Free resources
5100 	 */
5101 	if (handle != NULL) {
5102 		scf_handle_destroy(handle);
5103 	}
5104 	if (svc != NULL) {
5105 		scf_service_destroy(svc);
5106 	}
5107 	if (pg != NULL) {
5108 		scf_pg_destroy(pg);
5109 	}
5110 
5111 	return (ret);
5112 }
5113 
5114 /*
5115  * psRemoveViewEntry
5116  *
5117  * Remove a view entry
5118  *
5119  * luGuid - identifier of logical unit from which to remove view entry
5120  * viewEntryIndex - view entry name to remove
5121  *
5122  * returns:
5123  *  STMF_PS_SUCCESS on success
5124  *  STMF_PS_ERROR_* on failure
5125  */
5126 int
5127 psRemoveViewEntry(stmfGuid *lu, uint32_t viewEntryIndex)
5128 {
5129 	scf_handle_t	*handle = NULL;
5130 	scf_service_t	*svc = NULL;
5131 	scf_propertygroup_t	*pg = NULL;
5132 	char guidAsciiBuf[33]; /* size of ascii hex 16 byte guid with NULL */
5133 	char viewEntryPgName[VIEW_ENTRY_PG_SIZE];
5134 	char luPgName[LOGICAL_UNIT_PG_SIZE];
5135 	int ret = STMF_PS_SUCCESS;
5136 	sigset_t sigmaskRestore;
5137 
5138 	/* grab the signal hold lock */
5139 	(void) pthread_mutex_lock(&sigSetLock);
5140 
5141 	/*
5142 	 * hold signals until we're done
5143 	 */
5144 	if (holdSignal(&sigmaskRestore) != 0) {
5145 		(void) pthread_mutex_unlock(&sigSetLock);
5146 		return (STMF_PS_ERROR);
5147 	}
5148 
5149 	ret = iPsInit(&handle, &svc);
5150 	if (ret != STMF_PS_SUCCESS) {
5151 		goto out;
5152 	}
5153 
5154 	pg = scf_pg_create(handle);
5155 	if (pg == NULL) {
5156 		syslog(LOG_ERR, "scf pg alloc failed - %s",
5157 		    scf_strerror(scf_error()));
5158 		ret = STMF_PS_ERROR;
5159 		goto out;
5160 	}
5161 
5162 	/* Convert to ASCII uppercase hexadecimal string */
5163 	(void) snprintf(guidAsciiBuf, sizeof (guidAsciiBuf),
5164 	    "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
5165 	    lu->guid[0], lu->guid[1], lu->guid[2], lu->guid[3], lu->guid[4],
5166 	    lu->guid[5], lu->guid[6], lu->guid[7], lu->guid[8], lu->guid[9],
5167 	    lu->guid[10], lu->guid[11], lu->guid[12], lu->guid[13],
5168 	    lu->guid[14], lu->guid[15]);
5169 
5170 	(void) snprintf(luPgName, sizeof (luPgName), "%s-%s",
5171 	    STMF_LU_PREFIX, guidAsciiBuf);
5172 
5173 	/*
5174 	 * Format of view entry property group name:
5175 	 *	VE-<view_entry_index>-<lu_name>
5176 	 */
5177 	(void) snprintf(viewEntryPgName, sizeof (viewEntryPgName),
5178 	    "%s-%d-%s", STMF_VE_PREFIX, viewEntryIndex, guidAsciiBuf);
5179 
5180 	if (scf_service_get_pg(svc, viewEntryPgName, pg) == -1) {
5181 		if (scf_error() == SCF_ERROR_NOT_FOUND) {
5182 			ret = STMF_PS_ERROR_NOT_FOUND;
5183 		} else {
5184 			syslog(LOG_ERR, "get pg %s failed - %s",
5185 			    viewEntryPgName, scf_strerror(scf_error()));
5186 			ret = STMF_PS_ERROR;
5187 		}
5188 		goto out;
5189 	}
5190 
5191 	/*
5192 	 * update the logical unit property group to remove
5193 	 * the view entry and update the view entry count
5194 	 * If it fails, we won't delete the property group so that
5195 	 * we maintain consistency.
5196 	 */
5197 	if ((ret = iPsAddRemoveLuViewEntry(luPgName, viewEntryPgName,
5198 	    REMOVE)) != STMF_PS_SUCCESS) {
5199 		goto out;
5200 	}
5201 
5202 	/*
5203 	 * Delete the view entry. If this fails, we should try to add
5204 	 * the logical unit view entry property group back otherwise
5205 	 * we're inconsistent.
5206 	 */
5207 	if (scf_pg_delete(pg) == -1) {
5208 		syslog(LOG_ERR, "delete pg %s failed - %s", viewEntryPgName,
5209 		    scf_strerror(scf_error()));
5210 		if ((ret = iPsAddRemoveLuViewEntry(luPgName, viewEntryPgName,
5211 		    ADD)) != STMF_PS_SUCCESS) {
5212 			syslog(LOG_ERR, "add of view entry %s failed, possible"
5213 			    "inconsistency - %s", viewEntryPgName,
5214 			    scf_strerror(scf_error()));
5215 		}
5216 		ret = STMF_PS_ERROR;
5217 		goto out;
5218 	}
5219 
5220 out:
5221 	/*
5222 	 * Okay, we're done. Release the signals
5223 	 */
5224 	if (releaseSignal(&sigmaskRestore) != 0) {
5225 		/*
5226 		 * Don't set this as an STMF_PS_ERROR_*. We succeeded
5227 		 * the requested operation. But we do need to log it.
5228 		 */
5229 		syslog(LOG_ERR, "Unable to release one or more signals - %s",
5230 		    strerror(errno));
5231 	}
5232 
5233 	/*
5234 	 * Free resources
5235 	 */
5236 	if (handle != NULL) {
5237 		scf_handle_destroy(handle);
5238 	}
5239 	if (svc != NULL) {
5240 		scf_service_destroy(svc);
5241 	}
5242 	if (pg != NULL) {
5243 		scf_pg_destroy(pg);
5244 	}
5245 
5246 	/* release the signal hold lock */
5247 	(void) pthread_mutex_unlock(&sigSetLock);
5248 
5249 	return (ret);
5250 }
5251 
5252 
5253 
5254 /*
5255  * holdSignal
5256  *
5257  * Hold SIGINT, SIGTERM, SIGQUIT until further notice.
5258  *
5259  * Saves old signal mask on a per thread basis
5260  * and saves action for the process.
5261  *
5262  * Installs action for above signals.
5263  *
5264  * locks held: sigSetLock
5265  *
5266  * returns:
5267  *  0 on success
5268  *  non-zero otherwise
5269  */
5270 static int
5271 holdSignal(sigset_t *sigmaskRestore)
5272 {
5273 	struct sigaction act;
5274 	sigset_t sigmask;
5275 
5276 	/*
5277 	 * Return existing signal mask for this thread
5278 	 */
5279 	if (pthread_sigmask(0, NULL, sigmaskRestore) != 0) {
5280 		return (1);
5281 	}
5282 
5283 	(void) sigemptyset(&act.sa_mask);
5284 	act.sa_handler = sigHandler;
5285 	act.sa_flags = 0;
5286 
5287 	/*
5288 	 * Have we set the actions for the signals we want to catch?
5289 	 */
5290 	if (!actionSet) {
5291 		if (sigaction(SIGQUIT, &act, &currentActionQuit) != 0) {
5292 			return (1);
5293 		}
5294 
5295 		if (sigaction(SIGINT, &act, &currentActionInt) != 0) {
5296 			return (1);
5297 		}
5298 
5299 		if (sigaction(SIGTERM, &act, &currentActionTerm) != 0) {
5300 			return (1);
5301 		}
5302 
5303 		actionSet = B_TRUE;
5304 	}
5305 
5306 	/*
5307 	 * We still need to change the mask for the current thread
5308 	 */
5309 	if (sigfillset(&sigmask) != 0) {
5310 		return (1);
5311 	}
5312 
5313 	(void) sigdelset(&sigmask, SIGQUIT);
5314 
5315 	(void) sigdelset(&sigmask, SIGINT);
5316 
5317 	(void) sigdelset(&sigmask, SIGTERM);
5318 
5319 	if (pthread_sigmask(SIG_SETMASK, &sigmask, NULL) != 0) {
5320 		return (1);
5321 	}
5322 
5323 	return (0);
5324 }
5325 
5326 /*
5327  * releaseSignal
5328  *
5329  * Re-install the original signal mask and signal actions
5330  *
5331  * Also, raise any signals that were caught during the hold period and clear
5332  * the signal from the caught set (signalsCaught).
5333  *
5334  * locks held: sigSetLock
5335  *
5336  * Returns
5337  *  0 on success
5338  *  non-zero otherwise
5339  */
5340 static int
5341 releaseSignal(sigset_t *sigmaskRestore)
5342 {
5343 	int ret = 0;
5344 
5345 	if (sigaction(SIGQUIT, &currentActionQuit, NULL) != 0) {
5346 		ret = 1;
5347 	}
5348 
5349 	if (sigaction(SIGINT, &currentActionInt, NULL) != 0) {
5350 		ret = 1;
5351 	}
5352 
5353 	if (sigaction(SIGTERM, &currentActionTerm, NULL) != 0) {
5354 		ret = 1;
5355 	}
5356 
5357 	actionSet = B_FALSE;
5358 
5359 	/*
5360 	 * Restore previous signal mask for this thread
5361 	 */
5362 	if (pthread_sigmask(SIG_SETMASK, sigmaskRestore, NULL) != 0) {
5363 		syslog(LOG_ERR, "Unable to restore sigmask");
5364 	}
5365 
5366 	/*
5367 	 * Now raise signals that were raised while we were held
5368 	 */
5369 	if (sigismember(&signalsCaught, SIGTERM)) {
5370 		(void) sigdelset(&signalsCaught, SIGTERM);
5371 		(void) raise(SIGTERM);
5372 	}
5373 
5374 	if (sigismember(&signalsCaught, SIGINT)) {
5375 		(void) sigdelset(&signalsCaught, SIGINT);
5376 		(void) raise(SIGINT);
5377 	}
5378 
5379 	if (sigismember(&signalsCaught, SIGQUIT)) {
5380 		(void) sigdelset(&signalsCaught, SIGQUIT);
5381 		(void) raise(SIGQUIT);
5382 	}
5383 
5384 	return (ret);
5385 }
5386