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