xref: /illumos-gate/usr/src/cmd/stmfadm/stmfadm.c (revision 1ed6b69a5ca1ca3ee5e9a4931f74e2237c7e1c9f)
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 2010 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  * Copyright 2012 Milan Jurik. All rights reserved.
25  */
26 
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <strings.h>
30 #include <sys/types.h>
31 #include <unistd.h>
32 #include <wchar.h>
33 #include <libintl.h>
34 #include <errno.h>
35 #include <time.h>
36 #include <string.h>
37 #include <assert.h>
38 #include <getopt.h>
39 #include <cmdparse.h>
40 #include <stmfadm.h>
41 #include <libstmf.h>
42 #include <signal.h>
43 #include <pthread.h>
44 #include <locale.h>
45 
46 static int addHostGroupMemberFunc(int, char **, cmdOptions_t *, void *);
47 static int addTargetGroupMemberFunc(int, char **, cmdOptions_t *, void *);
48 static int addViewFunc(int, char **, cmdOptions_t *, void *);
49 static int createHostGroupFunc(int, char **, cmdOptions_t *, void *);
50 static int createLuFunc(int, char **, cmdOptions_t *, void *);
51 static int modifyLuFunc(int, char **, cmdOptions_t *, void *);
52 static int importLuFunc(int, char **, cmdOptions_t *, void *);
53 static int deleteLuFunc(int, char **, cmdOptions_t *, void *);
54 static int createTargetGroupFunc(int, char **, cmdOptions_t *, void *);
55 static int deleteHostGroupFunc(int, char **, cmdOptions_t *, void *);
56 static int deleteTargetGroupFunc(int, char **, cmdOptions_t *, void *);
57 static int listLuFunc(int, char **, cmdOptions_t *, void *);
58 static int listTargetFunc(int, char **, cmdOptions_t *, void *);
59 static int listViewFunc(int, char **, cmdOptions_t *, void *);
60 static int listHostGroupFunc(int, char **, cmdOptions_t *, void *);
61 static int listStateFunc(int, char **, cmdOptions_t *, void *);
62 static int listTargetGroupFunc(int, char **, cmdOptions_t *, void *);
63 static int offlineTargetFunc(int, char **, cmdOptions_t *, void *);
64 static int offlineLuFunc(int, char **, cmdOptions_t *, void *);
65 static int onlineTargetFunc(int, char **, cmdOptions_t *, void *);
66 static int onlineLuFunc(int, char **, cmdOptions_t *, void *);
67 static int onlineOfflineTarget(char *, int);
68 static int onlineOfflineLu(char *, int);
69 static int removeHostGroupMemberFunc(int, char **, cmdOptions_t *, void *);
70 static int removeTargetGroupMemberFunc(int, char **, cmdOptions_t *, void *);
71 static int callModify(char *, stmfGuid *, uint32_t, const char *, const char *);
72 static int removeViewFunc(int, char **, cmdOptions_t *, void *);
73 static char *getExecBasename(char *);
74 static int parseDevid(char *input, stmfDevid *devid);
75 static void printGroupProps(stmfGroupProperties *groupProps);
76 static int checkScsiNameString(wchar_t *, stmfDevid *);
77 static int checkHexUpper(char *);
78 static int checkIscsiName(wchar_t *);
79 static void printLuProps(stmfLogicalUnitProperties *luProps);
80 static int printExtLuProps(stmfGuid *guid);
81 static void printGuid(stmfGuid *guid, FILE *printWhere);
82 static void printTargetProps(stmfTargetProperties *);
83 static void printSessionProps(stmfSessionList *);
84 static int setLuPropFromInput(luResource, char *);
85 static int convertCharToPropId(char *, uint32_t *);
86 
87 
88 
89 /*
90  *  MAJOR - This should only change when there is an incompatible change made
91  *  to the interfaces or the output.
92  *
93  *  MINOR - This should change whenever there is a new command or new feature
94  *  with no incompatible change.
95  */
96 #define	VERSION_STRING_MAJOR	    "1"
97 #define	VERSION_STRING_MINOR	    "0"
98 #define	MAX_DEVID_INPUT		    256
99 #define	GUID_INPUT		    32
100 #define	MAX_LU_NBR		    16383
101 #define	ONLINE_LU		    0
102 #define	OFFLINE_LU		    1
103 #define	ONLINE_TARGET		    2
104 #define	OFFLINE_TARGET		    3
105 #define	PROPS_FORMAT		    "    %-18s: "
106 #define	VIEW_FORMAT		    "    %-13s: "
107 #define	LVL3_FORMAT		    "        %s"
108 #define	LVL4_FORMAT		    "            %s"
109 #define	DELAYED_EXEC_WAIT_INTERVAL  300 * 1000 * 1000	/* in nano sec */
110 #define	DELAYED_EXEC_WAIT_MAX	    30	/* Maximum number of interval times */
111 
112 /* SCSI Name String length definitions */
113 #define	SNS_EUI_16		    16
114 #define	SNS_EUI_24		    24
115 #define	SNS_EUI_32		    32
116 #define	SNS_NAA_16		    16
117 #define	SNS_NAA_32		    32
118 #define	SNS_WWN_16		    16
119 #define	SNS_IQN_223		    223
120 
121 /* LU Property strings */
122 #define	GUID			    "GUID"
123 #define	ALIAS			    "ALIAS"
124 #define	VID			    "VID"
125 #define	PID			    "PID"
126 #define	META_FILE		    "META"
127 #define	WRITE_PROTECT		    "WP"
128 #define	WRITEBACK_CACHE_DISABLE	    "WCD"
129 #define	COMPANY_ID		    "OUI"
130 #define	BLOCK_SIZE		    "BLK"
131 #define	SERIAL_NUMBER		    "SERIAL"
132 #define	MGMT_URL		    "MGMT-URL"
133 #define	HOST_ID			    "HOST-ID"
134 
135 #define	STMFADM_SUCCESS		    0
136 #define	STMFADM_FAILURE		    1
137 
138 #define	MODIFY_HELP "\n"\
139 "Description: Modify properties of a logical unit. \n" \
140 "Valid properties for -p, --lu-prop are: \n" \
141 "     alias    - alias for logical unit (up to 255 chars)\n" \
142 "     mgmt-url - Management URL address\n" \
143 "     wcd      - write cache disabled (true, false)\n" \
144 "     wp       - write protect (true, false)\n\n" \
145 "-f alters the meaning of the operand to be a file name\n" \
146 "rather than a LU name. This allows for modification\n" \
147 "of a logical unit that is not yet imported into stmf\n"
148 
149 #define	CREATE_HELP "\n"\
150 "Description: Create a logical unit. \n" \
151 "Valid properties for -p, --lu-prop are: \n" \
152 "     alias    - alias for logical unit (up to 255 chars)\n" \
153 "     blk      - block size in bytes in 2^n\n" \
154 "     guid     - 32 ascii hex characters in NAA format \n" \
155 "     host-id  - host identifier to be used for GUID generation \n" \
156 "                8 ascii hex characters\n" \
157 "     meta     - separate meta data file name\n" \
158 "     mgmt-url - Management URL address\n" \
159 "     oui      - organizational unique identifier\n" \
160 "                6 ascii hex characters of valid format\n" \
161 "     pid      - product identifier (up to 16 chars)\n" \
162 "     serial   - serial number (up to 252 chars)\n" \
163 "     vid      - vendor identifier (up to 8 chars)\n" \
164 "     wcd      - write cache disabled (true, false)\n" \
165 "     wp       - write protect (true, false)\n"
166 #define	ADD_VIEW_HELP "\n"\
167 "Description: Add a view entry to a logical unit. \n" \
168 "A view entry is comprised of three elements; the \n" \
169 "logical unit number, the target group name and the\n" \
170 "host group name. These three elements combine together\n" \
171 "to form a view for a given COMSTAR logical unit.\n" \
172 "This view is realized by a client, a SCSI initiator,\n" \
173 "via a REPORT LUNS command. \n"
174 
175 
176 
177 /* tables set up based on cmdparse instructions */
178 
179 /* add new options here */
180 optionTbl_t longOptions[] = {
181 	{"all", no_arg, 'a', NULL},
182 	{"group-name", required_arg, 'g', "group-name"},
183 	{"keep-views", no_arg, 'k', NULL},
184 	{"lu-name", required_arg, 'l', "LU-Name"},
185 	{"lun", required_arg, 'n', "logical-unit-number"},
186 	{"lu-prop", required_arg, 'p', "logical-unit-property=value"},
187 	{"file", no_arg, 'f', "filename"},
188 	{"size", required_arg, 's', "size K/M/G/T/P"},
189 	{"target-group", required_arg, 't', "group-name"},
190 	{"host-group", required_arg, 'h', "group-name"},
191 	{"verbose", no_arg, 'v', NULL},
192 	{NULL, 0, 0, 0}
193 };
194 
195 /*
196  * Add new subcommands here
197  */
198 subCommandProps_t subcommands[] = {
199 	{"add-hg-member", addHostGroupMemberFunc, "g", "g", NULL,
200 		OPERAND_MANDATORY_MULTIPLE, OPERANDSTRING_GROUP_MEMBER, NULL},
201 	{"add-tg-member", addTargetGroupMemberFunc, "g", "g", NULL,
202 		OPERAND_MANDATORY_MULTIPLE, OPERANDSTRING_GROUP_MEMBER, NULL},
203 	{"add-view", addViewFunc, "nth", NULL, NULL,
204 		OPERAND_MANDATORY_SINGLE, OPERANDSTRING_LU, ADD_VIEW_HELP},
205 	{"create-hg", createHostGroupFunc, NULL, NULL, NULL,
206 		OPERAND_MANDATORY_SINGLE, OPERANDSTRING_GROUP_NAME, NULL},
207 	{"create-tg", createTargetGroupFunc, NULL, NULL, NULL,
208 		OPERAND_MANDATORY_SINGLE, OPERANDSTRING_GROUP_NAME, NULL},
209 	{"create-lu", createLuFunc, "ps", NULL, NULL, OPERAND_MANDATORY_SINGLE,
210 		"lu file", CREATE_HELP},
211 	{"delete-hg", deleteHostGroupFunc, NULL, NULL, NULL,
212 		OPERAND_MANDATORY_SINGLE, OPERANDSTRING_GROUP_NAME, NULL},
213 	{"modify-lu", modifyLuFunc, "psf", NULL, NULL, OPERAND_MANDATORY_SINGLE,
214 		OPERANDSTRING_LU, MODIFY_HELP},
215 	{"delete-lu", deleteLuFunc, "k", NULL, NULL,
216 		OPERAND_MANDATORY_MULTIPLE, OPERANDSTRING_LU, NULL},
217 	{"delete-tg", deleteTargetGroupFunc, NULL, NULL, NULL,
218 		OPERAND_MANDATORY_SINGLE, OPERANDSTRING_GROUP_NAME, NULL},
219 	{"import-lu", importLuFunc, NULL, NULL, NULL,
220 		OPERAND_MANDATORY_SINGLE, "file name", NULL},
221 	{"list-hg", listHostGroupFunc, "v", NULL, NULL,
222 		OPERAND_OPTIONAL_MULTIPLE, OPERANDSTRING_GROUP_NAME, NULL},
223 	{"list-lu", listLuFunc, "v", NULL, NULL, OPERAND_OPTIONAL_MULTIPLE,
224 		OPERANDSTRING_LU, NULL},
225 	{"list-state", listStateFunc, NULL, NULL, NULL, OPERAND_NONE, NULL},
226 	{"list-target", listTargetFunc, "v", NULL, NULL,
227 		OPERAND_OPTIONAL_MULTIPLE, OPERANDSTRING_TARGET, NULL},
228 	{"list-tg", listTargetGroupFunc, "v", NULL, NULL,
229 		OPERAND_OPTIONAL_MULTIPLE, OPERANDSTRING_GROUP_NAME, NULL},
230 	{"list-view", listViewFunc, "l", "l", NULL,
231 		OPERAND_OPTIONAL_MULTIPLE, OPERANDSTRING_VIEW_ENTRY, NULL},
232 	{"online-lu", onlineLuFunc, NULL, NULL, NULL,
233 		OPERAND_MANDATORY_SINGLE, OPERANDSTRING_LU, NULL},
234 	{"offline-lu", offlineLuFunc, NULL, NULL, NULL,
235 		OPERAND_MANDATORY_SINGLE, OPERANDSTRING_LU, NULL},
236 	{"online-target", onlineTargetFunc, NULL, NULL, NULL,
237 		OPERAND_MANDATORY_SINGLE, OPERANDSTRING_TARGET, NULL},
238 	{"offline-target", offlineTargetFunc, NULL, NULL, NULL,
239 		OPERAND_MANDATORY_SINGLE, OPERANDSTRING_TARGET, NULL},
240 	{"remove-hg-member", removeHostGroupMemberFunc, "g", "g", NULL,
241 		OPERAND_MANDATORY_MULTIPLE, OPERANDSTRING_GROUP_MEMBER, NULL},
242 	{"remove-tg-member", removeTargetGroupMemberFunc, "g", "g", NULL,
243 		OPERAND_MANDATORY_MULTIPLE, OPERANDSTRING_GROUP_MEMBER, NULL},
244 	{"remove-view", removeViewFunc, "la", "l", NULL,
245 		OPERAND_OPTIONAL_MULTIPLE, OPERANDSTRING_VIEW_ENTRY, NULL},
246 	{NULL, 0, NULL, NULL, 0, NULL, 0, NULL, NULL}
247 };
248 
249 /* globals */
250 char *cmdName;
251 
252 /*
253  * addHostGroupMemberFunc
254  *
255  * Add members to a host group
256  *
257  */
258 /*ARGSUSED*/
259 static int
260 addHostGroupMemberFunc(int operandLen, char *operands[], cmdOptions_t *options,
261     void *args)
262 {
263 	int i;
264 	int ret = 0;
265 	int stmfRet;
266 	stmfGroupName groupName = {0};
267 	wchar_t groupNamePrint[sizeof (stmfGroupName)] = {0};
268 	stmfDevid devid;
269 
270 	for (; options->optval; options++) {
271 		switch (options->optval) {
272 			/* host group name */
273 			case 'g':
274 				(void) mbstowcs(groupNamePrint, options->optarg,
275 				    sizeof (stmfGroupName) - 1);
276 				bcopy(options->optarg, groupName,
277 				    strlen(options->optarg));
278 				break;
279 			default:
280 				(void) fprintf(stderr, "%s: %c: %s\n",
281 				    cmdName, options->optval,
282 				    gettext("unknown option"));
283 				return (1);
284 		}
285 	}
286 
287 	for (i = 0; i < operandLen; i++) {
288 		if (parseDevid(operands[i], &devid) != 0) {
289 			(void) fprintf(stderr, "%s: %s: %s\n",
290 			    cmdName, operands[i],
291 			    gettext("unrecognized device id"));
292 			ret++;
293 			continue;
294 		}
295 		stmfRet = stmfAddToHostGroup(&groupName, &devid);
296 		switch (stmfRet) {
297 			case STMF_STATUS_SUCCESS:
298 				break;
299 			case STMF_ERROR_EXISTS:
300 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
301 				    operands[i], gettext("already exists"));
302 				ret++;
303 				break;
304 			case STMF_ERROR_GROUP_NOT_FOUND:
305 				(void) fprintf(stderr, "%s: %ws: %s\n", cmdName,
306 				    groupNamePrint, gettext("not found"));
307 				ret++;
308 				break;
309 			case STMF_ERROR_PERM:
310 				(void) fprintf(stderr, "%s: %s\n", cmdName,
311 				    gettext("permission denied"));
312 				ret++;
313 				break;
314 			case STMF_ERROR_BUSY:
315 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
316 				    operands[i], gettext("resource busy"));
317 				ret++;
318 				break;
319 			case STMF_ERROR_SERVICE_NOT_FOUND:
320 				(void) fprintf(stderr, "%s: %s\n", cmdName,
321 				    gettext("STMF service not found"));
322 				ret++;
323 				break;
324 			case STMF_ERROR_SERVICE_DATA_VERSION:
325 				(void) fprintf(stderr, "%s: %s\n", cmdName,
326 				    gettext("STMF service version incorrect"));
327 				ret++;
328 				break;
329 			default:
330 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
331 				    operands[i], gettext("unknown error"));
332 				ret++;
333 				break;
334 		}
335 	}
336 
337 	return (ret);
338 }
339 
340 /*
341  * addTargetGroupMemberFunc
342  *
343  * Add members to a target group
344  *
345  */
346 /*ARGSUSED*/
347 static int
348 addTargetGroupMemberFunc(int operandLen, char *operands[],
349     cmdOptions_t *options, void *args)
350 {
351 	int i;
352 	int ret = 0;
353 	int stmfRet;
354 	stmfGroupName groupName = {0};
355 	wchar_t groupNamePrint[sizeof (stmfGroupName)] = {0};
356 	stmfDevid devid;
357 
358 	for (; options->optval; options++) {
359 		switch (options->optval) {
360 			/* target group name */
361 			case 'g':
362 				(void) mbstowcs(groupNamePrint, options->optarg,
363 				    sizeof (stmfGroupName) - 1);
364 				bcopy(options->optarg, groupName,
365 				    strlen(options->optarg));
366 				break;
367 			default:
368 				(void) fprintf(stderr, "%s: %c: %s\n",
369 				    cmdName, options->optval,
370 				    gettext("unknown option"));
371 				return (1);
372 		}
373 	}
374 
375 	for (i = 0; i < operandLen; i++) {
376 		if (parseDevid(operands[i], &devid) != 0) {
377 			(void) fprintf(stderr, "%s: %s: %s\n",
378 			    cmdName, operands[i],
379 			    gettext("unrecognized device id"));
380 			ret++;
381 			continue;
382 		}
383 		stmfRet = stmfAddToTargetGroup(&groupName, &devid);
384 		switch (stmfRet) {
385 			case STMF_STATUS_SUCCESS:
386 				break;
387 			case STMF_ERROR_EXISTS:
388 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
389 				    operands[i], gettext("already exists"));
390 				ret++;
391 				break;
392 			case STMF_ERROR_GROUP_NOT_FOUND:
393 				(void) fprintf(stderr, "%s: %ws: %s\n", cmdName,
394 				    groupNamePrint, gettext("not found"));
395 				ret++;
396 				break;
397 			case STMF_ERROR_PERM:
398 				(void) fprintf(stderr, "%s: %s\n", cmdName,
399 				    gettext("permission denied"));
400 				ret++;
401 				break;
402 			case STMF_ERROR_BUSY:
403 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
404 				    operands[i], gettext("resource busy"));
405 				ret++;
406 				break;
407 			case STMF_ERROR_SERVICE_NOT_FOUND:
408 				(void) fprintf(stderr, "%s: %s\n", cmdName,
409 				    gettext("STMF service not found"));
410 				ret++;
411 				break;
412 			case STMF_ERROR_SERVICE_ONLINE:
413 				(void) fprintf(stderr, "%s: %s\n", cmdName,
414 				    gettext("STMF service must be offline"));
415 				ret++;
416 				break;
417 			case STMF_ERROR_SERVICE_DATA_VERSION:
418 				(void) fprintf(stderr, "%s: %s\n", cmdName,
419 				    gettext("STMF service version incorrect"));
420 				ret++;
421 				break;
422 			case STMF_ERROR_TG_ONLINE:
423 				(void) fprintf(stderr, "%s: %s\n", cmdName,
424 				    gettext("STMF target must be offline"));
425 				ret++;
426 				break;
427 			default:
428 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
429 				    operands[i], gettext("unknown error"));
430 				ret++;
431 				break;
432 		}
433 	}
434 
435 	return (ret);
436 }
437 
438 /*
439  * parseDevid
440  *
441  * Converts char * input to a stmfDevid
442  *
443  * input - this should be in the following format with either a
444  * wwn. iqn. or eui. representation.
445  * A name string of the format:
446  *	wwn.<WWN> (FC/SAS address)
447  *	iqn.<iSCSI name> (iSCSI iqn)
448  *	eui.<WWN> (iSCSI eui name)
449  *
450  * devid - pointer to stmfDevid structure allocated by the caller.
451  *
452  * Returns:
453  *  0 on success
454  *  non-zero on failure
455  */
456 static int
457 parseDevid(char *input, stmfDevid *devid)
458 {
459 	wchar_t inputWc[MAX_DEVID_INPUT + 1] = {0};
460 
461 	/* convert to wcs */
462 	(void) mbstowcs(inputWc, input, MAX_DEVID_INPUT);
463 
464 	/*
465 	 * Check for known scsi name string formats
466 	 * If one is found, we're done
467 	 * If not, then it's a failure to parse
468 	 */
469 	if (checkScsiNameString(inputWc, devid) == 0) {
470 		return (0);
471 	}
472 
473 	return (-1);
474 }
475 
476 /*
477  * checkScsiNameString
478  *
479  * Validates known SCSI name string formats and converts to stmfDevid
480  * format
481  *
482  * input - input SCSI name string
483  * devid - pointer to stmfDevid structure allocated by the caller
484  *         on successful return, contains the devid based on input
485  *
486  * returns:
487  *         0 on success
488  *         -1 on failure
489  */
490 static int
491 checkScsiNameString(wchar_t *input, stmfDevid *devid)
492 {
493 	char *mbString = NULL;
494 	int mbStringLen;
495 	int len;
496 	int i;
497 
498 	/*
499 	 * Convert to multi-byte string
500 	 *
501 	 * This is used for either eui or naa formats
502 	 */
503 	mbString = calloc(1, (mbStringLen = wcstombs(mbString, input, 0)) + 1);
504 	if (mbString == NULL) {
505 		(void) fprintf(stderr, "%s: %s\n",
506 		    cmdName, "Insufficient memory\n");
507 		return (-1);
508 	}
509 	if (wcstombs(mbString, input, mbStringLen) == (size_t)-1) {
510 		return (-1);
511 	}
512 
513 	/*
514 	 * check for iqn format
515 	 */
516 	if (strncmp(mbString, "iqn.", 4) == 0) {
517 		if ((len = strlen(mbString)) > (SNS_IQN_223)) {
518 			return (-1);
519 		}
520 		for (i = 0; i < len; i++) {
521 			mbString[i] = tolower(mbString[i]);
522 		}
523 		if (checkIscsiName(input + 4) != 0) {
524 			return (-1);
525 		}
526 	} else if (strncmp(mbString, "wwn.", 4) == 0) {
527 		if ((len = strlen(mbString + 4)) != SNS_WWN_16) {
528 			return (-1);
529 		} else if (checkHexUpper(mbString + 4) != 0) {
530 			return (-1);
531 		}
532 	} else if (strncmp(mbString, "eui.", 4) == 0) {
533 		if ((len = strlen(mbString + 4)) != SNS_EUI_16) {
534 			return (-1);
535 		} else if (checkHexUpper(mbString + 4) != 0) {
536 			return (-1);
537 		}
538 	} else {
539 		return (-1);
540 	}
541 
542 	/*
543 	 * We have a validated name string.
544 	 * Go ahead and set the length and copy it.
545 	 */
546 	devid->identLength = strlen(mbString);
547 	bzero(devid->ident, STMF_IDENT_LENGTH);
548 	bcopy(mbString, devid->ident, devid->identLength);
549 
550 	return (0);
551 }
552 
553 
554 /*
555  * Checks whether the entire string is in hex and converts to upper
556  */
557 static int
558 checkHexUpper(char *input)
559 {
560 	int i;
561 
562 	for (i = 0; i < strlen(input); i++) {
563 		if (isxdigit(input[i])) {
564 			input[i] = toupper(input[i]);
565 			continue;
566 		}
567 		return (-1);
568 	}
569 
570 	return (0);
571 }
572 
573 /*
574  * checkIscsiName
575  *
576  * Purpose: Basic string checking on name
577  */
578 static int
579 checkIscsiName(wchar_t *input)
580 {
581 	int i;
582 
583 	for (i = 0; input[i] != 0; i++) {
584 		if (!iswalnum(input[i]) && input[i] != '-' &&
585 		    input[i] != '.' && input[i] != ':') {
586 			return (-1);
587 		}
588 	}
589 
590 	return (0);
591 }
592 
593 
594 /*
595  * addViewFunc
596  *
597  * Adds a view entry to a logical unit
598  *
599  */
600 /*ARGSUSED*/
601 static int
602 addViewFunc(int operandLen, char *operands[], cmdOptions_t *options,
603     void *args)
604 {
605 	stmfViewEntry viewEntry;
606 	stmfGuid inGuid;
607 	unsigned int guid[sizeof (stmfGuid)];
608 	uint16_t inputLuNbr;
609 	int ret = 0;
610 	int stmfRet;
611 	int i;
612 	char sGuid[GUID_INPUT + 1];
613 
614 	bzero(&viewEntry, sizeof (viewEntry));
615 	/* init view entry structure */
616 	viewEntry.allHosts = B_TRUE;
617 	viewEntry.allTargets = B_TRUE;
618 	viewEntry.luNbrValid = B_FALSE;
619 
620 	/* check input length */
621 	if (strlen(operands[0]) != GUID_INPUT) {
622 		(void) fprintf(stderr, "%s: %s: %s%d%s\n", cmdName, operands[0],
623 		    gettext("must be "), GUID_INPUT,
624 		    gettext(" hexadecimal digits"));
625 		return (1);
626 	}
627 
628 	for (; options->optval; options++) {
629 		switch (options->optval) {
630 			/* logical unit number */
631 			case 'n':
632 				viewEntry.luNbrValid = B_TRUE;
633 				inputLuNbr = atoi(options->optarg);
634 				if (inputLuNbr > MAX_LU_NBR) {
635 					(void) fprintf(stderr, "%s: %d: %s\n",
636 					    cmdName, inputLuNbr,
637 					    gettext("Logical unit number"
638 					    " must be less than 16384"));
639 					return (1);
640 				}
641 				viewEntry.luNbr[0] = inputLuNbr >> 8;
642 				viewEntry.luNbr[1] = inputLuNbr & 0xff;
643 				break;
644 			/* host group */
645 			case 'h':
646 				viewEntry.allHosts = B_FALSE;
647 				bcopy(options->optarg, viewEntry.hostGroup,
648 				    strlen(options->optarg));
649 				break;
650 			/* target group */
651 			case 't':
652 				viewEntry.allTargets = B_FALSE;
653 				bcopy(options->optarg, viewEntry.targetGroup,
654 				    strlen(options->optarg));
655 				break;
656 			default:
657 				(void) fprintf(stderr, "%s: %c: %s\n",
658 				    cmdName, options->optval,
659 				    gettext("unknown option"));
660 				return (1);
661 		}
662 	}
663 
664 	/* convert to lower case for scan */
665 	for (i = 0; i < 32; i++)
666 		sGuid[i] = tolower(operands[0][i]);
667 	sGuid[i] = 0;
668 
669 	(void) sscanf(sGuid, "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
670 	    &guid[0], &guid[1], &guid[2], &guid[3], &guid[4], &guid[5],
671 	    &guid[6], &guid[7], &guid[8], &guid[9], &guid[10], &guid[11],
672 	    &guid[12], &guid[13], &guid[14], &guid[15]);
673 
674 	for (i = 0; i < sizeof (stmfGuid); i++) {
675 		inGuid.guid[i] = guid[i];
676 	}
677 
678 	/* add the view entry */
679 	stmfRet = stmfAddViewEntry(&inGuid, &viewEntry);
680 	switch (stmfRet) {
681 		case STMF_STATUS_SUCCESS:
682 			break;
683 		case STMF_ERROR_EXISTS:
684 			(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
685 			    operands[0], gettext("already exists"));
686 			ret++;
687 			break;
688 		case STMF_ERROR_BUSY:
689 			(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
690 			    operands[0], gettext("resource busy"));
691 			ret++;
692 			break;
693 		case STMF_ERROR_SERVICE_NOT_FOUND:
694 			(void) fprintf(stderr, "%s: %s\n", cmdName,
695 			    gettext("STMF service not found"));
696 			ret++;
697 			break;
698 		case STMF_ERROR_PERM:
699 			(void) fprintf(stderr, "%s: %s\n", cmdName,
700 			    gettext("permission denied"));
701 			ret++;
702 			break;
703 		case STMF_ERROR_LUN_IN_USE:
704 			(void) fprintf(stderr, "%s: %s\n", cmdName,
705 			    gettext("LUN already in use"));
706 			ret++;
707 			break;
708 		case STMF_ERROR_VE_CONFLICT:
709 			(void) fprintf(stderr, "%s: %s\n", cmdName,
710 			    gettext("view entry exists"));
711 			ret++;
712 			break;
713 		case STMF_ERROR_CONFIG_NONE:
714 			(void) fprintf(stderr, "%s: %s\n", cmdName,
715 			    gettext("STMF service is not initialized"));
716 			ret++;
717 			break;
718 		case STMF_ERROR_SERVICE_DATA_VERSION:
719 			(void) fprintf(stderr, "%s: %s\n", cmdName,
720 			    gettext("STMF service version incorrect"));
721 			ret++;
722 			break;
723 		case STMF_ERROR_INVALID_HG:
724 			(void) fprintf(stderr, "%s: %s\n", cmdName,
725 			    gettext("invalid host group"));
726 			ret++;
727 			break;
728 		case STMF_ERROR_INVALID_TG:
729 			(void) fprintf(stderr, "%s: %s\n", cmdName,
730 			    gettext("invalid target group"));
731 			ret++;
732 			break;
733 		default:
734 			(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
735 			    operands[0], gettext("unknown error"));
736 			ret++;
737 			break;
738 	}
739 
740 	return (ret);
741 }
742 
743 /*
744  * createHostGroupFunc
745  *
746  * Create a host group
747  *
748  */
749 /*ARGSUSED*/
750 static int
751 createHostGroupFunc(int operandLen, char *operands[],
752     cmdOptions_t *options, void *args)
753 {
754 	int ret = 0;
755 	int stmfRet;
756 	wchar_t groupNamePrint[sizeof (stmfGroupName)] = {0};
757 	stmfGroupName groupName = {0};
758 
759 	(void) strlcpy(groupName, operands[0], sizeof (groupName));
760 	(void) mbstowcs(groupNamePrint, (char *)groupName,
761 	    sizeof (stmfGroupName) - 1);
762 	/* call create group */
763 	stmfRet = stmfCreateHostGroup(&groupName);
764 	switch (stmfRet) {
765 		case STMF_STATUS_SUCCESS:
766 			break;
767 		case STMF_ERROR_EXISTS:
768 			(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
769 			    operands[0], gettext("already exists"));
770 			ret++;
771 			break;
772 		case STMF_ERROR_BUSY:
773 			(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
774 			    operands[0], gettext("resource busy"));
775 			ret++;
776 			break;
777 		case STMF_ERROR_SERVICE_NOT_FOUND:
778 			(void) fprintf(stderr, "%s: %s\n", cmdName,
779 			    gettext("STMF service not found"));
780 			ret++;
781 			break;
782 		case STMF_ERROR_PERM:
783 			(void) fprintf(stderr, "%s: %s\n", cmdName,
784 			    gettext("permission denied"));
785 			ret++;
786 			break;
787 		case STMF_ERROR_SERVICE_DATA_VERSION:
788 			(void) fprintf(stderr, "%s: %s\n", cmdName,
789 			    gettext("STMF service version incorrect"));
790 			ret++;
791 			break;
792 		default:
793 			(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
794 			    operands[0], gettext("unknown error"));
795 			ret++;
796 			break;
797 	}
798 
799 	return (ret);
800 }
801 
802 /*
803  * createLuFunc
804  *
805  * Create a logical unit
806  *
807  */
808 /*ARGSUSED*/
809 static int
810 createLuFunc(int operandLen, char *operands[], cmdOptions_t *options,
811     void *args)
812 {
813 	luResource hdl = NULL;
814 	int ret = 0;
815 	int stmfRet = 0;
816 	char guidAsciiBuf[33];
817 	stmfGuid createdGuid;
818 
819 	stmfRet = stmfCreateLuResource(STMF_DISK, &hdl);
820 
821 	if (stmfRet != STMF_STATUS_SUCCESS) {
822 		(void) fprintf(stderr, "%s: %s\n",
823 		    cmdName, gettext("Failure to create lu resource\n"));
824 		return (1);
825 	}
826 
827 	for (; options->optval; options++) {
828 		switch (options->optval) {
829 			case 'p':
830 				ret = setLuPropFromInput(hdl, options->optarg);
831 				if (ret != 0) {
832 					(void) stmfFreeLuResource(hdl);
833 					return (1);
834 				}
835 				break;
836 			case 's':
837 				stmfRet = stmfSetLuProp(hdl, STMF_LU_PROP_SIZE,
838 				    options->optarg);
839 				if (stmfRet != STMF_STATUS_SUCCESS) {
840 					(void) fprintf(stderr, "%s: %c: %s\n",
841 					    cmdName, options->optval,
842 					    gettext("size param invalid"));
843 					(void) stmfFreeLuResource(hdl);
844 					return (1);
845 				}
846 				break;
847 			default:
848 				(void) fprintf(stderr, "%s: %c: %s\n",
849 				    cmdName, options->optval,
850 				    gettext("unknown option"));
851 				return (1);
852 		}
853 	}
854 
855 	stmfRet = stmfSetLuProp(hdl, STMF_LU_PROP_FILENAME, operands[0]);
856 
857 	if (stmfRet != STMF_STATUS_SUCCESS) {
858 		(void) fprintf(stderr, "%s: %s\n",
859 		    cmdName, gettext("could not set filename"));
860 		return (1);
861 	}
862 
863 	stmfRet = stmfCreateLu(hdl, &createdGuid);
864 	switch (stmfRet) {
865 		case STMF_STATUS_SUCCESS:
866 			break;
867 		case STMF_ERROR_BUSY:
868 		case STMF_ERROR_LU_BUSY:
869 			(void) fprintf(stderr, "%s: %s\n", cmdName,
870 			    gettext("resource busy"));
871 			ret++;
872 			break;
873 		case STMF_ERROR_PERM:
874 			(void) fprintf(stderr, "%s: %s\n", cmdName,
875 			    gettext("permission denied"));
876 			ret++;
877 			break;
878 		case STMF_ERROR_FILE_IN_USE:
879 			(void) fprintf(stderr, "%s: filename %s: %s\n", cmdName,
880 			    operands[0], gettext("in use"));
881 			ret++;
882 			break;
883 		case STMF_ERROR_INVALID_BLKSIZE:
884 			(void) fprintf(stderr, "%s: %s\n", cmdName,
885 			    gettext("invalid block size"));
886 			ret++;
887 			break;
888 		case STMF_ERROR_GUID_IN_USE:
889 			(void) fprintf(stderr, "%s: %s\n", cmdName,
890 			    gettext("guid in use"));
891 			ret++;
892 			break;
893 		case STMF_ERROR_META_FILE_NAME:
894 			(void) fprintf(stderr, "%s: %s\n", cmdName,
895 			    gettext("meta file error"));
896 			ret++;
897 			break;
898 		case STMF_ERROR_DATA_FILE_NAME:
899 			(void) fprintf(stderr, "%s: %s\n", cmdName,
900 			    gettext("data file error"));
901 			ret++;
902 			break;
903 		case STMF_ERROR_FILE_SIZE_INVALID:
904 			(void) fprintf(stderr, "%s: %s\n", cmdName,
905 			    gettext("file size invalid"));
906 			ret++;
907 			break;
908 		case STMF_ERROR_SIZE_OUT_OF_RANGE:
909 			(void) fprintf(stderr, "%s: %s\n", cmdName,
910 			    gettext("invalid size"));
911 			ret++;
912 			break;
913 		case STMF_ERROR_META_CREATION:
914 			(void) fprintf(stderr, "%s: %s\n", cmdName,
915 			    gettext("could not create meta file"));
916 			ret++;
917 			break;
918 		case STMF_ERROR_WRITE_CACHE_SET:
919 			(void) fprintf(stderr, "%s: %s\n", cmdName,
920 			    gettext("could not set write cache"));
921 			ret++;
922 			break;
923 		default:
924 			(void) fprintf(stderr, "%s: %s\n", cmdName,
925 			    gettext("unknown error"));
926 			ret++;
927 			break;
928 	}
929 
930 	if (ret != 0) {
931 		goto done;
932 	}
933 
934 	(void) snprintf(guidAsciiBuf, sizeof (guidAsciiBuf),
935 	    "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X"
936 	    "%02X%02X%02X%02X%02X%02X",
937 	    createdGuid.guid[0], createdGuid.guid[1], createdGuid.guid[2],
938 	    createdGuid.guid[3], createdGuid.guid[4], createdGuid.guid[5],
939 	    createdGuid.guid[6], createdGuid.guid[7], createdGuid.guid[8],
940 	    createdGuid.guid[9], createdGuid.guid[10], createdGuid.guid[11],
941 	    createdGuid.guid[12], createdGuid.guid[13], createdGuid.guid[14],
942 	    createdGuid.guid[15]);
943 	(void) printf("Logical unit created: %s\n", guidAsciiBuf);
944 
945 done:
946 	(void) stmfFreeLuResource(hdl);
947 	return (ret);
948 }
949 
950 /*
951  * createLuFunc
952  *
953  * Create a logical unit
954  *
955  */
956 /*ARGSUSED*/
957 static int
958 modifyLuFunc(int operandLen, char *operands[], cmdOptions_t *options,
959     void *args)
960 {
961 	stmfGuid inGuid;
962 	unsigned int guid[sizeof (stmfGuid)];
963 	int ret = 0;
964 	int i;
965 	char *fname = NULL;
966 	char *lasts = NULL;
967 	char sGuid[GUID_INPUT + 1];
968 	char *prop = NULL;
969 	char *propVal = NULL;
970 	boolean_t fnameUsed = B_FALSE;
971 	uint32_t propId;
972 	cmdOptions_t *optionStart = options;
973 
974 
975 	for (; options->optval; options++) {
976 		switch (options->optval) {
977 			case 'f':
978 				fnameUsed = B_TRUE;
979 				fname = operands[0];
980 				break;
981 		}
982 	}
983 	options = optionStart;
984 
985 	/* check input length */
986 	if (!fnameUsed && strlen(operands[0]) != GUID_INPUT) {
987 		(void) fprintf(stderr, "%s: %s: %s%d%s\n", cmdName, operands[0],
988 		    gettext("must be "), GUID_INPUT,
989 		    gettext(" hexadecimal digits"));
990 		return (1);
991 	}
992 
993 	if (!fnameUsed) {
994 		/* convert to lower case for scan */
995 		for (i = 0; i < 32; i++)
996 			sGuid[i] = tolower(operands[0][i]);
997 		sGuid[i] = 0;
998 		(void) sscanf(sGuid,
999 		    "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
1000 		    &guid[0], &guid[1], &guid[2], &guid[3], &guid[4], &guid[5],
1001 		    &guid[6], &guid[7], &guid[8], &guid[9], &guid[10],
1002 		    &guid[11], &guid[12], &guid[13], &guid[14], &guid[15]);
1003 
1004 		for (i = 0; i < sizeof (stmfGuid); i++) {
1005 			inGuid.guid[i] = guid[i];
1006 		}
1007 	}
1008 
1009 	for (; options->optval; options++) {
1010 		switch (options->optval) {
1011 			case 'p':
1012 				prop = strtok_r(options->optarg, "=", &lasts);
1013 				propVal = strtok_r(NULL, "=", &lasts);
1014 				ret = convertCharToPropId(prop, &propId);
1015 				if (ret != 0) {
1016 					(void) fprintf(stderr, "%s: %s: %s\n",
1017 					    cmdName,
1018 					gettext("invalid property specified"),
1019 					    prop);
1020 					return (1);
1021 				}
1022 				if (propVal ==  NULL &&
1023 				    propId != STMF_LU_PROP_MGMT_URL) {
1024 					(void) fprintf(stderr, "%s: %s: %s\n",
1025 					    cmdName, options->optarg,
1026 					    gettext("invalid property specifier"
1027 					    "- prop=val\n"));
1028 					return (1);
1029 				}
1030 				if (propVal ==  NULL) {
1031 					ret = callModify(fname, &inGuid, propId,
1032 					    "", prop);
1033 				} else {
1034 					ret = callModify(fname, &inGuid, propId,
1035 					    propVal, prop);
1036 				}
1037 				if (ret != 0) {
1038 					return (1);
1039 				}
1040 				break;
1041 			case 's':
1042 				if (callModify(fname, &inGuid,
1043 				    STMF_LU_PROP_SIZE, options->optarg,
1044 				    "size") != 0) {
1045 					return (1);
1046 				}
1047 				break;
1048 			case 'f':
1049 				break;
1050 			default:
1051 				(void) fprintf(stderr, "%s: %c: %s\n",
1052 				    cmdName, options->optval,
1053 				    gettext("unknown option"));
1054 				return (1);
1055 		}
1056 	}
1057 	return (ret);
1058 }
1059 
1060 static int
1061 callModify(char *fname, stmfGuid *luGuid, uint32_t prop, const char *propVal,
1062     const char *propString)
1063 {
1064 	int ret = 0;
1065 	int stmfRet = 0;
1066 
1067 	if (!fname) {
1068 		stmfRet = stmfModifyLu(luGuid, prop, propVal);
1069 	} else {
1070 		stmfRet = stmfModifyLuByFname(STMF_DISK, fname, prop,
1071 		    propVal);
1072 	}
1073 	switch (stmfRet) {
1074 		case STMF_STATUS_SUCCESS:
1075 			break;
1076 		case STMF_ERROR_BUSY:
1077 		case STMF_ERROR_LU_BUSY:
1078 			(void) fprintf(stderr, "%s: %s\n", cmdName,
1079 			    gettext("resource busy"));
1080 			ret++;
1081 			break;
1082 		case STMF_ERROR_PERM:
1083 			(void) fprintf(stderr, "%s: %s\n", cmdName,
1084 			    gettext("permission denied"));
1085 			ret++;
1086 			break;
1087 		case STMF_ERROR_INVALID_BLKSIZE:
1088 			(void) fprintf(stderr, "%s: %s\n", cmdName,
1089 			    gettext("invalid block size"));
1090 			ret++;
1091 			break;
1092 		case STMF_ERROR_GUID_IN_USE:
1093 			(void) fprintf(stderr, "%s: %s\n", cmdName,
1094 			    gettext("guid in use"));
1095 			ret++;
1096 			break;
1097 		case STMF_ERROR_META_FILE_NAME:
1098 			(void) fprintf(stderr, "%s: %s\n", cmdName,
1099 			    gettext("meta file error"));
1100 			ret++;
1101 			break;
1102 		case STMF_ERROR_DATA_FILE_NAME:
1103 			(void) fprintf(stderr, "%s: %s\n", cmdName,
1104 			    gettext("data file error"));
1105 			ret++;
1106 			break;
1107 		case STMF_ERROR_FILE_SIZE_INVALID:
1108 			(void) fprintf(stderr, "%s: %s\n", cmdName,
1109 			    gettext("file size invalid"));
1110 			ret++;
1111 			break;
1112 		case STMF_ERROR_SIZE_OUT_OF_RANGE:
1113 			(void) fprintf(stderr, "%s: %s\n", cmdName,
1114 			    gettext("invalid size"));
1115 			ret++;
1116 			break;
1117 		case STMF_ERROR_META_CREATION:
1118 			(void) fprintf(stderr, "%s: %s\n", cmdName,
1119 			    gettext("could not create meta file"));
1120 			ret++;
1121 			break;
1122 		case STMF_ERROR_INVALID_PROP:
1123 			(void) fprintf(stderr, "%s: %s\n", cmdName,
1124 			    gettext("invalid property for modify"));
1125 			ret++;
1126 			break;
1127 		case STMF_ERROR_WRITE_CACHE_SET:
1128 			(void) fprintf(stderr, "%s: %s\n", cmdName,
1129 			    gettext("could not set write cache"));
1130 			ret++;
1131 			break;
1132 		case STMF_ERROR_ACCESS_STATE_SET:
1133 			(void) fprintf(stderr, "%s: %s\n", cmdName,
1134 			    gettext("cannot modify while in standby mode"));
1135 			ret++;
1136 			break;
1137 		default:
1138 			(void) fprintf(stderr, "%s: %s: %s: %d\n", cmdName,
1139 			    gettext("could not set property"), propString,
1140 			    stmfRet);
1141 			ret++;
1142 			break;
1143 	}
1144 
1145 	return (ret);
1146 }
1147 
1148 
1149 /*
1150  * importLuFunc
1151  *
1152  * Create a logical unit
1153  *
1154  */
1155 /*ARGSUSED*/
1156 static int
1157 importLuFunc(int operandLen, char *operands[], cmdOptions_t *options,
1158     void *args)
1159 {
1160 	int stmfRet = 0;
1161 	int ret = 0;
1162 	char guidAsciiBuf[33];
1163 	stmfGuid createdGuid;
1164 
1165 	stmfRet = stmfImportLu(STMF_DISK, operands[0], &createdGuid);
1166 	switch (stmfRet) {
1167 		case STMF_STATUS_SUCCESS:
1168 			break;
1169 		case STMF_ERROR_BUSY:
1170 		case STMF_ERROR_LU_BUSY:
1171 			(void) fprintf(stderr, "%s: %s\n", cmdName,
1172 			    gettext("resource busy"));
1173 			ret++;
1174 			break;
1175 		case STMF_ERROR_PERM:
1176 			(void) fprintf(stderr, "%s: %s\n", cmdName,
1177 			    gettext("permission denied"));
1178 			ret++;
1179 			break;
1180 		case STMF_ERROR_FILE_IN_USE:
1181 			(void) fprintf(stderr, "%s: filename %s: %s\n", cmdName,
1182 			    operands[0], gettext("in use"));
1183 			ret++;
1184 			break;
1185 		case STMF_ERROR_GUID_IN_USE:
1186 			(void) fprintf(stderr, "%s: %s\n", cmdName,
1187 			    gettext("guid in use"));
1188 			ret++;
1189 			break;
1190 		case STMF_ERROR_META_FILE_NAME:
1191 			(void) fprintf(stderr, "%s: %s\n", cmdName,
1192 			    gettext("meta file error"));
1193 			ret++;
1194 			break;
1195 		case STMF_ERROR_DATA_FILE_NAME:
1196 			(void) fprintf(stderr, "%s: %s\n", cmdName,
1197 			    gettext("data file error"));
1198 			ret++;
1199 			break;
1200 		case STMF_ERROR_META_CREATION:
1201 			(void) fprintf(stderr, "%s: %s\n", cmdName,
1202 			    gettext("could not create meta file"));
1203 			ret++;
1204 			break;
1205 		case STMF_ERROR_WRITE_CACHE_SET:
1206 			(void) fprintf(stderr, "%s: %s\n", cmdName,
1207 			    gettext("could not set write cache"));
1208 			ret++;
1209 			break;
1210 		default:
1211 			(void) fprintf(stderr, "%s: %s\n", cmdName,
1212 			    gettext("unknown error"));
1213 			ret++;
1214 			break;
1215 	}
1216 
1217 	if (ret != STMF_STATUS_SUCCESS) {
1218 		goto done;
1219 	}
1220 
1221 	(void) snprintf(guidAsciiBuf, sizeof (guidAsciiBuf),
1222 	    "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X"
1223 	    "%02X%02X%02X%02X%02X%02X",
1224 	    createdGuid.guid[0], createdGuid.guid[1], createdGuid.guid[2],
1225 	    createdGuid.guid[3], createdGuid.guid[4], createdGuid.guid[5],
1226 	    createdGuid.guid[6], createdGuid.guid[7], createdGuid.guid[8],
1227 	    createdGuid.guid[9], createdGuid.guid[10], createdGuid.guid[11],
1228 	    createdGuid.guid[12], createdGuid.guid[13], createdGuid.guid[14],
1229 	    createdGuid.guid[15]);
1230 	(void) printf("Logical unit imported: %s\n", guidAsciiBuf);
1231 
1232 done:
1233 	return (ret);
1234 }
1235 
1236 static int
1237 setLuPropFromInput(luResource hdl, char *optarg)
1238 {
1239 	char *prop = NULL;
1240 	char *propVal = NULL;
1241 	char *lasts = NULL;
1242 	uint32_t propId;
1243 	int ret = 0;
1244 
1245 	prop = strtok_r(optarg, "=", &lasts);
1246 	if ((propVal = strtok_r(NULL, "=", &lasts)) == NULL) {
1247 		(void) fprintf(stderr, "%s: %s: %s\n",
1248 		    cmdName, optarg,
1249 		    gettext("invalid property specifier - prop=val\n"));
1250 		return (1);
1251 	}
1252 
1253 	ret = convertCharToPropId(prop, &propId);
1254 	if (ret != 0) {
1255 		(void) fprintf(stderr, "%s: %s: %s\n",
1256 		    cmdName, gettext("invalid property specified"), prop);
1257 		return (1);
1258 	}
1259 
1260 	ret = stmfSetLuProp(hdl, propId, propVal);
1261 	if (ret != STMF_STATUS_SUCCESS) {
1262 		(void) fprintf(stderr, "%s: %s %s: ",
1263 		    cmdName, gettext("unable to set"), prop);
1264 		switch (ret) {
1265 			case STMF_ERROR_INVALID_PROPSIZE:
1266 				(void) fprintf(stderr, "invalid length\n");
1267 				break;
1268 			case STMF_ERROR_INVALID_ARG:
1269 				(void) fprintf(stderr, "bad format\n");
1270 				break;
1271 			default:
1272 				(void) fprintf(stderr, "\n");
1273 				break;
1274 		}
1275 		return (1);
1276 	}
1277 
1278 	return (0);
1279 }
1280 
1281 static int
1282 convertCharToPropId(char *prop, uint32_t *propId)
1283 {
1284 	if (strcasecmp(prop, GUID) == 0) {
1285 		*propId = STMF_LU_PROP_GUID;
1286 	} else if (strcasecmp(prop, ALIAS) == 0) {
1287 		*propId = STMF_LU_PROP_ALIAS;
1288 	} else if (strcasecmp(prop, VID) == 0) {
1289 		*propId = STMF_LU_PROP_VID;
1290 	} else if (strcasecmp(prop, PID) == 0) {
1291 		*propId = STMF_LU_PROP_PID;
1292 	} else if (strcasecmp(prop, WRITE_PROTECT) == 0) {
1293 		*propId = STMF_LU_PROP_WRITE_PROTECT;
1294 	} else if (strcasecmp(prop, WRITEBACK_CACHE_DISABLE) == 0) {
1295 		*propId = STMF_LU_PROP_WRITE_CACHE_DISABLE;
1296 	} else if (strcasecmp(prop, BLOCK_SIZE) == 0) {
1297 		*propId = STMF_LU_PROP_BLOCK_SIZE;
1298 	} else if (strcasecmp(prop, SERIAL_NUMBER) == 0) {
1299 		*propId = STMF_LU_PROP_SERIAL_NUM;
1300 	} else if (strcasecmp(prop, COMPANY_ID) == 0) {
1301 		*propId = STMF_LU_PROP_COMPANY_ID;
1302 	} else if (strcasecmp(prop, META_FILE) == 0) {
1303 		*propId = STMF_LU_PROP_META_FILENAME;
1304 	} else if (strcasecmp(prop, MGMT_URL) == 0) {
1305 		*propId = STMF_LU_PROP_MGMT_URL;
1306 	} else if (strcasecmp(prop, HOST_ID) == 0) {
1307 		*propId = STMF_LU_PROP_HOST_ID;
1308 	} else {
1309 		return (1);
1310 	}
1311 	return (0);
1312 }
1313 
1314 /*
1315  * deleteLuFunc
1316  *
1317  * Delete a logical unit
1318  *
1319  */
1320 /*ARGSUSED*/
1321 static int
1322 deleteLuFunc(int operandLen, char *operands[], cmdOptions_t *options,
1323     void *args)
1324 {
1325 	int i, j;
1326 	int ret = 0;
1327 	int stmfRet;
1328 	unsigned int inGuid[sizeof (stmfGuid)];
1329 	stmfGuid delGuid;
1330 	boolean_t keepViews = B_FALSE;
1331 	boolean_t viewEntriesRemoved = B_FALSE;
1332 	boolean_t noLunFound = B_FALSE;
1333 	boolean_t views = B_FALSE;
1334 	boolean_t notValidHexNumber = B_FALSE;
1335 	char sGuid[GUID_INPUT + 1];
1336 	stmfViewEntryList *viewEntryList = NULL;
1337 
1338 	for (; options->optval; options++) {
1339 		switch (options->optval) {
1340 			/* Keep views for logical unit */
1341 			case 'k':
1342 				keepViews = B_TRUE;
1343 				break;
1344 			default:
1345 				(void) fprintf(stderr, "%s: %c: %s\n",
1346 				    cmdName, options->optval,
1347 				    gettext("unknown option"));
1348 				return (1);
1349 		}
1350 	}
1351 
1352 
1353 	for (i = 0; i < operandLen; i++) {
1354 		for (j = 0; j < GUID_INPUT; j++) {
1355 			if (!isxdigit(operands[i][j])) {
1356 				notValidHexNumber = B_TRUE;
1357 				break;
1358 			}
1359 			sGuid[j] = tolower(operands[i][j]);
1360 		}
1361 		if ((notValidHexNumber == B_TRUE) ||
1362 		    (strlen(operands[i]) != GUID_INPUT)) {
1363 			(void) fprintf(stderr, "%s: %s: %s%d%s\n",
1364 			    cmdName, operands[i], gettext("must be "),
1365 			    GUID_INPUT,
1366 			    gettext(" hexadecimal digits long"));
1367 			notValidHexNumber = B_FALSE;
1368 			ret++;
1369 			continue;
1370 		}
1371 
1372 		sGuid[j] = 0;
1373 
1374 		(void) sscanf(sGuid,
1375 		    "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
1376 		    &inGuid[0], &inGuid[1], &inGuid[2], &inGuid[3],
1377 		    &inGuid[4], &inGuid[5], &inGuid[6], &inGuid[7],
1378 		    &inGuid[8], &inGuid[9], &inGuid[10], &inGuid[11],
1379 		    &inGuid[12], &inGuid[13], &inGuid[14], &inGuid[15]);
1380 
1381 		for (j = 0; j < sizeof (stmfGuid); j++) {
1382 			delGuid.guid[j] = inGuid[j];
1383 		}
1384 
1385 		stmfRet = stmfDeleteLu(&delGuid);
1386 		switch (stmfRet) {
1387 			case STMF_STATUS_SUCCESS:
1388 				break;
1389 			case STMF_ERROR_NOT_FOUND:
1390 				noLunFound = B_TRUE;
1391 				break;
1392 			case STMF_ERROR_BUSY:
1393 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1394 				    gettext("resource busy"));
1395 				ret++;
1396 				break;
1397 			case STMF_ERROR_PERM:
1398 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1399 				    gettext("permission denied"));
1400 				ret++;
1401 				break;
1402 			default:
1403 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1404 				    gettext("unknown error"));
1405 				ret++;
1406 				break;
1407 		}
1408 
1409 		if (!keepViews) {
1410 			stmfRet = stmfGetViewEntryList(&delGuid,
1411 			    &viewEntryList);
1412 			if (stmfRet == STMF_STATUS_SUCCESS) {
1413 				for (j = 0; j < viewEntryList->cnt; j++) {
1414 					(void) stmfRemoveViewEntry(&delGuid,
1415 					    viewEntryList->ve[j].veIndex);
1416 				}
1417 				/* check if viewEntryList is empty */
1418 				if (viewEntryList->cnt != 0)
1419 					viewEntriesRemoved = B_TRUE;
1420 				stmfFreeMemory(viewEntryList);
1421 			} else {
1422 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1423 				    gettext("unable to remove view entries\n"));
1424 				ret++;
1425 			}
1426 
1427 		}
1428 		if (keepViews) {
1429 			stmfRet = stmfGetViewEntryList(&delGuid,
1430 			    &viewEntryList);
1431 			if (stmfRet == STMF_STATUS_SUCCESS) {
1432 				views = B_TRUE;
1433 				stmfFreeMemory(viewEntryList);
1434 			}
1435 		}
1436 
1437 		if ((!viewEntriesRemoved && noLunFound && !views) ||
1438 		    (!views && keepViews && noLunFound)) {
1439 			(void) fprintf(stderr, "%s: %s: %s\n",
1440 			    cmdName, sGuid,
1441 			    gettext("not found"));
1442 			ret++;
1443 		}
1444 		noLunFound = viewEntriesRemoved = views = B_FALSE;
1445 	}
1446 	return (ret);
1447 }
1448 
1449 
1450 /*
1451  * createTargetGroupFunc
1452  *
1453  * Create a target group
1454  *
1455  */
1456 /*ARGSUSED*/
1457 static int
1458 createTargetGroupFunc(int operandLen, char *operands[], cmdOptions_t *options,
1459     void *args)
1460 {
1461 	int ret = 0;
1462 	int stmfRet;
1463 	wchar_t groupNamePrint[sizeof (stmfGroupName)] = {0};
1464 	stmfGroupName groupName = {0};
1465 
1466 	(void) strlcpy(groupName, operands[0], sizeof (groupName));
1467 	(void) mbstowcs(groupNamePrint, (char *)groupName,
1468 	    sizeof (stmfGroupName) - 1);
1469 	/* call create group */
1470 	stmfRet = stmfCreateTargetGroup(&groupName);
1471 	switch (stmfRet) {
1472 		case STMF_STATUS_SUCCESS:
1473 			break;
1474 		case STMF_ERROR_EXISTS:
1475 			(void) fprintf(stderr, "%s: %ws: %s\n", cmdName,
1476 			    groupNamePrint, gettext("already exists"));
1477 			ret++;
1478 			break;
1479 		case STMF_ERROR_BUSY:
1480 			(void) fprintf(stderr, "%s: %ws: %s\n", cmdName,
1481 			    groupNamePrint, gettext("resource busy"));
1482 			ret++;
1483 			break;
1484 		case STMF_ERROR_PERM:
1485 			(void) fprintf(stderr, "%s: %s\n", cmdName,
1486 			    gettext("permission denied"));
1487 			ret++;
1488 			break;
1489 		case STMF_ERROR_SERVICE_NOT_FOUND:
1490 			(void) fprintf(stderr, "%s: %s\n", cmdName,
1491 			    gettext("STMF service not found"));
1492 			ret++;
1493 			break;
1494 		case STMF_ERROR_SERVICE_DATA_VERSION:
1495 			(void) fprintf(stderr, "%s: %s\n", cmdName,
1496 			    gettext("STMF service version incorrect"));
1497 			ret++;
1498 			break;
1499 		default:
1500 			(void) fprintf(stderr, "%s: %ws: %s\n", cmdName,
1501 			    groupNamePrint, gettext("unknown error"));
1502 			ret++;
1503 			break;
1504 	}
1505 
1506 	return (ret);
1507 }
1508 
1509 /*
1510  * deleteHostGroupFunc
1511  *
1512  * Delete a host group
1513  *
1514  */
1515 /*ARGSUSED*/
1516 static int
1517 deleteHostGroupFunc(int operandLen, char *operands[],
1518     cmdOptions_t *options, void *args)
1519 {
1520 	int ret = 0;
1521 	int stmfRet;
1522 	wchar_t groupNamePrint[sizeof (stmfGroupName)] = {0};
1523 	stmfGroupName groupName = {0};
1524 
1525 	(void) strlcpy(groupName, operands[0], sizeof (groupName));
1526 	(void) mbstowcs(groupNamePrint, (char *)groupName,
1527 	    sizeof (stmfGroupName) - 1);
1528 	/* call delete group */
1529 	stmfRet = stmfDeleteHostGroup(&groupName);
1530 	switch (stmfRet) {
1531 		case STMF_STATUS_SUCCESS:
1532 			break;
1533 		case STMF_ERROR_NOT_FOUND:
1534 			(void) fprintf(stderr, "%s: %ws: %s\n", cmdName,
1535 			    groupNamePrint, gettext("not found"));
1536 			ret++;
1537 			break;
1538 		case STMF_ERROR_BUSY:
1539 			(void) fprintf(stderr, "%s: %ws: %s\n", cmdName,
1540 			    groupNamePrint, gettext("resource busy"));
1541 			ret++;
1542 			break;
1543 		case STMF_ERROR_SERVICE_NOT_FOUND:
1544 			(void) fprintf(stderr, "%s: %s\n", cmdName,
1545 			    gettext("STMF service not found"));
1546 			ret++;
1547 			break;
1548 		case STMF_ERROR_PERM:
1549 			(void) fprintf(stderr, "%s: %s\n", cmdName,
1550 			    gettext("permission denied"));
1551 			ret++;
1552 			break;
1553 		case STMF_ERROR_GROUP_IN_USE:
1554 			(void) fprintf(stderr, "%s: %ws: %s\n", cmdName,
1555 			    groupNamePrint,
1556 			    gettext("group is in use by existing view entry"));
1557 			ret++;
1558 			break;
1559 		case STMF_ERROR_SERVICE_DATA_VERSION:
1560 			(void) fprintf(stderr, "%s: %s\n", cmdName,
1561 			    gettext("STMF service version incorrect"));
1562 			ret++;
1563 			break;
1564 		default:
1565 			(void) fprintf(stderr, "%s: %ws: %s\n", cmdName,
1566 			    groupNamePrint, gettext("unknown error"));
1567 			ret++;
1568 			break;
1569 	}
1570 
1571 	return (ret);
1572 }
1573 
1574 /*
1575  * deleteTargetGroupFunc
1576  *
1577  * Delete a target group
1578  *
1579  */
1580 /*ARGSUSED*/
1581 static int
1582 deleteTargetGroupFunc(int operandLen, char *operands[], cmdOptions_t *options,
1583     void *args)
1584 {
1585 	int ret = 0;
1586 	int stmfRet;
1587 	wchar_t groupNamePrint[sizeof (stmfGroupName)] = {0};
1588 	stmfGroupName groupName = {0};
1589 
1590 	(void) strlcpy(groupName, operands[0], sizeof (groupName));
1591 	(void) mbstowcs(groupNamePrint, (char *)groupName,
1592 	    sizeof (stmfGroupName) - 1);
1593 	/* call delete group */
1594 	stmfRet = stmfDeleteTargetGroup(&groupName);
1595 	switch (stmfRet) {
1596 		case STMF_STATUS_SUCCESS:
1597 			break;
1598 		case STMF_ERROR_NOT_FOUND:
1599 			(void) fprintf(stderr, "%s: %ws: %s\n", cmdName,
1600 			    groupNamePrint, gettext("not found"));
1601 			ret++;
1602 			break;
1603 		case STMF_ERROR_BUSY:
1604 			(void) fprintf(stderr, "%s: %ws: %s\n", cmdName,
1605 			    groupNamePrint, gettext("resource busy"));
1606 			ret++;
1607 			break;
1608 		case STMF_ERROR_SERVICE_NOT_FOUND:
1609 			(void) fprintf(stderr, "%s: %s\n", cmdName,
1610 			    gettext("STMF service not found"));
1611 			ret++;
1612 			break;
1613 		case STMF_ERROR_PERM:
1614 			(void) fprintf(stderr, "%s: %s\n", cmdName,
1615 			    gettext("permission denied"));
1616 			ret++;
1617 			break;
1618 		case STMF_ERROR_GROUP_IN_USE:
1619 			(void) fprintf(stderr, "%s: %ws: %s\n", cmdName,
1620 			    groupNamePrint,
1621 			    gettext("group is in use by existing view entry"));
1622 			ret++;
1623 			break;
1624 		case STMF_ERROR_SERVICE_DATA_VERSION:
1625 			(void) fprintf(stderr, "%s: %s\n", cmdName,
1626 			    gettext("STMF service version incorrect"));
1627 			ret++;
1628 			break;
1629 		default:
1630 			(void) fprintf(stderr, "%s: %ws: %s\n", cmdName,
1631 			    groupNamePrint, gettext("unknown error"));
1632 			ret++;
1633 			break;
1634 	}
1635 
1636 	return (ret);
1637 }
1638 
1639 /*
1640  * listHostGroupFunc
1641  *
1642  * Lists the specified host groups or all if none are specified
1643  *
1644  */
1645 /*ARGSUSED*/
1646 static int
1647 listHostGroupFunc(int operandLen, char *operands[], cmdOptions_t *options,
1648     void *args)
1649 {
1650 	int ret = 0;
1651 	int stmfRet;
1652 	int i, j, outerLoop;
1653 	boolean_t verbose = B_FALSE;
1654 	boolean_t found = B_TRUE;
1655 	boolean_t operandEntered;
1656 	stmfGroupList *groupList;
1657 	stmfGroupProperties *groupProps;
1658 	wchar_t operandName[sizeof (stmfGroupName)];
1659 	wchar_t groupNamePrint[sizeof (stmfGroupName)];
1660 
1661 	for (; options->optval; options++) {
1662 		switch (options->optval) {
1663 			case 'v':
1664 				verbose = B_TRUE;
1665 				break;
1666 			default:
1667 				(void) fprintf(stderr, "%s: %c: %s\n",
1668 				    cmdName, options->optval,
1669 				    gettext("unknown option"));
1670 				return (1);
1671 		}
1672 	}
1673 
1674 	if (operandLen > 0) {
1675 		outerLoop = operandLen;
1676 		operandEntered = B_TRUE;
1677 	} else {
1678 		outerLoop = 1;
1679 		operandEntered = B_FALSE;
1680 	}
1681 
1682 	stmfRet = stmfGetHostGroupList(&groupList);
1683 	if (stmfRet != STMF_STATUS_SUCCESS) {
1684 		switch (stmfRet) {
1685 			case STMF_ERROR_BUSY:
1686 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1687 				    gettext("resource busy"));
1688 				break;
1689 			case STMF_ERROR_SERVICE_NOT_FOUND:
1690 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1691 				    gettext("STMF service not found"));
1692 				break;
1693 			case STMF_ERROR_PERM:
1694 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1695 				    gettext("permission denied"));
1696 				break;
1697 			case STMF_ERROR_SERVICE_DATA_VERSION:
1698 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1699 				    gettext("STMF service version incorrect"));
1700 				break;
1701 			default:
1702 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1703 				    gettext("unknown error"));
1704 				break;
1705 		}
1706 		return (1);
1707 	}
1708 
1709 	for (i = 0; i < outerLoop; i++) {
1710 		for (found = B_FALSE, j = 0; j < groupList->cnt; j++) {
1711 			(void) mbstowcs(groupNamePrint,
1712 			    (char *)groupList->name[j],
1713 			    sizeof (stmfGroupName) - 1);
1714 			groupNamePrint[sizeof (stmfGroupName) - 1] = 0;
1715 			if (operandEntered) {
1716 				(void) mbstowcs(operandName, operands[i],
1717 				    sizeof (stmfGroupName) - 1);
1718 				operandName[sizeof (stmfGroupName) - 1] = 0;
1719 				if (wcscmp(operandName, groupNamePrint)
1720 				    == 0) {
1721 					found = B_TRUE;
1722 				}
1723 			}
1724 			if ((found && operandEntered) || !operandEntered) {
1725 				(void) printf("Host Group: %ws\n",
1726 				    groupNamePrint);
1727 				if (verbose) {
1728 					stmfRet = stmfGetHostGroupMembers(
1729 					    &(groupList->name[j]), &groupProps);
1730 					if (stmfRet != STMF_STATUS_SUCCESS) {
1731 						return (1);
1732 					}
1733 					printGroupProps(groupProps);
1734 				}
1735 				if (found && operandEntered) {
1736 					break;
1737 				}
1738 			}
1739 
1740 		}
1741 		if (operandEntered && !found) {
1742 			(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
1743 			    operands[i], gettext("not found"));
1744 			ret = 1;
1745 		}
1746 	}
1747 	return (ret);
1748 }
1749 
1750 /*
1751  * printGroupProps
1752  *
1753  * Prints group members for target or host groups
1754  *
1755  */
1756 static void
1757 printGroupProps(stmfGroupProperties *groupProps)
1758 {
1759 	int i;
1760 	wchar_t memberIdent[sizeof (groupProps->name[0].ident) + 1] = {0};
1761 
1762 
1763 	for (i = 0; i < groupProps->cnt; i++) {
1764 		(void) mbstowcs(memberIdent, (char *)groupProps->name[i].ident,
1765 		    sizeof (groupProps->name[0].ident));
1766 		(void) printf("\tMember: %ws\n", memberIdent);
1767 	}
1768 }
1769 
1770 /*
1771  * listTargetGroupFunc
1772  *
1773  * Lists the specified target groups or all if none are specified
1774  *
1775  */
1776 /*ARGSUSED*/
1777 static int
1778 listTargetGroupFunc(int operandLen, char *operands[], cmdOptions_t *options,
1779     void *args)
1780 {
1781 	int ret = 0;
1782 	int stmfRet;
1783 	int i, j, outerLoop;
1784 	boolean_t verbose = B_FALSE;
1785 	boolean_t found = B_TRUE;
1786 	boolean_t operandEntered;
1787 	stmfGroupList *groupList;
1788 	stmfGroupProperties *groupProps;
1789 	wchar_t operandName[sizeof (stmfGroupName)];
1790 	wchar_t groupNamePrint[sizeof (stmfGroupName)];
1791 
1792 	for (; options->optval; options++) {
1793 		switch (options->optval) {
1794 			case 'v':
1795 				verbose = B_TRUE;
1796 				break;
1797 			default:
1798 				(void) fprintf(stderr, "%s: %c: %s\n",
1799 				    cmdName, options->optval,
1800 				    gettext("unknown option"));
1801 				return (1);
1802 		}
1803 	}
1804 
1805 	if (operandLen > 0) {
1806 		outerLoop = operandLen;
1807 		operandEntered = B_TRUE;
1808 	} else {
1809 		outerLoop = 1;
1810 		operandEntered = B_FALSE;
1811 	}
1812 
1813 	stmfRet = stmfGetTargetGroupList(&groupList);
1814 	if (stmfRet != STMF_STATUS_SUCCESS) {
1815 		switch (stmfRet) {
1816 			case STMF_ERROR_BUSY:
1817 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1818 				    gettext("resource busy"));
1819 				break;
1820 			case STMF_ERROR_SERVICE_NOT_FOUND:
1821 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1822 				    gettext("STMF service not found"));
1823 				break;
1824 			case STMF_ERROR_SERVICE_DATA_VERSION:
1825 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1826 				    gettext("STMF service version incorrect"));
1827 				break;
1828 			case STMF_ERROR_PERM:
1829 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1830 				    gettext("permission denied"));
1831 				break;
1832 			default:
1833 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1834 				    gettext("unknown error"));
1835 				break;
1836 		}
1837 		return (1);
1838 	}
1839 
1840 	for (i = 0; i < outerLoop; i++) {
1841 		for (found = B_FALSE, j = 0; j < groupList->cnt; j++) {
1842 			(void) mbstowcs(groupNamePrint,
1843 			    (char *)groupList->name[j],
1844 			    sizeof (stmfGroupName) - 1);
1845 			groupNamePrint[sizeof (stmfGroupName) - 1] = 0;
1846 			if (operandEntered) {
1847 				(void) mbstowcs(operandName, operands[i],
1848 				    sizeof (stmfGroupName) - 1);
1849 				operandName[sizeof (stmfGroupName) - 1] = 0;
1850 				if (wcscmp(operandName, groupNamePrint)
1851 				    == 0) {
1852 					found = B_TRUE;
1853 				}
1854 			}
1855 			if ((found && operandEntered) || !operandEntered) {
1856 				(void) printf("Target Group: %ws\n",
1857 				    groupNamePrint);
1858 				if (verbose) {
1859 					stmfRet = stmfGetTargetGroupMembers(
1860 					    &(groupList->name[j]), &groupProps);
1861 					if (stmfRet != STMF_STATUS_SUCCESS) {
1862 						return (1);
1863 					}
1864 					printGroupProps(groupProps);
1865 				}
1866 				if (found && operandEntered) {
1867 					break;
1868 				}
1869 			}
1870 
1871 		}
1872 		if (operandEntered && !found) {
1873 			(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
1874 			    operands[i], gettext("not found"));
1875 			ret = 1;
1876 		}
1877 	}
1878 	return (ret);
1879 }
1880 
1881 /*
1882  * listLuFunc
1883  *
1884  * List the logical units and optionally the properties
1885  *
1886  */
1887 /*ARGSUSED*/
1888 static int
1889 listLuFunc(int operandLen, char *operands[], cmdOptions_t *options, void *args)
1890 {
1891 	cmdOptions_t *optionList = options;
1892 	boolean_t operandEntered;
1893 	int i, j;
1894 	int ret = 0;
1895 	int stmfRet;
1896 	int outerLoop;
1897 	unsigned int inGuid[sizeof (stmfGuid)];
1898 	stmfGuid cmpGuid;
1899 	boolean_t verbose = B_FALSE;
1900 	boolean_t found;
1901 	char sGuid[GUID_INPUT + 1];
1902 	stmfGuidList *luList;
1903 	stmfLogicalUnitProperties luProps;
1904 	boolean_t invalidInput = B_FALSE;
1905 	stmfViewEntryList *viewEntryList;
1906 
1907 	for (; optionList->optval; optionList++) {
1908 		switch (optionList->optval) {
1909 			case 'v':
1910 				verbose = B_TRUE;
1911 				break;
1912 		}
1913 	}
1914 
1915 	if ((stmfRet = stmfGetLogicalUnitList(&luList))
1916 	    != STMF_STATUS_SUCCESS) {
1917 		switch (stmfRet) {
1918 			case STMF_ERROR_SERVICE_NOT_FOUND:
1919 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1920 				    gettext("STMF service not found"));
1921 				break;
1922 			case STMF_ERROR_BUSY:
1923 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1924 				    gettext("resource busy"));
1925 				break;
1926 			case STMF_ERROR_PERM:
1927 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1928 				    gettext("permission denied"));
1929 				break;
1930 			case STMF_ERROR_SERVICE_DATA_VERSION:
1931 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1932 				    gettext("STMF service version incorrect"));
1933 				break;
1934 			default:
1935 				(void) fprintf(stderr, "%s: %s\n", cmdName,
1936 				    gettext("list failed"));
1937 				break;
1938 		}
1939 		return (1);
1940 	}
1941 
1942 	if (operandLen > 0) {
1943 		operandEntered = B_TRUE;
1944 		outerLoop = operandLen;
1945 	} else {
1946 		operandEntered = B_FALSE;
1947 		outerLoop = 1;
1948 	}
1949 
1950 
1951 	for (invalidInput = B_FALSE, i = 0; i < outerLoop; i++) {
1952 		if (operandEntered) {
1953 			if (strlen(operands[i]) != GUID_INPUT) {
1954 				invalidInput = B_TRUE;
1955 			} else {
1956 				for (j = 0; j < GUID_INPUT; j++) {
1957 					if (!isxdigit(operands[i][j])) {
1958 						invalidInput = B_TRUE;
1959 						break;
1960 					}
1961 				}
1962 			}
1963 			if (invalidInput) {
1964 				(void) fprintf(stderr, "%s: %s: %s%d%s\n",
1965 				    cmdName, operands[i], gettext("must be "),
1966 				    GUID_INPUT,
1967 				    gettext(" hexadecimal digits long"));
1968 				invalidInput = B_FALSE;
1969 				continue;
1970 			}
1971 
1972 			for (j = 0; j < GUID_INPUT; j++) {
1973 				sGuid[j] = tolower(operands[i][j]);
1974 			}
1975 			sGuid[j] = 0;
1976 
1977 			(void) sscanf(sGuid,
1978 			    "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
1979 			    &inGuid[0], &inGuid[1], &inGuid[2], &inGuid[3],
1980 			    &inGuid[4], &inGuid[5], &inGuid[6], &inGuid[7],
1981 			    &inGuid[8], &inGuid[9], &inGuid[10], &inGuid[11],
1982 			    &inGuid[12], &inGuid[13], &inGuid[14], &inGuid[15]);
1983 
1984 			for (j = 0; j < sizeof (stmfGuid); j++) {
1985 				cmpGuid.guid[j] = inGuid[j];
1986 			}
1987 		}
1988 
1989 		for (found = B_FALSE, j = 0; j < luList->cnt; j++) {
1990 			if (operandEntered) {
1991 				if (bcmp(luList->guid[j].guid, cmpGuid.guid,
1992 				    sizeof (stmfGuid)) == 0) {
1993 					found = B_TRUE;
1994 				}
1995 			}
1996 			if ((found && operandEntered) || !operandEntered) {
1997 				(void) printf("LU Name: ");
1998 				printGuid(&luList->guid[j], stdout);
1999 				(void) printf("\n");
2000 
2001 				if (verbose) {
2002 					stmfRet = stmfGetLogicalUnitProperties(
2003 					    &(luList->guid[j]), &luProps);
2004 					if (stmfRet == STMF_STATUS_SUCCESS) {
2005 						printLuProps(&luProps);
2006 					} else {
2007 						(void) fprintf(stderr, "%s:",
2008 						    cmdName);
2009 						printGuid(&luList->guid[j],
2010 						    stderr);
2011 						(void) fprintf(stderr, "%s\n",
2012 						    gettext(" get properties "
2013 						    "failed"));
2014 					}
2015 					stmfRet = stmfGetViewEntryList(
2016 					    &(luList->guid[j]),
2017 					    &viewEntryList);
2018 					(void) printf(PROPS_FORMAT,
2019 					    "View Entry Count");
2020 					if (stmfRet == STMF_STATUS_SUCCESS) {
2021 						(void) printf("%d",
2022 						    viewEntryList->cnt);
2023 					} else {
2024 						(void) printf("unknown");
2025 					}
2026 					(void) printf("\n");
2027 					ret = printExtLuProps(
2028 					    &(luList->guid[j]));
2029 				}
2030 				if (found && operandEntered) {
2031 					break;
2032 				}
2033 			}
2034 
2035 		}
2036 		if (operandEntered && !found) {
2037 			(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
2038 			    operands[i], gettext("not found"));
2039 			ret = 1;
2040 		}
2041 	}
2042 
2043 	return (ret);
2044 }
2045 
2046 static void
2047 printGuid(stmfGuid *guid, FILE *stream)
2048 {
2049 	int i;
2050 	for (i = 0; i < 16; i++) {
2051 		(void) fprintf(stream, "%02X", guid->guid[i]);
2052 	}
2053 }
2054 
2055 static int
2056 printExtLuProps(stmfGuid *guid)
2057 {
2058 	int stmfRet;
2059 	luResource hdl = NULL;
2060 	int ret = 0;
2061 	char propVal[MAXNAMELEN];
2062 	size_t propValSize = sizeof (propVal);
2063 
2064 	if ((stmfRet = stmfGetLuResource(guid, &hdl))
2065 	    != STMF_STATUS_SUCCESS) {
2066 		switch (stmfRet) {
2067 			case STMF_ERROR_BUSY:
2068 				(void) fprintf(stderr, "%s: %s\n", cmdName,
2069 				    gettext("resource busy"));
2070 				break;
2071 			case STMF_ERROR_PERM:
2072 				(void) fprintf(stderr, "%s: %s\n", cmdName,
2073 				    gettext("permission denied"));
2074 				break;
2075 			case STMF_ERROR_NOT_FOUND:
2076 				/* No error here */
2077 				return (0);
2078 			default:
2079 				(void) fprintf(stderr, "%s: %s\n", cmdName,
2080 				    gettext("get extended properties failed"));
2081 				break;
2082 		}
2083 		return (1);
2084 	}
2085 
2086 	stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_FILENAME, propVal,
2087 	    &propValSize);
2088 	(void) printf(PROPS_FORMAT, "Data File");
2089 	if (stmfRet == STMF_STATUS_SUCCESS) {
2090 		(void) printf("%s\n", propVal);
2091 	} else if (stmfRet == STMF_ERROR_NO_PROP) {
2092 		(void) printf("not set\n");
2093 	} else if (stmfRet == STMF_ERROR_NO_PROP_STANDBY) {
2094 		(void) printf("prop unavailable in standby\n");
2095 	} else {
2096 		(void) printf("<error retrieving property>\n");
2097 		ret++;
2098 	}
2099 
2100 	stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_META_FILENAME, propVal,
2101 	    &propValSize);
2102 	(void) printf(PROPS_FORMAT, "Meta File");
2103 	if (stmfRet == STMF_STATUS_SUCCESS) {
2104 		(void) printf("%s\n", propVal);
2105 	} else if (stmfRet == STMF_ERROR_NO_PROP) {
2106 		(void) printf("not set\n");
2107 	} else if (stmfRet == STMF_ERROR_NO_PROP_STANDBY) {
2108 		(void) printf("prop unavailable in standby\n");
2109 	} else {
2110 		(void) printf("<error retrieving property>\n");
2111 		ret++;
2112 	}
2113 
2114 	stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_SIZE, propVal,
2115 	    &propValSize);
2116 	(void) printf(PROPS_FORMAT, "Size");
2117 	if (stmfRet == STMF_STATUS_SUCCESS) {
2118 		(void) printf("%s\n", propVal);
2119 	} else if (stmfRet == STMF_ERROR_NO_PROP) {
2120 		(void) printf("not set\n");
2121 	} else if (stmfRet == STMF_ERROR_NO_PROP_STANDBY) {
2122 		(void) printf("prop unavailable in standby\n");
2123 	} else {
2124 		(void) printf("<error retrieving property>\n");
2125 		ret++;
2126 	}
2127 
2128 	stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_BLOCK_SIZE, propVal,
2129 	    &propValSize);
2130 	(void) printf(PROPS_FORMAT, "Block Size");
2131 	if (stmfRet == STMF_STATUS_SUCCESS) {
2132 		(void) printf("%s\n", propVal);
2133 	} else if (stmfRet == STMF_ERROR_NO_PROP) {
2134 		(void) printf("not set\n");
2135 	} else if (stmfRet == STMF_ERROR_NO_PROP_STANDBY) {
2136 		(void) printf("prop unavailable in standby\n");
2137 	} else {
2138 		(void) printf("<error retrieving property>\n");
2139 		ret++;
2140 	}
2141 
2142 	stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_MGMT_URL, propVal,
2143 	    &propValSize);
2144 	(void) printf(PROPS_FORMAT, "Management URL");
2145 	if (stmfRet == STMF_STATUS_SUCCESS) {
2146 		(void) printf("%s\n", propVal);
2147 	} else if (stmfRet == STMF_ERROR_NO_PROP) {
2148 		(void) printf("not set\n");
2149 	} else if (stmfRet == STMF_ERROR_NO_PROP_STANDBY) {
2150 		(void) printf("prop unavailable in standby\n");
2151 	} else {
2152 		(void) printf("<error retrieving property>\n");
2153 		ret++;
2154 	}
2155 
2156 	stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_VID, propVal,
2157 	    &propValSize);
2158 	(void) printf(PROPS_FORMAT, "Vendor ID");
2159 	if (stmfRet == STMF_STATUS_SUCCESS) {
2160 		(void) printf("%s\n", propVal);
2161 	} else if (stmfRet == STMF_ERROR_NO_PROP) {
2162 		(void) printf("not set\n");
2163 	} else if (stmfRet == STMF_ERROR_NO_PROP_STANDBY) {
2164 		(void) printf("prop unavailable in standby\n");
2165 	} else {
2166 		(void) printf("<error retrieving property>\n");
2167 		ret++;
2168 	}
2169 
2170 	stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_PID, propVal,
2171 	    &propValSize);
2172 	(void) printf(PROPS_FORMAT, "Product ID");
2173 	if (stmfRet == STMF_STATUS_SUCCESS) {
2174 		(void) printf("%s\n", propVal);
2175 	} else if (stmfRet == STMF_ERROR_NO_PROP) {
2176 		(void) printf("not set\n");
2177 	} else if (stmfRet == STMF_ERROR_NO_PROP_STANDBY) {
2178 		(void) printf("prop unavailable in standby\n");
2179 	} else {
2180 		(void) printf("<error retrieving property>\n");
2181 		ret++;
2182 	}
2183 
2184 	stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_SERIAL_NUM, propVal,
2185 	    &propValSize);
2186 	(void) printf(PROPS_FORMAT, "Serial Num");
2187 	if (stmfRet == STMF_STATUS_SUCCESS) {
2188 		(void) printf("%s\n", propVal);
2189 	} else if (stmfRet == STMF_ERROR_NO_PROP) {
2190 		(void) printf("not set\n");
2191 	} else if (stmfRet == STMF_ERROR_NO_PROP_STANDBY) {
2192 		(void) printf("prop unavailable in standby\n");
2193 	} else {
2194 		(void) printf("<error retrieving property>\n");
2195 		ret++;
2196 	}
2197 
2198 	stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_WRITE_PROTECT, propVal,
2199 	    &propValSize);
2200 	(void) printf(PROPS_FORMAT, "Write Protect");
2201 	if (stmfRet == STMF_STATUS_SUCCESS) {
2202 		(void) printf("%s\n",
2203 		    strcasecmp(propVal, "true") ? "Disabled" : "Enabled");
2204 	} else if (stmfRet == STMF_ERROR_NO_PROP) {
2205 		(void) printf("not set\n");
2206 	} else if (stmfRet == STMF_ERROR_NO_PROP_STANDBY) {
2207 		(void) printf("prop unavailable in standby\n");
2208 	} else {
2209 		(void) printf("<error retrieving property>\n");
2210 		ret++;
2211 	}
2212 
2213 	stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_WRITE_CACHE_DISABLE, propVal,
2214 	    &propValSize);
2215 	(void) printf(PROPS_FORMAT, "Writeback Cache");
2216 	if (stmfRet == STMF_STATUS_SUCCESS) {
2217 		(void) printf("%s\n",
2218 		    strcasecmp(propVal, "true") ? "Enabled" : "Disabled");
2219 	} else if (stmfRet == STMF_ERROR_NO_PROP) {
2220 		(void) printf("not set\n");
2221 	} else if (stmfRet == STMF_ERROR_NO_PROP_STANDBY) {
2222 		(void) printf("prop unavailable in standby\n");
2223 	} else {
2224 		(void) printf("<error retrieving property>\n");
2225 		ret++;
2226 	}
2227 
2228 	stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_ACCESS_STATE, propVal,
2229 	    &propValSize);
2230 	(void) printf(PROPS_FORMAT, "Access State");
2231 	if (stmfRet == STMF_STATUS_SUCCESS) {
2232 		if (strcmp(propVal, STMF_ACCESS_ACTIVE) == 0) {
2233 			(void) printf("%s\n", "Active");
2234 		} else if (strcmp(propVal,
2235 		    STMF_ACCESS_ACTIVE_TO_STANDBY) == 0) {
2236 			(void) printf("%s\n", "Active->Standby");
2237 		} else if (strcmp(propVal, STMF_ACCESS_STANDBY) == 0) {
2238 			(void) printf("%s\n", "Standby");
2239 		} else if (strcmp(propVal,
2240 		    STMF_ACCESS_STANDBY_TO_ACTIVE) == 0) {
2241 			(void) printf("%s\n", "Standby->Active");
2242 		} else {
2243 			(void) printf("%s\n", "Unknown");
2244 		}
2245 	} else if (stmfRet == STMF_ERROR_NO_PROP) {
2246 		(void) printf("not set\n");
2247 	} else {
2248 		(void) printf("<error retrieving property>\n");
2249 		ret++;
2250 	}
2251 
2252 done:
2253 	(void) stmfFreeLuResource(hdl);
2254 	return (ret);
2255 
2256 }
2257 
2258 
2259 /*
2260  * printLuProps
2261  *
2262  * Prints the properties for a logical unit
2263  *
2264  */
2265 static void
2266 printLuProps(stmfLogicalUnitProperties *luProps)
2267 {
2268 	(void) printf(PROPS_FORMAT, "Operational Status");
2269 	switch (luProps->status) {
2270 		case STMF_LOGICAL_UNIT_ONLINE:
2271 			(void) printf("Online");
2272 			break;
2273 		case STMF_LOGICAL_UNIT_OFFLINE:
2274 			(void) printf("Offline");
2275 			break;
2276 		case STMF_LOGICAL_UNIT_ONLINING:
2277 			(void) printf("Onlining");
2278 			break;
2279 		case STMF_LOGICAL_UNIT_OFFLINING:
2280 			(void) printf("Offlining");
2281 			break;
2282 		case STMF_LOGICAL_UNIT_UNREGISTERED:
2283 			(void) printf("unregistered");
2284 			(void) strncpy(luProps->providerName, "unregistered",
2285 			    sizeof (luProps->providerName));
2286 			break;
2287 		default:
2288 			(void) printf("unknown");
2289 			break;
2290 	}
2291 	(void) printf("\n");
2292 	(void) printf(PROPS_FORMAT, "Provider Name");
2293 	if (luProps->providerName[0] != 0) {
2294 		(void) printf("%s", luProps->providerName);
2295 	} else {
2296 		(void) printf("unknown");
2297 	}
2298 	(void) printf("\n");
2299 	(void) printf(PROPS_FORMAT, "Alias");
2300 	if (luProps->alias[0] != 0) {
2301 		(void) printf("%s", luProps->alias);
2302 	} else {
2303 		(void) printf("-");
2304 	}
2305 	(void) printf("\n");
2306 }
2307 
2308 /*
2309  * printTargetProps
2310  *
2311  * Prints the properties for a target
2312  *
2313  */
2314 static void
2315 printTargetProps(stmfTargetProperties *targetProps)
2316 {
2317 	(void) printf(PROPS_FORMAT, "Operational Status");
2318 	switch (targetProps->status) {
2319 		case STMF_TARGET_PORT_ONLINE:
2320 			(void) printf("Online");
2321 			break;
2322 		case STMF_TARGET_PORT_OFFLINE:
2323 			(void) printf("Offline");
2324 			break;
2325 		case STMF_TARGET_PORT_ONLINING:
2326 			(void) printf("Onlining");
2327 			break;
2328 		case STMF_TARGET_PORT_OFFLINING:
2329 			(void) printf("Offlining");
2330 			break;
2331 		default:
2332 			(void) printf("unknown");
2333 			break;
2334 	}
2335 	(void) printf("\n");
2336 	(void) printf(PROPS_FORMAT, "Provider Name");
2337 	if (targetProps->providerName[0] != 0) {
2338 		(void) printf("%s", targetProps->providerName);
2339 	}
2340 	(void) printf("\n");
2341 	(void) printf(PROPS_FORMAT, "Alias");
2342 	if (targetProps->alias[0] != 0) {
2343 		(void) printf("%s", targetProps->alias);
2344 	} else {
2345 		(void) printf("-");
2346 	}
2347 	(void) printf("\n");
2348 	(void) printf(PROPS_FORMAT, "Protocol");
2349 	switch (targetProps->protocol) {
2350 		case STMF_PROTOCOL_FIBRE_CHANNEL:
2351 			(void) printf("%s", "Fibre Channel");
2352 			break;
2353 		case STMF_PROTOCOL_ISCSI:
2354 			(void) printf("%s", "iSCSI");
2355 			break;
2356 		case STMF_PROTOCOL_SRP:
2357 			(void) printf("%s", "SRP");
2358 			break;
2359 		case STMF_PROTOCOL_SAS:
2360 			(void) printf("%s", "SAS");
2361 			break;
2362 		default:
2363 			(void) printf("%s", "unknown");
2364 			break;
2365 	}
2366 
2367 	(void) printf("\n");
2368 }
2369 
2370 /*
2371  * printSessionProps
2372  *
2373  * Prints the session data
2374  *
2375  */
2376 static void
2377 printSessionProps(stmfSessionList *sessionList)
2378 {
2379 	int i;
2380 	char *cTime;
2381 	wchar_t initiator[STMF_IDENT_LENGTH + 1];
2382 
2383 	(void) printf(PROPS_FORMAT, "Sessions");
2384 	(void) printf("%d\n", sessionList->cnt);
2385 	for (i = 0; i < sessionList->cnt; i++) {
2386 		(void) mbstowcs(initiator,
2387 		    (char *)sessionList->session[i].initiator.ident,
2388 		    STMF_IDENT_LENGTH);
2389 		initiator[STMF_IDENT_LENGTH] = 0;
2390 		(void) printf(LVL3_FORMAT, "Initiator: ");
2391 		(void) printf("%ws\n", initiator);
2392 		(void) printf(LVL4_FORMAT, "Alias: ");
2393 		if (sessionList->session[i].alias[0] != 0) {
2394 			(void) printf("%s", sessionList->session[i].alias);
2395 		} else {
2396 			(void) printf("-");
2397 		}
2398 		(void) printf("\n");
2399 		(void) printf(LVL4_FORMAT, "Logged in since: ");
2400 		cTime = ctime(&(sessionList->session[i].creationTime));
2401 		if (cTime != NULL) {
2402 			(void) printf("%s", cTime);
2403 		} else {
2404 			(void) printf("unknown\n");
2405 		}
2406 	}
2407 }
2408 
2409 static int
2410 getStmfState(stmfState *state)
2411 {
2412 	int ret;
2413 
2414 	ret = stmfGetState(state);
2415 	switch (ret) {
2416 		case STMF_STATUS_SUCCESS:
2417 			break;
2418 		case STMF_ERROR_PERM:
2419 			(void) fprintf(stderr, "%s: %s\n", cmdName,
2420 			    gettext("permission denied"));
2421 			break;
2422 		case STMF_ERROR_SERVICE_NOT_FOUND:
2423 			(void) fprintf(stderr, "%s: %s\n", cmdName,
2424 			    gettext("STMF service not found"));
2425 			break;
2426 		case STMF_ERROR_BUSY:
2427 			(void) fprintf(stderr, "%s: %s\n", cmdName,
2428 			    gettext("resource busy"));
2429 			break;
2430 		case STMF_ERROR_SERVICE_DATA_VERSION:
2431 			(void) fprintf(stderr, "%s: %s\n", cmdName,
2432 			    gettext("STMF service version incorrect"));
2433 			break;
2434 		default:
2435 			(void) fprintf(stderr, "%s: %s: %d\n", cmdName,
2436 			    gettext("unknown error"), ret);
2437 			break;
2438 	}
2439 	return (ret);
2440 }
2441 
2442 /*
2443  * listStateFunc
2444  *
2445  * List the operational and config state of the stmf service
2446  *
2447  */
2448 /*ARGSUSED*/
2449 static int
2450 listStateFunc(int operandLen, char *operands[], cmdOptions_t *options,
2451     void *args)
2452 {
2453 	int ret;
2454 	stmfState state;
2455 	boolean_t aluaEnabled;
2456 	uint32_t node;
2457 
2458 	if ((ret = getStmfState(&state)) != STMF_STATUS_SUCCESS)
2459 		return (ret);
2460 
2461 	(void) printf("%-18s: ", "Operational Status");
2462 	switch (state.operationalState) {
2463 		case STMF_SERVICE_STATE_ONLINE:
2464 			(void) printf("online");
2465 			break;
2466 		case STMF_SERVICE_STATE_OFFLINE:
2467 			(void) printf("offline");
2468 			break;
2469 		case STMF_SERVICE_STATE_ONLINING:
2470 			(void) printf("onlining");
2471 			break;
2472 		case STMF_SERVICE_STATE_OFFLINING:
2473 			(void) printf("offlining");
2474 			break;
2475 		default:
2476 			(void) printf("unknown");
2477 			break;
2478 	}
2479 	(void) printf("\n");
2480 	(void) printf("%-18s: ", "Config Status");
2481 	switch (state.configState) {
2482 		case STMF_CONFIG_STATE_NONE:
2483 			(void) printf("uninitialized");
2484 			break;
2485 		case STMF_CONFIG_STATE_INIT:
2486 			(void) printf("initializing");
2487 			break;
2488 		case STMF_CONFIG_STATE_INIT_DONE:
2489 			(void) printf("initialized");
2490 			break;
2491 		default:
2492 			(void) printf("unknown");
2493 			break;
2494 	}
2495 	(void) printf("\n");
2496 	ret = stmfGetAluaState(&aluaEnabled, &node);
2497 	switch (ret) {
2498 		case STMF_STATUS_SUCCESS:
2499 			break;
2500 		case STMF_ERROR_PERM:
2501 			(void) fprintf(stderr, "%s: %s\n", cmdName,
2502 			    gettext("permission denied"));
2503 			break;
2504 		case STMF_ERROR_BUSY:
2505 			(void) fprintf(stderr, "%s: %s\n", cmdName,
2506 			    gettext("resource busy"));
2507 			break;
2508 		default:
2509 			(void) fprintf(stderr, "%s: %s: %d\n", cmdName,
2510 			    gettext("unknown error"), ret);
2511 			break;
2512 	}
2513 	(void) printf("%-18s: ", "ALUA Status");
2514 	if (ret == STMF_STATUS_SUCCESS) {
2515 		if (aluaEnabled == B_TRUE) {
2516 			(void) printf("enabled");
2517 		} else {
2518 			(void) printf("disabled");
2519 		}
2520 	} else {
2521 		(void) printf("unknown");
2522 	}
2523 
2524 	(void) printf("\n");
2525 	(void) printf("%-18s: ", "ALUA Node");
2526 	if (ret == STMF_STATUS_SUCCESS) {
2527 		(void) printf("%d", node);
2528 	} else {
2529 		(void) printf("unknown");
2530 	}
2531 	(void) printf("\n");
2532 	return (ret);
2533 }
2534 
2535 /*
2536  * listTargetFunc
2537  *
2538  * list the targets and optionally their properties
2539  *
2540  */
2541 /*ARGSUSED*/
2542 static int
2543 listTargetFunc(int operandLen, char *operands[], cmdOptions_t *options,
2544     void *args)
2545 {
2546 	cmdOptions_t *optionList = options;
2547 	int ret = 0;
2548 	int stmfRet;
2549 	int i, j;
2550 	int outerLoop;
2551 	stmfSessionList *sessionList;
2552 	stmfDevid devid;
2553 	boolean_t operandEntered, found, verbose = B_FALSE;
2554 	stmfDevidList *targetList;
2555 	wchar_t targetIdent[STMF_IDENT_LENGTH + 1];
2556 	stmfTargetProperties targetProps;
2557 
2558 	if ((stmfRet = stmfGetTargetList(&targetList)) != STMF_STATUS_SUCCESS) {
2559 		switch (stmfRet) {
2560 			case STMF_ERROR_NOT_FOUND:
2561 				ret = 0;
2562 				break;
2563 			case STMF_ERROR_SERVICE_OFFLINE:
2564 				(void) fprintf(stderr, "%s: %s\n", cmdName,
2565 				    gettext("STMF service offline"));
2566 				break;
2567 			case STMF_ERROR_BUSY:
2568 				(void) fprintf(stderr, "%s: %s\n", cmdName,
2569 				    gettext("resource busy"));
2570 				break;
2571 			case STMF_ERROR_SERVICE_DATA_VERSION:
2572 				(void) fprintf(stderr, "%s: %s\n", cmdName,
2573 				    gettext("STMF service version incorrect"));
2574 				break;
2575 			case STMF_ERROR_PERM:
2576 				(void) fprintf(stderr, "%s: %s\n", cmdName,
2577 				    gettext("permission denied"));
2578 				break;
2579 			default:
2580 				(void) fprintf(stderr, "%s: %s\n", cmdName,
2581 				    gettext("unknown error"));
2582 				break;
2583 		}
2584 		return (1);
2585 	}
2586 
2587 	for (; optionList->optval; optionList++) {
2588 		switch (optionList->optval) {
2589 			case 'v':
2590 				verbose = B_TRUE;
2591 				break;
2592 		}
2593 	}
2594 
2595 	if (operandLen > 0) {
2596 		outerLoop = operandLen;
2597 		operandEntered = B_TRUE;
2598 	} else {
2599 		outerLoop = 1;
2600 		operandEntered = B_FALSE;
2601 	}
2602 
2603 	for (i = 0; i < outerLoop; i++) {
2604 		if (operandEntered) {
2605 			bzero(&devid, sizeof (devid));
2606 			(void) parseDevid(operands[i], &devid);
2607 		}
2608 		for (found = B_FALSE, j = 0; j < targetList->cnt; j++) {
2609 			if (operandEntered) {
2610 				if (bcmp(&devid, &(targetList->devid[j]),
2611 				    sizeof (devid)) == 0) {
2612 					found = B_TRUE;
2613 				}
2614 			}
2615 			if ((found && operandEntered) || !operandEntered) {
2616 				(void) mbstowcs(targetIdent,
2617 				    (char *)targetList->devid[j].ident,
2618 				    STMF_IDENT_LENGTH);
2619 				targetIdent[STMF_IDENT_LENGTH] = 0;
2620 				(void) printf("Target: %ws\n", targetIdent);
2621 				if (verbose) {
2622 					stmfRet = stmfGetTargetProperties(
2623 					    &(targetList->devid[j]),
2624 					    &targetProps);
2625 					if (stmfRet == STMF_STATUS_SUCCESS) {
2626 						printTargetProps(&targetProps);
2627 					} else {
2628 						(void) fprintf(stderr, "%s:",
2629 						    cmdName);
2630 						(void) fprintf(stderr, "%s\n",
2631 						    gettext(" get properties"
2632 						    " failed"));
2633 					}
2634 					stmfRet = stmfGetSessionList(
2635 					    &(targetList->devid[j]),
2636 					    &sessionList);
2637 					if (stmfRet == STMF_STATUS_SUCCESS) {
2638 						printSessionProps(sessionList);
2639 					} else {
2640 						(void) fprintf(stderr, "%s:",
2641 						    cmdName);
2642 						(void) fprintf(stderr, "%s\n",
2643 						    gettext(" get session info"
2644 						    " failed"));
2645 					}
2646 				}
2647 				if (found && operandEntered) {
2648 					break;
2649 				}
2650 			}
2651 
2652 		}
2653 		if (operandEntered && !found) {
2654 			(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
2655 			    operands[i], "not found");
2656 			ret = 1;
2657 		}
2658 	}
2659 	return (ret);
2660 }
2661 
2662 /*
2663  * listViewFunc
2664  *
2665  * list the view entries for the specified logical unit
2666  *
2667  */
2668 /*ARGSUSED*/
2669 static int
2670 listViewFunc(int operandLen, char *operands[], cmdOptions_t *options,
2671     void *args)
2672 {
2673 	stmfViewEntryList *viewEntryList;
2674 	stmfGuid inGuid;
2675 	unsigned int guid[sizeof (stmfGuid)];
2676 	int ret = 0;
2677 	int stmfRet;
2678 	int i, j, outerLoop;
2679 	boolean_t found = B_TRUE;
2680 	boolean_t operandEntered;
2681 	uint16_t outputLuNbr;
2682 	wchar_t groupName[sizeof (stmfGroupName)];
2683 	char sGuid[GUID_INPUT + 1];
2684 
2685 
2686 	for (; options->optval; options++) {
2687 		switch (options->optval) {
2688 			case 'l':
2689 				if (strlen(options->optarg) != GUID_INPUT) {
2690 					(void) fprintf(stderr,
2691 					    "%s: %s: %s%d%s\n",
2692 					    cmdName, options->optarg,
2693 					    gettext("must be "), GUID_INPUT,
2694 					    gettext(" hexadecimal digits"
2695 					    " long"));
2696 					return (1);
2697 				}
2698 				bcopy(options->optarg, sGuid, GUID_INPUT);
2699 				break;
2700 			default:
2701 				(void) fprintf(stderr, "%s: %c: %s\n",
2702 				    cmdName, options->optval,
2703 				    gettext("unknown option"));
2704 				return (1);
2705 		}
2706 	}
2707 
2708 	if (operandLen > 0) {
2709 		outerLoop = operandLen;
2710 		operandEntered = B_TRUE;
2711 	} else {
2712 		outerLoop = 1;
2713 		operandEntered = B_FALSE;
2714 	}
2715 
2716 	for (i = 0; i < 32; i++)
2717 		sGuid[i] = tolower(sGuid[i]);
2718 	sGuid[i] = 0;
2719 
2720 	(void) sscanf(sGuid, "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
2721 	    &guid[0], &guid[1], &guid[2], &guid[3], &guid[4], &guid[5],
2722 	    &guid[6], &guid[7], &guid[8], &guid[9], &guid[10], &guid[11],
2723 	    &guid[12], &guid[13], &guid[14], &guid[15]);
2724 
2725 	for (i = 0; i < sizeof (stmfGuid); i++) {
2726 		inGuid.guid[i] = guid[i];
2727 	}
2728 
2729 	if ((stmfRet = stmfGetViewEntryList(&inGuid, &viewEntryList))
2730 	    != STMF_STATUS_SUCCESS) {
2731 
2732 		switch (stmfRet) {
2733 			case STMF_ERROR_BUSY:
2734 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
2735 				    sGuid, gettext("resource busy"));
2736 				break;
2737 			case STMF_ERROR_SERVICE_NOT_FOUND:
2738 				(void) fprintf(stderr, "%s: %s\n", cmdName,
2739 				    gettext("STMF service not found"));
2740 				break;
2741 			case STMF_ERROR_SERVICE_DATA_VERSION:
2742 				(void) fprintf(stderr, "%s: %s\n", cmdName,
2743 				    gettext("STMF service version incorrect"));
2744 				break;
2745 			case STMF_ERROR_PERM:
2746 				(void) fprintf(stderr, "%s: %s\n", cmdName,
2747 				    gettext("permission denied"));
2748 				break;
2749 			default:
2750 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
2751 				    sGuid, gettext("unknown error"));
2752 				break;
2753 		}
2754 		return (1);
2755 	}
2756 
2757 	if (viewEntryList->cnt == 0) {
2758 		(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
2759 		    sGuid, gettext("no views found"));
2760 		return (1);
2761 	}
2762 
2763 	for (i = 0; i < outerLoop; i++) {
2764 		for (found = B_FALSE, j = 0; j < viewEntryList->cnt; j++) {
2765 			if (operandEntered) {
2766 				if (atoi(operands[i]) ==
2767 				    viewEntryList->ve[j].veIndex) {
2768 					found = B_TRUE;
2769 				}
2770 			}
2771 			if ((found && operandEntered) || !operandEntered) {
2772 				(void) printf("View Entry: %d\n",
2773 				    viewEntryList->ve[j].veIndex);
2774 				(void) printf(VIEW_FORMAT, "Host group");
2775 				if (viewEntryList->ve[j].allHosts) {
2776 					(void) printf("All\n");
2777 				} else {
2778 					(void) mbstowcs(groupName,
2779 					    viewEntryList->ve[j].hostGroup,
2780 					    sizeof (stmfGroupName) - 1);
2781 					groupName[sizeof (stmfGroupName) - 1]
2782 					    = 0;
2783 					(void) printf("%ws\n", groupName);
2784 				}
2785 				(void) printf(VIEW_FORMAT, "Target group");
2786 				if (viewEntryList->ve[j].allTargets) {
2787 					(void) printf("All\n");
2788 				} else {
2789 					(void) mbstowcs(groupName,
2790 					    viewEntryList->ve[j].targetGroup,
2791 					    sizeof (stmfGroupName) - 1);
2792 					groupName[sizeof (stmfGroupName) - 1]
2793 					    = 0;
2794 					(void) printf("%ws\n", groupName);
2795 				}
2796 				outputLuNbr = ((viewEntryList->ve[j].luNbr[0] &
2797 				    0x3F) << 8) | viewEntryList->ve[j].luNbr[1];
2798 				(void) printf(VIEW_FORMAT, "LUN");
2799 				(void) printf("%d\n", outputLuNbr);
2800 				if (found && operandEntered) {
2801 					break;
2802 				}
2803 			}
2804 		}
2805 		if (operandEntered && !found) {
2806 			(void) fprintf(stderr, "%s: %s, %s: %s\n", cmdName,
2807 			    sGuid, operands[i], gettext("not found"));
2808 			ret = 1;
2809 		}
2810 	}
2811 
2812 	return (ret);
2813 }
2814 
2815 
2816 /*
2817  * onlineOfflineLu
2818  *
2819  * Purpose: Online or offline a logical unit
2820  *
2821  * lu - logical unit to online or offline
2822  *
2823  * state - ONLINE_LU
2824  *         OFFLINE_LU
2825  */
2826 static int
2827 onlineOfflineLu(char *lu, int state)
2828 {
2829 	char sGuid[GUID_INPUT + 1];
2830 	stmfGuid inGuid;
2831 	unsigned int guid[sizeof (stmfGuid)];
2832 	int i;
2833 	int ret = 0, stmfRet;
2834 	stmfLogicalUnitProperties luProps;
2835 
2836 	if (strlen(lu) != GUID_INPUT) {
2837 		(void) fprintf(stderr, "%s: %s: %s %d %s\n", cmdName, lu,
2838 		    gettext("must be"), GUID_INPUT,
2839 		    gettext("hexadecimal digits long"));
2840 		return (1);
2841 	}
2842 
2843 	bcopy(lu, sGuid, GUID_INPUT);
2844 
2845 	for (i = 0; i < 32; i++)
2846 		sGuid[i] = tolower(sGuid[i]);
2847 	sGuid[i] = 0;
2848 
2849 	(void) sscanf(sGuid, "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
2850 	    &guid[0], &guid[1], &guid[2], &guid[3], &guid[4], &guid[5],
2851 	    &guid[6], &guid[7], &guid[8], &guid[9], &guid[10], &guid[11],
2852 	    &guid[12], &guid[13], &guid[14], &guid[15]);
2853 
2854 	for (i = 0; i < sizeof (stmfGuid); i++) {
2855 		inGuid.guid[i] = guid[i];
2856 	}
2857 
2858 	if (state == ONLINE_LU) {
2859 		ret = stmfOnlineLogicalUnit(&inGuid);
2860 	} else if (state == OFFLINE_LU) {
2861 		ret = stmfOfflineLogicalUnit(&inGuid);
2862 	} else {
2863 		return (STMFADM_FAILURE);
2864 	}
2865 	if (ret != STMF_STATUS_SUCCESS) {
2866 		switch (ret) {
2867 			case STMF_ERROR_PERM:
2868 				(void) fprintf(stderr, "%s: %s\n", cmdName,
2869 				    gettext("permission denied"));
2870 				break;
2871 			case STMF_ERROR_SERVICE_NOT_FOUND:
2872 				(void) fprintf(stderr, "%s: %s\n", cmdName,
2873 				    gettext("STMF service not found"));
2874 				break;
2875 			case STMF_ERROR_BUSY:
2876 				(void) fprintf(stderr, "%s: %s\n", cmdName,
2877 				    gettext("resource busy"));
2878 				break;
2879 			case STMF_ERROR_NOT_FOUND:
2880 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
2881 				    lu, gettext("not found"));
2882 				break;
2883 			case STMF_ERROR_SERVICE_DATA_VERSION:
2884 				(void) fprintf(stderr, "%s: %s\n", cmdName,
2885 				    gettext("STMF service version incorrect"));
2886 				break;
2887 			default:
2888 				(void) fprintf(stderr, "%s: %s\n", cmdName,
2889 				    gettext("unknown error"));
2890 				break;
2891 		}
2892 	} else {
2893 		struct timespec	ts = {0};
2894 		unsigned int	count = 0;
2895 		uint32_t	ret_state;
2896 
2897 		ret_state = (state == ONLINE_LU) ?
2898 		    STMF_LOGICAL_UNIT_ONLINING : STMF_LOGICAL_UNIT_OFFLINING;
2899 		ts.tv_nsec = DELAYED_EXEC_WAIT_INTERVAL;
2900 
2901 		/* CONSTCOND */
2902 		while (1) {
2903 			stmfRet = stmfGetLogicalUnitProperties(&inGuid,
2904 			    &luProps);
2905 			if (stmfRet == STMF_STATUS_SUCCESS)
2906 				ret_state = luProps.status;
2907 
2908 			if ((state == ONLINE_LU &&
2909 			    ret_state == STMF_LOGICAL_UNIT_ONLINE) ||
2910 			    (state == OFFLINE_LU &&
2911 			    ret_state == STMF_LOGICAL_UNIT_OFFLINE))
2912 				return (STMFADM_SUCCESS);
2913 
2914 			if ((state == ONLINE_LU &&
2915 			    ret_state == STMF_LOGICAL_UNIT_OFFLINE) ||
2916 			    (state == OFFLINE_LU &&
2917 			    ret_state == STMF_LOGICAL_UNIT_ONLINE))
2918 				return (STMFADM_FAILURE);
2919 
2920 			if (++count ==  DELAYED_EXEC_WAIT_MAX) {
2921 				(void) fprintf(stderr, "%s: %s\n", cmdName,
2922 				    gettext("Logical Unit state change request "
2923 				    "submitted. Waiting for completion "
2924 				    "timed out"));
2925 				return (STMFADM_FAILURE);
2926 			}
2927 			(void) nanosleep(&ts, NULL);
2928 		}
2929 	}
2930 	return (STMFADM_FAILURE);
2931 }
2932 
2933 /*
2934  * onlineLuFunc
2935  *
2936  * Purpose: Online a logical unit
2937  *
2938  */
2939 /*ARGSUSED*/
2940 static int
2941 onlineLuFunc(int operandLen, char *operands[], cmdOptions_t *options,
2942     void *args)
2943 {
2944 	int ret;
2945 	stmfState state;
2946 
2947 	ret = getStmfState(&state);
2948 	if (ret != STMF_STATUS_SUCCESS)
2949 		return (ret);
2950 	if (state.operationalState == STMF_SERVICE_STATE_OFFLINE ||
2951 	    state.operationalState == STMF_SERVICE_STATE_OFFLINING) {
2952 		(void) fprintf(stderr, "%s: %s\n", cmdName,
2953 		    gettext("STMF service is offline"));
2954 		return (1);
2955 	}
2956 	return (onlineOfflineLu(operands[0], ONLINE_LU));
2957 }
2958 
2959 /*
2960  * offlineLuFunc
2961  *
2962  * Purpose: Offline a logical unit
2963  *
2964  */
2965 /*ARGSUSED*/
2966 static int
2967 offlineLuFunc(int operandLen, char *operands[], cmdOptions_t *options,
2968     void *args)
2969 {
2970 	return (onlineOfflineLu(operands[0], OFFLINE_LU));
2971 }
2972 
2973 /*
2974  * onlineOfflineTarget
2975  *
2976  * Purpose: Online or offline a target
2977  *
2978  * target - target to online or offline
2979  *
2980  * state - ONLINE_TARGET
2981  *         OFFLINE_TARGET
2982  */
2983 static int
2984 onlineOfflineTarget(char *target, int state)
2985 {
2986 	int ret = 0, stmfRet = 0;
2987 	stmfDevid devid;
2988 	stmfTargetProperties targetProps;
2989 
2990 	if (parseDevid(target, &devid) != 0) {
2991 		(void) fprintf(stderr, "%s: %s: %s\n",
2992 		    cmdName, target, gettext("unrecognized device id"));
2993 		return (1);
2994 	}
2995 	if (state == ONLINE_TARGET) {
2996 		ret = stmfOnlineTarget(&devid);
2997 	} else if (state == OFFLINE_TARGET) {
2998 		ret = stmfOfflineTarget(&devid);
2999 	} else {
3000 		return (STMFADM_FAILURE);
3001 	}
3002 	if (ret != STMF_STATUS_SUCCESS) {
3003 		switch (ret) {
3004 			case STMF_ERROR_PERM:
3005 				(void) fprintf(stderr, "%s: %s\n", cmdName,
3006 				    gettext("permission denied"));
3007 				break;
3008 			case STMF_ERROR_SERVICE_NOT_FOUND:
3009 				(void) fprintf(stderr, "%s: %s\n", cmdName,
3010 				    gettext("STMF service not found"));
3011 				break;
3012 			case STMF_ERROR_BUSY:
3013 				(void) fprintf(stderr, "%s: %s\n", cmdName,
3014 				    gettext("resource busy"));
3015 				break;
3016 			case STMF_ERROR_NOT_FOUND:
3017 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
3018 				    target, gettext("not found"));
3019 				break;
3020 			case STMF_ERROR_SERVICE_DATA_VERSION:
3021 				(void) fprintf(stderr, "%s: %s\n", cmdName,
3022 				    gettext("STMF service version incorrect"));
3023 				break;
3024 			default:
3025 				(void) fprintf(stderr, "%s: %s\n", cmdName,
3026 				    gettext("unknown error"));
3027 				break;
3028 		}
3029 	} else {
3030 		struct timespec  ts = {0};
3031 		unsigned int count = 0;
3032 		uint32_t	ret_state;
3033 
3034 		ret_state = (state == ONLINE_TARGET) ?
3035 		    STMF_TARGET_PORT_ONLINING : STMF_TARGET_PORT_OFFLINING;
3036 		ts.tv_nsec = DELAYED_EXEC_WAIT_INTERVAL;
3037 
3038 		/* CONSTCOND */
3039 		while (1) {
3040 			stmfRet = stmfGetTargetProperties(&devid, &targetProps);
3041 			if (stmfRet == STMF_STATUS_SUCCESS)
3042 				ret_state = targetProps.status;
3043 
3044 			if ((state == ONLINE_TARGET &&
3045 			    ret_state == STMF_TARGET_PORT_ONLINE) ||
3046 			    (state == OFFLINE_TARGET &&
3047 			    ret_state == STMF_TARGET_PORT_OFFLINE)) {
3048 				return (STMFADM_SUCCESS);
3049 			}
3050 
3051 			if ((state == ONLINE_TARGET &&
3052 			    ret_state == STMF_TARGET_PORT_OFFLINE) ||
3053 			    (state == OFFLINE_TARGET &&
3054 			    ret_state == STMF_TARGET_PORT_ONLINE)) {
3055 				return (STMFADM_FAILURE);
3056 			}
3057 
3058 			if (++count ==  DELAYED_EXEC_WAIT_MAX) {
3059 				(void) fprintf(stderr, "%s: %s\n", cmdName,
3060 				    gettext("Target state change request "
3061 				    "submitted. Waiting for completion "
3062 				    "timed out."));
3063 				return (STMFADM_FAILURE);
3064 			}
3065 			(void) nanosleep(&ts, NULL);
3066 		}
3067 	}
3068 	return (STMFADM_FAILURE);
3069 }
3070 
3071 /*
3072  * onlineTargetFunc
3073  *
3074  * Purpose: Online a target
3075  *
3076  */
3077 /*ARGSUSED*/
3078 static int
3079 onlineTargetFunc(int operandLen, char *operands[], cmdOptions_t *options,
3080     void *args)
3081 {
3082 	int ret;
3083 	stmfState state;
3084 
3085 	ret = getStmfState(&state);
3086 	if (ret != STMF_STATUS_SUCCESS)
3087 		return (ret);
3088 	if (state.operationalState == STMF_SERVICE_STATE_OFFLINE ||
3089 	    state.operationalState == STMF_SERVICE_STATE_OFFLINING) {
3090 		(void) fprintf(stderr, "%s: %s\n", cmdName,
3091 		    gettext("STMF service is offline"));
3092 		return (1);
3093 	}
3094 	return (onlineOfflineTarget(operands[0], ONLINE_TARGET));
3095 }
3096 
3097 /*
3098  * offlineTargetFunc
3099  *
3100  * Purpose: Offline a target
3101  *
3102  */
3103 /*ARGSUSED*/
3104 static int
3105 offlineTargetFunc(int operandLen, char *operands[], cmdOptions_t *options,
3106     void *args)
3107 {
3108 	return (onlineOfflineTarget(operands[0], OFFLINE_TARGET));
3109 }
3110 
3111 
3112 /*ARGSUSED*/
3113 static int
3114 removeHostGroupMemberFunc(int operandLen, char *operands[],
3115     cmdOptions_t *options, void *args)
3116 {
3117 	int i;
3118 	int ret = 0;
3119 	int stmfRet;
3120 	stmfGroupName groupName = {0};
3121 	stmfDevid devid;
3122 	wchar_t groupNamePrint[sizeof (stmfGroupName)] = {0};
3123 
3124 	for (; options->optval; options++) {
3125 		switch (options->optval) {
3126 			case 'g':
3127 				(void) mbstowcs(groupNamePrint, options->optarg,
3128 				    sizeof (stmfGroupName) - 1);
3129 				bcopy(options->optarg, groupName,
3130 				    strlen(options->optarg));
3131 				break;
3132 			default:
3133 				(void) fprintf(stderr, "%s: %c: %s\n",
3134 				    cmdName, options->optval,
3135 				    gettext("unknown option"));
3136 				return (1);
3137 		}
3138 	}
3139 
3140 	for (i = 0; i < operandLen; i++) {
3141 		if (parseDevid(operands[i], &devid) != 0) {
3142 			(void) fprintf(stderr, "%s: %s: %s\n",
3143 			    cmdName, operands[i],
3144 			    gettext("unrecognized device id"));
3145 			ret++;
3146 			continue;
3147 		}
3148 		stmfRet = stmfRemoveFromHostGroup(&groupName, &devid);
3149 		switch (stmfRet) {
3150 			case STMF_STATUS_SUCCESS:
3151 				break;
3152 			case STMF_ERROR_MEMBER_NOT_FOUND:
3153 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
3154 				    operands[i], gettext("not found"));
3155 				ret++;
3156 				break;
3157 			case STMF_ERROR_GROUP_NOT_FOUND:
3158 				(void) fprintf(stderr, "%s: %ws: %s\n", cmdName,
3159 				    groupNamePrint, gettext("not found"));
3160 				ret++;
3161 				break;
3162 			case STMF_ERROR_BUSY:
3163 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
3164 				    operands[i], "resource busy");
3165 				ret++;
3166 				break;
3167 			case STMF_ERROR_SERVICE_NOT_FOUND:
3168 				(void) fprintf(stderr, "%s: %s\n", cmdName,
3169 				    gettext("STMF service not found"));
3170 				ret++;
3171 				break;
3172 			case STMF_ERROR_SERVICE_DATA_VERSION:
3173 				(void) fprintf(stderr, "%s: %s\n", cmdName,
3174 				    gettext("STMF service version incorrect"));
3175 				ret++;
3176 				break;
3177 			case STMF_ERROR_PERM:
3178 				(void) fprintf(stderr, "%s: %s\n", cmdName,
3179 				    gettext("permission denied"));
3180 				ret++;
3181 				break;
3182 			default:
3183 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
3184 				    operands[i], gettext("unknown error"));
3185 				ret++;
3186 				break;
3187 		}
3188 	}
3189 
3190 	return (ret);
3191 }
3192 
3193 /*
3194  * removeTargetGroupMemberFunc
3195  *
3196  * Removes one or more members from a target group
3197  *
3198  */
3199 /*ARGSUSED*/
3200 static int
3201 removeTargetGroupMemberFunc(int operandLen, char *operands[],
3202     cmdOptions_t *options, void *args)
3203 {
3204 	int i;
3205 	int ret = 0;
3206 	int stmfRet;
3207 	stmfGroupName groupName = {0};
3208 	stmfDevid devid;
3209 	wchar_t groupNamePrint[sizeof (stmfGroupName)] = {0};
3210 
3211 	for (; options->optval; options++) {
3212 		switch (options->optval) {
3213 			case 'g':
3214 				(void) mbstowcs(groupNamePrint, options->optarg,
3215 				    sizeof (stmfGroupName) - 1);
3216 				bcopy(options->optarg, groupName,
3217 				    strlen(options->optarg));
3218 				break;
3219 			default:
3220 				(void) fprintf(stderr, "%s: %c: %s\n",
3221 				    cmdName, options->optval,
3222 				    gettext("unknown option"));
3223 				return (1);
3224 		}
3225 	}
3226 
3227 	for (i = 0; i < operandLen; i++) {
3228 		if (parseDevid(operands[i], &devid) != 0) {
3229 			(void) fprintf(stderr, "%s: %s: %s\n",
3230 			    cmdName, operands[i],
3231 			    gettext("unrecognized device id"));
3232 			ret++;
3233 			continue;
3234 		}
3235 		stmfRet = stmfRemoveFromTargetGroup(&groupName, &devid);
3236 		switch (stmfRet) {
3237 			case STMF_STATUS_SUCCESS:
3238 				break;
3239 			case STMF_ERROR_MEMBER_NOT_FOUND:
3240 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
3241 				    operands[i], gettext("not found"));
3242 				ret++;
3243 				break;
3244 			case STMF_ERROR_GROUP_NOT_FOUND:
3245 				(void) fprintf(stderr, "%s: %ws: %s\n", cmdName,
3246 				    groupNamePrint, gettext("not found"));
3247 				ret++;
3248 				break;
3249 			case STMF_ERROR_BUSY:
3250 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
3251 				    operands[i], gettext("resource busy"));
3252 				ret++;
3253 				break;
3254 			case STMF_ERROR_SERVICE_NOT_FOUND:
3255 				(void) fprintf(stderr, "%s: %s\n", cmdName,
3256 				    gettext("STMF service not found"));
3257 				ret++;
3258 				break;
3259 			case STMF_ERROR_PERM:
3260 				(void) fprintf(stderr, "%s: %s\n", cmdName,
3261 				    gettext("permission denied"));
3262 				ret++;
3263 				break;
3264 			case STMF_ERROR_SERVICE_DATA_VERSION:
3265 				(void) fprintf(stderr, "%s: %s\n", cmdName,
3266 				    gettext("STMF service version incorrect"));
3267 				ret++;
3268 				break;
3269 			case STMF_ERROR_TG_ONLINE:
3270 				(void) fprintf(stderr, "%s: %s\n", cmdName,
3271 				    gettext("STMF target must be offline"));
3272 				ret++;
3273 				break;
3274 			default:
3275 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
3276 				    operands[i], gettext("unknown error"));
3277 				ret++;
3278 				break;
3279 		}
3280 	}
3281 
3282 	return (ret);
3283 }
3284 
3285 /*
3286  * removeViewFunc
3287  *
3288  * Removes one or more view entries from a logical unit
3289  *
3290  */
3291 /*ARGSUSED*/
3292 static int
3293 removeViewFunc(int operandLen, char *operands[], cmdOptions_t *options,
3294     void *args)
3295 {
3296 	char sGuid[GUID_INPUT + 1];
3297 	stmfViewEntryList *viewEntryList;
3298 	stmfGuid inGuid;
3299 	uint32_t count;
3300 	unsigned int guid[sizeof (stmfGuid)];
3301 	char *endPtr;
3302 	uint32_t veNbr;
3303 	int i;
3304 	boolean_t all = B_FALSE;
3305 	boolean_t luInput = B_FALSE;
3306 	int ret = 0;
3307 	int stmfRet;
3308 
3309 	/* Note: 'l' is required */
3310 	for (; options->optval; options++) {
3311 		switch (options->optval) {
3312 			case 'l':
3313 				if (strlen(options->optarg) != GUID_INPUT) {
3314 					(void) fprintf(stderr,
3315 					    "%s: %s: %s %d %s\n",
3316 					    cmdName, options->optarg,
3317 					    gettext("must be"), GUID_INPUT,
3318 					    gettext("hexadecimal digits long"));
3319 					return (1);
3320 				}
3321 				bcopy(options->optarg, sGuid, GUID_INPUT);
3322 				luInput = B_TRUE;
3323 				break;
3324 			case 'a':
3325 				/* removing all view entries for this GUID */
3326 				all = B_TRUE;
3327 				break;
3328 			default:
3329 				(void) fprintf(stderr, "%s: %c: %s\n",
3330 				    cmdName, options->optval,
3331 				    "unknown option");
3332 				return (1);
3333 		}
3334 	}
3335 
3336 	if (!all && operandLen == 0) {
3337 		(void) fprintf(stderr, "%s: %s\n", cmdName,
3338 		    gettext("no view entries specified"));
3339 		return (1);
3340 	}
3341 
3342 	if (!luInput) {
3343 		(void) fprintf(stderr, "%s: %s\n", cmdName,
3344 		    gettext("logical unit (-l) not specified"));
3345 		return (1);
3346 	}
3347 
3348 	for (i = 0; i < 32; i++)
3349 		sGuid[i] = tolower(sGuid[i]);
3350 	sGuid[i] = 0;
3351 
3352 	(void) sscanf(sGuid, "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
3353 	    &guid[0], &guid[1], &guid[2], &guid[3], &guid[4], &guid[5],
3354 	    &guid[6], &guid[7], &guid[8], &guid[9], &guid[10], &guid[11],
3355 	    &guid[12], &guid[13], &guid[14], &guid[15]);
3356 
3357 	for (i = 0; i < sizeof (stmfGuid); i++) {
3358 		inGuid.guid[i] = guid[i];
3359 	}
3360 
3361 	if ((stmfRet = stmfGetViewEntryList(&inGuid, &viewEntryList))
3362 	    != STMF_STATUS_SUCCESS) {
3363 
3364 		switch (stmfRet) {
3365 			case STMF_ERROR_BUSY:
3366 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
3367 				    sGuid, gettext("resource busy"));
3368 				break;
3369 			case STMF_ERROR_SERVICE_NOT_FOUND:
3370 				(void) fprintf(stderr, "%s: %s\n", cmdName,
3371 				    gettext("STMF service not found"));
3372 				break;
3373 			case STMF_ERROR_SERVICE_DATA_VERSION:
3374 				(void) fprintf(stderr, "%s: %s\n", cmdName,
3375 				    gettext("STMF service version incorrect"));
3376 				break;
3377 			case STMF_ERROR_PERM:
3378 				(void) fprintf(stderr, "%s: %s\n", cmdName,
3379 				    gettext("permission denied"));
3380 				break;
3381 			default:
3382 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
3383 				    sGuid, gettext("unknown error"));
3384 				break;
3385 		}
3386 		return (1);
3387 	}
3388 
3389 	if (viewEntryList->cnt == 0) {
3390 		(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
3391 		    sGuid, gettext("no views found"));
3392 		return (1);
3393 	}
3394 
3395 	if (all) {
3396 		count = viewEntryList->cnt;
3397 	} else {
3398 		count = operandLen;
3399 	}
3400 
3401 	for (i = 0; i < count; i++) {
3402 		if (all) {
3403 			veNbr = viewEntryList->ve[i].veIndex;
3404 		} else {
3405 			endPtr = NULL;
3406 			veNbr = strtol(operands[i], &endPtr, 10);
3407 			if (endPtr && *endPtr != 0) {
3408 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
3409 				    operands[i], gettext("invalid input"));
3410 				continue;
3411 			}
3412 		}
3413 		stmfRet = stmfRemoveViewEntry(&inGuid, veNbr);
3414 		switch (stmfRet) {
3415 			case STMF_STATUS_SUCCESS:
3416 				break;
3417 			case STMF_ERROR_NOT_FOUND:
3418 				(void) fprintf(stderr, "%s: %s: %d: %s\n",
3419 				    cmdName, sGuid, veNbr,
3420 				    gettext("not found"));
3421 				ret++;
3422 				break;
3423 			case STMF_ERROR_BUSY:
3424 				(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
3425 				    sGuid, gettext("resource busy"));
3426 				ret++;
3427 				break;
3428 			case STMF_ERROR_SERVICE_NOT_FOUND:
3429 				(void) fprintf(stderr, "%s: %s\n", cmdName,
3430 				    gettext("STMF service not found"));
3431 				ret++;
3432 				break;
3433 			case STMF_ERROR_CONFIG_NONE:
3434 				(void) fprintf(stderr, "%s: %s\n", cmdName,
3435 				    gettext("STMF service is not initialized"));
3436 				ret++;
3437 				break;
3438 			case STMF_ERROR_SERVICE_DATA_VERSION:
3439 				(void) fprintf(stderr, "%s: %s\n", cmdName,
3440 				    gettext("STMF service version incorrect"));
3441 				ret++;
3442 				break;
3443 			default:
3444 				(void) fprintf(stderr, "%s: %s, %d: %s",
3445 				    cmdName, sGuid, veNbr,
3446 				    gettext("unknown error"));
3447 				ret++;
3448 				break;
3449 		}
3450 	}
3451 
3452 	return (ret);
3453 }
3454 
3455 /*
3456  * input:
3457  *  execFullName - exec name of program (argv[0])
3458  *
3459  *  copied from usr/src/cmd/zoneadm/zoneadm.c in OS/Net
3460  *  (changed name to lowerCamelCase to keep consistent with this file)
3461  *
3462  * Returns:
3463  *  command name portion of execFullName
3464  */
3465 static char *
3466 getExecBasename(char *execFullname)
3467 {
3468 	char *lastSlash, *execBasename;
3469 
3470 	/* guard against '/' at end of command invocation */
3471 	for (;;) {
3472 		lastSlash = strrchr(execFullname, '/');
3473 		if (lastSlash == NULL) {
3474 			execBasename = execFullname;
3475 			break;
3476 		} else {
3477 			execBasename = lastSlash + 1;
3478 			if (*execBasename == '\0') {
3479 				*lastSlash = '\0';
3480 				continue;
3481 			}
3482 			break;
3483 		}
3484 	}
3485 	return (execBasename);
3486 }
3487 
3488 int
3489 main(int argc, char *argv[])
3490 {
3491 	synTables_t synTables;
3492 	char versionString[VERSION_STRING_MAX_LEN];
3493 	int ret;
3494 	int funcRet;
3495 	void *subcommandArgs = NULL;
3496 
3497 	(void) setlocale(LC_ALL, "");
3498 	(void) textdomain(TEXT_DOMAIN);
3499 	/* set global command name */
3500 	cmdName = getExecBasename(argv[0]);
3501 
3502 	(void) snprintf(versionString, VERSION_STRING_MAX_LEN, "%s.%s",
3503 	    VERSION_STRING_MAJOR, VERSION_STRING_MINOR);
3504 	synTables.versionString = versionString;
3505 	synTables.longOptionTbl = &longOptions[0];
3506 	synTables.subCommandPropsTbl = &subcommands[0];
3507 
3508 	ret = cmdParse(argc, argv, synTables, subcommandArgs, &funcRet);
3509 	if (ret != 0) {
3510 		return (ret);
3511 	}
3512 
3513 	return (funcRet);
3514 } /* end main */
3515