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