xref: /illumos-gate/usr/src/lib/libstmf/common/stmf.c (revision 33f5ff17)
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  * Copyright 2012 Milan Jurik. All rights reserved.
24  */
25 
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <wchar.h>
29 #include <strings.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <fcntl.h>
33 #include <unistd.h>
34 #include <libintl.h>
35 #include <errno.h>
36 #include <string.h>
37 #include <assert.h>
38 #include <libnvpair.h>
39 #include <pthread.h>
40 #include <syslog.h>
41 #include <libstmf.h>
42 #include <netinet/in.h>
43 #include <inttypes.h>
44 #include <store.h>
45 #include <locale.h>
46 #include <math.h>
47 #include <libstmf_impl.h>
48 #include <sys/stmf_ioctl.h>
49 #include <sys/stmf_sbd_ioctl.h>
50 #include <sys/pppt_ioctl.h>
51 #include <macros.h>
52 
53 #define	STMF_PATH    "/devices/pseudo/stmf@0:admin"
54 #define	SBD_PATH    "/devices/pseudo/stmf_sbd@0:admin"
55 #define	PPPT_PATH    "/devices/pseudo/pppt@0:pppt"
56 
57 #define	EUI "eui."
58 #define	WWN "wwn."
59 #define	IQN "iqn."
60 #define	LU_ASCII_GUID_SIZE 32
61 #define	LU_GUID_SIZE 16
62 #define	OUI_ASCII_SIZE 6
63 #define	HOST_ID_ASCII_SIZE 8
64 #define	OUI_SIZE 3
65 #define	HOST_ID_SIZE 4
66 #define	IDENT_LENGTH_BYTE 3
67 
68 /* various initial allocation values */
69 #define	ALLOC_LU		8192
70 #define	ALLOC_TARGET_PORT	2048
71 #define	ALLOC_PROVIDER		64
72 #define	ALLOC_GROUP		2048
73 #define	ALLOC_SESSION		2048
74 #define	ALLOC_VE		256
75 #define	ALLOC_PP_DATA_SIZE	128*1024
76 #define	ALLOC_GRP_MEMBER	256
77 
78 #define	MAX_ISCSI_NAME	223
79 #define	MAX_SERIAL_SIZE 252 + 1
80 #define	MAX_LU_ALIAS_SIZE 256
81 #define	MAX_SBD_PROPS	MAXPATHLEN + MAX_SERIAL_SIZE + MAX_LU_ALIAS_SIZE
82 
83 #define	OPEN_STMF 0
84 #define	OPEN_EXCL_STMF O_EXCL
85 
86 #define	OPEN_SBD 0
87 #define	OPEN_EXCL_SBD O_EXCL
88 
89 #define	OPEN_PPPT 0
90 #define	OPEN_EXCL_PPPT O_EXCL
91 
92 #define	LOGICAL_UNIT_TYPE 0
93 #define	TARGET_TYPE 1
94 #define	STMF_SERVICE_TYPE 2
95 
96 #define	HOST_GROUP   1
97 #define	TARGET_GROUP 2
98 
99 /* set default persistence here */
100 #define	STMF_DEFAULT_PERSIST	STMF_PERSIST_SMF
101 
102 #define	MAX_PROVIDER_RETRY 30
103 
104 static int openStmf(int, int *fd);
105 static int openSbd(int, int *fd);
106 static int openPppt(int, int *fd);
107 static int groupIoctl(int fd, int cmd, stmfGroupName *);
108 static int loadStore(int fd);
109 static int initializeConfig();
110 static int groupMemberIoctl(int fd, int cmd, stmfGroupName *, stmfDevid *);
111 static int guidCompare(const void *, const void *);
112 static int addViewEntryIoctl(int fd, stmfGuid *, stmfViewEntry *);
113 static int loadHostGroups(int fd, stmfGroupList *);
114 static int loadTargetGroups(int fd, stmfGroupList *);
115 static int getStmfState(stmf_state_desc_t *);
116 static int setStmfState(int fd, stmf_state_desc_t *, int);
117 static int setProviderData(int fd, char *, nvlist_t *, int, uint64_t *);
118 static int createDiskResource(luResourceImpl *);
119 static int createDiskLu(diskResource *, stmfGuid *);
120 static int deleteDiskLu(stmfGuid *luGuid);
121 static int getDiskProp(luResourceImpl *, uint32_t, char *, size_t *);
122 static int getDiskAllProps(stmfGuid *luGuid, luResource *hdl);
123 static int loadDiskPropsFromDriver(luResourceImpl *, sbd_lu_props_t *);
124 static int removeGuidFromDiskStore(stmfGuid *);
125 static int addGuidToDiskStore(stmfGuid *, char *);
126 static int persistDiskGuid(stmfGuid *, char *, boolean_t);
127 static int setDiskProp(luResourceImpl *, uint32_t, const char *);
128 static int getDiskGlobalProp(uint32_t prop, char *propVal, size_t *propLen);
129 static int checkHexUpper(char *);
130 static int strToShift(const char *);
131 static int niceStrToNum(const char *, uint64_t *);
132 static void diskError(uint32_t, int *);
133 static int importDiskLu(char *fname, stmfGuid *);
134 static int modifyDiskLu(diskResource *, stmfGuid *, const char *);
135 static int modifyDiskLuProp(stmfGuid *, const char *, uint32_t, const char *);
136 static int validateModifyDiskProp(uint32_t);
137 static uint8_t iGetPersistMethod();
138 static int groupListIoctl(stmfGroupList **, int);
139 static int iLoadGroupFromPs(stmfGroupList **, int);
140 static int groupMemberListIoctl(stmfGroupName *, stmfGroupProperties **, int);
141 static int getProviderData(char *, nvlist_t **, int, uint64_t *);
142 static int setDiskStandby(stmfGuid *luGuid);
143 static int setDiskGlobalProp(uint32_t, const char *);
144 static int viewEntryCompare(const void *, const void *);
145 static void deleteNonActiveLus();
146 static int loadStmfProp(int fd);
147 
148 static pthread_mutex_t persistenceTypeLock = PTHREAD_MUTEX_INITIALIZER;
149 static int iPersistType = 0;
150 /* when B_TRUE, no need to access SMF anymore. Just use iPersistType */
151 static boolean_t iLibSetPersist = B_FALSE;
152 
153 /*
154  * Open for stmf module
155  *
156  * flag - open flag (OPEN_STMF, OPEN_EXCL_STMF)
157  * fd - pointer to integer. On success, contains the stmf file descriptor
158  */
159 static int
openStmf(int flag,int * fd)160 openStmf(int flag, int *fd)
161 {
162 	int ret = STMF_STATUS_ERROR;
163 
164 	if ((*fd = open(STMF_PATH, O_NDELAY | O_RDONLY | flag)) != -1) {
165 		ret = STMF_STATUS_SUCCESS;
166 	} else {
167 		if (errno == EBUSY) {
168 			ret = STMF_ERROR_BUSY;
169 		} else if (errno == EACCES) {
170 			ret = STMF_ERROR_PERM;
171 		} else {
172 			ret = STMF_STATUS_ERROR;
173 		}
174 		syslog(LOG_DEBUG, "openStmf:open failure:%s:errno(%d)",
175 		    STMF_PATH, errno);
176 	}
177 
178 	return (ret);
179 }
180 
181 /*
182  * Open for sbd module
183  *
184  * flag - open flag (OPEN_SBD, OPEN_EXCL_SBD)
185  * fd - pointer to integer. On success, contains the stmf file descriptor
186  */
187 static int
openSbd(int flag,int * fd)188 openSbd(int flag, int *fd)
189 {
190 	int ret = STMF_STATUS_ERROR;
191 
192 	if ((*fd = open(SBD_PATH, O_NDELAY | O_RDONLY | flag)) != -1) {
193 		ret = STMF_STATUS_SUCCESS;
194 	} else {
195 		if (errno == EBUSY) {
196 			ret = STMF_ERROR_BUSY;
197 		} else if (errno == EACCES) {
198 			ret = STMF_ERROR_PERM;
199 		} else {
200 			ret = STMF_STATUS_ERROR;
201 		}
202 		syslog(LOG_DEBUG, "openSbd:open failure:%s:errno(%d)",
203 		    SBD_PATH, errno);
204 	}
205 
206 	return (ret);
207 }
208 
209 /*
210  * Open for pppt module
211  *
212  * flag - open flag (OPEN_PPPT, OPEN_EXCL_PPPT)
213  * fd - pointer to integer. On success, contains the stmf file descriptor
214  */
215 static int
openPppt(int flag,int * fd)216 openPppt(int flag, int *fd)
217 {
218 	int ret = STMF_STATUS_ERROR;
219 
220 	if ((*fd = open(PPPT_PATH, O_RDONLY | flag)) != -1) {
221 		ret = STMF_STATUS_SUCCESS;
222 	} else {
223 		if (errno == EBUSY) {
224 			ret = STMF_ERROR_BUSY;
225 		} else if (errno == EACCES) {
226 			ret = STMF_ERROR_PERM;
227 		} else {
228 			ret = STMF_STATUS_ERROR;
229 		}
230 		syslog(LOG_DEBUG, "openPppt:open failure:%s:errno(%d)",
231 		    PPPT_PATH, errno);
232 	}
233 
234 	return (ret);
235 }
236 
237 /*
238  * initializeConfig
239  *
240  * This routine should be called before any ioctl requiring initialization
241  * which is basically everything except stmfGetState(), setStmfState() and
242  * stmfLoadConfig().
243  */
244 static int
initializeConfig()245 initializeConfig()
246 {
247 	int ret;
248 	stmfState state;
249 
250 
251 	ret = stmfGetState(&state);
252 	if (ret != STMF_STATUS_SUCCESS) {
253 		return (ret);
254 	}
255 
256 	/* if we've already initialized or in the process, return success */
257 	if (state.configState == STMF_CONFIG_STATE_INIT_DONE ||
258 	    state.configState == STMF_CONFIG_STATE_INIT) {
259 		return (STMF_STATUS_SUCCESS);
260 	}
261 
262 	ret = stmfLoadConfig();
263 	if (ret != STMF_STATUS_SUCCESS) {
264 		syslog(LOG_DEBUG,
265 		    "initializeConfig:stmfLoadConfig:error(%d)", ret);
266 		return (ret);
267 	}
268 
269 	ret = stmfGetState(&state);
270 	if (ret != STMF_STATUS_SUCCESS) {
271 		syslog(LOG_DEBUG,
272 		    "initializeConfig:stmfGetState:error(%d)", ret);
273 		return (ret);
274 	}
275 
276 	if (state.configState != STMF_CONFIG_STATE_INIT_DONE) {
277 		syslog(LOG_DEBUG, "initializeConfig:state.configState(%d)",
278 		    state.configState);
279 		ret = STMF_STATUS_ERROR;
280 	}
281 
282 	return (ret);
283 }
284 
285 
286 /*
287  * groupIoctl
288  *
289  * Purpose: issue ioctl for create/delete on group
290  *
291  * cmd - valid STMF ioctl group cmd
292  * groupName - groupName to create or delete
293  */
294 static int
groupIoctl(int fd,int cmd,stmfGroupName * groupName)295 groupIoctl(int fd, int cmd, stmfGroupName *groupName)
296 {
297 	int ret = STMF_STATUS_SUCCESS;
298 	int ioctlRet;
299 	stmf_iocdata_t stmfIoctl;
300 	stmf_group_name_t iGroupName;
301 
302 	bzero(&iGroupName, sizeof (iGroupName));
303 
304 	bcopy(groupName, &iGroupName.name, strlen((char *)groupName));
305 
306 	iGroupName.name_size = strlen((char *)groupName);
307 
308 	bzero(&stmfIoctl, sizeof (stmfIoctl));
309 	/*
310 	 * Issue ioctl to create the host group
311 	 */
312 	stmfIoctl.stmf_version = STMF_VERSION_1;
313 	stmfIoctl.stmf_ibuf_size = sizeof (iGroupName);
314 	stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&iGroupName;
315 	ioctlRet = ioctl(fd, cmd, &stmfIoctl);
316 	if (ioctlRet != 0) {
317 		switch (errno) {
318 			case EPERM:
319 			case EACCES:
320 				ret = STMF_ERROR_PERM;
321 				break;
322 			default:
323 				switch (stmfIoctl.stmf_error) {
324 					case STMF_IOCERR_TG_EXISTS:
325 					case STMF_IOCERR_HG_EXISTS:
326 						ret = STMF_ERROR_EXISTS;
327 						break;
328 					case STMF_IOCERR_TG_IN_USE:
329 					case STMF_IOCERR_HG_IN_USE:
330 						ret = STMF_ERROR_GROUP_IN_USE;
331 						break;
332 					case STMF_IOCERR_INVALID_HG:
333 					case STMF_IOCERR_INVALID_TG:
334 						ret = STMF_ERROR_NOT_FOUND;
335 						break;
336 					default:
337 						syslog(LOG_DEBUG,
338 						    "groupIoctl:error(%d)",
339 						    stmfIoctl.stmf_error);
340 						ret = STMF_STATUS_ERROR;
341 						break;
342 				}
343 				break;
344 		}
345 	}
346 done:
347 	return (ret);
348 }
349 
350 /*
351  * groupMemberIoctl
352  *
353  * Purpose: issue ioctl for add/remove member on group
354  *
355  * cmd - valid STMF ioctl group member cmd
356  * groupName - groupName to add to or remove from
357  * devid - group member to add or remove
358  */
359 static int
groupMemberIoctl(int fd,int cmd,stmfGroupName * groupName,stmfDevid * devid)360 groupMemberIoctl(int fd, int cmd, stmfGroupName *groupName, stmfDevid *devid)
361 {
362 	int ret = STMF_STATUS_SUCCESS;
363 	int ioctlRet;
364 	stmf_iocdata_t stmfIoctl;
365 	stmf_group_op_data_t stmfGroupData;
366 
367 	bzero(&stmfGroupData, sizeof (stmfGroupData));
368 
369 	bcopy(groupName, &stmfGroupData.group.name, strlen((char *)groupName));
370 
371 	stmfGroupData.group.name_size = strlen((char *)groupName);
372 	stmfGroupData.ident[IDENT_LENGTH_BYTE] = devid->identLength;
373 	bcopy(&(devid->ident), &stmfGroupData.ident[IDENT_LENGTH_BYTE + 1],
374 	    devid->identLength);
375 
376 	bzero(&stmfIoctl, sizeof (stmfIoctl));
377 	/*
378 	 * Issue ioctl to add to the host group
379 	 */
380 	stmfIoctl.stmf_version = STMF_VERSION_1;
381 	stmfIoctl.stmf_ibuf_size = sizeof (stmfGroupData);
382 	stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&stmfGroupData;
383 	ioctlRet = ioctl(fd, cmd, &stmfIoctl);
384 	if (ioctlRet != 0) {
385 		switch (errno) {
386 			case EBUSY:
387 				switch (stmfIoctl.stmf_error) {
388 					case STMF_IOCERR_TG_NEED_TG_OFFLINE:
389 						ret = STMF_ERROR_TG_ONLINE;
390 						break;
391 					default:
392 						ret = STMF_ERROR_BUSY;
393 						break;
394 				}
395 				break;
396 			case EPERM:
397 			case EACCES:
398 				ret = STMF_ERROR_PERM;
399 				break;
400 			default:
401 				switch (stmfIoctl.stmf_error) {
402 					case STMF_IOCERR_TG_ENTRY_EXISTS:
403 					case STMF_IOCERR_HG_ENTRY_EXISTS:
404 						ret = STMF_ERROR_EXISTS;
405 						break;
406 					case STMF_IOCERR_INVALID_TG_ENTRY:
407 					case STMF_IOCERR_INVALID_HG_ENTRY:
408 						ret =
409 						    STMF_ERROR_MEMBER_NOT_FOUND;
410 						break;
411 					case STMF_IOCERR_INVALID_TG:
412 					case STMF_IOCERR_INVALID_HG:
413 						ret =
414 						    STMF_ERROR_GROUP_NOT_FOUND;
415 						break;
416 					default:
417 						syslog(LOG_DEBUG,
418 						    "groupMemberIoctl:error"
419 						    "(%d)",
420 						    stmfIoctl.stmf_error);
421 						ret = STMF_STATUS_ERROR;
422 						break;
423 				}
424 				break;
425 		}
426 	}
427 done:
428 	return (ret);
429 }
430 
431 /*
432  * qsort function
433  * sort on veIndex
434  */
435 static int
viewEntryCompare(const void * p1,const void * p2)436 viewEntryCompare(const void *p1, const void *p2)
437 {
438 
439 	stmfViewEntry *v1 = (stmfViewEntry *)p1, *v2 = (stmfViewEntry *)p2;
440 	if (v1->veIndex > v2->veIndex)
441 		return (1);
442 	if (v1->veIndex < v2->veIndex)
443 		return (-1);
444 	return (0);
445 }
446 
447 /*
448  * guidCompare
449  *
450  * qsort function
451  * sort on guid
452  */
453 static int
guidCompare(const void * p1,const void * p2)454 guidCompare(const void *p1, const void *p2)
455 {
456 
457 	stmfGuid *g1 = (stmfGuid *)p1, *g2 = (stmfGuid *)p2;
458 	int i;
459 
460 	for (i = 0; i < sizeof (stmfGuid); i++) {
461 		if (g1->guid[i] > g2->guid[i])
462 			return (1);
463 		if (g1->guid[i] < g2->guid[i])
464 			return (-1);
465 	}
466 
467 	return (0);
468 }
469 
470 /*
471  * stmfAddToHostGroup
472  *
473  * Purpose: Adds an initiator to an existing host group
474  *
475  * hostGroupName - name of an existing host group
476  * hostName - name of initiator to add
477  */
478 int
stmfAddToHostGroup(stmfGroupName * hostGroupName,stmfDevid * hostName)479 stmfAddToHostGroup(stmfGroupName *hostGroupName, stmfDevid *hostName)
480 {
481 	int ret;
482 	int fd;
483 
484 	if (hostGroupName == NULL ||
485 	    (strnlen((char *)hostGroupName, sizeof (stmfGroupName))
486 	    == sizeof (stmfGroupName)) || hostName == NULL) {
487 		return (STMF_ERROR_INVALID_ARG);
488 	}
489 
490 	/* call init */
491 	ret = initializeConfig();
492 	if (ret != STMF_STATUS_SUCCESS) {
493 		return (ret);
494 	}
495 
496 	/*
497 	 * Open control node for stmf
498 	 */
499 	if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
500 		return (ret);
501 
502 	if ((ret = groupMemberIoctl(fd, STMF_IOCTL_ADD_HG_ENTRY, hostGroupName,
503 	    hostName)) != STMF_STATUS_SUCCESS) {
504 		goto done;
505 	}
506 
507 	if (iGetPersistMethod() == STMF_PERSIST_NONE) {
508 		goto done;
509 	}
510 
511 	ret = psAddHostGroupMember((char *)hostGroupName,
512 	    (char *)hostName->ident);
513 	switch (ret) {
514 		case STMF_PS_SUCCESS:
515 			ret = STMF_STATUS_SUCCESS;
516 			break;
517 		case STMF_PS_ERROR_EXISTS:
518 			ret = STMF_ERROR_EXISTS;
519 			break;
520 		case STMF_PS_ERROR_GROUP_NOT_FOUND:
521 			ret = STMF_ERROR_GROUP_NOT_FOUND;
522 			break;
523 		case STMF_PS_ERROR_BUSY:
524 			ret = STMF_ERROR_BUSY;
525 			break;
526 		case STMF_PS_ERROR_SERVICE_NOT_FOUND:
527 			ret = STMF_ERROR_SERVICE_NOT_FOUND;
528 			break;
529 		case STMF_PS_ERROR_VERSION_MISMATCH:
530 			ret = STMF_ERROR_SERVICE_DATA_VERSION;
531 			break;
532 		default:
533 			syslog(LOG_DEBUG,
534 			    "stmfAddToHostGroup:psAddHostGroupMember:error(%d)",
535 			    ret);
536 			ret = STMF_STATUS_ERROR;
537 			break;
538 	}
539 
540 done:
541 	(void) close(fd);
542 	return (ret);
543 }
544 
545 /*
546  * stmfAddToTargetGroup
547  *
548  * Purpose: Adds a local port to an existing target group
549  *
550  * targetGroupName - name of an existing target group
551  * targetName - name of target to add
552  */
553 int
stmfAddToTargetGroup(stmfGroupName * targetGroupName,stmfDevid * targetName)554 stmfAddToTargetGroup(stmfGroupName *targetGroupName, stmfDevid *targetName)
555 {
556 	int ret;
557 	int fd;
558 
559 	if (targetGroupName == NULL ||
560 	    (strnlen((char *)targetGroupName, sizeof (stmfGroupName))
561 	    == sizeof (stmfGroupName)) || targetName == NULL) {
562 		return (STMF_ERROR_INVALID_ARG);
563 	}
564 
565 	/* call init */
566 	ret = initializeConfig();
567 	if (ret != STMF_STATUS_SUCCESS) {
568 		return (ret);
569 	}
570 
571 	/*
572 	 * Open control node for stmf
573 	 */
574 	if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
575 		return (ret);
576 
577 	if ((ret = groupMemberIoctl(fd, STMF_IOCTL_ADD_TG_ENTRY,
578 	    targetGroupName, targetName)) != STMF_STATUS_SUCCESS) {
579 		goto done;
580 	}
581 
582 	if (iGetPersistMethod() == STMF_PERSIST_NONE) {
583 		goto done;
584 	}
585 
586 	ret = psAddTargetGroupMember((char *)targetGroupName,
587 	    (char *)targetName->ident);
588 	switch (ret) {
589 		case STMF_PS_SUCCESS:
590 			ret = STMF_STATUS_SUCCESS;
591 			break;
592 		case STMF_PS_ERROR_EXISTS:
593 			ret = STMF_ERROR_EXISTS;
594 			break;
595 		case STMF_PS_ERROR_GROUP_NOT_FOUND:
596 			ret = STMF_ERROR_GROUP_NOT_FOUND;
597 			break;
598 		case STMF_PS_ERROR_BUSY:
599 			ret = STMF_ERROR_BUSY;
600 			break;
601 		case STMF_PS_ERROR_SERVICE_NOT_FOUND:
602 			ret = STMF_ERROR_SERVICE_NOT_FOUND;
603 			break;
604 		case STMF_PS_ERROR_VERSION_MISMATCH:
605 			ret = STMF_ERROR_SERVICE_DATA_VERSION;
606 			break;
607 		default:
608 			syslog(LOG_DEBUG,
609 			    "stmfAddToTargetGroup:psAddTargetGroupMember:"
610 			    "error(%d)", ret);
611 			ret = STMF_STATUS_ERROR;
612 			break;
613 	}
614 
615 done:
616 	(void) close(fd);
617 	return (ret);
618 }
619 
620 /*
621  * addViewEntryIoctl
622  *
623  * Purpose: Issues ioctl to add a view entry
624  *
625  * lu - Logical Unit identifier to which the view entry is added
626  * viewEntry - view entry to add
627  * init - When set to B_TRUE, we are in the init state, i.e. don't call open
628  */
629 static int
addViewEntryIoctl(int fd,stmfGuid * lu,stmfViewEntry * viewEntry)630 addViewEntryIoctl(int fd, stmfGuid *lu, stmfViewEntry *viewEntry)
631 {
632 	int ret = STMF_STATUS_SUCCESS;
633 	int ioctlRet;
634 	stmf_iocdata_t stmfIoctl;
635 	stmf_view_op_entry_t ioctlViewEntry;
636 
637 	bzero(&ioctlViewEntry, sizeof (ioctlViewEntry));
638 	/*
639 	 * don't set ve_ndx or ve_ndx_valid as ve_ndx_valid should be
640 	 * false on input
641 	 */
642 	ioctlViewEntry.ve_lu_number_valid = viewEntry->luNbrValid;
643 	ioctlViewEntry.ve_all_hosts = viewEntry->allHosts;
644 	ioctlViewEntry.ve_all_targets = viewEntry->allTargets;
645 
646 	if (viewEntry->allHosts == B_FALSE) {
647 		bcopy(viewEntry->hostGroup, &ioctlViewEntry.ve_host_group.name,
648 		    sizeof (stmfGroupName));
649 		ioctlViewEntry.ve_host_group.name_size =
650 		    strlen((char *)viewEntry->hostGroup);
651 	}
652 	if (viewEntry->allTargets == B_FALSE) {
653 		bcopy(viewEntry->targetGroup,
654 		    &ioctlViewEntry.ve_target_group.name,
655 		    sizeof (stmfGroupName));
656 		ioctlViewEntry.ve_target_group.name_size =
657 		    strlen((char *)viewEntry->targetGroup);
658 	}
659 	if (viewEntry->luNbrValid) {
660 		bcopy(viewEntry->luNbr, &ioctlViewEntry.ve_lu_nbr,
661 		    sizeof (ioctlViewEntry.ve_lu_nbr));
662 	}
663 	bcopy(lu, &ioctlViewEntry.ve_guid, sizeof (stmfGuid));
664 
665 	bzero(&stmfIoctl, sizeof (stmfIoctl));
666 	/*
667 	 * Issue ioctl to add to the view entry
668 	 */
669 	stmfIoctl.stmf_version = STMF_VERSION_1;
670 	stmfIoctl.stmf_ibuf_size = sizeof (ioctlViewEntry);
671 	stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&ioctlViewEntry;
672 	stmfIoctl.stmf_obuf_size = sizeof (ioctlViewEntry);
673 	stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)&ioctlViewEntry;
674 	ioctlRet = ioctl(fd, STMF_IOCTL_ADD_VIEW_ENTRY, &stmfIoctl);
675 	if (ioctlRet != 0) {
676 		switch (errno) {
677 			case EBUSY:
678 				ret = STMF_ERROR_BUSY;
679 				break;
680 			case EPERM:
681 				ret = STMF_ERROR_PERM;
682 				break;
683 			case EACCES:
684 				switch (stmfIoctl.stmf_error) {
685 					case STMF_IOCERR_UPDATE_NEED_CFG_INIT:
686 						ret = STMF_ERROR_CONFIG_NONE;
687 						break;
688 					default:
689 						ret = STMF_ERROR_PERM;
690 						break;
691 				}
692 				break;
693 			default:
694 				switch (stmfIoctl.stmf_error) {
695 					case STMF_IOCERR_LU_NUMBER_IN_USE:
696 						ret = STMF_ERROR_LUN_IN_USE;
697 						break;
698 					case STMF_IOCERR_VIEW_ENTRY_CONFLICT:
699 						ret = STMF_ERROR_VE_CONFLICT;
700 						break;
701 					case STMF_IOCERR_UPDATE_NEED_CFG_INIT:
702 						ret = STMF_ERROR_CONFIG_NONE;
703 						break;
704 					case STMF_IOCERR_INVALID_HG:
705 						ret = STMF_ERROR_INVALID_HG;
706 						break;
707 					case STMF_IOCERR_INVALID_TG:
708 						ret = STMF_ERROR_INVALID_TG;
709 						break;
710 					default:
711 						syslog(LOG_DEBUG,
712 						    "addViewEntryIoctl"
713 						    ":error(%d)",
714 						    stmfIoctl.stmf_error);
715 						ret = STMF_STATUS_ERROR;
716 						break;
717 				}
718 				break;
719 		}
720 		goto done;
721 	}
722 
723 	/* copy lu nbr back to caller's view entry on success */
724 	viewEntry->veIndex = ioctlViewEntry.ve_ndx;
725 	if (ioctlViewEntry.ve_lu_number_valid) {
726 		bcopy(&ioctlViewEntry.ve_lu_nbr, viewEntry->luNbr,
727 		    sizeof (ioctlViewEntry.ve_lu_nbr));
728 	}
729 	viewEntry->luNbrValid = B_TRUE;
730 
731 done:
732 	return (ret);
733 }
734 
735 /*
736  * stmfAddViewEntry
737  *
738  * Purpose: Adds a view entry to a logical unit
739  *
740  * lu - guid of the logical unit to which the view entry is added
741  * viewEntry - view entry structure to add
742  */
743 int
stmfAddViewEntry(stmfGuid * lu,stmfViewEntry * viewEntry)744 stmfAddViewEntry(stmfGuid *lu, stmfViewEntry *viewEntry)
745 {
746 	int ret;
747 	int fd;
748 	stmfViewEntry iViewEntry;
749 
750 	if (lu == NULL || viewEntry == NULL) {
751 		return (STMF_ERROR_INVALID_ARG);
752 	}
753 
754 	/* initialize and set internal view entry */
755 	bzero(&iViewEntry, sizeof (iViewEntry));
756 
757 	if (!viewEntry->allHosts) {
758 		bcopy(viewEntry->hostGroup, iViewEntry.hostGroup,
759 		    sizeof (iViewEntry.hostGroup));
760 	} else {
761 		iViewEntry.allHosts = B_TRUE;
762 	}
763 
764 	if (!viewEntry->allTargets) {
765 		bcopy(viewEntry->targetGroup, iViewEntry.targetGroup,
766 		    sizeof (iViewEntry.targetGroup));
767 	} else {
768 		iViewEntry.allTargets = B_TRUE;
769 	}
770 
771 	if (viewEntry->luNbrValid) {
772 		iViewEntry.luNbrValid = B_TRUE;
773 		bcopy(viewEntry->luNbr, iViewEntry.luNbr,
774 		    sizeof (iViewEntry.luNbr));
775 	}
776 
777 	/*
778 	 * set users return view entry index valid flag to false
779 	 * in case of failure
780 	 */
781 	viewEntry->veIndexValid = B_FALSE;
782 
783 	/* Check to ensure service exists */
784 	if (psCheckService() != STMF_STATUS_SUCCESS) {
785 		return (STMF_ERROR_SERVICE_NOT_FOUND);
786 	}
787 
788 	/* call init */
789 	ret = initializeConfig();
790 	if (ret != STMF_STATUS_SUCCESS) {
791 		return (ret);
792 	}
793 
794 	/*
795 	 * Open control node for stmf
796 	 */
797 	if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
798 		return (ret);
799 
800 	/*
801 	 * First add the view entry to the driver
802 	 */
803 	ret = addViewEntryIoctl(fd, lu, &iViewEntry);
804 	if (ret != STMF_STATUS_SUCCESS) {
805 		goto done;
806 	}
807 
808 	if (iGetPersistMethod() == STMF_PERSIST_NONE) {
809 		goto done;
810 	}
811 
812 	/*
813 	 * If the add to driver was successful, add it to the persistent
814 	 * store.
815 	 */
816 	ret = psAddViewEntry(lu, &iViewEntry);
817 	switch (ret) {
818 		case STMF_PS_SUCCESS:
819 			ret = STMF_STATUS_SUCCESS;
820 			break;
821 		case STMF_PS_ERROR_NOT_FOUND:
822 			ret = STMF_ERROR_NOT_FOUND;
823 			break;
824 		case STMF_PS_ERROR_BUSY:
825 			ret = STMF_ERROR_BUSY;
826 			break;
827 		case STMF_PS_ERROR_SERVICE_NOT_FOUND:
828 			ret = STMF_ERROR_SERVICE_NOT_FOUND;
829 			break;
830 		case STMF_PS_ERROR_VERSION_MISMATCH:
831 			ret = STMF_ERROR_SERVICE_DATA_VERSION;
832 			break;
833 		default:
834 			syslog(LOG_DEBUG,
835 			    "stmfAddViewEntry:psAddViewEntry:error(%d)", ret);
836 			ret = STMF_STATUS_ERROR;
837 			break;
838 	}
839 
840 done:
841 	(void) close(fd);
842 
843 	if (ret == STMF_STATUS_SUCCESS) {
844 		/* set caller's view entry on success */
845 		viewEntry->veIndexValid = iViewEntry.veIndexValid;
846 		viewEntry->veIndex = iViewEntry.veIndex;
847 		viewEntry->luNbrValid = B_TRUE;
848 		bcopy(iViewEntry.luNbr, viewEntry->luNbr,
849 		    sizeof (iViewEntry.luNbr));
850 	}
851 	return (ret);
852 }
853 
854 /*
855  * stmfClearProviderData
856  *
857  * Purpose: delete all provider data for specified provider
858  *
859  * providerName - name of provider for which data should be deleted
860  */
861 int
stmfClearProviderData(char * providerName,int providerType)862 stmfClearProviderData(char *providerName, int providerType)
863 {
864 	int ret;
865 	int fd;
866 	int ioctlRet;
867 	int savedErrno;
868 	stmf_iocdata_t stmfIoctl;
869 	stmf_ppioctl_data_t ppi;
870 
871 	/* call init */
872 	ret = initializeConfig();
873 	if (ret != STMF_STATUS_SUCCESS) {
874 		return (ret);
875 	}
876 
877 	if (providerName == NULL) {
878 		return (STMF_ERROR_INVALID_ARG);
879 	}
880 
881 	if (providerType != STMF_LU_PROVIDER_TYPE &&
882 	    providerType != STMF_PORT_PROVIDER_TYPE) {
883 		return (STMF_ERROR_INVALID_ARG);
884 	}
885 
886 	/*
887 	 * Open control node for stmf
888 	 */
889 	if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
890 		return (ret);
891 
892 	bzero(&ppi, sizeof (ppi));
893 
894 	(void) strncpy(ppi.ppi_name, providerName, sizeof (ppi.ppi_name));
895 
896 	switch (providerType) {
897 		case STMF_LU_PROVIDER_TYPE:
898 			ppi.ppi_lu_provider = 1;
899 			break;
900 		case STMF_PORT_PROVIDER_TYPE:
901 			ppi.ppi_port_provider = 1;
902 			break;
903 		default:
904 			ret = STMF_ERROR_INVALID_ARG;
905 			goto done;
906 	}
907 
908 	bzero(&stmfIoctl, sizeof (stmfIoctl));
909 
910 	stmfIoctl.stmf_version = STMF_VERSION_1;
911 	stmfIoctl.stmf_ibuf_size = sizeof (stmf_ppioctl_data_t);
912 	stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&ppi;
913 
914 	ioctlRet = ioctl(fd, STMF_IOCTL_CLEAR_PP_DATA, &stmfIoctl);
915 	if (ioctlRet != 0) {
916 		savedErrno = errno;
917 		switch (savedErrno) {
918 			case EBUSY:
919 				ret = STMF_ERROR_BUSY;
920 				break;
921 			case EPERM:
922 			case EACCES:
923 				ret = STMF_ERROR_PERM;
924 				break;
925 			default:
926 				syslog(LOG_DEBUG,
927 				    "stmfClearProviderData:ioctl error(%d)",
928 				    ioctlRet);
929 				ret = STMF_STATUS_ERROR;
930 				break;
931 		}
932 		if (savedErrno != ENOENT) {
933 			goto done;
934 		}
935 	}
936 
937 	if (iGetPersistMethod() == STMF_PERSIST_NONE) {
938 		goto done;
939 	}
940 
941 	ret = psClearProviderData(providerName, providerType);
942 	switch (ret) {
943 		case STMF_PS_SUCCESS:
944 			ret = STMF_STATUS_SUCCESS;
945 			break;
946 		case STMF_PS_ERROR_NOT_FOUND:
947 			ret = STMF_ERROR_NOT_FOUND;
948 			break;
949 		case STMF_PS_ERROR_BUSY:
950 			ret = STMF_ERROR_BUSY;
951 			break;
952 		case STMF_PS_ERROR_SERVICE_NOT_FOUND:
953 			ret = STMF_ERROR_SERVICE_NOT_FOUND;
954 			break;
955 		case STMF_PS_ERROR_VERSION_MISMATCH:
956 			ret = STMF_ERROR_SERVICE_DATA_VERSION;
957 			break;
958 		default:
959 			syslog(LOG_DEBUG,
960 			    "stmfClearProviderData:psClearProviderData"
961 			    ":error(%d)", ret);
962 			ret = STMF_STATUS_ERROR;
963 			break;
964 	}
965 
966 done:
967 	(void) close(fd);
968 	return (ret);
969 }
970 
971 /*
972  * stmfCreateHostGroup
973  *
974  * Purpose: Create a new initiator group
975  *
976  * hostGroupName - name of host group to create
977  */
978 int
stmfCreateHostGroup(stmfGroupName * hostGroupName)979 stmfCreateHostGroup(stmfGroupName *hostGroupName)
980 {
981 	int ret;
982 	int fd;
983 
984 	if (hostGroupName == NULL ||
985 	    (strnlen((char *)hostGroupName, sizeof (stmfGroupName))
986 	    == sizeof (stmfGroupName))) {
987 		return (STMF_ERROR_INVALID_ARG);
988 	}
989 
990 	/* Check to ensure service exists */
991 	if (psCheckService() != STMF_STATUS_SUCCESS) {
992 		return (STMF_ERROR_SERVICE_NOT_FOUND);
993 	}
994 
995 	/* call init */
996 	ret = initializeConfig();
997 	if (ret != STMF_STATUS_SUCCESS) {
998 		return (ret);
999 	}
1000 
1001 	/*
1002 	 * Open control node for stmf
1003 	 */
1004 	if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
1005 		return (ret);
1006 
1007 	if ((ret = groupIoctl(fd, STMF_IOCTL_CREATE_HOST_GROUP,
1008 	    hostGroupName)) != STMF_STATUS_SUCCESS) {
1009 		goto done;
1010 	}
1011 
1012 	if (iGetPersistMethod() == STMF_PERSIST_NONE) {
1013 		goto done;
1014 	}
1015 
1016 	ret = psCreateHostGroup((char *)hostGroupName);
1017 	switch (ret) {
1018 		case STMF_PS_SUCCESS:
1019 			ret = STMF_STATUS_SUCCESS;
1020 			break;
1021 		case STMF_PS_ERROR_EXISTS:
1022 			ret = STMF_ERROR_EXISTS;
1023 			break;
1024 		case STMF_PS_ERROR_BUSY:
1025 			ret = STMF_ERROR_BUSY;
1026 			break;
1027 		case STMF_PS_ERROR_SERVICE_NOT_FOUND:
1028 			ret = STMF_ERROR_SERVICE_NOT_FOUND;
1029 			break;
1030 		case STMF_PS_ERROR_VERSION_MISMATCH:
1031 			ret = STMF_ERROR_SERVICE_DATA_VERSION;
1032 			break;
1033 		default:
1034 			syslog(LOG_DEBUG,
1035 			    "stmfCreateHostGroup:psCreateHostGroup:error(%d)",
1036 			    ret);
1037 			ret = STMF_STATUS_ERROR;
1038 			break;
1039 	}
1040 
1041 done:
1042 	(void) close(fd);
1043 	return (ret);
1044 }
1045 
1046 /*
1047  * stmfCreateLu
1048  *
1049  * Purpose: Create a logical unit
1050  *
1051  * hdl - handle to logical unit resource created via stmfCreateLuResource
1052  *
1053  * luGuid - If non-NULL, on success, contains the guid of the created logical
1054  *	    unit
1055  */
1056 int
stmfCreateLu(luResource hdl,stmfGuid * luGuid)1057 stmfCreateLu(luResource hdl, stmfGuid *luGuid)
1058 {
1059 	int ret = STMF_STATUS_SUCCESS;
1060 	luResourceImpl *luPropsHdl = hdl;
1061 
1062 	if (hdl == NULL) {
1063 		return (STMF_ERROR_INVALID_ARG);
1064 	}
1065 
1066 	if (luPropsHdl->type == STMF_DISK) {
1067 		ret = createDiskLu((diskResource *)luPropsHdl->resource,
1068 		    luGuid);
1069 	} else {
1070 		return (STMF_ERROR_INVALID_ARG);
1071 	}
1072 
1073 	return (ret);
1074 }
1075 
1076 /*
1077  * stmfCreateLuResource
1078  *
1079  * Purpose: Create resource handle for a logical unit
1080  *
1081  * dType - Type of logical unit resource to create
1082  *	   Can be: STMF_DISK
1083  *
1084  * hdl - pointer to luResource
1085  */
1086 int
stmfCreateLuResource(uint16_t dType,luResource * hdl)1087 stmfCreateLuResource(uint16_t dType, luResource *hdl)
1088 {
1089 	int ret = STMF_STATUS_SUCCESS;
1090 
1091 	if (dType != STMF_DISK || hdl == NULL) {
1092 		return (STMF_ERROR_INVALID_ARG);
1093 	}
1094 
1095 	*hdl = calloc(1, sizeof (luResourceImpl));
1096 	if (*hdl == NULL) {
1097 		return (STMF_ERROR_NOMEM);
1098 	}
1099 
1100 	ret = createDiskResource((luResourceImpl *)*hdl);
1101 	if (ret != STMF_STATUS_SUCCESS) {
1102 		free(*hdl);
1103 		return (ret);
1104 	}
1105 
1106 	return (STMF_STATUS_SUCCESS);
1107 }
1108 
1109 /*
1110  * Creates a disk logical unit
1111  *
1112  * disk - pointer to diskResource structure that represents the properties
1113  *        for the disk logical unit to be created.
1114  */
1115 static int
createDiskLu(diskResource * disk,stmfGuid * createdGuid)1116 createDiskLu(diskResource *disk, stmfGuid *createdGuid)
1117 {
1118 	int ret = STMF_STATUS_SUCCESS;
1119 	int dataFileNameLen = 0;
1120 	int metaFileNameLen = 0;
1121 	int serialNumLen = 0;
1122 	int luAliasLen = 0;
1123 	int luMgmtUrlLen = 0;
1124 	int sluBufSize = 0;
1125 	int bufOffset = 0;
1126 	int fd = 0;
1127 	int ioctlRet;
1128 	int savedErrno;
1129 	stmfGuid guid;
1130 	stmf_iocdata_t sbdIoctl = {0};
1131 
1132 	sbd_create_and_reg_lu_t *sbdLu = NULL;
1133 
1134 	/*
1135 	 * Open control node for sbd
1136 	 */
1137 	if ((ret = openSbd(OPEN_SBD, &fd)) != STMF_STATUS_SUCCESS)
1138 		return (ret);
1139 
1140 	/* data file name must be specified */
1141 	if (disk->luDataFileNameValid) {
1142 		dataFileNameLen = strlen(disk->luDataFileName);
1143 	} else {
1144 		(void) close(fd);
1145 		return (STMF_ERROR_MISSING_PROP_VAL);
1146 	}
1147 
1148 	sluBufSize += dataFileNameLen + 1;
1149 
1150 	if (disk->luMetaFileNameValid) {
1151 		metaFileNameLen = strlen(disk->luMetaFileName);
1152 		sluBufSize += metaFileNameLen + 1;
1153 	}
1154 
1155 	serialNumLen = strlen(disk->serialNum);
1156 	sluBufSize += serialNumLen;
1157 
1158 	if (disk->luAliasValid) {
1159 		luAliasLen = strlen(disk->luAlias);
1160 		sluBufSize += luAliasLen + 1;
1161 	}
1162 
1163 	if (disk->luMgmtUrlValid) {
1164 		luMgmtUrlLen = strlen(disk->luMgmtUrl);
1165 		sluBufSize += luMgmtUrlLen + 1;
1166 	}
1167 
1168 	/*
1169 	 * 8 is the size of the buffer set aside for
1170 	 * concatenation of variable length fields
1171 	 */
1172 	sbdLu = (sbd_create_and_reg_lu_t *)calloc(1,
1173 	    sizeof (sbd_create_and_reg_lu_t) + sluBufSize - 8);
1174 	if (sbdLu == NULL) {
1175 		return (STMF_ERROR_NOMEM);
1176 	}
1177 
1178 	sbdLu->slu_struct_size = sizeof (sbd_create_and_reg_lu_t) +
1179 	    sluBufSize - 8;
1180 
1181 	if (metaFileNameLen) {
1182 		sbdLu->slu_meta_fname_valid = 1;
1183 		sbdLu->slu_meta_fname_off = bufOffset;
1184 		bcopy(disk->luMetaFileName, &(sbdLu->slu_buf[bufOffset]),
1185 		    metaFileNameLen + 1);
1186 		bufOffset += metaFileNameLen + 1;
1187 	}
1188 
1189 	bcopy(disk->luDataFileName, &(sbdLu->slu_buf[bufOffset]),
1190 	    dataFileNameLen + 1);
1191 	sbdLu->slu_data_fname_off = bufOffset;
1192 	bufOffset += dataFileNameLen + 1;
1193 
1194 	/* currently, serial # is not passed null terminated to the driver */
1195 	if (disk->serialNumValid) {
1196 		sbdLu->slu_serial_valid = 1;
1197 		sbdLu->slu_serial_off = bufOffset;
1198 		sbdLu->slu_serial_size = serialNumLen;
1199 		bcopy(disk->serialNum, &(sbdLu->slu_buf[bufOffset]),
1200 		    serialNumLen);
1201 		bufOffset += serialNumLen;
1202 	}
1203 
1204 	if (disk->luAliasValid) {
1205 		sbdLu->slu_alias_valid = 1;
1206 		sbdLu->slu_alias_off = bufOffset;
1207 		bcopy(disk->luAlias, &(sbdLu->slu_buf[bufOffset]),
1208 		    luAliasLen + 1);
1209 		bufOffset += luAliasLen + 1;
1210 	}
1211 
1212 	if (disk->luMgmtUrlValid) {
1213 		sbdLu->slu_mgmt_url_valid = 1;
1214 		sbdLu->slu_mgmt_url_off = bufOffset;
1215 		bcopy(disk->luMgmtUrl, &(sbdLu->slu_buf[bufOffset]),
1216 		    luMgmtUrlLen + 1);
1217 		bufOffset += luMgmtUrlLen + 1;
1218 	}
1219 
1220 	if (disk->luSizeValid) {
1221 		sbdLu->slu_lu_size_valid = 1;
1222 		sbdLu->slu_lu_size = disk->luSize;
1223 	}
1224 
1225 	if (disk->luGuidValid) {
1226 		sbdLu->slu_guid_valid = 1;
1227 		bcopy(disk->luGuid, sbdLu->slu_guid, sizeof (disk->luGuid));
1228 	}
1229 
1230 	if (disk->vidValid) {
1231 		sbdLu->slu_vid_valid = 1;
1232 		bcopy(disk->vid, sbdLu->slu_vid, sizeof (disk->vid));
1233 	}
1234 
1235 	if (disk->pidValid) {
1236 		sbdLu->slu_pid_valid = 1;
1237 		bcopy(disk->pid, sbdLu->slu_pid, sizeof (disk->pid));
1238 	}
1239 
1240 	if (disk->revValid) {
1241 		sbdLu->slu_rev_valid = 1;
1242 		bcopy(disk->rev, sbdLu->slu_rev, sizeof (disk->rev));
1243 	}
1244 
1245 	if (disk->companyIdValid) {
1246 		sbdLu->slu_company_id_valid = 1;
1247 		sbdLu->slu_company_id = disk->companyId;
1248 	}
1249 
1250 	if (disk->hostIdValid) {
1251 		sbdLu->slu_host_id_valid = 1;
1252 		sbdLu->slu_host_id = disk->hostId;
1253 	}
1254 
1255 	if (disk->blkSizeValid) {
1256 		sbdLu->slu_blksize_valid = 1;
1257 		sbdLu->slu_blksize = disk->blkSize;
1258 	}
1259 
1260 	if (disk->writeProtectEnableValid) {
1261 		if (disk->writeProtectEnable) {
1262 			sbdLu->slu_write_protected = 1;
1263 		}
1264 	}
1265 
1266 	if (disk->writebackCacheDisableValid) {
1267 		sbdLu->slu_writeback_cache_disable_valid = 1;
1268 		if (disk->writebackCacheDisable) {
1269 			sbdLu->slu_writeback_cache_disable = 1;
1270 		}
1271 	}
1272 
1273 	sbdIoctl.stmf_version = STMF_VERSION_1;
1274 	sbdIoctl.stmf_ibuf_size = sbdLu->slu_struct_size;
1275 	sbdIoctl.stmf_ibuf = (uint64_t)(unsigned long)sbdLu;
1276 	sbdIoctl.stmf_obuf_size = sbdLu->slu_struct_size;
1277 	sbdIoctl.stmf_obuf = (uint64_t)(unsigned long)sbdLu;
1278 
1279 	ioctlRet = ioctl(fd, SBD_IOCTL_CREATE_AND_REGISTER_LU, &sbdIoctl);
1280 	if (ioctlRet != 0) {
1281 		savedErrno = errno;
1282 		switch (savedErrno) {
1283 			case EBUSY:
1284 				ret = STMF_ERROR_BUSY;
1285 				break;
1286 			case EPERM:
1287 			case EACCES:
1288 				ret = STMF_ERROR_PERM;
1289 				break;
1290 			default:
1291 				diskError(sbdIoctl.stmf_error, &ret);
1292 				if (ret == STMF_STATUS_ERROR) {
1293 					syslog(LOG_DEBUG,
1294 					"createDiskLu:ioctl "
1295 					"error(%d) (%d) (%d)", ioctlRet,
1296 					    sbdIoctl.stmf_error, savedErrno);
1297 				}
1298 				break;
1299 		}
1300 	}
1301 
1302 	if (ret != STMF_STATUS_SUCCESS) {
1303 		goto done;
1304 	}
1305 
1306 	/*
1307 	 * on success, copy the resulting guid into the caller's guid if not
1308 	 * NULL
1309 	 */
1310 	if (createdGuid) {
1311 		bcopy(sbdLu->slu_guid, createdGuid->guid,
1312 		    sizeof (sbdLu->slu_guid));
1313 	}
1314 
1315 	bcopy(sbdLu->slu_guid, guid.guid, sizeof (sbdLu->slu_guid));
1316 	if (disk->luMetaFileNameValid) {
1317 		ret = addGuidToDiskStore(&guid, disk->luMetaFileName);
1318 	} else {
1319 		ret = addGuidToDiskStore(&guid, disk->luDataFileName);
1320 	}
1321 done:
1322 	free(sbdLu);
1323 	(void) close(fd);
1324 	return (ret);
1325 }
1326 
1327 
1328 /*
1329  * stmfImportLu
1330  *
1331  * Purpose: Import a previously created logical unit
1332  *
1333  * dType - Type of logical unit
1334  *         Can be: STMF_DISK
1335  *
1336  * luGuid - If non-NULL, on success, contains the guid of the imported logical
1337  *	    unit
1338  *
1339  * fname - A file name where the metadata resides
1340  *
1341  */
1342 int
stmfImportLu(uint16_t dType,char * fname,stmfGuid * luGuid)1343 stmfImportLu(uint16_t dType, char *fname, stmfGuid *luGuid)
1344 {
1345 	int ret = STMF_STATUS_SUCCESS;
1346 
1347 	if (dType == STMF_DISK) {
1348 		ret = importDiskLu(fname, luGuid);
1349 	} else {
1350 		return (STMF_ERROR_INVALID_ARG);
1351 	}
1352 
1353 	return (ret);
1354 }
1355 
1356 /*
1357  * importDiskLu
1358  *
1359  * filename - filename to import
1360  * createdGuid - if not NULL, on success contains the imported guid
1361  *
1362  */
1363 static int
importDiskLu(char * fname,stmfGuid * createdGuid)1364 importDiskLu(char *fname, stmfGuid *createdGuid)
1365 {
1366 	int ret = STMF_STATUS_SUCCESS;
1367 	int fd = 0;
1368 	int ioctlRet;
1369 	int savedErrno;
1370 	int metaFileNameLen;
1371 	stmfGuid iGuid;
1372 	int iluBufSize = 0;
1373 	sbd_import_lu_t *sbdLu = NULL;
1374 	stmf_iocdata_t sbdIoctl = {0};
1375 
1376 	if (fname == NULL) {
1377 		return (STMF_ERROR_INVALID_ARG);
1378 	}
1379 
1380 	/*
1381 	 * Open control node for sbd
1382 	 */
1383 	if ((ret = openSbd(OPEN_SBD, &fd)) != STMF_STATUS_SUCCESS)
1384 		return (ret);
1385 
1386 	metaFileNameLen = strlen(fname);
1387 	iluBufSize += metaFileNameLen + 1;
1388 
1389 	/*
1390 	 * 8 is the size of the buffer set aside for
1391 	 * concatenation of variable length fields
1392 	 */
1393 	sbdLu = (sbd_import_lu_t *)calloc(1,
1394 	    sizeof (sbd_import_lu_t) + iluBufSize - 8);
1395 	if (sbdLu == NULL) {
1396 		(void) close(fd);
1397 		return (STMF_ERROR_NOMEM);
1398 	}
1399 
1400 	/*
1401 	 * Accept either a data file or meta data file.
1402 	 * sbd will do the right thing here either way.
1403 	 * i.e. if it's a data file, it assumes that the
1404 	 * meta data is shared with the data.
1405 	 */
1406 	(void) strncpy(sbdLu->ilu_meta_fname, fname, metaFileNameLen);
1407 
1408 	sbdLu->ilu_struct_size = sizeof (sbd_import_lu_t) + iluBufSize - 8;
1409 
1410 	sbdIoctl.stmf_version = STMF_VERSION_1;
1411 	sbdIoctl.stmf_ibuf_size = sbdLu->ilu_struct_size;
1412 	sbdIoctl.stmf_ibuf = (uint64_t)(unsigned long)sbdLu;
1413 	sbdIoctl.stmf_obuf_size = sbdLu->ilu_struct_size;
1414 	sbdIoctl.stmf_obuf = (uint64_t)(unsigned long)sbdLu;
1415 
1416 	ioctlRet = ioctl(fd, SBD_IOCTL_IMPORT_LU, &sbdIoctl);
1417 	if (ioctlRet != 0) {
1418 
1419 		if (createdGuid && sbdIoctl.stmf_error ==
1420 		    SBD_RET_FILE_ALREADY_REGISTERED) {
1421 			bcopy(sbdLu->ilu_ret_guid, createdGuid->guid,
1422 			    sizeof (sbdLu->ilu_ret_guid));
1423 		}
1424 
1425 		savedErrno = errno;
1426 		switch (savedErrno) {
1427 			case EBUSY:
1428 				ret = STMF_ERROR_BUSY;
1429 				break;
1430 			case EPERM:
1431 			case EACCES:
1432 				ret = STMF_ERROR_PERM;
1433 				break;
1434 			default:
1435 				diskError(sbdIoctl.stmf_error, &ret);
1436 				if (ret == STMF_STATUS_ERROR) {
1437 					syslog(LOG_DEBUG,
1438 					"importDiskLu:ioctl "
1439 					"error(%d) (%d) (%d)", ioctlRet,
1440 					    sbdIoctl.stmf_error, savedErrno);
1441 				}
1442 				break;
1443 		}
1444 	}
1445 
1446 
1447 	if (ret != STMF_STATUS_SUCCESS) {
1448 		goto done;
1449 	}
1450 
1451 	/*
1452 	 * on success, copy the resulting guid into the caller's guid if not
1453 	 * NULL and add it to the persistent store for sbd
1454 	 */
1455 	if (createdGuid) {
1456 		bcopy(sbdLu->ilu_ret_guid, createdGuid->guid,
1457 		    sizeof (sbdLu->ilu_ret_guid));
1458 		ret = addGuidToDiskStore(createdGuid, fname);
1459 	} else {
1460 		bcopy(sbdLu->ilu_ret_guid, iGuid.guid,
1461 		    sizeof (sbdLu->ilu_ret_guid));
1462 		ret = addGuidToDiskStore(&iGuid, fname);
1463 	}
1464 done:
1465 	free(sbdLu);
1466 	(void) close(fd);
1467 	return (ret);
1468 }
1469 
1470 /*
1471  * diskError
1472  *
1473  * Purpose: Translate sbd driver error
1474  */
1475 static void
diskError(uint32_t stmfError,int * ret)1476 diskError(uint32_t stmfError, int *ret)
1477 {
1478 	switch (stmfError) {
1479 		case SBD_RET_META_CREATION_FAILED:
1480 		case SBD_RET_ZFS_META_CREATE_FAILED:
1481 			*ret = STMF_ERROR_META_CREATION;
1482 			break;
1483 		case SBD_RET_INVALID_BLKSIZE:
1484 			*ret = STMF_ERROR_INVALID_BLKSIZE;
1485 			break;
1486 		case SBD_RET_FILE_ALREADY_REGISTERED:
1487 			*ret = STMF_ERROR_FILE_IN_USE;
1488 			break;
1489 		case SBD_RET_GUID_ALREADY_REGISTERED:
1490 			*ret = STMF_ERROR_GUID_IN_USE;
1491 			break;
1492 		case SBD_RET_META_PATH_NOT_ABSOLUTE:
1493 		case SBD_RET_META_FILE_LOOKUP_FAILED:
1494 		case SBD_RET_META_FILE_OPEN_FAILED:
1495 		case SBD_RET_META_FILE_GETATTR_FAILED:
1496 		case SBD_RET_NO_META:
1497 			*ret = STMF_ERROR_META_FILE_NAME;
1498 			break;
1499 		case SBD_RET_DATA_PATH_NOT_ABSOLUTE:
1500 		case SBD_RET_DATA_FILE_LOOKUP_FAILED:
1501 		case SBD_RET_DATA_FILE_OPEN_FAILED:
1502 		case SBD_RET_DATA_FILE_GETATTR_FAILED:
1503 			*ret = STMF_ERROR_DATA_FILE_NAME;
1504 			break;
1505 		case SBD_RET_FILE_SIZE_ERROR:
1506 			*ret = STMF_ERROR_FILE_SIZE_INVALID;
1507 			break;
1508 		case SBD_RET_SIZE_OUT_OF_RANGE:
1509 			*ret = STMF_ERROR_SIZE_OUT_OF_RANGE;
1510 			break;
1511 		case SBD_RET_LU_BUSY:
1512 			*ret = STMF_ERROR_LU_BUSY;
1513 			break;
1514 		case SBD_RET_WRITE_CACHE_SET_FAILED:
1515 			*ret = STMF_ERROR_WRITE_CACHE_SET;
1516 			break;
1517 		case SBD_RET_ACCESS_STATE_FAILED:
1518 			*ret = STMF_ERROR_ACCESS_STATE_SET;
1519 			break;
1520 		default:
1521 			*ret = STMF_STATUS_ERROR;
1522 			break;
1523 	}
1524 }
1525 
1526 /*
1527  * Creates a logical unit resource of type STMF_DISK.
1528  *
1529  * No defaults should be set here as all defaults are derived from the
1530  * driver's default settings.
1531  */
1532 static int
createDiskResource(luResourceImpl * hdl)1533 createDiskResource(luResourceImpl *hdl)
1534 {
1535 	hdl->type = STMF_DISK;
1536 
1537 	hdl->resource = calloc(1, sizeof (diskResource));
1538 	if (hdl->resource == NULL) {
1539 		return (STMF_ERROR_NOMEM);
1540 	}
1541 
1542 	return (STMF_STATUS_SUCCESS);
1543 }
1544 
1545 /*
1546  * stmfDeleteLu
1547  *
1548  * Purpose: Delete a logical unit
1549  *
1550  * hdl - handle to logical unit resource created via stmfCreateLuResource
1551  *
1552  * luGuid - If non-NULL, on success, contains the guid of the created logical
1553  *	    unit
1554  */
1555 int
stmfDeleteLu(stmfGuid * luGuid)1556 stmfDeleteLu(stmfGuid *luGuid)
1557 {
1558 	int ret = STMF_STATUS_SUCCESS;
1559 	stmfLogicalUnitProperties luProps;
1560 
1561 	if (luGuid == NULL) {
1562 		return (STMF_ERROR_INVALID_ARG);
1563 	}
1564 
1565 	/* Check logical unit provider name to call correct dtype function */
1566 	if ((ret = stmfGetLogicalUnitProperties(luGuid, &luProps))
1567 	    != STMF_STATUS_SUCCESS) {
1568 		return (ret);
1569 	} else {
1570 		if (strcmp(luProps.providerName, "sbd") == 0) {
1571 			ret = deleteDiskLu(luGuid);
1572 		} else if (luProps.status == STMF_LOGICAL_UNIT_UNREGISTERED) {
1573 			return (STMF_ERROR_NOT_FOUND);
1574 		} else {
1575 			return (STMF_ERROR_INVALID_ARG);
1576 		}
1577 	}
1578 
1579 	return (ret);
1580 }
1581 
1582 static int
deleteDiskLu(stmfGuid * luGuid)1583 deleteDiskLu(stmfGuid *luGuid)
1584 {
1585 	int ret = STMF_STATUS_SUCCESS;
1586 	int fd;
1587 	int savedErrno;
1588 	int ioctlRet;
1589 	sbd_delete_lu_t deleteLu = {0};
1590 
1591 	stmf_iocdata_t sbdIoctl = {0};
1592 
1593 	/*
1594 	 * Open control node for sbd
1595 	 */
1596 	if ((ret = openSbd(OPEN_SBD, &fd)) != STMF_STATUS_SUCCESS)
1597 		return (ret);
1598 
1599 	ret = removeGuidFromDiskStore(luGuid);
1600 	if (ret != STMF_STATUS_SUCCESS) {
1601 		goto done;
1602 	}
1603 
1604 	bcopy(luGuid, deleteLu.dlu_guid, sizeof (deleteLu.dlu_guid));
1605 	deleteLu.dlu_by_guid = 1;
1606 
1607 	sbdIoctl.stmf_version = STMF_VERSION_1;
1608 	sbdIoctl.stmf_ibuf_size = sizeof (deleteLu);
1609 	sbdIoctl.stmf_ibuf = (uint64_t)(unsigned long)&deleteLu;
1610 	ioctlRet = ioctl(fd, SBD_IOCTL_DELETE_LU, &sbdIoctl);
1611 	if (ioctlRet != 0) {
1612 		savedErrno = errno;
1613 		switch (savedErrno) {
1614 			case EBUSY:
1615 				ret = STMF_ERROR_BUSY;
1616 				break;
1617 			case EPERM:
1618 			case EACCES:
1619 				ret = STMF_ERROR_PERM;
1620 				break;
1621 			case ENOENT:
1622 				ret = STMF_ERROR_NOT_FOUND;
1623 				break;
1624 			default:
1625 				syslog(LOG_DEBUG,
1626 				    "deleteDiskLu:ioctl error(%d) (%d) (%d)",
1627 				    ioctlRet, sbdIoctl.stmf_error, savedErrno);
1628 				ret = STMF_STATUS_ERROR;
1629 				break;
1630 		}
1631 	}
1632 
1633 done:
1634 	(void) close(fd);
1635 	return (ret);
1636 }
1637 
1638 /*
1639  * stmfLuStandby
1640  *
1641  * Purpose: Sets access state to standby
1642  *
1643  * luGuid - guid of registered logical unit
1644  *
1645  */
1646 int
stmfLuStandby(stmfGuid * luGuid)1647 stmfLuStandby(stmfGuid *luGuid)
1648 {
1649 	int ret = STMF_STATUS_SUCCESS;
1650 	stmfLogicalUnitProperties luProps;
1651 
1652 	if (luGuid == NULL) {
1653 		return (STMF_ERROR_INVALID_ARG);
1654 	}
1655 
1656 	/* Check logical unit provider name to call correct dtype function */
1657 	if ((ret = stmfGetLogicalUnitProperties(luGuid, &luProps))
1658 	    != STMF_STATUS_SUCCESS) {
1659 		return (ret);
1660 	} else {
1661 		if (strcmp(luProps.providerName, "sbd") == 0) {
1662 			ret = setDiskStandby(luGuid);
1663 		} else if (luProps.status == STMF_LOGICAL_UNIT_UNREGISTERED) {
1664 			return (STMF_ERROR_NOT_FOUND);
1665 		} else {
1666 			return (STMF_ERROR_INVALID_ARG);
1667 		}
1668 	}
1669 
1670 	return (ret);
1671 }
1672 
1673 static int
setDiskStandby(stmfGuid * luGuid)1674 setDiskStandby(stmfGuid *luGuid)
1675 {
1676 	int ret = STMF_STATUS_SUCCESS;
1677 	stmf_iocdata_t sbdIoctl = {0};
1678 	sbd_set_lu_standby_t sbdLu = {0};
1679 	int ioctlRet;
1680 	int savedErrno;
1681 	int fd = 0;
1682 
1683 	/*
1684 	 * Open control node for sbd
1685 	 */
1686 	if ((ret = openSbd(OPEN_SBD, &fd)) != STMF_STATUS_SUCCESS)
1687 		return (ret);
1688 
1689 	bcopy(luGuid, &sbdLu.stlu_guid, sizeof (stmfGuid));
1690 
1691 	sbdIoctl.stmf_version = STMF_VERSION_1;
1692 	sbdIoctl.stmf_ibuf_size = sizeof (sbd_set_lu_standby_t);
1693 	sbdIoctl.stmf_ibuf = (uint64_t)(unsigned long)&sbdLu;
1694 
1695 	ioctlRet = ioctl(fd, SBD_IOCTL_SET_LU_STANDBY, &sbdIoctl);
1696 	if (ioctlRet != 0) {
1697 		savedErrno = errno;
1698 		switch (savedErrno) {
1699 			case EBUSY:
1700 				ret = STMF_ERROR_BUSY;
1701 				break;
1702 			case EPERM:
1703 			case EACCES:
1704 				ret = STMF_ERROR_PERM;
1705 				break;
1706 			default:
1707 				diskError(sbdIoctl.stmf_error, &ret);
1708 				if (ret == STMF_STATUS_ERROR) {
1709 					syslog(LOG_DEBUG,
1710 					"setDiskStandby:ioctl "
1711 					"error(%d) (%d) (%d)", ioctlRet,
1712 					    sbdIoctl.stmf_error, savedErrno);
1713 				}
1714 				break;
1715 		}
1716 	}
1717 	(void) close(fd);
1718 	return (ret);
1719 }
1720 
1721 /*
1722  * stmfModifyLu
1723  *
1724  * Purpose: Modify properties of a logical unit
1725  *
1726  * luGuid - guid of registered logical unit
1727  * prop - property to modify
1728  * propVal - property value to set
1729  *
1730  */
1731 int
stmfModifyLu(stmfGuid * luGuid,uint32_t prop,const char * propVal)1732 stmfModifyLu(stmfGuid *luGuid, uint32_t prop, const char *propVal)
1733 {
1734 	int ret = STMF_STATUS_SUCCESS;
1735 	stmfLogicalUnitProperties luProps;
1736 
1737 	if (luGuid == NULL) {
1738 		return (STMF_ERROR_INVALID_ARG);
1739 	}
1740 
1741 	/* Check logical unit provider name to call correct dtype function */
1742 	if ((ret = stmfGetLogicalUnitProperties(luGuid, &luProps))
1743 	    != STMF_STATUS_SUCCESS) {
1744 		return (ret);
1745 	} else {
1746 		if (strcmp(luProps.providerName, "sbd") == 0) {
1747 			ret = modifyDiskLuProp(luGuid, NULL, prop, propVal);
1748 		} else if (luProps.status == STMF_LOGICAL_UNIT_UNREGISTERED) {
1749 			return (STMF_ERROR_NOT_FOUND);
1750 		} else {
1751 			return (STMF_ERROR_INVALID_ARG);
1752 		}
1753 	}
1754 
1755 	return (ret);
1756 }
1757 
1758 /*
1759  * stmfModifyLuByFname
1760  *
1761  * Purpose: Modify a device by filename. Device does not need to be registered.
1762  *
1763  * dType - type of device to modify
1764  *         STMF_DISK
1765  *
1766  * fname - filename or meta filename
1767  * prop - valid property identifier
1768  * propVal - property value
1769  *
1770  */
1771 int
stmfModifyLuByFname(uint16_t dType,const char * fname,uint32_t prop,const char * propVal)1772 stmfModifyLuByFname(uint16_t dType, const char *fname, uint32_t prop,
1773     const char *propVal)
1774 {
1775 	int ret = STMF_STATUS_SUCCESS;
1776 	if (fname == NULL) {
1777 		return (STMF_ERROR_INVALID_ARG);
1778 	}
1779 
1780 	if (dType == STMF_DISK) {
1781 		ret = modifyDiskLuProp(NULL, fname, prop, propVal);
1782 	} else {
1783 		return (STMF_ERROR_INVALID_ARG);
1784 	}
1785 
1786 	return (ret);
1787 }
1788 
1789 static int
modifyDiskLuProp(stmfGuid * luGuid,const char * fname,uint32_t prop,const char * propVal)1790 modifyDiskLuProp(stmfGuid *luGuid, const char *fname, uint32_t prop,
1791     const char *propVal)
1792 {
1793 	int ret = STMF_STATUS_SUCCESS;
1794 	luResource hdl = NULL;
1795 	luResourceImpl *luPropsHdl;
1796 
1797 	ret = stmfCreateLuResource(STMF_DISK, &hdl);
1798 	if (ret != STMF_STATUS_SUCCESS) {
1799 		return (ret);
1800 	}
1801 	ret = validateModifyDiskProp(prop);
1802 	if (ret != STMF_STATUS_SUCCESS) {
1803 		(void) stmfFreeLuResource(hdl);
1804 		return (STMF_ERROR_INVALID_PROP);
1805 	}
1806 	ret = stmfSetLuProp(hdl, prop, propVal);
1807 	if (ret != STMF_STATUS_SUCCESS) {
1808 		(void) stmfFreeLuResource(hdl);
1809 		return (ret);
1810 	}
1811 	luPropsHdl = hdl;
1812 	ret = modifyDiskLu((diskResource *)luPropsHdl->resource, luGuid, fname);
1813 	(void) stmfFreeLuResource(hdl);
1814 	return (ret);
1815 }
1816 
1817 static int
validateModifyDiskProp(uint32_t prop)1818 validateModifyDiskProp(uint32_t prop)
1819 {
1820 	switch (prop) {
1821 		case STMF_LU_PROP_ALIAS:
1822 		case STMF_LU_PROP_SIZE:
1823 		case STMF_LU_PROP_MGMT_URL:
1824 		case STMF_LU_PROP_WRITE_PROTECT:
1825 		case STMF_LU_PROP_WRITE_CACHE_DISABLE:
1826 			return (STMF_STATUS_SUCCESS);
1827 		default:
1828 			return (STMF_STATUS_ERROR);
1829 	}
1830 }
1831 
1832 static int
modifyDiskLu(diskResource * disk,stmfGuid * luGuid,const char * fname)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
removeGuidFromDiskStore(stmfGuid * guid)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
addGuidToDiskStore(stmfGuid * guid,char * filename)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
persistDiskGuid(stmfGuid * guid,char * filename,boolean_t persist)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
stmfGetLuProp(luResource hdl,uint32_t prop,char * propVal,size_t * propLen)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
stmfGetLuResource(stmfGuid * luGuid,luResource * hdl)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
getDiskAllProps(stmfGuid * luGuid,luResource * hdl)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
loadDiskPropsFromDriver(luResourceImpl * hdl,sbd_lu_props_t * sbdProps)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
stmfGetGlobalLuProp(uint16_t dType,uint32_t prop,char * propVal,size_t * propLen)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
getDiskGlobalProp(uint32_t prop,char * propVal,size_t * propLen)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
stmfSetGlobalLuProp(uint16_t dType,uint32_t prop,const char * propVal)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
setDiskGlobalProp(uint32_t resourceProp,const char * propVal)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 	}
2548 
2549 	/*
2550 	 * Open control node for sbd
2551 	 */
2552 	if ((ret = openSbd(OPEN_SBD, &fd)) != STMF_STATUS_SUCCESS)
2553 		return (ret);
2554 
2555 	propLen = strlen(propVal);
2556 	mluBufSize += propLen + 1;
2557 	sbdGlobalPropsSize += sizeof (sbd_global_props_t) - 8 +
2558 	    max(8, mluBufSize);
2559 	/*
2560 	 * 8 is the size of the buffer set aside for
2561 	 * concatenation of variable length fields
2562 	 */
2563 	sbdGlobalProps = (sbd_global_props_t *)calloc(1, sbdGlobalPropsSize);
2564 	if (sbdGlobalProps == NULL) {
2565 		(void) close(fd);
2566 		return (STMF_ERROR_NOMEM);
2567 	}
2568 
2569 	sbdGlobalProps->mlu_struct_size = sbdGlobalPropsSize;
2570 
2571 	switch (resourceProp) {
2572 		case STMF_LU_PROP_MGMT_URL:
2573 			sbdGlobalProps->mlu_mgmt_url_valid = 1;
2574 			bcopy(propVal, &(sbdGlobalProps->mlu_buf),
2575 			    propLen + 1);
2576 			break;
2577 		default:
2578 			ret = STMF_ERROR_NO_PROP;
2579 			goto done;
2580 	}
2581 
2582 	sbdIoctl.stmf_version = STMF_VERSION_1;
2583 	sbdIoctl.stmf_ibuf_size = sbdGlobalProps->mlu_struct_size;
2584 	sbdIoctl.stmf_ibuf = (uint64_t)(unsigned long)sbdGlobalProps;
2585 
2586 	ioctlRet = ioctl(fd, SBD_IOCTL_SET_GLOBAL_LU, &sbdIoctl);
2587 	if (ioctlRet != 0) {
2588 		savedErrno = errno;
2589 		switch (savedErrno) {
2590 			case EBUSY:
2591 				ret = STMF_ERROR_BUSY;
2592 				break;
2593 			case EPERM:
2594 			case EACCES:
2595 				ret = STMF_ERROR_PERM;
2596 				break;
2597 			default:
2598 				diskError(sbdIoctl.stmf_error, &ret);
2599 				if (ret == STMF_STATUS_ERROR) {
2600 					syslog(LOG_DEBUG,
2601 					"modifyDiskLu:ioctl "
2602 					"error(%d) (%d) (%d)", ioctlRet,
2603 					    sbdIoctl.stmf_error, savedErrno);
2604 				}
2605 				break;
2606 		}
2607 	}
2608 
2609 done:
2610 	free(sbdGlobalProps);
2611 	(void) close(fd);
2612 	return (ret);
2613 }
2614 
2615 
2616 /*
2617  * stmfSetLuProp
2618  *
2619  * Purpose: set a property on an luResource
2620  *
2621  * hdl - allocated luResource
2622  * prop - property identifier
2623  * propVal - property value to be set
2624  */
2625 int
stmfSetLuProp(luResource hdl,uint32_t prop,const char * propVal)2626 stmfSetLuProp(luResource hdl, uint32_t prop, const char *propVal)
2627 {
2628 	int ret = STMF_STATUS_SUCCESS;
2629 	luResourceImpl *luPropsHdl = hdl;
2630 	if (hdl == NULL) {
2631 		return (STMF_ERROR_INVALID_ARG);
2632 	}
2633 
2634 	if (luPropsHdl->type == STMF_DISK) {
2635 		ret = setDiskProp(luPropsHdl, prop, propVal);
2636 	} else {
2637 		return (STMF_ERROR_INVALID_ARG);
2638 	}
2639 
2640 	return (ret);
2641 }
2642 
2643 /*
2644  * getDiskProp
2645  *
2646  * Purpose: retrieve a given property from a logical unit resource of type disk
2647  *
2648  * hdl - allocated luResourceImpl
2649  * prop - property identifier
2650  * propVal - pointer to character to contain the retrieved property value
2651  * propLen - On input this is the length of propVal. On failure, it contains the
2652  *           number of bytes required for propVal
2653  */
2654 static int
getDiskProp(luResourceImpl * hdl,uint32_t prop,char * propVal,size_t * propLen)2655 getDiskProp(luResourceImpl *hdl, uint32_t prop, char *propVal, size_t *propLen)
2656 {
2657 	int ret = STMF_STATUS_SUCCESS;
2658 	diskResource *diskLu = hdl->resource;
2659 	char accessState[20];
2660 	size_t reqLen;
2661 
2662 	if (prop == STMF_LU_PROP_ACCESS_STATE) {
2663 		if (diskLu->accessState == SBD_LU_ACTIVE) {
2664 			(void) strlcpy(accessState, STMF_ACCESS_ACTIVE,
2665 			    sizeof (accessState));
2666 		} else if (diskLu->accessState == SBD_LU_TRANSITION_TO_ACTIVE) {
2667 			(void) strlcpy(accessState,
2668 			    STMF_ACCESS_STANDBY_TO_ACTIVE,
2669 			    sizeof (accessState));
2670 		} else if (diskLu->accessState == SBD_LU_STANDBY) {
2671 			(void) strlcpy(accessState, STMF_ACCESS_STANDBY,
2672 			    sizeof (accessState));
2673 		} else if (diskLu->accessState ==
2674 		    SBD_LU_TRANSITION_TO_STANDBY) {
2675 			(void) strlcpy(accessState,
2676 			    STMF_ACCESS_ACTIVE_TO_STANDBY,
2677 			    sizeof (accessState));
2678 		}
2679 		if ((reqLen = strlcpy(propVal, accessState,
2680 		    *propLen)) >= *propLen) {
2681 			*propLen = reqLen + 1;
2682 			return (STMF_ERROR_INVALID_ARG);
2683 		}
2684 		return (0);
2685 	}
2686 
2687 	if (diskLu->accessState != SBD_LU_ACTIVE) {
2688 		return (STMF_ERROR_NO_PROP_STANDBY);
2689 	}
2690 
2691 	switch (prop) {
2692 		case STMF_LU_PROP_BLOCK_SIZE:
2693 			if (diskLu->blkSizeValid == B_FALSE) {
2694 				return (STMF_ERROR_NO_PROP);
2695 			}
2696 			reqLen = snprintf(propVal, *propLen, "%llu",
2697 			    (u_longlong_t)diskLu->blkSize);
2698 			if (reqLen >= *propLen) {
2699 				*propLen = reqLen + 1;
2700 				return (STMF_ERROR_INVALID_ARG);
2701 			}
2702 			break;
2703 		case STMF_LU_PROP_FILENAME:
2704 			if (diskLu->luDataFileNameValid == B_FALSE) {
2705 				return (STMF_ERROR_NO_PROP);
2706 			}
2707 			if ((reqLen = strlcpy(propVal, diskLu->luDataFileName,
2708 			    *propLen)) >= *propLen) {
2709 				*propLen = reqLen + 1;
2710 				return (STMF_ERROR_INVALID_ARG);
2711 			}
2712 			break;
2713 		case STMF_LU_PROP_META_FILENAME:
2714 			if (diskLu->luMetaFileNameValid == B_FALSE) {
2715 				return (STMF_ERROR_NO_PROP);
2716 			}
2717 			if ((reqLen = strlcpy(propVal, diskLu->luMetaFileName,
2718 			    *propLen)) >= *propLen) {
2719 				*propLen = reqLen + 1;
2720 				return (STMF_ERROR_INVALID_ARG);
2721 			}
2722 			break;
2723 		case STMF_LU_PROP_MGMT_URL:
2724 			if (diskLu->luMgmtUrlValid == B_FALSE) {
2725 				return (STMF_ERROR_NO_PROP);
2726 			}
2727 			if ((reqLen = strlcpy(propVal, diskLu->luMgmtUrl,
2728 			    *propLen)) >= *propLen) {
2729 				*propLen = reqLen + 1;
2730 				return (STMF_ERROR_INVALID_ARG);
2731 			}
2732 			break;
2733 		case STMF_LU_PROP_GUID:
2734 			if (diskLu->luGuidValid == B_FALSE) {
2735 				return (STMF_ERROR_NO_PROP);
2736 			}
2737 			reqLen = snprintf(propVal, *propLen,
2738 			    "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X"
2739 			    "%02X%02X%02X%02X",
2740 			    diskLu->luGuid[0], diskLu->luGuid[1],
2741 			    diskLu->luGuid[2], diskLu->luGuid[3],
2742 			    diskLu->luGuid[4], diskLu->luGuid[5],
2743 			    diskLu->luGuid[6], diskLu->luGuid[7],
2744 			    diskLu->luGuid[8], diskLu->luGuid[9],
2745 			    diskLu->luGuid[10], diskLu->luGuid[11],
2746 			    diskLu->luGuid[12], diskLu->luGuid[13],
2747 			    diskLu->luGuid[14], diskLu->luGuid[15]);
2748 			if (reqLen >= *propLen) {
2749 				*propLen = reqLen + 1;
2750 				return (STMF_ERROR_INVALID_ARG);
2751 			}
2752 			break;
2753 		case STMF_LU_PROP_SERIAL_NUM:
2754 			if (diskLu->serialNumValid == B_FALSE) {
2755 				return (STMF_ERROR_NO_PROP);
2756 			}
2757 			if ((reqLen = strlcpy(propVal, diskLu->serialNum,
2758 			    *propLen)) >= *propLen) {
2759 				*propLen = reqLen + 1;
2760 				return (STMF_ERROR_INVALID_ARG);
2761 			}
2762 			break;
2763 		case STMF_LU_PROP_SIZE:
2764 			if (diskLu->luSizeValid == B_FALSE) {
2765 				return (STMF_ERROR_NO_PROP);
2766 			}
2767 			(void) snprintf(propVal, *propLen, "%llu",
2768 			    (u_longlong_t)diskLu->luSize);
2769 			break;
2770 		case STMF_LU_PROP_ALIAS:
2771 			if (diskLu->luAliasValid == B_FALSE) {
2772 				return (STMF_ERROR_NO_PROP);
2773 			}
2774 			if ((reqLen = strlcpy(propVal, diskLu->luAlias,
2775 			    *propLen)) >= *propLen) {
2776 				*propLen = reqLen + 1;
2777 				return (STMF_ERROR_INVALID_ARG);
2778 			}
2779 			break;
2780 		case STMF_LU_PROP_VID:
2781 			if (diskLu->vidValid == B_FALSE) {
2782 				return (STMF_ERROR_NO_PROP);
2783 			}
2784 			if (*propLen <= sizeof (diskLu->vid)) {
2785 				return (STMF_ERROR_INVALID_ARG);
2786 			}
2787 			bcopy(diskLu->vid, propVal, sizeof (diskLu->vid));
2788 			propVal[sizeof (diskLu->vid)] = 0;
2789 			break;
2790 		case STMF_LU_PROP_PID:
2791 			if (diskLu->pidValid == B_FALSE) {
2792 				return (STMF_ERROR_NO_PROP);
2793 			}
2794 			if (*propLen <= sizeof (diskLu->pid)) {
2795 				return (STMF_ERROR_INVALID_ARG);
2796 			}
2797 			bcopy(diskLu->pid, propVal, sizeof (diskLu->pid));
2798 			propVal[sizeof (diskLu->pid)] = 0;
2799 			break;
2800 		case STMF_LU_PROP_WRITE_PROTECT:
2801 			if (diskLu->writeProtectEnableValid == B_FALSE) {
2802 				return (STMF_ERROR_NO_PROP);
2803 			}
2804 			if (diskLu->writeProtectEnable) {
2805 				if ((reqLen = strlcpy(propVal, "true",
2806 				    *propLen)) >= *propLen) {
2807 					*propLen = reqLen + 1;
2808 					return (STMF_ERROR_INVALID_ARG);
2809 				}
2810 			} else {
2811 				if ((reqLen = strlcpy(propVal, "false",
2812 				    *propLen)) >= *propLen) {
2813 					*propLen = reqLen + 1;
2814 					return (STMF_ERROR_INVALID_ARG);
2815 				}
2816 			}
2817 			break;
2818 		case STMF_LU_PROP_WRITE_CACHE_DISABLE:
2819 			if (diskLu->writebackCacheDisableValid == B_FALSE) {
2820 				return (STMF_ERROR_NO_PROP);
2821 			}
2822 			if (diskLu->writebackCacheDisable) {
2823 				if ((reqLen = strlcpy(propVal, "true",
2824 				    *propLen)) >= *propLen) {
2825 					*propLen = reqLen + 1;
2826 					return (STMF_ERROR_INVALID_ARG);
2827 				}
2828 			} else {
2829 				if ((reqLen = strlcpy(propVal, "false",
2830 				    *propLen)) >= *propLen) {
2831 					*propLen = reqLen + 1;
2832 					return (STMF_ERROR_INVALID_ARG);
2833 				}
2834 			}
2835 			break;
2836 		default:
2837 			ret = STMF_ERROR_INVALID_PROP;
2838 			break;
2839 	}
2840 
2841 	return (ret);
2842 }
2843 
2844 /*
2845  * setDiskProp
2846  *
2847  * Purpose: set properties for resource of type disk
2848  *
2849  * hdl - allocated luResourceImpl
2850  * resourceProp - valid resource identifier
2851  * propVal - valid resource value
2852  */
2853 static int
setDiskProp(luResourceImpl * hdl,uint32_t resourceProp,const char * propVal)2854 setDiskProp(luResourceImpl *hdl, uint32_t resourceProp, const char *propVal)
2855 {
2856 	int ret = STMF_STATUS_SUCCESS;
2857 	int i;
2858 	diskResource *diskLu = hdl->resource;
2859 	unsigned long long numericProp = 0;
2860 	char guidProp[LU_ASCII_GUID_SIZE + 1];
2861 	char ouiProp[OUI_ASCII_SIZE + 1];
2862 	char hostIdProp[HOST_ID_ASCII_SIZE + 1];
2863 	unsigned int oui[OUI_SIZE];
2864 	unsigned int hostId[HOST_ID_SIZE];
2865 	unsigned int guid[LU_GUID_SIZE];
2866 	int propSize;
2867 
2868 
2869 	if (propVal == NULL) {
2870 		return (STMF_ERROR_INVALID_ARG);
2871 	}
2872 
2873 	switch (resourceProp) {
2874 		case STMF_LU_PROP_ALIAS:
2875 			if (strlcpy(diskLu->luAlias, propVal,
2876 			    sizeof (diskLu->luAlias)) >=
2877 			    sizeof (diskLu->luAlias)) {
2878 				return (STMF_ERROR_INVALID_PROPSIZE);
2879 			}
2880 			diskLu->luAliasValid = B_TRUE;
2881 			break;
2882 		case STMF_LU_PROP_BLOCK_SIZE: {
2883 			const char *tmp = propVal;
2884 			while (*tmp) {
2885 				if (!isdigit(*tmp++)) {
2886 					return (STMF_ERROR_INVALID_ARG);
2887 				}
2888 			}
2889 			(void) sscanf(propVal, "%llu", &numericProp);
2890 			if (numericProp > UINT16_MAX) {
2891 				return (STMF_ERROR_INVALID_PROPSIZE);
2892 			}
2893 			diskLu->blkSize = numericProp;
2894 			diskLu->blkSizeValid = B_TRUE;
2895 			break;
2896 		}
2897 		case STMF_LU_PROP_COMPANY_ID:
2898 			if ((strlcpy(ouiProp, propVal, sizeof (ouiProp))) >=
2899 			    sizeof (ouiProp)) {
2900 				return (STMF_ERROR_INVALID_ARG);
2901 			}
2902 			if (checkHexUpper(ouiProp) != 0) {
2903 				return (STMF_ERROR_INVALID_ARG);
2904 			}
2905 			(void) sscanf(ouiProp, "%2X%2X%2X",
2906 			    &oui[0], &oui[1], &oui[2]);
2907 
2908 			diskLu->companyId = 0;
2909 			diskLu->companyId += oui[0] << 16;
2910 			diskLu->companyId += oui[1] << 8;
2911 			diskLu->companyId += oui[2];
2912 			if (diskLu->companyId == 0) {
2913 				return (STMF_ERROR_INVALID_ARG);
2914 			}
2915 			diskLu->companyIdValid = B_TRUE;
2916 			break;
2917 		case STMF_LU_PROP_HOST_ID:
2918 			if ((strlcpy(hostIdProp, propVal,
2919 			    sizeof (hostIdProp))) >= sizeof (hostIdProp)) {
2920 				return (STMF_ERROR_INVALID_ARG);
2921 			}
2922 			if (checkHexUpper(hostIdProp) != 0) {
2923 				return (STMF_ERROR_INVALID_ARG);
2924 			}
2925 			(void) sscanf(hostIdProp, "%2X%2X%2X%2X",
2926 			    &hostId[0], &hostId[1], &hostId[2], &hostId[3]);
2927 
2928 			diskLu->hostId = 0;
2929 			diskLu->hostId += hostId[0] << 24;
2930 			diskLu->hostId += hostId[1] << 16;
2931 			diskLu->hostId += hostId[2] << 8;
2932 			diskLu->hostId += hostId[3];
2933 			if (diskLu->hostId == 0) {
2934 				return (STMF_ERROR_INVALID_ARG);
2935 			}
2936 			diskLu->hostIdValid = B_TRUE;
2937 			break;
2938 		case STMF_LU_PROP_GUID:
2939 			if (strlen(propVal) != LU_ASCII_GUID_SIZE) {
2940 				return (STMF_ERROR_INVALID_PROPSIZE);
2941 			}
2942 
2943 			if ((strlcpy(guidProp, propVal, sizeof (guidProp))) >=
2944 			    sizeof (guidProp)) {
2945 				return (STMF_ERROR_INVALID_ARG);
2946 			}
2947 
2948 			if (checkHexUpper(guidProp) != 0) {
2949 				return (STMF_ERROR_INVALID_ARG);
2950 			}
2951 
2952 			(void) sscanf(guidProp,
2953 			    "%2X%2X%2X%2X%2X%2X%2X%2X%2X%2X%2X%2X%2X%2X%2X%2X",
2954 			    &guid[0], &guid[1], &guid[2], &guid[3], &guid[4],
2955 			    &guid[5], &guid[6], &guid[7], &guid[8], &guid[9],
2956 			    &guid[10], &guid[11], &guid[12], &guid[13],
2957 			    &guid[14], &guid[15]);
2958 			for (i = 0; i < sizeof (diskLu->luGuid); i++) {
2959 				diskLu->luGuid[i] = guid[i];
2960 			}
2961 			diskLu->luGuidValid = B_TRUE;
2962 			break;
2963 		case STMF_LU_PROP_FILENAME:
2964 			if ((strlcpy(diskLu->luDataFileName, propVal,
2965 			    sizeof (diskLu->luDataFileName))) >=
2966 			    sizeof (diskLu->luDataFileName)) {
2967 				return (STMF_ERROR_INVALID_PROPSIZE);
2968 			}
2969 			diskLu->luDataFileNameValid = B_TRUE;
2970 			break;
2971 		case STMF_LU_PROP_META_FILENAME:
2972 			if ((strlcpy(diskLu->luMetaFileName, propVal,
2973 			    sizeof (diskLu->luMetaFileName))) >=
2974 			    sizeof (diskLu->luMetaFileName)) {
2975 				return (STMF_ERROR_INVALID_PROPSIZE);
2976 			}
2977 			diskLu->luMetaFileNameValid = B_TRUE;
2978 			break;
2979 		case STMF_LU_PROP_MGMT_URL:
2980 			if ((strlcpy(diskLu->luMgmtUrl, propVal,
2981 			    sizeof (diskLu->luMgmtUrl))) >=
2982 			    sizeof (diskLu->luMgmtUrl)) {
2983 				return (STMF_ERROR_INVALID_PROPSIZE);
2984 			}
2985 			diskLu->luMgmtUrlValid = B_TRUE;
2986 			break;
2987 		case STMF_LU_PROP_PID:
2988 			if ((propSize = strlen(propVal)) >
2989 			    sizeof (diskLu->pid)) {
2990 				return (STMF_ERROR_INVALID_PROPSIZE);
2991 			}
2992 			(void) strncpy(diskLu->pid, propVal, propSize);
2993 			diskLu->pidValid = B_TRUE;
2994 			break;
2995 		case STMF_LU_PROP_SERIAL_NUM:
2996 			if ((propSize = strlen(propVal)) >
2997 			    (sizeof (diskLu->serialNum) - 1)) {
2998 				return (STMF_ERROR_INVALID_PROPSIZE);
2999 			}
3000 			(void) strncpy(diskLu->serialNum, propVal, propSize);
3001 			diskLu->serialNumValid = B_TRUE;
3002 			break;
3003 		case STMF_LU_PROP_SIZE:
3004 			if ((niceStrToNum(propVal, &diskLu->luSize) != 0)) {
3005 				return (STMF_ERROR_INVALID_ARG);
3006 			}
3007 			diskLu->luSizeValid = B_TRUE;
3008 			break;
3009 		case STMF_LU_PROP_VID:
3010 			if ((propSize = strlen(propVal)) >
3011 			    sizeof (diskLu->vid)) {
3012 				return (STMF_ERROR_INVALID_PROPSIZE);
3013 			}
3014 			(void) strncpy(diskLu->vid, propVal, propSize);
3015 			diskLu->vidValid = B_TRUE;
3016 			break;
3017 		case STMF_LU_PROP_WRITE_PROTECT:
3018 			if (strcasecmp(propVal, "TRUE") == 0) {
3019 				diskLu->writeProtectEnable = B_TRUE;
3020 			} else if (strcasecmp(propVal, "FALSE") == 0) {
3021 				diskLu->writeProtectEnable = B_FALSE;
3022 			} else {
3023 				return (STMF_ERROR_INVALID_ARG);
3024 			}
3025 			diskLu->writeProtectEnableValid = B_TRUE;
3026 			break;
3027 		case STMF_LU_PROP_WRITE_CACHE_DISABLE:
3028 			if (strcasecmp(propVal, "TRUE") == 0) {
3029 				diskLu->writebackCacheDisable = B_TRUE;
3030 			} else if (strcasecmp(propVal, "FALSE") == 0) {
3031 				diskLu->writebackCacheDisable = B_FALSE;
3032 			} else {
3033 				return (STMF_ERROR_INVALID_ARG);
3034 			}
3035 			diskLu->writebackCacheDisableValid = B_TRUE;
3036 			break;
3037 		case STMF_LU_PROP_ACCESS_STATE:
3038 			ret = STMF_ERROR_INVALID_PROP;
3039 			break;
3040 		default:
3041 			ret = STMF_ERROR_INVALID_PROP;
3042 			break;
3043 	}
3044 	return (ret);
3045 }
3046 
3047 static int
checkHexUpper(char * buf)3048 checkHexUpper(char *buf)
3049 {
3050 	int i;
3051 
3052 	for (i = 0; i < strlen(buf); i++) {
3053 		if (isxdigit(buf[i])) {
3054 			buf[i] = toupper(buf[i]);
3055 			continue;
3056 		}
3057 		return (-1);
3058 	}
3059 
3060 	return (0);
3061 }
3062 
3063 /*
3064  * Given a numeric suffix, convert the value into a number of bits that the
3065  * resulting value must be shifted.
3066  * Code lifted from libzfs_util.c
3067  */
3068 static int
strToShift(const char * buf)3069 strToShift(const char *buf)
3070 {
3071 	const char *ends = "BKMGTPE";
3072 	int i;
3073 
3074 	if (buf[0] == '\0')
3075 		return (0);
3076 
3077 	for (i = 0; i < strlen(ends); i++) {
3078 		if (toupper(buf[0]) == ends[i])
3079 			return (10*i);
3080 	}
3081 
3082 	return (-1);
3083 }
3084 
3085 int
stmfFreeLuResource(luResource hdl)3086 stmfFreeLuResource(luResource hdl)
3087 {
3088 	int ret = STMF_STATUS_SUCCESS;
3089 	if (hdl == NULL) {
3090 		return (STMF_ERROR_INVALID_ARG);
3091 	}
3092 
3093 	luResourceImpl *hdlImpl = hdl;
3094 	free(hdlImpl->resource);
3095 	free(hdlImpl);
3096 	return (ret);
3097 }
3098 
3099 /*
3100  * Convert a string of the form '100G' into a real number. Used when setting
3101  * the size of a logical unit.
3102  * Code lifted from libzfs_util.c
3103  */
3104 static int
niceStrToNum(const char * value,uint64_t * num)3105 niceStrToNum(const char *value, uint64_t *num)
3106 {
3107 	char *end;
3108 	int shift;
3109 
3110 	*num = 0;
3111 
3112 	/* Check to see if this looks like a number.  */
3113 	if ((value[0] < '0' || value[0] > '9') && value[0] != '.') {
3114 		return (-1);
3115 	}
3116 
3117 	/* Rely on stroull() to process the numeric portion.  */
3118 	errno = 0;
3119 	*num = strtoull(value, &end, 10);
3120 
3121 	/*
3122 	 * Check for ERANGE, which indicates that the value is too large to fit
3123 	 * in a 64-bit value.
3124 	 */
3125 	if (errno == ERANGE) {
3126 		return (-1);
3127 	}
3128 
3129 	/*
3130 	 * If we have a decimal value, then do the computation with floating
3131 	 * point arithmetic.  Otherwise, use standard arithmetic.
3132 	 */
3133 	if (*end == '.') {
3134 		double fval = strtod(value, &end);
3135 
3136 		if ((shift = strToShift(end)) == -1) {
3137 			return (-1);
3138 		}
3139 
3140 		fval *= pow(2, shift);
3141 
3142 		if (fval > UINT64_MAX) {
3143 			return (-1);
3144 		}
3145 
3146 		*num = (uint64_t)fval;
3147 	} else {
3148 		if ((shift = strToShift(end)) == -1) {
3149 			return (-1);
3150 		}
3151 
3152 		/* Check for overflow */
3153 		if (shift >= 64 || (*num << shift) >> shift != *num) {
3154 			return (-1);
3155 		}
3156 
3157 		*num <<= shift;
3158 	}
3159 
3160 	return (0);
3161 }
3162 
3163 /*
3164  * stmfCreateTargetGroup
3165  *
3166  * Purpose: Create a local port group
3167  *
3168  * targetGroupName - name of local port group to create
3169  */
3170 int
stmfCreateTargetGroup(stmfGroupName * targetGroupName)3171 stmfCreateTargetGroup(stmfGroupName *targetGroupName)
3172 {
3173 	int ret;
3174 	int fd;
3175 
3176 	if (targetGroupName == NULL ||
3177 	    (strnlen((char *)targetGroupName, sizeof (stmfGroupName))
3178 	    == sizeof (stmfGroupName))) {
3179 		return (STMF_ERROR_INVALID_ARG);
3180 	}
3181 
3182 	/* Check to ensure service exists */
3183 	if (psCheckService() != STMF_STATUS_SUCCESS) {
3184 		return (STMF_ERROR_SERVICE_NOT_FOUND);
3185 	}
3186 
3187 	/* call init */
3188 	ret = initializeConfig();
3189 	if (ret != STMF_STATUS_SUCCESS) {
3190 		return (ret);
3191 	}
3192 
3193 	/*
3194 	 * Open control node for stmf
3195 	 */
3196 	if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
3197 		return (ret);
3198 
3199 	/*
3200 	 * Add the group to the driver
3201 	 */
3202 	if ((ret = groupIoctl(fd, STMF_IOCTL_CREATE_TARGET_GROUP,
3203 	    targetGroupName)) != STMF_STATUS_SUCCESS) {
3204 		goto done;
3205 	}
3206 
3207 	if (iGetPersistMethod() == STMF_PERSIST_NONE) {
3208 		goto done;
3209 	}
3210 
3211 	/*
3212 	 * If the add to the driver was successful, add it to the persistent
3213 	 * store.
3214 	 */
3215 	ret = psCreateTargetGroup((char *)targetGroupName);
3216 	switch (ret) {
3217 		case STMF_PS_SUCCESS:
3218 			ret = STMF_STATUS_SUCCESS;
3219 			break;
3220 		case STMF_PS_ERROR_EXISTS:
3221 			ret = STMF_ERROR_EXISTS;
3222 			break;
3223 		case STMF_PS_ERROR_BUSY:
3224 			ret = STMF_ERROR_BUSY;
3225 			break;
3226 		case STMF_PS_ERROR_SERVICE_NOT_FOUND:
3227 			ret = STMF_ERROR_SERVICE_NOT_FOUND;
3228 			break;
3229 		case STMF_PS_ERROR_VERSION_MISMATCH:
3230 			ret = STMF_ERROR_SERVICE_DATA_VERSION;
3231 			break;
3232 		default:
3233 			syslog(LOG_DEBUG,
3234 			    "stmfCreateTargetGroup:psCreateTargetGroup"
3235 			    ":error(%d)", ret);
3236 			ret = STMF_STATUS_ERROR;
3237 			break;
3238 	}
3239 
3240 done:
3241 	(void) close(fd);
3242 	return (ret);
3243 }
3244 
3245 /*
3246  * stmfDeleteHostGroup
3247  *
3248  * Purpose: Delete an initiator or local port group
3249  *
3250  * hostGroupName - group to delete
3251  */
3252 int
stmfDeleteHostGroup(stmfGroupName * hostGroupName)3253 stmfDeleteHostGroup(stmfGroupName *hostGroupName)
3254 {
3255 	int ret;
3256 	int fd;
3257 
3258 	if (hostGroupName == NULL) {
3259 		return (STMF_ERROR_INVALID_ARG);
3260 	}
3261 
3262 	/* Check to ensure service exists */
3263 	if (psCheckService() != STMF_STATUS_SUCCESS) {
3264 		return (STMF_ERROR_SERVICE_NOT_FOUND);
3265 	}
3266 
3267 	/* call init */
3268 	ret = initializeConfig();
3269 	if (ret != STMF_STATUS_SUCCESS) {
3270 		return (ret);
3271 	}
3272 
3273 	/*
3274 	 * Open control node for stmf
3275 	 */
3276 	if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
3277 		return (ret);
3278 
3279 	/*
3280 	 * Remove the group from the driver
3281 	 */
3282 	if ((ret = groupIoctl(fd, STMF_IOCTL_REMOVE_HOST_GROUP,
3283 	    hostGroupName)) != STMF_STATUS_SUCCESS) {
3284 		goto done;
3285 	}
3286 
3287 	if (iGetPersistMethod() == STMF_PERSIST_NONE) {
3288 		goto done;
3289 	}
3290 
3291 	/*
3292 	 * If the remove from the driver was successful, remove it from the
3293 	 * persistent store.
3294 	 */
3295 	ret = psDeleteHostGroup((char *)hostGroupName);
3296 	switch (ret) {
3297 		case STMF_PS_SUCCESS:
3298 			ret = STMF_STATUS_SUCCESS;
3299 			break;
3300 		case STMF_PS_ERROR_NOT_FOUND:
3301 			ret = STMF_ERROR_NOT_FOUND;
3302 			break;
3303 		case STMF_PS_ERROR_BUSY:
3304 			ret = STMF_ERROR_BUSY;
3305 			break;
3306 		case STMF_PS_ERROR_SERVICE_NOT_FOUND:
3307 			ret = STMF_ERROR_SERVICE_NOT_FOUND;
3308 			break;
3309 		case STMF_PS_ERROR_VERSION_MISMATCH:
3310 			ret = STMF_ERROR_SERVICE_DATA_VERSION;
3311 			break;
3312 		default:
3313 			syslog(LOG_DEBUG,
3314 			    "stmfDeleteHostGroup:psDeleteHostGroup:error(%d)",
3315 			    ret);
3316 			ret = STMF_STATUS_ERROR;
3317 			break;
3318 	}
3319 
3320 done:
3321 	(void) close(fd);
3322 	return (ret);
3323 }
3324 
3325 /*
3326  * stmfDeleteTargetGroup
3327  *
3328  * Purpose: Delete an initiator or local port group
3329  *
3330  * targetGroupName - group to delete
3331  */
3332 int
stmfDeleteTargetGroup(stmfGroupName * targetGroupName)3333 stmfDeleteTargetGroup(stmfGroupName *targetGroupName)
3334 {
3335 	int ret = STMF_STATUS_SUCCESS;
3336 	int fd;
3337 
3338 	if (targetGroupName == NULL) {
3339 		return (STMF_ERROR_INVALID_ARG);
3340 	}
3341 
3342 	/* Check to ensure service exists */
3343 	if (psCheckService() != STMF_STATUS_SUCCESS) {
3344 		return (STMF_ERROR_SERVICE_NOT_FOUND);
3345 	}
3346 
3347 	/* call init */
3348 	ret = initializeConfig();
3349 	if (ret != STMF_STATUS_SUCCESS) {
3350 		return (ret);
3351 	}
3352 
3353 	/*
3354 	 * Open control node for stmf
3355 	 */
3356 	if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
3357 		return (ret);
3358 
3359 	/*
3360 	 * Remove the group from the driver
3361 	 */
3362 	if ((ret = groupIoctl(fd, STMF_IOCTL_REMOVE_TARGET_GROUP,
3363 	    targetGroupName)) != STMF_STATUS_SUCCESS) {
3364 		goto done;
3365 	}
3366 
3367 	if (iGetPersistMethod() == STMF_PERSIST_NONE) {
3368 		goto done;
3369 	}
3370 
3371 	/*
3372 	 * If the remove from the driver was successful, remove it from the
3373 	 * persistent store.
3374 	 */
3375 	ret = psDeleteTargetGroup((char *)targetGroupName);
3376 	switch (ret) {
3377 		case STMF_PS_SUCCESS:
3378 			ret = STMF_STATUS_SUCCESS;
3379 			break;
3380 		case STMF_PS_ERROR_NOT_FOUND:
3381 			ret = STMF_ERROR_NOT_FOUND;
3382 			break;
3383 		case STMF_PS_ERROR_BUSY:
3384 			ret = STMF_ERROR_BUSY;
3385 			break;
3386 		case STMF_PS_ERROR_SERVICE_NOT_FOUND:
3387 			ret = STMF_ERROR_SERVICE_NOT_FOUND;
3388 			break;
3389 		case STMF_PS_ERROR_VERSION_MISMATCH:
3390 			ret = STMF_ERROR_SERVICE_DATA_VERSION;
3391 			break;
3392 		default:
3393 			syslog(LOG_DEBUG,
3394 			    "stmfDeleteTargetGroup:psDeleteTargetGroup"
3395 			    ":error(%d)", ret);
3396 			ret = STMF_STATUS_ERROR;
3397 			break;
3398 	}
3399 
3400 done:
3401 	(void) close(fd);
3402 	return (ret);
3403 }
3404 
3405 /*
3406  * stmfDevidFromIscsiName
3407  *
3408  * Purpose: convert an iSCSI name to an stmf devid
3409  *
3410  * iscsiName - unicode nul terminated utf-8 encoded iSCSI name
3411  * devid - on success, contains the converted iscsi name
3412  */
3413 int
stmfDevidFromIscsiName(char * iscsiName,stmfDevid * devid)3414 stmfDevidFromIscsiName(char *iscsiName, stmfDevid *devid)
3415 {
3416 	if (devid == NULL || iscsiName == NULL)
3417 		return (STMF_ERROR_INVALID_ARG);
3418 
3419 	bzero(devid, sizeof (stmfDevid));
3420 
3421 	/* Validate size of target */
3422 	if ((devid->identLength = strlen(iscsiName)) > MAX_ISCSI_NAME ||
3423 	    devid->identLength < strlen(EUI) ||
3424 	    devid->identLength < strlen(IQN)) {
3425 		return (STMF_ERROR_INVALID_ARG);
3426 	}
3427 
3428 	if ((strncmp(iscsiName, EUI, strlen(EUI)) != 0) &&
3429 	    strncmp(iscsiName, IQN, strlen(IQN)) != 0) {
3430 		return (STMF_ERROR_INVALID_ARG);
3431 	}
3432 
3433 	/* copy UTF-8 bytes to ident */
3434 	bcopy(iscsiName, devid->ident, devid->identLength);
3435 
3436 	return (STMF_STATUS_SUCCESS);
3437 }
3438 
3439 /*
3440  * stmfDevidFromWwn
3441  *
3442  * Purpose: convert a WWN to an stmf devid
3443  *
3444  * wwn - 8-byte wwn identifier
3445  * devid - on success, contains the converted wwn
3446  */
3447 int
stmfDevidFromWwn(uchar_t * wwn,stmfDevid * devid)3448 stmfDevidFromWwn(uchar_t *wwn, stmfDevid *devid)
3449 {
3450 	if (wwn == NULL || devid == NULL)
3451 		return (STMF_ERROR_INVALID_ARG);
3452 
3453 	bzero(devid, sizeof (stmfDevid));
3454 
3455 	/* Copy eui prefix */
3456 	(void) bcopy(WWN, devid->ident, strlen(WWN));
3457 
3458 	/* Convert to ASCII uppercase hexadecimal string */
3459 	(void) snprintf((char *)&devid->ident[strlen(WWN)],
3460 	    sizeof (devid->ident), "%02X%02X%02X%02X%02X%02X%02X%02X",
3461 	    wwn[0], wwn[1], wwn[2], wwn[3], wwn[4], wwn[5], wwn[6], wwn[7]);
3462 
3463 	devid->identLength = strlen((char *)devid->ident);
3464 
3465 	return (STMF_STATUS_SUCCESS);
3466 }
3467 
3468 /*
3469  * stmfFreeMemory
3470  *
3471  * Purpose: Free memory allocated by this library
3472  *
3473  * memory - previously allocated pointer of memory managed by library
3474  */
3475 void
stmfFreeMemory(void * memory)3476 stmfFreeMemory(void *memory)
3477 {
3478 	free(memory);
3479 }
3480 
3481 /*
3482  * get host group, target group list from stmf
3483  *
3484  * groupType - HOST_GROUP, TARGET_GROUP
3485  */
3486 static int
groupListIoctl(stmfGroupList ** groupList,int groupType)3487 groupListIoctl(stmfGroupList **groupList, int groupType)
3488 {
3489 	int ret;
3490 	int fd;
3491 	int ioctlRet;
3492 	int i;
3493 	int cmd;
3494 	stmf_iocdata_t stmfIoctl;
3495 	/* framework group list */
3496 	stmf_group_name_t *iGroupList = NULL;
3497 	uint32_t groupListSize;
3498 
3499 	if (groupList == NULL) {
3500 		return (STMF_ERROR_INVALID_ARG);
3501 	}
3502 
3503 	if (groupType == HOST_GROUP) {
3504 		cmd = STMF_IOCTL_GET_HG_LIST;
3505 	} else if (groupType == TARGET_GROUP) {
3506 		cmd = STMF_IOCTL_GET_TG_LIST;
3507 	} else {
3508 		return (STMF_ERROR_INVALID_ARG);
3509 	}
3510 
3511 	/* call init */
3512 	ret = initializeConfig();
3513 	if (ret != STMF_STATUS_SUCCESS) {
3514 		return (ret);
3515 	}
3516 
3517 	/*
3518 	 * Open control node for stmf
3519 	 */
3520 	if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
3521 		return (ret);
3522 
3523 	/*
3524 	 * Allocate ioctl input buffer
3525 	 */
3526 	groupListSize = ALLOC_GROUP;
3527 	groupListSize = groupListSize * (sizeof (stmf_group_name_t));
3528 	iGroupList = (stmf_group_name_t *)calloc(1, groupListSize);
3529 	if (iGroupList == NULL) {
3530 		ret = STMF_ERROR_NOMEM;
3531 		goto done;
3532 	}
3533 
3534 	bzero(&stmfIoctl, sizeof (stmfIoctl));
3535 	/*
3536 	 * Issue ioctl to get the group list
3537 	 */
3538 	stmfIoctl.stmf_version = STMF_VERSION_1;
3539 	stmfIoctl.stmf_obuf_size = groupListSize;
3540 	stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)iGroupList;
3541 	ioctlRet = ioctl(fd, cmd, &stmfIoctl);
3542 	if (ioctlRet != 0) {
3543 		switch (errno) {
3544 			case EBUSY:
3545 				ret = STMF_ERROR_BUSY;
3546 				break;
3547 			case EPERM:
3548 			case EACCES:
3549 				ret = STMF_ERROR_PERM;
3550 				break;
3551 			default:
3552 				syslog(LOG_DEBUG,
3553 				    "groupListIoctl:ioctl errno(%d)",
3554 				    errno);
3555 				ret = STMF_STATUS_ERROR;
3556 				break;
3557 		}
3558 		goto done;
3559 	}
3560 	/*
3561 	 * Check whether input buffer was large enough
3562 	 */
3563 	if (stmfIoctl.stmf_obuf_max_nentries > ALLOC_GROUP) {
3564 		groupListSize = stmfIoctl.stmf_obuf_max_nentries *
3565 		    sizeof (stmf_group_name_t);
3566 		iGroupList = realloc(iGroupList, groupListSize);
3567 		if (iGroupList == NULL) {
3568 			ret = STMF_ERROR_NOMEM;
3569 			goto done;
3570 		}
3571 		stmfIoctl.stmf_obuf_size = groupListSize;
3572 		stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)iGroupList;
3573 		ioctlRet = ioctl(fd, cmd, &stmfIoctl);
3574 		if (ioctlRet != 0) {
3575 			switch (errno) {
3576 				case EBUSY:
3577 					ret = STMF_ERROR_BUSY;
3578 					break;
3579 				case EPERM:
3580 				case EACCES:
3581 					ret = STMF_ERROR_PERM;
3582 					break;
3583 				default:
3584 					syslog(LOG_DEBUG,
3585 					    "groupListIoctl:ioctl errno(%d)",
3586 					    errno);
3587 					ret = STMF_STATUS_ERROR;
3588 					break;
3589 			}
3590 			goto done;
3591 		}
3592 	}
3593 
3594 	/* allocate and copy to caller's buffer */
3595 	*groupList = (stmfGroupList *)calloc(1, sizeof (stmfGroupList) +
3596 	    sizeof (stmfGroupName) * stmfIoctl.stmf_obuf_nentries);
3597 	if (*groupList == NULL) {
3598 		ret = STMF_ERROR_NOMEM;
3599 		goto done;
3600 	}
3601 	(*groupList)->cnt = stmfIoctl.stmf_obuf_nentries;
3602 	for (i = 0; i < stmfIoctl.stmf_obuf_nentries; i++) {
3603 		bcopy(iGroupList[i].name, (*groupList)->name[i],
3604 		    sizeof (stmfGroupName));
3605 	}
3606 
3607 done:
3608 	free(iGroupList);
3609 	(void) close(fd);
3610 	return (ret);
3611 }
3612 
3613 /*
3614  * get host group members, target group members from stmf
3615  *
3616  * groupProps - allocated on success
3617  *
3618  * groupType - HOST_GROUP, TARGET_GROUP
3619  */
3620 static int
groupMemberListIoctl(stmfGroupName * groupName,stmfGroupProperties ** groupProps,int groupType)3621 groupMemberListIoctl(stmfGroupName *groupName, stmfGroupProperties **groupProps,
3622     int groupType)
3623 {
3624 	int ret;
3625 	int fd;
3626 	int ioctlRet;
3627 	int i;
3628 	int cmd;
3629 	stmf_iocdata_t stmfIoctl;
3630 	/* framework group list */
3631 	stmf_group_name_t iGroupName;
3632 	stmf_ge_ident_t *iGroupMembers;
3633 	uint32_t groupListSize;
3634 
3635 	if (groupName == NULL) {
3636 		return (STMF_ERROR_INVALID_ARG);
3637 	}
3638 
3639 	if (groupType == HOST_GROUP) {
3640 		cmd = STMF_IOCTL_GET_HG_ENTRIES;
3641 	} else if (groupType == TARGET_GROUP) {
3642 		cmd = STMF_IOCTL_GET_TG_ENTRIES;
3643 	} else {
3644 		return (STMF_ERROR_INVALID_ARG);
3645 	}
3646 
3647 	/* call init */
3648 	ret = initializeConfig();
3649 	if (ret != STMF_STATUS_SUCCESS) {
3650 		return (ret);
3651 	}
3652 
3653 	/*
3654 	 * Open control node for stmf
3655 	 */
3656 	if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
3657 		return (ret);
3658 
3659 	bzero(&iGroupName, sizeof (iGroupName));
3660 
3661 	bcopy(groupName, &iGroupName.name, strlen((char *)groupName));
3662 
3663 	iGroupName.name_size = strlen((char *)groupName);
3664 
3665 	/*
3666 	 * Allocate ioctl input buffer
3667 	 */
3668 	groupListSize = ALLOC_GRP_MEMBER;
3669 	groupListSize = groupListSize * (sizeof (stmf_ge_ident_t));
3670 	iGroupMembers = (stmf_ge_ident_t *)calloc(1, groupListSize);
3671 	if (iGroupMembers == NULL) {
3672 		ret = STMF_ERROR_NOMEM;
3673 		goto done;
3674 	}
3675 
3676 	bzero(&stmfIoctl, sizeof (stmfIoctl));
3677 	/*
3678 	 * Issue ioctl to get the group list
3679 	 */
3680 	stmfIoctl.stmf_version = STMF_VERSION_1;
3681 	stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&iGroupName;
3682 	stmfIoctl.stmf_ibuf_size = sizeof (stmf_group_name_t);
3683 	stmfIoctl.stmf_obuf_size = groupListSize;
3684 	stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)iGroupMembers;
3685 	ioctlRet = ioctl(fd, cmd, &stmfIoctl);
3686 	if (ioctlRet != 0) {
3687 		switch (errno) {
3688 			case EBUSY:
3689 				ret = STMF_ERROR_BUSY;
3690 				break;
3691 			case EPERM:
3692 			case EACCES:
3693 				ret = STMF_ERROR_PERM;
3694 				break;
3695 			default:
3696 				syslog(LOG_DEBUG,
3697 				    "groupListIoctl:ioctl errno(%d)",
3698 				    errno);
3699 				ret = STMF_STATUS_ERROR;
3700 				break;
3701 		}
3702 		goto done;
3703 	}
3704 	/*
3705 	 * Check whether input buffer was large enough
3706 	 */
3707 	if (stmfIoctl.stmf_obuf_max_nentries > ALLOC_GRP_MEMBER) {
3708 		groupListSize = stmfIoctl.stmf_obuf_max_nentries *
3709 		    sizeof (stmf_ge_ident_t);
3710 		iGroupMembers = realloc(iGroupMembers, groupListSize);
3711 		if (iGroupMembers == NULL) {
3712 			ret = STMF_ERROR_NOMEM;
3713 			goto done;
3714 		}
3715 		stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&iGroupName;
3716 		stmfIoctl.stmf_ibuf_size = sizeof (stmf_group_name_t);
3717 		stmfIoctl.stmf_obuf_size = groupListSize;
3718 		stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)iGroupMembers;
3719 		ioctlRet = ioctl(fd, cmd, &stmfIoctl);
3720 		if (ioctlRet != 0) {
3721 			switch (errno) {
3722 				case EBUSY:
3723 					ret = STMF_ERROR_BUSY;
3724 					break;
3725 				case EPERM:
3726 				case EACCES:
3727 					ret = STMF_ERROR_PERM;
3728 					break;
3729 				default:
3730 					syslog(LOG_DEBUG,
3731 					    "groupListIoctl:ioctl errno(%d)",
3732 					    errno);
3733 					ret = STMF_STATUS_ERROR;
3734 					break;
3735 			}
3736 			goto done;
3737 		}
3738 	}
3739 
3740 	/* allocate and copy to caller's buffer */
3741 	*groupProps = (stmfGroupProperties *)calloc(1,
3742 	    sizeof (stmfGroupProperties) +
3743 	    sizeof (stmfDevid) * stmfIoctl.stmf_obuf_nentries);
3744 	if (*groupProps == NULL) {
3745 		ret = STMF_ERROR_NOMEM;
3746 		goto done;
3747 	}
3748 	(*groupProps)->cnt = stmfIoctl.stmf_obuf_nentries;
3749 	for (i = 0; i < stmfIoctl.stmf_obuf_nentries; i++) {
3750 		(*groupProps)->name[i].identLength =
3751 		    iGroupMembers[i].ident_size;