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