xref: /onnv-gate/usr/src/cmd/format/menu_scsi.c (revision 7563:84ec90ffc3f7)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7563SPrasad.Singamsetty@Sun.COM  * Common Development and Distribution License (the "License").
6*7563SPrasad.Singamsetty@Sun.COM  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate 
220Sstevel@tonic-gate /*
23*7563SPrasad.Singamsetty@Sun.COM  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate /*
280Sstevel@tonic-gate  * This file contains functions implementing the scsi menu commands.
290Sstevel@tonic-gate  *
300Sstevel@tonic-gate  * These functions are intended for expert use only, and provide
310Sstevel@tonic-gate  * a raw access to a scsi device's mode pages.  The ability to
320Sstevel@tonic-gate  * issue a raw format command is also provided, should a page be
330Sstevel@tonic-gate  * changed that requires a format.
340Sstevel@tonic-gate  */
350Sstevel@tonic-gate #include "global.h"
360Sstevel@tonic-gate #include <stdlib.h>
370Sstevel@tonic-gate #include <ctype.h>
380Sstevel@tonic-gate 
390Sstevel@tonic-gate #include "io.h"
400Sstevel@tonic-gate #include "menu.h"
410Sstevel@tonic-gate #include "misc.h"
420Sstevel@tonic-gate #include "menu_scsi.h"
430Sstevel@tonic-gate #include "ctlr_scsi.h"
440Sstevel@tonic-gate #include "startup.h"
45767Ssjelinek #include "checkdev.h"
460Sstevel@tonic-gate 
470Sstevel@tonic-gate 
480Sstevel@tonic-gate #ifdef	__STDC__
490Sstevel@tonic-gate /*
500Sstevel@tonic-gate  *	ANSI prototypes for local static functions
510Sstevel@tonic-gate  */
520Sstevel@tonic-gate static int	do_mode_sense(int);
530Sstevel@tonic-gate static int	do_mode_sense_all(void);
540Sstevel@tonic-gate static int	do_mode_select(struct chg_list *);
550Sstevel@tonic-gate static int	do_format(void);
560Sstevel@tonic-gate static void	do_list(void);
570Sstevel@tonic-gate static int	do_inquiry(void);
580Sstevel@tonic-gate static void	do_apply(void);
590Sstevel@tonic-gate static void	do_cancel(void);
600Sstevel@tonic-gate static void	do_display(void);
610Sstevel@tonic-gate static int	parse_change_spec(char *, char *, int, struct chg_list *);
620Sstevel@tonic-gate static void	add_new_change_list_item(struct chg_list *);
630Sstevel@tonic-gate static void	free_change_list(void);
640Sstevel@tonic-gate static void	do_default(char *);
650Sstevel@tonic-gate static void	default_all_pages(void);
660Sstevel@tonic-gate static int	default_page(int);
670Sstevel@tonic-gate #else
680Sstevel@tonic-gate static int	do_mode_sense();
690Sstevel@tonic-gate static int	do_mode_sense_all();
700Sstevel@tonic-gate static int	do_mode_select();
710Sstevel@tonic-gate static int	do_format();
720Sstevel@tonic-gate static void	do_list();
730Sstevel@tonic-gate static int	do_inquiry();
740Sstevel@tonic-gate static void	do_apply();
750Sstevel@tonic-gate static void	do_cancel();
760Sstevel@tonic-gate static void	do_display();
770Sstevel@tonic-gate static int	parse_change_spec();
780Sstevel@tonic-gate static void	add_new_change_list_item();
790Sstevel@tonic-gate static void	free_change_list();
800Sstevel@tonic-gate static void	do_default();
810Sstevel@tonic-gate static void	default_all_pages();
820Sstevel@tonic-gate static int	default_page();
830Sstevel@tonic-gate #endif	/* __STDC__ */
840Sstevel@tonic-gate 
850Sstevel@tonic-gate 
860Sstevel@tonic-gate /*
870Sstevel@tonic-gate  * Menu data for the SCSI menu display
880Sstevel@tonic-gate  */
890Sstevel@tonic-gate static char	*scsi_menu_strings[] = {
900Sstevel@tonic-gate 	"p<n>                   - display a mode sense page",
910Sstevel@tonic-gate 	"p<n> b<n> <op> [~]<n>  - change a byte and issue mode select",
920Sstevel@tonic-gate 	"b<n> <op> [~]<n>       - add an operation to the mode select list",
930Sstevel@tonic-gate 	"                             for the current page",
940Sstevel@tonic-gate 	"",
950Sstevel@tonic-gate 	"        where:  p<n> specifies the page with page code <n>",
960Sstevel@tonic-gate 	"                b<n> specifies byte <n> of the page",
970Sstevel@tonic-gate 	"                <op> can be one of the following operators:",
980Sstevel@tonic-gate 	"                     =    (set specified value)",
990Sstevel@tonic-gate 	"                     |=   (bitwise OR with current value)",
1000Sstevel@tonic-gate 	"                     &=   (bitwise AND with current value)",
1010Sstevel@tonic-gate 	"                <n> can be a decimal value in the range 0-255,",
1020Sstevel@tonic-gate 	"                or two hexadecimal digits, in the form 0x<xx>.",
1030Sstevel@tonic-gate 	"                [~] complements the specified value",
1040Sstevel@tonic-gate 	"",
1050Sstevel@tonic-gate 	"apply                  - apply mode select list",
1060Sstevel@tonic-gate 	"cancel                 - cancel mode select list",
1070Sstevel@tonic-gate 	"display                - display mode select list",
1080Sstevel@tonic-gate 	"all                    - display all supported mode sense pages",
1090Sstevel@tonic-gate 	"default p<n>           - mode select page <n> to default values",
1100Sstevel@tonic-gate 	"default all            - mode select all pages to default values",
1110Sstevel@tonic-gate 	"format                 - format without standard mode selects",
1120Sstevel@tonic-gate 	"inquiry                - display device's inquiry response",
1130Sstevel@tonic-gate 	"list                   - list common SCSI-2 mode pages",
1140Sstevel@tonic-gate 	"!<cmd>                 - execute <cmd> , then return"
1150Sstevel@tonic-gate };
1160Sstevel@tonic-gate 
1170Sstevel@tonic-gate #define	N_SCSI_STRINGS	(sizeof (scsi_menu_strings) / sizeof (char *))
1180Sstevel@tonic-gate 
1190Sstevel@tonic-gate /*
1200Sstevel@tonic-gate  * Command types
1210Sstevel@tonic-gate  */
1220Sstevel@tonic-gate #define	CMD_ALL			0
1230Sstevel@tonic-gate #define	CMD_FORMAT		1
1240Sstevel@tonic-gate #define	CMD_QUIT		2
1250Sstevel@tonic-gate #define	CMD_HELP		3
1260Sstevel@tonic-gate #define	CMD_LIST		4
1270Sstevel@tonic-gate #define	CMD_INQUIRY		5
1280Sstevel@tonic-gate #define	CMD_APPLY		6
1290Sstevel@tonic-gate #define	CMD_CANCEL		7
1300Sstevel@tonic-gate #define	CMD_DISPLAY		8
1310Sstevel@tonic-gate 
1320Sstevel@tonic-gate /*
1330Sstevel@tonic-gate  * SCSI menu commands for minimum recognition
1340Sstevel@tonic-gate  */
1350Sstevel@tonic-gate static struct slist	cmds_list[] = {
1360Sstevel@tonic-gate 	{ "all",	NULL,	CMD_ALL },
1370Sstevel@tonic-gate 	{ "format",	NULL,	CMD_FORMAT },
1380Sstevel@tonic-gate 	{ "quit",	NULL,	CMD_QUIT },
1390Sstevel@tonic-gate 	{ "help",	NULL,	CMD_HELP },
1400Sstevel@tonic-gate 	{ "?",		NULL,	CMD_HELP },
1410Sstevel@tonic-gate 	{ "list",	NULL,	CMD_LIST },
1420Sstevel@tonic-gate 	{ "inquiry",	NULL,	CMD_INQUIRY },
1430Sstevel@tonic-gate 	{ "apply",	NULL,	CMD_APPLY },
1440Sstevel@tonic-gate 	{ "cancel",	NULL,	CMD_CANCEL },
1450Sstevel@tonic-gate 	{ "display",	NULL,	CMD_DISPLAY },
1460Sstevel@tonic-gate 	{ NULL	}
1470Sstevel@tonic-gate };
1480Sstevel@tonic-gate 
1490Sstevel@tonic-gate /*
1500Sstevel@tonic-gate  * Implied page for mode select change lists
1510Sstevel@tonic-gate  */
1520Sstevel@tonic-gate static	int		current_page;
1530Sstevel@tonic-gate static	struct chg_list	*change_list;
1540Sstevel@tonic-gate 
1550Sstevel@tonic-gate /*
1560Sstevel@tonic-gate  * Manage the SCSI menu.
1570Sstevel@tonic-gate  * Parse input and dispatch to the appropriate functions.
1580Sstevel@tonic-gate  * The commands we accept are not simple one-word commands,
1590Sstevel@tonic-gate  * so we cannot use the standard format menu-handling functions.
1600Sstevel@tonic-gate  */
1610Sstevel@tonic-gate int
c_scsi()1620Sstevel@tonic-gate c_scsi()
1630Sstevel@tonic-gate {
1640Sstevel@tonic-gate 	int			i;
1650Sstevel@tonic-gate 	struct env		env;
1660Sstevel@tonic-gate 	char			**menu;
1670Sstevel@tonic-gate 	struct menu_item	scsi_menu[N_SCSI_STRINGS+1];
1680Sstevel@tonic-gate 	struct chg_list		change_item;
1690Sstevel@tonic-gate 	struct chg_list		*chg_item;
1700Sstevel@tonic-gate 	char			s[MAXPATHLEN], nclean[MAXPATHLEN];
1710Sstevel@tonic-gate 	char			*p;
1720Sstevel@tonic-gate 	char			*p2;
1730Sstevel@tonic-gate 	int			cmd;
1740Sstevel@tonic-gate 	int			pageno;
1750Sstevel@tonic-gate 	int			help = 1;
1760Sstevel@tonic-gate 
1770Sstevel@tonic-gate 	/*
1780Sstevel@tonic-gate 	 * Warn casual users that maybe they should not be
1790Sstevel@tonic-gate 	 * using this menu.
1800Sstevel@tonic-gate 	 */
1810Sstevel@tonic-gate 	fmt_print("\n"
1820Sstevel@tonic-gate "Warning:  these functions are intended for expert use only, for\n"
1830Sstevel@tonic-gate "debugging disk devices and for unusual configuration settings.\n"
1840Sstevel@tonic-gate "It is recommended that you do not use this menu for normal disk\n"
1850Sstevel@tonic-gate "configuration and formatting, unless you have explicit instructions,\n"
1860Sstevel@tonic-gate "or know exactly what you are doing.\n");
1870Sstevel@tonic-gate 
1880Sstevel@tonic-gate 	/*
1890Sstevel@tonic-gate 	 * Initialize change list and current page to empty
1900Sstevel@tonic-gate 	 */
1910Sstevel@tonic-gate 	current_page = -1;
1920Sstevel@tonic-gate 	change_list = NULL;
1930Sstevel@tonic-gate 
1940Sstevel@tonic-gate 	/*
1950Sstevel@tonic-gate 	 * Build and display the menu.
1960Sstevel@tonic-gate 	 * we only use this for display purposes.
1970Sstevel@tonic-gate 	 */
1980Sstevel@tonic-gate 	for (i = 0; i < N_SCSI_STRINGS; i++) {
1990Sstevel@tonic-gate 		scsi_menu[i].menu_cmd = scsi_menu_strings[i];
2000Sstevel@tonic-gate 		scsi_menu[i].menu_func = NULL;
2010Sstevel@tonic-gate 		scsi_menu[i].menu_state = true;
2020Sstevel@tonic-gate 	}
2030Sstevel@tonic-gate 	scsi_menu[i].menu_cmd = NULL;
2040Sstevel@tonic-gate 	menu = create_menu_list(scsi_menu);
2050Sstevel@tonic-gate 	/*
2060Sstevel@tonic-gate 	 * Save the environment so a ctrl-C out of a command lands here.
2070Sstevel@tonic-gate 	 */
2080Sstevel@tonic-gate 	saveenv(env);
2090Sstevel@tonic-gate 	for (;;) {
2100Sstevel@tonic-gate 		if (help) {
2110Sstevel@tonic-gate 			help = 0;
2120Sstevel@tonic-gate 			fmt_print("\n\nSCSI MENU:\n");
2130Sstevel@tonic-gate 			display_menu_list(menu);
2140Sstevel@tonic-gate 		}
2150Sstevel@tonic-gate 		/*
2160Sstevel@tonic-gate 		 * Prompt and get next input line.  We don't use the
2170Sstevel@tonic-gate 		 * standard input routine, since we need a little
2180Sstevel@tonic-gate 		 * more flexibility in parsing the input.
2190Sstevel@tonic-gate 		 */
2200Sstevel@tonic-gate 		fmt_print("scsi> ");
2210Sstevel@tonic-gate 		get_inputline(nclean, sizeof (nclean));
2220Sstevel@tonic-gate 
2230Sstevel@tonic-gate 		clean_token(s, nclean);
2240Sstevel@tonic-gate 
2250Sstevel@tonic-gate 		/*
2260Sstevel@tonic-gate 		 * Mark the saved environment active so the user can now
2270Sstevel@tonic-gate 		 * do a ctrl-C to get out of the command.
2280Sstevel@tonic-gate 		 */
2290Sstevel@tonic-gate 		useenv();
2300Sstevel@tonic-gate 
2310Sstevel@tonic-gate 		/*
2320Sstevel@tonic-gate 		 * Figure out what the user chose
2330Sstevel@tonic-gate 		 */
2340Sstevel@tonic-gate 		i = find_value(cmds_list, s, &cmd);
2350Sstevel@tonic-gate 		if (i == 1) {
2360Sstevel@tonic-gate 			switch (cmd) {
2370Sstevel@tonic-gate 			case CMD_ALL:
2380Sstevel@tonic-gate 				(void) do_mode_sense_all();
2390Sstevel@tonic-gate 				break;
2400Sstevel@tonic-gate 			case CMD_FORMAT:
2410Sstevel@tonic-gate 				(void) do_format();
2420Sstevel@tonic-gate 				break;
2430Sstevel@tonic-gate 			case CMD_QUIT:
2440Sstevel@tonic-gate 				goto exit;
2450Sstevel@tonic-gate 				/*NOTREACHED*/
2460Sstevel@tonic-gate 			case CMD_HELP:
2470Sstevel@tonic-gate 				fmt_print("\n\nSCSI MENU:\n");
2480Sstevel@tonic-gate 				display_menu_list(menu);
2490Sstevel@tonic-gate 				break;
2500Sstevel@tonic-gate 			case CMD_LIST:
2510Sstevel@tonic-gate 				do_list();
2520Sstevel@tonic-gate 				break;
2530Sstevel@tonic-gate 			case CMD_INQUIRY:
2540Sstevel@tonic-gate 				(void) do_inquiry();
2550Sstevel@tonic-gate 				break;
2560Sstevel@tonic-gate 			case CMD_APPLY:
2570Sstevel@tonic-gate 				do_apply();
2580Sstevel@tonic-gate 				break;
2590Sstevel@tonic-gate 			case CMD_CANCEL:
2600Sstevel@tonic-gate 				do_cancel();
2610Sstevel@tonic-gate 				break;
2620Sstevel@tonic-gate 			case CMD_DISPLAY:
2630Sstevel@tonic-gate 				do_display();
2640Sstevel@tonic-gate 				break;
2650Sstevel@tonic-gate 			}
2660Sstevel@tonic-gate 		} else if (s[0] == 'd') {
2670Sstevel@tonic-gate 			do_default(s);
2680Sstevel@tonic-gate 		} else if (s[0] == 'p') {
2690Sstevel@tonic-gate 			p = s + 1;
2700Sstevel@tonic-gate 			pageno = (int)strtol(p, &p2, 0);
2710Sstevel@tonic-gate 			if (p2 == p) {
2720Sstevel@tonic-gate 				err_print("Syntax error: %s\n", s);
2730Sstevel@tonic-gate 				goto error;
2740Sstevel@tonic-gate 			}
2750Sstevel@tonic-gate 			current_page = pageno;
2760Sstevel@tonic-gate 			for (p = p2; *p == ' '; p++)
2770Sstevel@tonic-gate 				;
2780Sstevel@tonic-gate 			if (*p == 0) {
2790Sstevel@tonic-gate 				(void) do_mode_sense(pageno);
2800Sstevel@tonic-gate 			} else if (*p == 'b') {
2810Sstevel@tonic-gate 				if (parse_change_spec(s, p, pageno,
282*7563SPrasad.Singamsetty@Sun.COM 				    &change_item)) {
2830Sstevel@tonic-gate 					(void) do_mode_select(&change_item);
2840Sstevel@tonic-gate 				}
2850Sstevel@tonic-gate 			}
2860Sstevel@tonic-gate 		} else if (s[0] == 'b') {
2870Sstevel@tonic-gate 				if (current_page == -1) {
2880Sstevel@tonic-gate 					err_print("\
2890Sstevel@tonic-gate Please display the page on which you'd like to do a mode select\n");
2900Sstevel@tonic-gate 					goto error;
2910Sstevel@tonic-gate 				}
2920Sstevel@tonic-gate 				chg_item = (struct chg_list *)
293*7563SPrasad.Singamsetty@Sun.COM 				    zalloc(sizeof (struct chg_list));
2940Sstevel@tonic-gate 				if (parse_change_spec(s, s, current_page,
295*7563SPrasad.Singamsetty@Sun.COM 				    chg_item)) {
2960Sstevel@tonic-gate 					add_new_change_list_item(chg_item);
2970Sstevel@tonic-gate 				} else {
2980Sstevel@tonic-gate 					destroy_data((char *)chg_item);
2990Sstevel@tonic-gate 				}
3000Sstevel@tonic-gate 		} else if (s[0] == '!') {
3011383Spr131582 			(void) execute_shell(&s[1], sizeof (s) - 1);
3020Sstevel@tonic-gate 			help = 1;
3030Sstevel@tonic-gate 		} else if (s[0] != 0) {
3040Sstevel@tonic-gate 			err_print("Syntax error: %s\n", s);
3050Sstevel@tonic-gate 		}
3060Sstevel@tonic-gate error:
3070Sstevel@tonic-gate 		/*
3080Sstevel@tonic-gate 		 * Mark the saved environment inactive so ctrl-C doesn't
3090Sstevel@tonic-gate 		 * work at the menu itself.
3100Sstevel@tonic-gate 		 */
3110Sstevel@tonic-gate 		unuseenv();
3120Sstevel@tonic-gate 	}
3130Sstevel@tonic-gate exit:
3140Sstevel@tonic-gate 	/*
3150Sstevel@tonic-gate 	 * Clean up the environment stack and free the menu
3160Sstevel@tonic-gate 	 */
3170Sstevel@tonic-gate 	clearenv();
3180Sstevel@tonic-gate 	destroy_data((char *)menu);
3190Sstevel@tonic-gate 
3200Sstevel@tonic-gate 	/*
3210Sstevel@tonic-gate 	 * Clean up the change list, if anything left over
3220Sstevel@tonic-gate 	 */
3230Sstevel@tonic-gate 	free_change_list();
3240Sstevel@tonic-gate 
3250Sstevel@tonic-gate 	/*
3260Sstevel@tonic-gate 	 * Make sure user is prompted with previous menu
3270Sstevel@tonic-gate 	 */
3280Sstevel@tonic-gate 	last_menu++;
3290Sstevel@tonic-gate 
3300Sstevel@tonic-gate 	return (0);
3310Sstevel@tonic-gate }
3320Sstevel@tonic-gate 
3330Sstevel@tonic-gate 
3340Sstevel@tonic-gate /*
3350Sstevel@tonic-gate  * Do a mode sense on a particular page, and dump the data.
3360Sstevel@tonic-gate  * Get all the various flavors:  default, current, saved, changeable.
3370Sstevel@tonic-gate  */
3380Sstevel@tonic-gate static int
do_mode_sense(pageno)3390Sstevel@tonic-gate do_mode_sense(pageno)
3400Sstevel@tonic-gate 	int	pageno;
3410Sstevel@tonic-gate {
3420Sstevel@tonic-gate 	struct scsi_ms_header	header;
3430Sstevel@tonic-gate 	struct mode_page	*pg;
3440Sstevel@tonic-gate 	char			msbuf[MAX_MODE_SENSE_SIZE];
3450Sstevel@tonic-gate 	int			result = 0;
3460Sstevel@tonic-gate 
3470Sstevel@tonic-gate 	char	*default_msg	= "default:     ";
3480Sstevel@tonic-gate 	char	*saved_msg	= "saved:       ";
3490Sstevel@tonic-gate 	char	*current_msg	= "current:     ";
3500Sstevel@tonic-gate 	char	*changeable_msg	= "changeable:  ";
3510Sstevel@tonic-gate 
3520Sstevel@tonic-gate 
3530Sstevel@tonic-gate 	pg = (struct mode_page *)msbuf;
3540Sstevel@tonic-gate 
3550Sstevel@tonic-gate 	fmt_print("\nPage 0x%x:\n", pageno);
3560Sstevel@tonic-gate 	if (uscsi_mode_sense(cur_file, pageno, MODE_SENSE_PC_DEFAULT,
3570Sstevel@tonic-gate 			msbuf, MAX_MODE_SENSE_SIZE, &header)) {
3580Sstevel@tonic-gate 		err_print("%sfailed\n", default_msg);
3590Sstevel@tonic-gate 		result = 1;
3600Sstevel@tonic-gate 	} else {
3610Sstevel@tonic-gate 		dump(default_msg, msbuf, MODESENSE_PAGE_LEN(pg),
3620Sstevel@tonic-gate 			HEX_ONLY);
3630Sstevel@tonic-gate 	}
3640Sstevel@tonic-gate 
3650Sstevel@tonic-gate 	if (uscsi_mode_sense(cur_file, pageno, MODE_SENSE_PC_CURRENT,
3660Sstevel@tonic-gate 			msbuf, MAX_MODE_SENSE_SIZE, &header)) {
3670Sstevel@tonic-gate 		err_print("%sfailed\n", current_msg);
3680Sstevel@tonic-gate 		result = 1;
3690Sstevel@tonic-gate 	} else {
3700Sstevel@tonic-gate 		dump(current_msg, msbuf, MODESENSE_PAGE_LEN(pg),
3710Sstevel@tonic-gate 			HEX_ONLY);
3720Sstevel@tonic-gate 	}
3730Sstevel@tonic-gate 
3740Sstevel@tonic-gate 	if (uscsi_mode_sense(cur_file, pageno, MODE_SENSE_PC_SAVED,
3750Sstevel@tonic-gate 			msbuf, MAX_MODE_SENSE_SIZE, &header)) {
3760Sstevel@tonic-gate 		err_print("%sfailed\n", saved_msg);
3770Sstevel@tonic-gate 		result = 1;
3780Sstevel@tonic-gate 	} else {
3790Sstevel@tonic-gate 		dump(saved_msg, msbuf, MODESENSE_PAGE_LEN(pg),
3800Sstevel@tonic-gate 			HEX_ONLY);
3810Sstevel@tonic-gate 	}
3820Sstevel@tonic-gate 
3830Sstevel@tonic-gate 	if (uscsi_mode_sense(cur_file, pageno, MODE_SENSE_PC_CHANGEABLE,
3840Sstevel@tonic-gate 			msbuf, MAX_MODE_SENSE_SIZE, &header)) {
3850Sstevel@tonic-gate 		err_print("%sfailed\n", changeable_msg);
3860Sstevel@tonic-gate 		result = 1;
3870Sstevel@tonic-gate 	} else {
3880Sstevel@tonic-gate 		dump(changeable_msg, msbuf, MODESENSE_PAGE_LEN(pg),
3890Sstevel@tonic-gate 			HEX_ONLY);
3900Sstevel@tonic-gate 	}
3910Sstevel@tonic-gate 
3920Sstevel@tonic-gate 	fmt_print("\n");
3930Sstevel@tonic-gate 	return (result);
3940Sstevel@tonic-gate }
3950Sstevel@tonic-gate 
3960Sstevel@tonic-gate 
3970Sstevel@tonic-gate /*
3980Sstevel@tonic-gate  * Dump all the pages a device supports
3990Sstevel@tonic-gate  */
4000Sstevel@tonic-gate static int
do_mode_sense_all()4010Sstevel@tonic-gate do_mode_sense_all()
4020Sstevel@tonic-gate {
4030Sstevel@tonic-gate 	int	result = 0;
4040Sstevel@tonic-gate 
4050Sstevel@tonic-gate 	if (scsi_dump_mode_sense_pages(MODE_SENSE_PC_DEFAULT)) {
4060Sstevel@tonic-gate 		result = 1;
4070Sstevel@tonic-gate 	}
4080Sstevel@tonic-gate 	if (scsi_dump_mode_sense_pages(MODE_SENSE_PC_CURRENT)) {
4090Sstevel@tonic-gate 		result = 1;
4100Sstevel@tonic-gate 	}
4110Sstevel@tonic-gate 	if (scsi_dump_mode_sense_pages(MODE_SENSE_PC_SAVED)) {
4120Sstevel@tonic-gate 		result = 1;
4130Sstevel@tonic-gate 	}
4140Sstevel@tonic-gate 	if (scsi_dump_mode_sense_pages(MODE_SENSE_PC_CHANGEABLE)) {
4150Sstevel@tonic-gate 		result = 1;
4160Sstevel@tonic-gate 	}
4170Sstevel@tonic-gate 	fmt_print("\n");
4180Sstevel@tonic-gate 	return (result);
4190Sstevel@tonic-gate }
4200Sstevel@tonic-gate 
4210Sstevel@tonic-gate 
4220Sstevel@tonic-gate /*
4230Sstevel@tonic-gate  * Get the current mode sense for a particular page, change
4240Sstevel@tonic-gate  * a byte, and issue a mode select.  Note that we can only
4250Sstevel@tonic-gate  * change a value if the device indicates that those bits
4260Sstevel@tonic-gate  * are changeable.
4270Sstevel@tonic-gate  */
4280Sstevel@tonic-gate static int
do_mode_select(change_item)4290Sstevel@tonic-gate do_mode_select(change_item)
4300Sstevel@tonic-gate 	struct chg_list	*change_item;
4310Sstevel@tonic-gate {
4320Sstevel@tonic-gate 	struct scsi_ms_header	header;
4330Sstevel@tonic-gate 	char			saved[MAX_MODE_SENSE_SIZE];
4340Sstevel@tonic-gate 	char			changeable[MAX_MODE_SENSE_SIZE];
4350Sstevel@tonic-gate 	struct mode_page	*pg;
4360Sstevel@tonic-gate 	struct mode_page	*pg2;
4370Sstevel@tonic-gate 	int			length;
4380Sstevel@tonic-gate 	int			pageno;
4390Sstevel@tonic-gate 	int			flags;
4400Sstevel@tonic-gate 	int			result = 0;
4410Sstevel@tonic-gate 
4420Sstevel@tonic-gate 	pageno = change_item->pageno;
4430Sstevel@tonic-gate 
4440Sstevel@tonic-gate 	/*
4450Sstevel@tonic-gate 	 * Get changeable mode sense
4460Sstevel@tonic-gate 	 */
4470Sstevel@tonic-gate 	if (uscsi_mode_sense(cur_file, pageno, MODE_SENSE_PC_CHANGEABLE,
4480Sstevel@tonic-gate 			changeable, MAX_MODE_SENSE_SIZE, &header)) {
4490Sstevel@tonic-gate 		err_print("Mode sense on page %x (changeable) failed\n",
4500Sstevel@tonic-gate 			pageno);
4510Sstevel@tonic-gate 		return (1);
4520Sstevel@tonic-gate 	}
4530Sstevel@tonic-gate 
4540Sstevel@tonic-gate 	/*
4550Sstevel@tonic-gate 	 * Get saved mode sense.  If saved fails, use current values.
4560Sstevel@tonic-gate 	 */
4570Sstevel@tonic-gate 	if (uscsi_mode_sense(cur_file, pageno, MODE_SENSE_PC_SAVED,
4580Sstevel@tonic-gate 			saved, MAX_MODE_SENSE_SIZE, &header)) {
4590Sstevel@tonic-gate 		err_print("Mode sense on page %x (saved) failed\n",
4600Sstevel@tonic-gate 			pageno);
4610Sstevel@tonic-gate 		if (uscsi_mode_sense(cur_file, pageno, MODE_SENSE_PC_CURRENT,
4620Sstevel@tonic-gate 				saved, MAX_MODE_SENSE_SIZE, &header)) {
4630Sstevel@tonic-gate 			err_print("Mode sense on page %x (current) failed\n",
4640Sstevel@tonic-gate 				pageno);
4650Sstevel@tonic-gate 			return (1);
4660Sstevel@tonic-gate 		} else {
4670Sstevel@tonic-gate 			err_print("Using current values instead\n");
4680Sstevel@tonic-gate 		}
4690Sstevel@tonic-gate 	}
4700Sstevel@tonic-gate 
4710Sstevel@tonic-gate 	/*
4720Sstevel@tonic-gate 	 * Use the intersection of the saved and changeable
4730Sstevel@tonic-gate 	 */
4740Sstevel@tonic-gate 	pg = (struct mode_page *)saved;
4750Sstevel@tonic-gate 	pg2 = (struct mode_page *)changeable;
4760Sstevel@tonic-gate 	length = min(MODESENSE_PAGE_LEN(pg), MODESENSE_PAGE_LEN(pg2));
4770Sstevel@tonic-gate 
4780Sstevel@tonic-gate 	/*
4790Sstevel@tonic-gate 	 * Try making this change to this page
4800Sstevel@tonic-gate 	 */
4810Sstevel@tonic-gate 	if (apply_chg_list(pageno, length, (uchar_t *)saved,
4820Sstevel@tonic-gate 			(uchar_t *)changeable, change_item)) {
4830Sstevel@tonic-gate 		/*
4840Sstevel@tonic-gate 		 * A change was made.  Do a mode select
4850Sstevel@tonic-gate 		 * We always want to set the Page Format bit.
4860Sstevel@tonic-gate 		 * Set the Save Page bit if the drive indicates
4870Sstevel@tonic-gate 		 * that it can save this page.
4880Sstevel@tonic-gate 		 */
4890Sstevel@tonic-gate 		flags = MODE_SELECT_PF;
4900Sstevel@tonic-gate 		if (pg->ps) {
4910Sstevel@tonic-gate 			flags |= MODE_SELECT_SP;
4920Sstevel@tonic-gate 		}
4930Sstevel@tonic-gate 		pg->ps = 0;
4940Sstevel@tonic-gate 		header.mode_header.length = 0;
4950Sstevel@tonic-gate 		header.mode_header.device_specific = 0;
4960Sstevel@tonic-gate 		if (uscsi_mode_select(cur_file, pageno, flags,
4970Sstevel@tonic-gate 				saved, length, &header)) {
4980Sstevel@tonic-gate 			/*
4990Sstevel@tonic-gate 			 * Failed - try not saving parameters,
5000Sstevel@tonic-gate 			 * if possible.
5010Sstevel@tonic-gate 			 */
5020Sstevel@tonic-gate 			if (flags & MODE_SELECT_SP) {
5030Sstevel@tonic-gate 				flags &= ~MODE_SELECT_SP;
5040Sstevel@tonic-gate 				if (uscsi_mode_select(cur_file, pageno,
5050Sstevel@tonic-gate 						flags, saved,
5060Sstevel@tonic-gate 						length, &header)) {
5070Sstevel@tonic-gate 					result = 1;
5080Sstevel@tonic-gate 				}
5090Sstevel@tonic-gate 			} else {
5100Sstevel@tonic-gate 				result = 1;
5110Sstevel@tonic-gate 			}
5120Sstevel@tonic-gate 		}
5130Sstevel@tonic-gate 
5140Sstevel@tonic-gate 		if (result) {
5150Sstevel@tonic-gate 			fmt_print("\n\
5160Sstevel@tonic-gate Mode select on page %x failed.\n", pageno);
5170Sstevel@tonic-gate 		} else if ((flags & MODE_SELECT_SP) == 0) {
5180Sstevel@tonic-gate 			fmt_print("\n\
5190Sstevel@tonic-gate Mode select on page %x ok, but unable to save change permanently.\n", pageno);
5200Sstevel@tonic-gate 		} else {
5210Sstevel@tonic-gate 			fmt_print("\n\
5220Sstevel@tonic-gate Mode select on page %x ok.\n", pageno);
5230Sstevel@tonic-gate 		}
5240Sstevel@tonic-gate 	} else {
5250Sstevel@tonic-gate 		err_print("\nDevice cannot support this change\n");
5260Sstevel@tonic-gate 	}
5270Sstevel@tonic-gate 
5280Sstevel@tonic-gate 	fmt_print("\n");
5290Sstevel@tonic-gate 	return (result);
5300Sstevel@tonic-gate }
5310Sstevel@tonic-gate 
5320Sstevel@tonic-gate 
5330Sstevel@tonic-gate /*
5340Sstevel@tonic-gate  * Format a device, without any of the standard mode selects.
5350Sstevel@tonic-gate  * Ask if we should format with the P or the P&G lists.
5360Sstevel@tonic-gate  */
5370Sstevel@tonic-gate static int
do_format()5380Sstevel@tonic-gate do_format()
5390Sstevel@tonic-gate {
5400Sstevel@tonic-gate 	struct uscsi_cmd	ucmd;
5410Sstevel@tonic-gate 	union scsi_cdb		cdb;
5420Sstevel@tonic-gate 	struct scsi_defect_hdr	defect_hdr;
5430Sstevel@tonic-gate 	int			status;
5440Sstevel@tonic-gate 	u_ioparam_t		ioparam;
5450Sstevel@tonic-gate 	int			deflt;
5460Sstevel@tonic-gate 	int			grown_list;
5470Sstevel@tonic-gate 
5480Sstevel@tonic-gate 	fmt_print("\n");
5490Sstevel@tonic-gate 	/*
5500Sstevel@tonic-gate 	 * Are there mounted partitions?
5510Sstevel@tonic-gate 	 */
552*7563SPrasad.Singamsetty@Sun.COM 	if (checkmount((diskaddr_t)-1, (diskaddr_t)-1)) {
5530Sstevel@tonic-gate 		err_print("Cannot format disk with mounted partitions\n\n");
5540Sstevel@tonic-gate 		return (-1);
5550Sstevel@tonic-gate 	}
5560Sstevel@tonic-gate 
5570Sstevel@tonic-gate 	/*
5580Sstevel@tonic-gate 	 * Is any of the partitions being used for swapping.
5590Sstevel@tonic-gate 	 */
560*7563SPrasad.Singamsetty@Sun.COM 	if (checkswap((diskaddr_t)-1, (diskaddr_t)-1)) {
5610Sstevel@tonic-gate 		err_print("Cannot format disk while its partitions are \
5620Sstevel@tonic-gate currently being used for swapping.\n\n");
5630Sstevel@tonic-gate 		return (-1);
5640Sstevel@tonic-gate 	}
565767Ssjelinek 	/*
566767Ssjelinek 	 * Are any being used for SVM, VxVM or live upgrade.
567767Ssjelinek 	 */
568767Ssjelinek 	if (checkdevinuse(cur_disk->disk_name, (diskaddr_t)-1,
569767Ssjelinek 	    (diskaddr_t)-1, 0, 0)) {
570767Ssjelinek 		err_print("Cannot format disk while its partitions are "
571767Ssjelinek 		    "currently being used as described.\n");
572767Ssjelinek 		return (-1);
573767Ssjelinek 	}
5740Sstevel@tonic-gate 
5750Sstevel@tonic-gate 	/*
5760Sstevel@tonic-gate 	 * Let the user choose between formatting with either
5770Sstevel@tonic-gate 	 * the P, or the P&G lists.  Note that yes is 0, no is 1.
5780Sstevel@tonic-gate 	 */
5790Sstevel@tonic-gate 	deflt = 0;
5800Sstevel@tonic-gate 	ioparam.io_charlist = confirm_list;
5810Sstevel@tonic-gate 	grown_list = !input(FIO_MSTR, "Format with the Grown Defects list",
582*7563SPrasad.Singamsetty@Sun.COM 	    '?', &ioparam, &deflt, DATA_INPUT);
5830Sstevel@tonic-gate 
5840Sstevel@tonic-gate 	/*
5850Sstevel@tonic-gate 	 * Construct the uscsi format ioctl.
5860Sstevel@tonic-gate 	 * To format with the P and G list, we set the fmtData
5870Sstevel@tonic-gate 	 * and cmpLst bits to zero.  To format with just the
5880Sstevel@tonic-gate 	 * P list, we set the fmtData bit (meaning that we will
5890Sstevel@tonic-gate 	 * send down a defect list in the data phase) and the
5900Sstevel@tonic-gate 	 * cmpLst bit (meaning that the list we send is the
5910Sstevel@tonic-gate 	 * complete G list), and a defect list header with
5920Sstevel@tonic-gate 	 * a defect list length of zero.
5930Sstevel@tonic-gate 	 */
5940Sstevel@tonic-gate 	(void) memset((char *)&ucmd, 0, sizeof (ucmd));
5950Sstevel@tonic-gate 	(void) memset((char *)&cdb, 0, sizeof (union scsi_cdb));
5960Sstevel@tonic-gate 	cdb.scc_cmd = SCMD_FORMAT;
5970Sstevel@tonic-gate 	ucmd.uscsi_cdb = (caddr_t)&cdb;
5980Sstevel@tonic-gate 	ucmd.uscsi_cdblen = CDB_GROUP0;
5990Sstevel@tonic-gate 	if (!grown_list) {
6000Sstevel@tonic-gate 		/*
6010Sstevel@tonic-gate 		 * No G list.   Send empty defect list to replace it.
6020Sstevel@tonic-gate 		 */
6030Sstevel@tonic-gate 		cdb.cdb_opaque[1] = FPB_DATA | FPB_CMPLT | FPB_BFI;
6040Sstevel@tonic-gate 		(void) memset((char *)&defect_hdr, 0, sizeof (defect_hdr));
6050Sstevel@tonic-gate 		ucmd.uscsi_bufaddr = (caddr_t)&defect_hdr;
6060Sstevel@tonic-gate 		ucmd.uscsi_buflen = sizeof (defect_hdr);
6070Sstevel@tonic-gate 	}
6080Sstevel@tonic-gate 
6090Sstevel@tonic-gate 	/*
6100Sstevel@tonic-gate 	 * Issue the format ioctl
6110Sstevel@tonic-gate 	 */
6120Sstevel@tonic-gate 	fmt_print("Formatting...\n");
6130Sstevel@tonic-gate 	(void) fflush(stdout);
6140Sstevel@tonic-gate 	status = uscsi_cmd(cur_file, &ucmd, F_NORMAL);
6150Sstevel@tonic-gate 	fmt_print(status ? "Format failed\n\n" : "Format ok\n\n");
6160Sstevel@tonic-gate 	return (status);
6170Sstevel@tonic-gate }
6180Sstevel@tonic-gate 
6190Sstevel@tonic-gate 
6200Sstevel@tonic-gate /*
6210Sstevel@tonic-gate  * List common SCSI-2 mode pages
6220Sstevel@tonic-gate  */
6230Sstevel@tonic-gate static void
do_list()6240Sstevel@tonic-gate do_list()
6250Sstevel@tonic-gate {
6260Sstevel@tonic-gate 	fmt_print("\n\
6270Sstevel@tonic-gate Common SCSI-2 pages applicable to direct-access devices:\n\n");
6280Sstevel@tonic-gate 	fmt_print("Page 0x1   - Read-Write Error Recovery Page\n");
6290Sstevel@tonic-gate 	fmt_print("Page 0x2   - Disconnect-Reconnect Page\n");
6300Sstevel@tonic-gate 	fmt_print("Page 0x3   - Format Device Page\n");
6310Sstevel@tonic-gate 	fmt_print("Page 0x4   - Rigid Disk Geometry Page\n");
6320Sstevel@tonic-gate 	fmt_print("Page 0x7   - Verify Error Recovery Page\n");
6330Sstevel@tonic-gate 	fmt_print("Page 0x8   - Caching Page\n");
6340Sstevel@tonic-gate 	fmt_print("Page 0xA   - Control Mode Page\n");
6350Sstevel@tonic-gate 	fmt_print("\n");
6360Sstevel@tonic-gate }
6370Sstevel@tonic-gate 
6380Sstevel@tonic-gate 
6390Sstevel@tonic-gate /*
6400Sstevel@tonic-gate  * Labels for the various fields of the scsi_inquiry structure
6410Sstevel@tonic-gate  */
6420Sstevel@tonic-gate static char *scsi_inquiry_labels[] = {
6430Sstevel@tonic-gate 	"Vendor:                     ",
6440Sstevel@tonic-gate 	"Product:                    ",
6450Sstevel@tonic-gate 	"Revision:                   ",
6460Sstevel@tonic-gate 	"Removable media:            ",
6470Sstevel@tonic-gate 	"Device type:                ",
6480Sstevel@tonic-gate 	"ISO version:                ",
6490Sstevel@tonic-gate 	"ECMA version:               ",
6500Sstevel@tonic-gate 	"ANSI version:               ",
6510Sstevel@tonic-gate 	"Async event notification:   ",
6520Sstevel@tonic-gate 	"Terminate i/o process msg:  ",
6530Sstevel@tonic-gate 	"Response data format:       ",
6540Sstevel@tonic-gate 	"Additional length:          ",
6550Sstevel@tonic-gate 	"Relative addressing:        ",
6560Sstevel@tonic-gate 	"32 bit transfers:           ",
6570Sstevel@tonic-gate 	"16 bit transfers:           ",
6580Sstevel@tonic-gate 	"Synchronous transfers:      ",
6590Sstevel@tonic-gate 	"Linked commands:            ",
6600Sstevel@tonic-gate 	"Command queueing:           ",
6610Sstevel@tonic-gate 	"Soft reset option:          "
6620Sstevel@tonic-gate };
6630Sstevel@tonic-gate 
6640Sstevel@tonic-gate 
6650Sstevel@tonic-gate /*
6660Sstevel@tonic-gate  * Dump the full inquiry as returned by the device
6670Sstevel@tonic-gate  */
6680Sstevel@tonic-gate static int
do_inquiry()6690Sstevel@tonic-gate do_inquiry()
6700Sstevel@tonic-gate {
6710Sstevel@tonic-gate 	char			inqbuf[255];
6720Sstevel@tonic-gate 	struct scsi_inquiry	*inq;
6730Sstevel@tonic-gate 	char			**p;
6740Sstevel@tonic-gate 
6750Sstevel@tonic-gate 	inq = (struct scsi_inquiry *)inqbuf;
6760Sstevel@tonic-gate 
6770Sstevel@tonic-gate 	if (uscsi_inquiry(cur_file, inqbuf, sizeof (inqbuf))) {
6780Sstevel@tonic-gate 		err_print("\nInquiry failed\n");
6790Sstevel@tonic-gate 		return (1);
6800Sstevel@tonic-gate 	}
6810Sstevel@tonic-gate 
6820Sstevel@tonic-gate 	fmt_print("\nInquiry:\n");
6830Sstevel@tonic-gate 	/*
6840Sstevel@tonic-gate 	 * The SCSI-2 spec defines "Additional length" as (n-4) bytes,
6850Sstevel@tonic-gate 	 * where n is the last byte of the INQUIRY data.  Thus
6860Sstevel@tonic-gate 	 * there are n+1 bytes of INQUIRY data.  We need to add 5 to
6870Sstevel@tonic-gate 	 * inq_len in order to get all the INQUIRY data.
6880Sstevel@tonic-gate 	 */
6890Sstevel@tonic-gate 	dump("    ", inqbuf, inq->inq_len + 5, HEX_ASCII);
6900Sstevel@tonic-gate 	fmt_print("\n");
6910Sstevel@tonic-gate 
6920Sstevel@tonic-gate 	p = scsi_inquiry_labels;
6930Sstevel@tonic-gate 
6940Sstevel@tonic-gate 	fmt_print("%s", *p++);
6950Sstevel@tonic-gate 	print_buf(inq->inq_vid, sizeof (inq->inq_vid));
6960Sstevel@tonic-gate 	fmt_print("\n%s", *p++);
6970Sstevel@tonic-gate 	print_buf(inq->inq_pid, sizeof (inq->inq_pid));
6980Sstevel@tonic-gate 	fmt_print("\n%s", *p++);
6990Sstevel@tonic-gate 	print_buf(inq->inq_revision, sizeof (inq->inq_revision));
7000Sstevel@tonic-gate 
7010Sstevel@tonic-gate 	fmt_print("\n%s%s\n", *p++, inq->inq_rmb ? "yes" : "no");
7020Sstevel@tonic-gate 	fmt_print("%s%d\n", *p++, inq->inq_qual);
7030Sstevel@tonic-gate 	fmt_print("%s%d\n", *p++, inq->inq_iso);
7040Sstevel@tonic-gate 	fmt_print("%s%d\n", *p++, inq->inq_ecma);
7050Sstevel@tonic-gate 	fmt_print("%s%d\n", *p++, inq->inq_ansi);
7060Sstevel@tonic-gate 	fmt_print("%s%s\n", *p++, inq->inq_aenc ? "yes" : "no");
7070Sstevel@tonic-gate 	fmt_print("%s%s\n", *p++, inq->inq_trmiop ? "yes" : "no");
7080Sstevel@tonic-gate 	fmt_print("%s%d\n", *p++, inq->inq_rdf);
7090Sstevel@tonic-gate 	fmt_print("%s%d\n", *p++, inq->inq_len);
7100Sstevel@tonic-gate 	fmt_print("%s%s\n", *p++, inq->inq_reladdr ? "yes" : "no");
7110Sstevel@tonic-gate 	fmt_print("%s%s\n", *p++, inq->inq_wbus32 ? "yes" : "no");
7120Sstevel@tonic-gate 	fmt_print("%s%s\n", *p++, inq->inq_wbus16 ? "yes" : "no");
7130Sstevel@tonic-gate 	fmt_print("%s%s\n", *p++, inq->inq_sync ? "yes" : "no");
7140Sstevel@tonic-gate 	fmt_print("%s%s\n", *p++, inq->inq_linked ? "yes" : "no");
7150Sstevel@tonic-gate 	fmt_print("%s%s\n", *p++, inq->inq_cmdque ? "yes" : "no");
7160Sstevel@tonic-gate 	fmt_print("%s%s\n", *p++, inq->inq_sftre ? "yes" : "no");
7170Sstevel@tonic-gate 
7180Sstevel@tonic-gate 	fmt_print("\n");
7190Sstevel@tonic-gate 	return (0);
7200Sstevel@tonic-gate }
7210Sstevel@tonic-gate 
7220Sstevel@tonic-gate 
7230Sstevel@tonic-gate static void
do_apply()7240Sstevel@tonic-gate do_apply()
7250Sstevel@tonic-gate {
7260Sstevel@tonic-gate 	if (change_list == NULL) {
7270Sstevel@tonic-gate 		fmt_print("\nlist empty.\n");
7280Sstevel@tonic-gate 	} else {
7290Sstevel@tonic-gate 		(void) do_mode_select(change_list);
7300Sstevel@tonic-gate 		free_change_list();
7310Sstevel@tonic-gate 	}
7320Sstevel@tonic-gate }
7330Sstevel@tonic-gate 
7340Sstevel@tonic-gate 
7350Sstevel@tonic-gate static void
do_cancel()7360Sstevel@tonic-gate do_cancel()
7370Sstevel@tonic-gate {
7380Sstevel@tonic-gate 	if (change_list == NULL) {
7390Sstevel@tonic-gate 		fmt_print("\nlist empty.\n");
7400Sstevel@tonic-gate 	} else {
7410Sstevel@tonic-gate 		free_change_list();
7420Sstevel@tonic-gate 	}
7430Sstevel@tonic-gate }
7440Sstevel@tonic-gate 
7450Sstevel@tonic-gate 
7460Sstevel@tonic-gate static void
do_display()7470Sstevel@tonic-gate do_display()
7480Sstevel@tonic-gate {
7490Sstevel@tonic-gate 	struct chg_list	*cp;
7500Sstevel@tonic-gate 
7510Sstevel@tonic-gate 	if (change_list == NULL) {
7520Sstevel@tonic-gate 		fmt_print("\nlist empty.\n");
7530Sstevel@tonic-gate 	} else {
7540Sstevel@tonic-gate 		fmt_print("\nPage 0x%x\n", current_page);
7550Sstevel@tonic-gate 		for (cp = change_list; cp != NULL; cp = cp->next) {
7560Sstevel@tonic-gate 			fmt_print("   b0x%x ", cp->byteno);
7570Sstevel@tonic-gate 			switch (cp->mode) {
7580Sstevel@tonic-gate 			case CHG_MODE_ABS:
7590Sstevel@tonic-gate 				fmt_print("= 0x%x\n", cp->value);
7600Sstevel@tonic-gate 				break;
7610Sstevel@tonic-gate 			case CHG_MODE_SET:
7620Sstevel@tonic-gate 				fmt_print("|= 0x%x\n", cp->value);
7630Sstevel@tonic-gate 				break;
7640Sstevel@tonic-gate 			case CHG_MODE_CLR:
7650Sstevel@tonic-gate 				fmt_print("&= ~0x%x\n",
766*7563SPrasad.Singamsetty@Sun.COM 				    (~(cp->value)) & 0xff);
7670Sstevel@tonic-gate 				break;
7680Sstevel@tonic-gate 			default:
7690Sstevel@tonic-gate 				impossible("do_display");
7700Sstevel@tonic-gate 				/*NOTREACHED*/
7710Sstevel@tonic-gate 			}
7720Sstevel@tonic-gate 		}
7730Sstevel@tonic-gate 		fmt_print("\n");
7740Sstevel@tonic-gate 	}
7750Sstevel@tonic-gate }
7760Sstevel@tonic-gate 
7770Sstevel@tonic-gate 
7780Sstevel@tonic-gate static int
parse_change_spec(full_input,input,pageno,chg_item)7790Sstevel@tonic-gate parse_change_spec(full_input, input, pageno, chg_item)
7800Sstevel@tonic-gate 	char		*full_input;
7810Sstevel@tonic-gate 	char		*input;
7820Sstevel@tonic-gate 	int		pageno;
7830Sstevel@tonic-gate 	struct chg_list	*chg_item;
7840Sstevel@tonic-gate {
7850Sstevel@tonic-gate 	char		*p;
7860Sstevel@tonic-gate 	int		tilde;
7870Sstevel@tonic-gate 
7880Sstevel@tonic-gate 	assert(*input == 'b');
7890Sstevel@tonic-gate 
7900Sstevel@tonic-gate 	chg_item->pageno = pageno;
7910Sstevel@tonic-gate 	chg_item->next = NULL;
7920Sstevel@tonic-gate 
7930Sstevel@tonic-gate 	input++;
7940Sstevel@tonic-gate 	chg_item->byteno = (int)strtol(input, &p, 0);
7950Sstevel@tonic-gate 	if (p == input) {
7960Sstevel@tonic-gate 		err_print("Syntax error: %s\n", full_input);
7970Sstevel@tonic-gate 		return (0);
7980Sstevel@tonic-gate 	}
7990Sstevel@tonic-gate 	if (chg_item->byteno < 2) {
8000Sstevel@tonic-gate 		err_print(" Unsupported byte offset: %d\n",
8010Sstevel@tonic-gate 			chg_item->byteno);
8020Sstevel@tonic-gate 		return (0);
8030Sstevel@tonic-gate 	}
8040Sstevel@tonic-gate 	for (input = p; *input == ' '; input++)
8050Sstevel@tonic-gate 		;
8060Sstevel@tonic-gate 	chg_item->mode = CHG_MODE_UNDEFINED;
8070Sstevel@tonic-gate 	switch (*input++) {
8080Sstevel@tonic-gate 	case '=':
8090Sstevel@tonic-gate 		chg_item->mode = CHG_MODE_ABS;
8100Sstevel@tonic-gate 		break;
8110Sstevel@tonic-gate 	case '|':
8120Sstevel@tonic-gate 		if (*input++ == '=') {
8130Sstevel@tonic-gate 			chg_item->mode = CHG_MODE_SET;
8140Sstevel@tonic-gate 		}
8150Sstevel@tonic-gate 		break;
8160Sstevel@tonic-gate 	case '&':
8170Sstevel@tonic-gate 		if (*input++ == '=') {
8180Sstevel@tonic-gate 			chg_item->mode = CHG_MODE_CLR;
8190Sstevel@tonic-gate 		}
8200Sstevel@tonic-gate 		break;
8210Sstevel@tonic-gate 	}
8220Sstevel@tonic-gate 	if (chg_item->mode == CHG_MODE_UNDEFINED) {
8230Sstevel@tonic-gate 		err_print("Syntax error: %s\n", full_input);
8240Sstevel@tonic-gate 		return (0);
8250Sstevel@tonic-gate 	}
8260Sstevel@tonic-gate 	for (; *input == ' '; input++)
8270Sstevel@tonic-gate 		;
8280Sstevel@tonic-gate 	if (*input == '~') {
8290Sstevel@tonic-gate 		tilde = 1;
8300Sstevel@tonic-gate 		for (input++; *input == ' '; input++)
8310Sstevel@tonic-gate 			;
8320Sstevel@tonic-gate 	} else {
8330Sstevel@tonic-gate 		tilde = 0;
8340Sstevel@tonic-gate 	}
8350Sstevel@tonic-gate 	chg_item->value = (int)strtol(input, &p, 0);
8360Sstevel@tonic-gate 	if (p == input || *p != 0) {
8370Sstevel@tonic-gate 		err_print("Syntax error: %s\n", full_input);
8380Sstevel@tonic-gate 		return (0);
8390Sstevel@tonic-gate 	}
8400Sstevel@tonic-gate 	/*
8410Sstevel@tonic-gate 	 * Apply complement if selected.
8420Sstevel@tonic-gate 	 * Constrain to a byte value.
8430Sstevel@tonic-gate 	 */
8440Sstevel@tonic-gate 	if (tilde) {
8450Sstevel@tonic-gate 		chg_item->value = ~chg_item->value;
8460Sstevel@tonic-gate 	}
8470Sstevel@tonic-gate 	chg_item->value &= 0xff;
8480Sstevel@tonic-gate 
8490Sstevel@tonic-gate 	return (1);
8500Sstevel@tonic-gate }
8510Sstevel@tonic-gate 
8520Sstevel@tonic-gate 
8530Sstevel@tonic-gate static void
add_new_change_list_item(chg_item)8540Sstevel@tonic-gate add_new_change_list_item(chg_item)
8550Sstevel@tonic-gate 	struct chg_list		*chg_item;
8560Sstevel@tonic-gate {
8570Sstevel@tonic-gate 	struct chg_list	*cp;
8580Sstevel@tonic-gate 
8590Sstevel@tonic-gate 	if (change_list == NULL) {
8600Sstevel@tonic-gate 		change_list = chg_item;
8610Sstevel@tonic-gate 	} else {
8620Sstevel@tonic-gate 		for (cp = change_list; cp->next != NULL; cp = cp->next)
8630Sstevel@tonic-gate 			;
8640Sstevel@tonic-gate 		cp->next = chg_item;
8650Sstevel@tonic-gate 	}
8660Sstevel@tonic-gate 	chg_item->next = NULL;
8670Sstevel@tonic-gate }
8680Sstevel@tonic-gate 
8690Sstevel@tonic-gate 
8700Sstevel@tonic-gate static void
free_change_list()8710Sstevel@tonic-gate free_change_list()
8720Sstevel@tonic-gate {
8730Sstevel@tonic-gate 	struct chg_list	*cp;
8740Sstevel@tonic-gate 	struct chg_list	*cp2;
8750Sstevel@tonic-gate 
8760Sstevel@tonic-gate 	cp = change_list;
8770Sstevel@tonic-gate 	while (cp != NULL) {
8780Sstevel@tonic-gate 		cp2 = cp->next;
8790Sstevel@tonic-gate 		destroy_data((char *)cp);
8800Sstevel@tonic-gate 		cp = cp2;
8810Sstevel@tonic-gate 	}
8820Sstevel@tonic-gate 	change_list = NULL;
8830Sstevel@tonic-gate }
8840Sstevel@tonic-gate 
8850Sstevel@tonic-gate 
8860Sstevel@tonic-gate static void
do_default(input)8870Sstevel@tonic-gate do_default(input)
8880Sstevel@tonic-gate 	char		*input;
8890Sstevel@tonic-gate {
8900Sstevel@tonic-gate 	char		*s = input;
8910Sstevel@tonic-gate 	char		*p;
8920Sstevel@tonic-gate 	int		n;
8930Sstevel@tonic-gate 
8940Sstevel@tonic-gate 	/*
8950Sstevel@tonic-gate 	 * Reset current page indicator
8960Sstevel@tonic-gate 	 */
8970Sstevel@tonic-gate 	current_page = -1;
8980Sstevel@tonic-gate 
8990Sstevel@tonic-gate 	/*
9000Sstevel@tonic-gate 	 * Skip the leading "default" command, which we
9010Sstevel@tonic-gate 	 * must have, or we wouldn't have come here,
9020Sstevel@tonic-gate 	 * and any white space.
9030Sstevel@tonic-gate 	 */
9040Sstevel@tonic-gate 	while (isspace(*s)) {
9050Sstevel@tonic-gate 		s++;
9060Sstevel@tonic-gate 	}
9070Sstevel@tonic-gate 
9080Sstevel@tonic-gate 	while (*s && isascii(*s) && isalpha(*s)) {
9090Sstevel@tonic-gate 		s++;
9100Sstevel@tonic-gate 	}
9110Sstevel@tonic-gate 
9120Sstevel@tonic-gate 	while (isspace(*s)) {
9130Sstevel@tonic-gate 		s++;
9140Sstevel@tonic-gate 	}
9150Sstevel@tonic-gate 
9160Sstevel@tonic-gate 	/*
9170Sstevel@tonic-gate 	 * Subsequent modifier must be either "p<n>", or "all".
9180Sstevel@tonic-gate 	 */
9190Sstevel@tonic-gate 	if (*s == 'p') {
9200Sstevel@tonic-gate 		s++;
9210Sstevel@tonic-gate 		n = (int)strtol(s, &p, 0);
9220Sstevel@tonic-gate 		if (p == s || *p != 0) {
9230Sstevel@tonic-gate 			err_print("Syntax error: %s\n", input);
9240Sstevel@tonic-gate 		} else {
9250Sstevel@tonic-gate 			fmt_print("\n");
9260Sstevel@tonic-gate 			(void) default_page(n);
9270Sstevel@tonic-gate 			fmt_print("\n");
9280Sstevel@tonic-gate 		}
9290Sstevel@tonic-gate 	} else if (*s == 'a') {
9300Sstevel@tonic-gate 		default_all_pages();
9310Sstevel@tonic-gate 	} else {
9320Sstevel@tonic-gate 		err_print("Syntax error: %s\n", input);
9330Sstevel@tonic-gate 	}
9340Sstevel@tonic-gate }
9350Sstevel@tonic-gate 
9360Sstevel@tonic-gate 
9370Sstevel@tonic-gate static void
default_all_pages()9380Sstevel@tonic-gate default_all_pages()
9390Sstevel@tonic-gate {
9400Sstevel@tonic-gate 	char			*p;
9410Sstevel@tonic-gate 	struct mode_header	*mh;
9420Sstevel@tonic-gate 	struct mode_page	*mp;
9430Sstevel@tonic-gate 	int			n;
9440Sstevel@tonic-gate 	struct uscsi_cmd	ucmd;
9450Sstevel@tonic-gate 	union scsi_cdb		cdb;
9460Sstevel@tonic-gate 	char			msbuf[MAX_MODE_SENSE_SIZE];
9470Sstevel@tonic-gate 	int			nbytes = sizeof (msbuf);
9480Sstevel@tonic-gate 	int			status;
9490Sstevel@tonic-gate 
9500Sstevel@tonic-gate 	/*
9510Sstevel@tonic-gate 	 * Build and execute the uscsi ioctl.  Note that
9520Sstevel@tonic-gate 	 * we cannot simply call uscsi_mode_sense() here,
9530Sstevel@tonic-gate 	 * since that function attempts to valididate the
9540Sstevel@tonic-gate 	 * returned data, and the page 0x3f has a unique
9550Sstevel@tonic-gate 	 * format.
9560Sstevel@tonic-gate 	 */
9570Sstevel@tonic-gate 	nbytes = MAX_MODE_SENSE_SIZE;
9580Sstevel@tonic-gate 	(void) memset(msbuf, 0, nbytes);
9590Sstevel@tonic-gate 	(void) memset((char *)&ucmd, 0, sizeof (ucmd));
9600Sstevel@tonic-gate 	(void) memset((char *)&cdb, 0, sizeof (union scsi_cdb));
9610Sstevel@tonic-gate 	cdb.scc_cmd = SCMD_MODE_SENSE;
9620Sstevel@tonic-gate 	FORMG0COUNT(&cdb, (uchar_t)nbytes);
9630Sstevel@tonic-gate 	cdb.cdb_opaque[2] = MODE_SENSE_PC_DEFAULT | 0x3f;
9640Sstevel@tonic-gate 	ucmd.uscsi_cdb = (caddr_t)&cdb;
9650Sstevel@tonic-gate 	ucmd.uscsi_cdblen = CDB_GROUP0;
9660Sstevel@tonic-gate 	ucmd.uscsi_bufaddr = msbuf;
9670Sstevel@tonic-gate 	ucmd.uscsi_buflen = nbytes;
968*7563SPrasad.Singamsetty@Sun.COM 	status = uscsi_cmd(cur_file, &ucmd, (option_msg) ? F_NORMAL : F_SILENT);
9690Sstevel@tonic-gate 	if (status) {
9700Sstevel@tonic-gate 		if (!option_msg) {
9710Sstevel@tonic-gate 			err_print("\nMode sense page 0x3f failed\n");
9720Sstevel@tonic-gate 		}
9730Sstevel@tonic-gate 		return;
9740Sstevel@tonic-gate 	}
9750Sstevel@tonic-gate 
9760Sstevel@tonic-gate 	fmt_print("\n");
9770Sstevel@tonic-gate 
9780Sstevel@tonic-gate 	/*
9790Sstevel@tonic-gate 	 * Now parse the page 0x3f
9800Sstevel@tonic-gate 	 */
9810Sstevel@tonic-gate 	mh = (struct mode_header *)msbuf;
9820Sstevel@tonic-gate 	nbytes = mh->length - sizeof (struct mode_header) -
983*7563SPrasad.Singamsetty@Sun.COM 	    mh->bdesc_length + 1;
9840Sstevel@tonic-gate 	p = msbuf + sizeof (struct mode_header) + mh->bdesc_length;
9850Sstevel@tonic-gate 
9860Sstevel@tonic-gate 	while (nbytes > 0) {
9870Sstevel@tonic-gate 		mp = (struct mode_page *)p;
9880Sstevel@tonic-gate 		n = mp->length + sizeof (struct mode_page);
9890Sstevel@tonic-gate 		nbytes -= n;
9900Sstevel@tonic-gate 		if (nbytes < 0)
9910Sstevel@tonic-gate 			break;
9920Sstevel@tonic-gate 		if (default_page(mp->code) == 0) {
9930Sstevel@tonic-gate 			goto error;
9940Sstevel@tonic-gate 		}
9950Sstevel@tonic-gate 		p += n;
9960Sstevel@tonic-gate 	}
9970Sstevel@tonic-gate 
9980Sstevel@tonic-gate 	if (nbytes < 0) {
9990Sstevel@tonic-gate 		err_print("Mode sense page 0x3f formatted incorrectly:\n");
10000Sstevel@tonic-gate 	}
10010Sstevel@tonic-gate error:
10020Sstevel@tonic-gate 	fmt_print("\n");
10030Sstevel@tonic-gate }
10040Sstevel@tonic-gate 
10050Sstevel@tonic-gate 
10060Sstevel@tonic-gate static int
default_page(pageno)10070Sstevel@tonic-gate default_page(pageno)
10080Sstevel@tonic-gate 	int		pageno;
10090Sstevel@tonic-gate {
10100Sstevel@tonic-gate 	struct scsi_ms_header	header;
10110Sstevel@tonic-gate 	char			saved[MAX_MODE_SENSE_SIZE];
10120Sstevel@tonic-gate 	char			current[MAX_MODE_SENSE_SIZE];
10130Sstevel@tonic-gate 	char			dfault[MAX_MODE_SENSE_SIZE];
10140Sstevel@tonic-gate 	struct mode_page	*sp;
10150Sstevel@tonic-gate 	struct mode_page	*cp;
10160Sstevel@tonic-gate 	struct mode_page	*dp;
10170Sstevel@tonic-gate 	int			length;
10180Sstevel@tonic-gate 	int			flags;
10190Sstevel@tonic-gate 	int			i;
10200Sstevel@tonic-gate 	int			need_mode_select;
10210Sstevel@tonic-gate 
10220Sstevel@tonic-gate 	/*
10230Sstevel@tonic-gate 	 * Get default mode sense
10240Sstevel@tonic-gate 	 */
10250Sstevel@tonic-gate 	if (uscsi_mode_sense(cur_file, pageno, MODE_SENSE_PC_DEFAULT,
10260Sstevel@tonic-gate 			dfault, MAX_MODE_SENSE_SIZE, &header)) {
10270Sstevel@tonic-gate 		err_print("Mode sense on page %x (dfault) failed\n",
10280Sstevel@tonic-gate 			pageno);
10290Sstevel@tonic-gate 		return (0);
10300Sstevel@tonic-gate 	}
10310Sstevel@tonic-gate 
10320Sstevel@tonic-gate 	/*
10330Sstevel@tonic-gate 	 * Get the current mode sense.
10340Sstevel@tonic-gate 	 */
10350Sstevel@tonic-gate 	if (uscsi_mode_sense(cur_file, pageno, MODE_SENSE_PC_CURRENT,
10360Sstevel@tonic-gate 			current, MAX_MODE_SENSE_SIZE, &header)) {
10370Sstevel@tonic-gate 		err_print("Mode sense on page %x (current) failed\n",
10380Sstevel@tonic-gate 			pageno);
10390Sstevel@tonic-gate 		return (0);
10400Sstevel@tonic-gate 	}
10410Sstevel@tonic-gate 
10420Sstevel@tonic-gate 	/*
10430Sstevel@tonic-gate 	 * Get saved mode sense.  If this fails, assume it is
10440Sstevel@tonic-gate 	 * the same as the current.
10450Sstevel@tonic-gate 	 */
10460Sstevel@tonic-gate 	if (uscsi_mode_sense(cur_file, pageno, MODE_SENSE_PC_SAVED,
10470Sstevel@tonic-gate 			saved, MAX_MODE_SENSE_SIZE, &header)) {
10480Sstevel@tonic-gate 		(void) memcpy(saved, current, MAX_MODE_SENSE_SIZE);
10490Sstevel@tonic-gate 	}
10500Sstevel@tonic-gate 
10510Sstevel@tonic-gate 	/*
10520Sstevel@tonic-gate 	 * Determine if we need a mode select on this page.
10530Sstevel@tonic-gate 	 * Just deal with the intersection of the three pages.
10540Sstevel@tonic-gate 	 */
10550Sstevel@tonic-gate 	sp = (struct mode_page *)saved;
10560Sstevel@tonic-gate 	cp = (struct mode_page *)current;
10570Sstevel@tonic-gate 	dp = (struct mode_page *)dfault;
10580Sstevel@tonic-gate 	length = min(MODESENSE_PAGE_LEN(sp), MODESENSE_PAGE_LEN(cp));
10590Sstevel@tonic-gate 	length = min(length, MODESENSE_PAGE_LEN(dp));
10600Sstevel@tonic-gate 
10610Sstevel@tonic-gate 	need_mode_select = 0;
10620Sstevel@tonic-gate 	for (i = 2; i < length; i++) {
10630Sstevel@tonic-gate 		if (current[i] != dfault[i] || saved[i] != dfault[i]) {
10640Sstevel@tonic-gate 			current[i] = dfault[i];
10650Sstevel@tonic-gate 			need_mode_select = 1;
10660Sstevel@tonic-gate 		}
10670Sstevel@tonic-gate 	}
10680Sstevel@tonic-gate 
10690Sstevel@tonic-gate 	if (need_mode_select == 0) {
10700Sstevel@tonic-gate 		fmt_print("Defaulting page 0x%x: ok\n",
10710Sstevel@tonic-gate 			pageno);
10720Sstevel@tonic-gate 		return (1);
10730Sstevel@tonic-gate 	}
10740Sstevel@tonic-gate 
10750Sstevel@tonic-gate 	/*
10760Sstevel@tonic-gate 	 * A change was made.  Do a mode select
10770Sstevel@tonic-gate 	 * We always want to set the Page Format bit.
10780Sstevel@tonic-gate 	 * Set the Save Page bit if the drive indicates
10790Sstevel@tonic-gate 	 * that it can save this page.
10800Sstevel@tonic-gate 	 */
10810Sstevel@tonic-gate 	length = MODESENSE_PAGE_LEN(cp);
10820Sstevel@tonic-gate 	flags = MODE_SELECT_PF;
10830Sstevel@tonic-gate 	if (cp->ps) {
10840Sstevel@tonic-gate 		flags |= MODE_SELECT_SP;
10850Sstevel@tonic-gate 	}
10860Sstevel@tonic-gate 	cp->ps = 0;
10870Sstevel@tonic-gate 	header.mode_header.length = 0;
10880Sstevel@tonic-gate 	header.mode_header.device_specific = 0;
10890Sstevel@tonic-gate 	if (uscsi_mode_select(cur_file, pageno, flags,
10900Sstevel@tonic-gate 			current, length, &header)) {
10910Sstevel@tonic-gate 		/*
10920Sstevel@tonic-gate 		 * Failed - try not saving parameters,
10930Sstevel@tonic-gate 		 * if possible.
10940Sstevel@tonic-gate 		 */
10950Sstevel@tonic-gate 		if (flags & MODE_SELECT_SP) {
10960Sstevel@tonic-gate 			flags &= ~MODE_SELECT_SP;
10970Sstevel@tonic-gate 			if (uscsi_mode_select(cur_file, pageno, flags,
10980Sstevel@tonic-gate 					saved, length, &header)) {
10990Sstevel@tonic-gate 				fmt_print("Defaulting page 0x%x: failed\n",
11000Sstevel@tonic-gate 					pageno);
11010Sstevel@tonic-gate 			} else {
11020Sstevel@tonic-gate 				fmt_print("Defaulting page 0x%x: ",
11030Sstevel@tonic-gate 					pageno);
11040Sstevel@tonic-gate 				fmt_print("cannot save page permanently\n");
11050Sstevel@tonic-gate 			}
11060Sstevel@tonic-gate 		} else {
11070Sstevel@tonic-gate 			fmt_print("Defaulting page 0x%x: ", pageno);
11080Sstevel@tonic-gate 			fmt_print("cannot save page permanently\n");
11090Sstevel@tonic-gate 		}
11100Sstevel@tonic-gate 	} else {
11110Sstevel@tonic-gate 		fmt_print("Defaulting page 0x%x: mode select ok\n", pageno);
11120Sstevel@tonic-gate 	}
11130Sstevel@tonic-gate 
11140Sstevel@tonic-gate 	return (1);
11150Sstevel@tonic-gate }
1116