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