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