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