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