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