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