xref: /illumos-gate/usr/src/cmd/format/menu_scsi.c (revision b12aaafb)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5342440ecSPrasad Singamsetty  * Common Development and Distribution License (the "License").
6342440ecSPrasad Singamsetty  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate 
227c478bd9Sstevel@tonic-gate /*
23342440ecSPrasad Singamsetty  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate /*
287c478bd9Sstevel@tonic-gate  * This file contains functions implementing the scsi menu commands.
297c478bd9Sstevel@tonic-gate  *
307c478bd9Sstevel@tonic-gate  * These functions are intended for expert use only, and provide
317c478bd9Sstevel@tonic-gate  * a raw access to a scsi device's mode pages.  The ability to
327c478bd9Sstevel@tonic-gate  * issue a raw format command is also provided, should a page be
337c478bd9Sstevel@tonic-gate  * changed that requires a format.
347c478bd9Sstevel@tonic-gate  */
357c478bd9Sstevel@tonic-gate #include "global.h"
367c478bd9Sstevel@tonic-gate #include <stdlib.h>
377c478bd9Sstevel@tonic-gate #include <ctype.h>
387c478bd9Sstevel@tonic-gate 
397c478bd9Sstevel@tonic-gate #include "io.h"
407c478bd9Sstevel@tonic-gate #include "menu.h"
417c478bd9Sstevel@tonic-gate #include "misc.h"
427c478bd9Sstevel@tonic-gate #include "menu_scsi.h"
437c478bd9Sstevel@tonic-gate #include "ctlr_scsi.h"
447c478bd9Sstevel@tonic-gate #include "startup.h"
453e1bd7a2Ssjelinek #include "checkdev.h"
467c478bd9Sstevel@tonic-gate 
477c478bd9Sstevel@tonic-gate static int	do_mode_sense(int);
487c478bd9Sstevel@tonic-gate static int	do_mode_sense_all(void);
497c478bd9Sstevel@tonic-gate static int	do_mode_select(struct chg_list *);
507c478bd9Sstevel@tonic-gate static int	do_format(void);
517c478bd9Sstevel@tonic-gate static void	do_list(void);
527c478bd9Sstevel@tonic-gate static int	do_inquiry(void);
537c478bd9Sstevel@tonic-gate static void	do_apply(void);
547c478bd9Sstevel@tonic-gate static void	do_cancel(void);
557c478bd9Sstevel@tonic-gate static void	do_display(void);
567c478bd9Sstevel@tonic-gate static int	parse_change_spec(char *, char *, int, struct chg_list *);
577c478bd9Sstevel@tonic-gate static void	add_new_change_list_item(struct chg_list *);
587c478bd9Sstevel@tonic-gate static void	free_change_list(void);
597c478bd9Sstevel@tonic-gate static void	do_default(char *);
607c478bd9Sstevel@tonic-gate static void	default_all_pages(void);
617c478bd9Sstevel@tonic-gate static int	default_page(int);
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate /*
647c478bd9Sstevel@tonic-gate  * Menu data for the SCSI menu display
657c478bd9Sstevel@tonic-gate  */
667c478bd9Sstevel@tonic-gate static char	*scsi_menu_strings[] = {
677c478bd9Sstevel@tonic-gate 	"p<n>                   - display a mode sense page",
687c478bd9Sstevel@tonic-gate 	"p<n> b<n> <op> [~]<n>  - change a byte and issue mode select",
697c478bd9Sstevel@tonic-gate 	"b<n> <op> [~]<n>       - add an operation to the mode select list",
707c478bd9Sstevel@tonic-gate 	"                             for the current page",
717c478bd9Sstevel@tonic-gate 	"",
727c478bd9Sstevel@tonic-gate 	"        where:  p<n> specifies the page with page code <n>",
737c478bd9Sstevel@tonic-gate 	"                b<n> specifies byte <n> of the page",
747c478bd9Sstevel@tonic-gate 	"                <op> can be one of the following operators:",
757c478bd9Sstevel@tonic-gate 	"                     =    (set specified value)",
767c478bd9Sstevel@tonic-gate 	"                     |=   (bitwise OR with current value)",
777c478bd9Sstevel@tonic-gate 	"                     &=   (bitwise AND with current value)",
787c478bd9Sstevel@tonic-gate 	"                <n> can be a decimal value in the range 0-255,",
797c478bd9Sstevel@tonic-gate 	"                or two hexadecimal digits, in the form 0x<xx>.",
807c478bd9Sstevel@tonic-gate 	"                [~] complements the specified value",
817c478bd9Sstevel@tonic-gate 	"",
827c478bd9Sstevel@tonic-gate 	"apply                  - apply mode select list",
837c478bd9Sstevel@tonic-gate 	"cancel                 - cancel mode select list",
847c478bd9Sstevel@tonic-gate 	"display                - display mode select list",
857c478bd9Sstevel@tonic-gate 	"all                    - display all supported mode sense pages",
867c478bd9Sstevel@tonic-gate 	"default p<n>           - mode select page <n> to default values",
877c478bd9Sstevel@tonic-gate 	"default all            - mode select all pages to default values",
887c478bd9Sstevel@tonic-gate 	"format                 - format without standard mode selects",
897c478bd9Sstevel@tonic-gate 	"inquiry                - display device's inquiry response",
907c478bd9Sstevel@tonic-gate 	"list                   - list common SCSI-2 mode pages",
917c478bd9Sstevel@tonic-gate 	"!<cmd>                 - execute <cmd> , then return"
927c478bd9Sstevel@tonic-gate };
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate #define	N_SCSI_STRINGS	(sizeof (scsi_menu_strings) / sizeof (char *))
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate /*
977c478bd9Sstevel@tonic-gate  * Command types
987c478bd9Sstevel@tonic-gate  */
997c478bd9Sstevel@tonic-gate #define	CMD_ALL			0
1007c478bd9Sstevel@tonic-gate #define	CMD_FORMAT		1
1017c478bd9Sstevel@tonic-gate #define	CMD_QUIT		2
1027c478bd9Sstevel@tonic-gate #define	CMD_HELP		3
1037c478bd9Sstevel@tonic-gate #define	CMD_LIST		4
1047c478bd9Sstevel@tonic-gate #define	CMD_INQUIRY		5
1057c478bd9Sstevel@tonic-gate #define	CMD_APPLY		6
1067c478bd9Sstevel@tonic-gate #define	CMD_CANCEL		7
1077c478bd9Sstevel@tonic-gate #define	CMD_DISPLAY		8
1087c478bd9Sstevel@tonic-gate 
1097c478bd9Sstevel@tonic-gate /*
1107c478bd9Sstevel@tonic-gate  * SCSI menu commands for minimum recognition
1117c478bd9Sstevel@tonic-gate  */
1127c478bd9Sstevel@tonic-gate static struct slist	cmds_list[] = {
1137c478bd9Sstevel@tonic-gate 	{ "all",	NULL,	CMD_ALL },
1147c478bd9Sstevel@tonic-gate 	{ "format",	NULL,	CMD_FORMAT },
1157c478bd9Sstevel@tonic-gate 	{ "quit",	NULL,	CMD_QUIT },
1167c478bd9Sstevel@tonic-gate 	{ "help",	NULL,	CMD_HELP },
1177c478bd9Sstevel@tonic-gate 	{ "?",		NULL,	CMD_HELP },
1187c478bd9Sstevel@tonic-gate 	{ "list",	NULL,	CMD_LIST },
1197c478bd9Sstevel@tonic-gate 	{ "inquiry",	NULL,	CMD_INQUIRY },
1207c478bd9Sstevel@tonic-gate 	{ "apply",	NULL,	CMD_APPLY },
1217c478bd9Sstevel@tonic-gate 	{ "cancel",	NULL,	CMD_CANCEL },
1227c478bd9Sstevel@tonic-gate 	{ "display",	NULL,	CMD_DISPLAY },
1237c478bd9Sstevel@tonic-gate 	{ NULL	}
1247c478bd9Sstevel@tonic-gate };
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate /*
1277c478bd9Sstevel@tonic-gate  * Implied page for mode select change lists
1287c478bd9Sstevel@tonic-gate  */
1297c478bd9Sstevel@tonic-gate static	int		current_page;
1307c478bd9Sstevel@tonic-gate static	struct chg_list	*change_list;
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate /*
1337c478bd9Sstevel@tonic-gate  * Manage the SCSI menu.
1347c478bd9Sstevel@tonic-gate  * Parse input and dispatch to the appropriate functions.
1357c478bd9Sstevel@tonic-gate  * The commands we accept are not simple one-word commands,
1367c478bd9Sstevel@tonic-gate  * so we cannot use the standard format menu-handling functions.
1377c478bd9Sstevel@tonic-gate  */
1387c478bd9Sstevel@tonic-gate int
c_scsi(void)139*b12aaafbSToomas Soome c_scsi(void)
1407c478bd9Sstevel@tonic-gate {
1417c478bd9Sstevel@tonic-gate 	int			i;
1427c478bd9Sstevel@tonic-gate 	struct env		env;
1437c478bd9Sstevel@tonic-gate 	char			**menu;
1447c478bd9Sstevel@tonic-gate 	struct menu_item	scsi_menu[N_SCSI_STRINGS+1];
1457c478bd9Sstevel@tonic-gate 	struct chg_list		change_item;
1467c478bd9Sstevel@tonic-gate 	struct chg_list		*chg_item;
1477c478bd9Sstevel@tonic-gate 	char			s[MAXPATHLEN], nclean[MAXPATHLEN];
1487c478bd9Sstevel@tonic-gate 	char			*p;
1497c478bd9Sstevel@tonic-gate 	char			*p2;
1507c478bd9Sstevel@tonic-gate 	int			cmd;
1517c478bd9Sstevel@tonic-gate 	int			pageno;
1527c478bd9Sstevel@tonic-gate 	int			help = 1;
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate 	/*
1557c478bd9Sstevel@tonic-gate 	 * Warn casual users that maybe they should not be
1567c478bd9Sstevel@tonic-gate 	 * using this menu.
1577c478bd9Sstevel@tonic-gate 	 */
1587c478bd9Sstevel@tonic-gate 	fmt_print("\n"
1597c478bd9Sstevel@tonic-gate "Warning:  these functions are intended for expert use only, for\n"
1607c478bd9Sstevel@tonic-gate "debugging disk devices and for unusual configuration settings.\n"
1617c478bd9Sstevel@tonic-gate "It is recommended that you do not use this menu for normal disk\n"
1627c478bd9Sstevel@tonic-gate "configuration and formatting, unless you have explicit instructions,\n"
1637c478bd9Sstevel@tonic-gate "or know exactly what you are doing.\n");
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate 	/*
1667c478bd9Sstevel@tonic-gate 	 * Initialize change list and current page to empty
1677c478bd9Sstevel@tonic-gate 	 */
1687c478bd9Sstevel@tonic-gate 	current_page = -1;
1697c478bd9Sstevel@tonic-gate 	change_list = NULL;
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate 	/*
1727c478bd9Sstevel@tonic-gate 	 * Build and display the menu.
1737c478bd9Sstevel@tonic-gate 	 * we only use this for display purposes.
1747c478bd9Sstevel@tonic-gate 	 */
1757c478bd9Sstevel@tonic-gate 	for (i = 0; i < N_SCSI_STRINGS; i++) {
1767c478bd9Sstevel@tonic-gate 		scsi_menu[i].menu_cmd = scsi_menu_strings[i];
1777c478bd9Sstevel@tonic-gate 		scsi_menu[i].menu_func = NULL;
1787c478bd9Sstevel@tonic-gate 		scsi_menu[i].menu_state = true;
1797c478bd9Sstevel@tonic-gate 	}
1807c478bd9Sstevel@tonic-gate 	scsi_menu[i].menu_cmd = NULL;
1817c478bd9Sstevel@tonic-gate 	menu = create_menu_list(scsi_menu);
1827c478bd9Sstevel@tonic-gate 	/*
1837c478bd9Sstevel@tonic-gate 	 * Save the environment so a ctrl-C out of a command lands here.
1847c478bd9Sstevel@tonic-gate 	 */
1857c478bd9Sstevel@tonic-gate 	saveenv(env);
1867c478bd9Sstevel@tonic-gate 	for (;;) {
1877c478bd9Sstevel@tonic-gate 		if (help) {
1887c478bd9Sstevel@tonic-gate 			help = 0;
1897c478bd9Sstevel@tonic-gate 			fmt_print("\n\nSCSI MENU:\n");
1907c478bd9Sstevel@tonic-gate 			display_menu_list(menu);
1917c478bd9Sstevel@tonic-gate 		}
1927c478bd9Sstevel@tonic-gate 		/*
1937c478bd9Sstevel@tonic-gate 		 * Prompt and get next input line.  We don't use the
1947c478bd9Sstevel@tonic-gate 		 * standard input routine, since we need a little
1957c478bd9Sstevel@tonic-gate 		 * more flexibility in parsing the input.
1967c478bd9Sstevel@tonic-gate 		 */
1977c478bd9Sstevel@tonic-gate 		fmt_print("scsi> ");
1987c478bd9Sstevel@tonic-gate 		get_inputline(nclean, sizeof (nclean));
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate 		clean_token(s, nclean);
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate 		/*
2037c478bd9Sstevel@tonic-gate 		 * Mark the saved environment active so the user can now
2047c478bd9Sstevel@tonic-gate 		 * do a ctrl-C to get out of the command.
2057c478bd9Sstevel@tonic-gate 		 */
2067c478bd9Sstevel@tonic-gate 		useenv();
2077c478bd9Sstevel@tonic-gate 
2087c478bd9Sstevel@tonic-gate 		/*
2097c478bd9Sstevel@tonic-gate 		 * Figure out what the user chose
2107c478bd9Sstevel@tonic-gate 		 */
2117c478bd9Sstevel@tonic-gate 		i = find_value(cmds_list, s, &cmd);
2127c478bd9Sstevel@tonic-gate 		if (i == 1) {
2137c478bd9Sstevel@tonic-gate 			switch (cmd) {
2147c478bd9Sstevel@tonic-gate 			case CMD_ALL:
2157c478bd9Sstevel@tonic-gate 				(void) do_mode_sense_all();
2167c478bd9Sstevel@tonic-gate 				break;
2177c478bd9Sstevel@tonic-gate 			case CMD_FORMAT:
2187c478bd9Sstevel@tonic-gate 				(void) do_format();
2197c478bd9Sstevel@tonic-gate 				break;
2207c478bd9Sstevel@tonic-gate 			case CMD_QUIT:
2217c478bd9Sstevel@tonic-gate 				goto exit;
2227c478bd9Sstevel@tonic-gate 				/*NOTREACHED*/
2237c478bd9Sstevel@tonic-gate 			case CMD_HELP:
2247c478bd9Sstevel@tonic-gate 				fmt_print("\n\nSCSI MENU:\n");
2257c478bd9Sstevel@tonic-gate 				display_menu_list(menu);
2267c478bd9Sstevel@tonic-gate 				break;
2277c478bd9Sstevel@tonic-gate 			case CMD_LIST:
2287c478bd9Sstevel@tonic-gate 				do_list();
2297c478bd9Sstevel@tonic-gate 				break;
2307c478bd9Sstevel@tonic-gate 			case CMD_INQUIRY:
2317c478bd9Sstevel@tonic-gate 				(void) do_inquiry();
2327c478bd9Sstevel@tonic-gate 				break;
2337c478bd9Sstevel@tonic-gate 			case CMD_APPLY:
2347c478bd9Sstevel@tonic-gate 				do_apply();
2357c478bd9Sstevel@tonic-gate 				break;
2367c478bd9Sstevel@tonic-gate 			case CMD_CANCEL:
2377c478bd9Sstevel@tonic-gate 				do_cancel();
2387c478bd9Sstevel@tonic-gate 				break;
2397c478bd9Sstevel@tonic-gate 			case CMD_DISPLAY:
2407c478bd9Sstevel@tonic-gate 				do_display();
2417c478bd9Sstevel@tonic-gate 				break;
2427c478bd9Sstevel@tonic-gate 			}
2437c478bd9Sstevel@tonic-gate 		} else if (s[0] == 'd') {
2447c478bd9Sstevel@tonic-gate 			do_default(s);
2457c478bd9Sstevel@tonic-gate 		} else if (s[0] == 'p') {
2467c478bd9Sstevel@tonic-gate 			p = s + 1;
2477c478bd9Sstevel@tonic-gate 			pageno = (int)strtol(p, &p2, 0);
2487c478bd9Sstevel@tonic-gate 			if (p2 == p) {
2497c478bd9Sstevel@tonic-gate 				err_print("Syntax error: %s\n", s);
2507c478bd9Sstevel@tonic-gate 				goto error;
2517c478bd9Sstevel@tonic-gate 			}
2527c478bd9Sstevel@tonic-gate 			current_page = pageno;
2537c478bd9Sstevel@tonic-gate 			for (p = p2; *p == ' '; p++)
2547c478bd9Sstevel@tonic-gate 				;
2557c478bd9Sstevel@tonic-gate 			if (*p == 0) {
2567c478bd9Sstevel@tonic-gate 				(void) do_mode_sense(pageno);
2577c478bd9Sstevel@tonic-gate 			} else if (*p == 'b') {
2587c478bd9Sstevel@tonic-gate 				if (parse_change_spec(s, p, pageno,
259342440ecSPrasad Singamsetty 				    &change_item)) {
2607c478bd9Sstevel@tonic-gate 					(void) do_mode_select(&change_item);
2617c478bd9Sstevel@tonic-gate 				}
2627c478bd9Sstevel@tonic-gate 			}
2637c478bd9Sstevel@tonic-gate 		} else if (s[0] == 'b') {
2647c478bd9Sstevel@tonic-gate 				if (current_page == -1) {
2657c478bd9Sstevel@tonic-gate 					err_print("\
2667c478bd9Sstevel@tonic-gate Please display the page on which you'd like to do a mode select\n");
2677c478bd9Sstevel@tonic-gate 					goto error;
2687c478bd9Sstevel@tonic-gate 				}
2697c478bd9Sstevel@tonic-gate 				chg_item = (struct chg_list *)
270342440ecSPrasad Singamsetty 				    zalloc(sizeof (struct chg_list));
2717c478bd9Sstevel@tonic-gate 				if (parse_change_spec(s, s, current_page,
272342440ecSPrasad Singamsetty 				    chg_item)) {
2737c478bd9Sstevel@tonic-gate 					add_new_change_list_item(chg_item);
2747c478bd9Sstevel@tonic-gate 				} else {
2757c478bd9Sstevel@tonic-gate 					destroy_data((char *)chg_item);
2767c478bd9Sstevel@tonic-gate 				}
2777c478bd9Sstevel@tonic-gate 		} else if (s[0] == '!') {
278f1c60556Spr 			(void) execute_shell(&s[1], sizeof (s) - 1);
2797c478bd9Sstevel@tonic-gate 			help = 1;
2807c478bd9Sstevel@tonic-gate 		} else if (s[0] != 0) {
2817c478bd9Sstevel@tonic-gate 			err_print("Syntax error: %s\n", s);
2827c478bd9Sstevel@tonic-gate 		}
2837c478bd9Sstevel@tonic-gate error:
2847c478bd9Sstevel@tonic-gate 		/*
2857c478bd9Sstevel@tonic-gate 		 * Mark the saved environment inactive so ctrl-C doesn't
2867c478bd9Sstevel@tonic-gate 		 * work at the menu itself.
2877c478bd9Sstevel@tonic-gate 		 */
2887c478bd9Sstevel@tonic-gate 		unuseenv();
2897c478bd9Sstevel@tonic-gate 	}
2907c478bd9Sstevel@tonic-gate exit:
2917c478bd9Sstevel@tonic-gate 	/*
2927c478bd9Sstevel@tonic-gate 	 * Clean up the environment stack and free the menu
2937c478bd9Sstevel@tonic-gate 	 */
2947c478bd9Sstevel@tonic-gate 	clearenv();
2957c478bd9Sstevel@tonic-gate 	destroy_data((char *)menu);
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate 	/*
2987c478bd9Sstevel@tonic-gate 	 * Clean up the change list, if anything left over
2997c478bd9Sstevel@tonic-gate 	 */
3007c478bd9Sstevel@tonic-gate 	free_change_list();
3017c478bd9Sstevel@tonic-gate 
3027c478bd9Sstevel@tonic-gate 	/*
3037c478bd9Sstevel@tonic-gate 	 * Make sure user is prompted with previous menu
3047c478bd9Sstevel@tonic-gate 	 */
3057c478bd9Sstevel@tonic-gate 	last_menu++;
3067c478bd9Sstevel@tonic-gate 
3077c478bd9Sstevel@tonic-gate 	return (0);
3087c478bd9Sstevel@tonic-gate }
3097c478bd9Sstevel@tonic-gate 
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate /*
3127c478bd9Sstevel@tonic-gate  * Do a mode sense on a particular page, and dump the data.
3137c478bd9Sstevel@tonic-gate  * Get all the various flavors:  default, current, saved, changeable.
3147c478bd9Sstevel@tonic-gate  */
3157c478bd9Sstevel@tonic-gate static int
do_mode_sense(int pageno)316*b12aaafbSToomas Soome do_mode_sense(int pageno)
3177c478bd9Sstevel@tonic-gate {
3187c478bd9Sstevel@tonic-gate 	struct scsi_ms_header	header;
3197c478bd9Sstevel@tonic-gate 	struct mode_page	*pg;
3207c478bd9Sstevel@tonic-gate 	char			msbuf[MAX_MODE_SENSE_SIZE];
3217c478bd9Sstevel@tonic-gate 	int			result = 0;
3227c478bd9Sstevel@tonic-gate 
3237c478bd9Sstevel@tonic-gate 	char	*default_msg	= "default:     ";
3247c478bd9Sstevel@tonic-gate 	char	*saved_msg	= "saved:       ";
3257c478bd9Sstevel@tonic-gate 	char	*current_msg	= "current:     ";
3267c478bd9Sstevel@tonic-gate 	char	*changeable_msg	= "changeable:  ";
3277c478bd9Sstevel@tonic-gate 
3287c478bd9Sstevel@tonic-gate 
3297c478bd9Sstevel@tonic-gate 	pg = (struct mode_page *)msbuf;
3307c478bd9Sstevel@tonic-gate 
3317c478bd9Sstevel@tonic-gate 	fmt_print("\nPage 0x%x:\n", pageno);
3327c478bd9Sstevel@tonic-gate 	if (uscsi_mode_sense(cur_file, pageno, MODE_SENSE_PC_DEFAULT,
333*b12aaafbSToomas Soome 	    msbuf, MAX_MODE_SENSE_SIZE, &header)) {
3347c478bd9Sstevel@tonic-gate 		err_print("%sfailed\n", default_msg);
3357c478bd9Sstevel@tonic-gate 		result = 1;
3367c478bd9Sstevel@tonic-gate 	} else {
337*b12aaafbSToomas Soome 		dump(default_msg, msbuf, MODESENSE_PAGE_LEN(pg), HEX_ONLY);
3387c478bd9Sstevel@tonic-gate 	}
3397c478bd9Sstevel@tonic-gate 
3407c478bd9Sstevel@tonic-gate 	if (uscsi_mode_sense(cur_file, pageno, MODE_SENSE_PC_CURRENT,
341*b12aaafbSToomas Soome 	    msbuf, MAX_MODE_SENSE_SIZE, &header)) {
3427c478bd9Sstevel@tonic-gate 		err_print("%sfailed\n", current_msg);
3437c478bd9Sstevel@tonic-gate 		result = 1;
3447c478bd9Sstevel@tonic-gate 	} else {
345*b12aaafbSToomas Soome 		dump(current_msg, msbuf, MODESENSE_PAGE_LEN(pg), HEX_ONLY);
3467c478bd9Sstevel@tonic-gate 	}
3477c478bd9Sstevel@tonic-gate 
3487c478bd9Sstevel@tonic-gate 	if (uscsi_mode_sense(cur_file, pageno, MODE_SENSE_PC_SAVED,
349*b12aaafbSToomas Soome 	    msbuf, MAX_MODE_SENSE_SIZE, &header)) {
3507c478bd9Sstevel@tonic-gate 		err_print("%sfailed\n", saved_msg);
3517c478bd9Sstevel@tonic-gate 		result = 1;
3527c478bd9Sstevel@tonic-gate 	} else {
353*b12aaafbSToomas Soome 		dump(saved_msg, msbuf, MODESENSE_PAGE_LEN(pg), HEX_ONLY);
3547c478bd9Sstevel@tonic-gate 	}
3557c478bd9Sstevel@tonic-gate 
3567c478bd9Sstevel@tonic-gate 	if (uscsi_mode_sense(cur_file, pageno, MODE_SENSE_PC_CHANGEABLE,
357*b12aaafbSToomas Soome 	    msbuf, MAX_MODE_SENSE_SIZE, &header)) {
3587c478bd9Sstevel@tonic-gate 		err_print("%sfailed\n", changeable_msg);
3597c478bd9Sstevel@tonic-gate 		result = 1;
3607c478bd9Sstevel@tonic-gate 	} else {
361*b12aaafbSToomas Soome 		dump(changeable_msg, msbuf, MODESENSE_PAGE_LEN(pg), HEX_ONLY);
3627c478bd9Sstevel@tonic-gate 	}
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate 	fmt_print("\n");
3657c478bd9Sstevel@tonic-gate 	return (result);
3667c478bd9Sstevel@tonic-gate }
3677c478bd9Sstevel@tonic-gate 
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate /*
3707c478bd9Sstevel@tonic-gate  * Dump all the pages a device supports
3717c478bd9Sstevel@tonic-gate  */
3727c478bd9Sstevel@tonic-gate static int
do_mode_sense_all(void)373*b12aaafbSToomas Soome do_mode_sense_all(void)
3747c478bd9Sstevel@tonic-gate {
3757c478bd9Sstevel@tonic-gate 	int	result = 0;
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate 	if (scsi_dump_mode_sense_pages(MODE_SENSE_PC_DEFAULT)) {
3787c478bd9Sstevel@tonic-gate 		result = 1;
3797c478bd9Sstevel@tonic-gate 	}
3807c478bd9Sstevel@tonic-gate 	if (scsi_dump_mode_sense_pages(MODE_SENSE_PC_CURRENT)) {
3817c478bd9Sstevel@tonic-gate 		result = 1;
3827c478bd9Sstevel@tonic-gate 	}
3837c478bd9Sstevel@tonic-gate 	if (scsi_dump_mode_sense_pages(MODE_SENSE_PC_SAVED)) {
3847c478bd9Sstevel@tonic-gate 		result = 1;
3857c478bd9Sstevel@tonic-gate 	}
3867c478bd9Sstevel@tonic-gate 	if (scsi_dump_mode_sense_pages(MODE_SENSE_PC_CHANGEABLE)) {
3877c478bd9Sstevel@tonic-gate 		result = 1;
3887c478bd9Sstevel@tonic-gate 	}
3897c478bd9Sstevel@tonic-gate 	fmt_print("\n");
3907c478bd9Sstevel@tonic-gate 	return (result);
3917c478bd9Sstevel@tonic-gate }
3927c478bd9Sstevel@tonic-gate 
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate /*
3957c478bd9Sstevel@tonic-gate  * Get the current mode sense for a particular page, change
3967c478bd9Sstevel@tonic-gate  * a byte, and issue a mode select.  Note that we can only
3977c478bd9Sstevel@tonic-gate  * change a value if the device indicates that those bits
3987c478bd9Sstevel@tonic-gate  * are changeable.
3997c478bd9Sstevel@tonic-gate  */
4007c478bd9Sstevel@tonic-gate static int
do_mode_select(struct chg_list * change_item)401*b12aaafbSToomas Soome do_mode_select(struct chg_list *change_item)
4027c478bd9Sstevel@tonic-gate {
4037c478bd9Sstevel@tonic-gate 	struct scsi_ms_header	header;
4047c478bd9Sstevel@tonic-gate 	char			saved[MAX_MODE_SENSE_SIZE];
4057c478bd9Sstevel@tonic-gate 	char			changeable[MAX_MODE_SENSE_SIZE];
4067c478bd9Sstevel@tonic-gate 	struct mode_page	*pg;
4077c478bd9Sstevel@tonic-gate 	struct mode_page	*pg2;
4087c478bd9Sstevel@tonic-gate 	int			length;
4097c478bd9Sstevel@tonic-gate 	int			pageno;
4107c478bd9Sstevel@tonic-gate 	int			flags;
4117c478bd9Sstevel@tonic-gate 	int			result = 0;
4127c478bd9Sstevel@tonic-gate 
4137c478bd9Sstevel@tonic-gate 	pageno = change_item->pageno;
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate 	/*
4167c478bd9Sstevel@tonic-gate 	 * Get changeable mode sense
4177c478bd9Sstevel@tonic-gate 	 */
4187c478bd9Sstevel@tonic-gate 	if (uscsi_mode_sense(cur_file, pageno, MODE_SENSE_PC_CHANGEABLE,
419*b12aaafbSToomas Soome 	    changeable, MAX_MODE_SENSE_SIZE, &header)) {
4207c478bd9Sstevel@tonic-gate 		err_print("Mode sense on page %x (changeable) failed\n",
421*b12aaafbSToomas Soome 		    pageno);
4227c478bd9Sstevel@tonic-gate 		return (1);
4237c478bd9Sstevel@tonic-gate 	}
4247c478bd9Sstevel@tonic-gate 
4257c478bd9Sstevel@tonic-gate 	/*
4267c478bd9Sstevel@tonic-gate 	 * Get saved mode sense.  If saved fails, use current values.
4277c478bd9Sstevel@tonic-gate 	 */
4287c478bd9Sstevel@tonic-gate 	if (uscsi_mode_sense(cur_file, pageno, MODE_SENSE_PC_SAVED,
429*b12aaafbSToomas Soome 	    saved, MAX_MODE_SENSE_SIZE, &header)) {
430*b12aaafbSToomas Soome 		err_print("Mode sense on page %x (saved) failed\n", pageno);
4317c478bd9Sstevel@tonic-gate 		if (uscsi_mode_sense(cur_file, pageno, MODE_SENSE_PC_CURRENT,
432*b12aaafbSToomas Soome 		    saved, MAX_MODE_SENSE_SIZE, &header)) {
4337c478bd9Sstevel@tonic-gate 			err_print("Mode sense on page %x (current) failed\n",
434*b12aaafbSToomas Soome 			    pageno);
4357c478bd9Sstevel@tonic-gate 			return (1);
4367c478bd9Sstevel@tonic-gate 		} else {
4377c478bd9Sstevel@tonic-gate 			err_print("Using current values instead\n");
4387c478bd9Sstevel@tonic-gate 		}
4397c478bd9Sstevel@tonic-gate 	}
4407c478bd9Sstevel@tonic-gate 
4417c478bd9Sstevel@tonic-gate 	/*
4427c478bd9Sstevel@tonic-gate 	 * Use the intersection of the saved and changeable
4437c478bd9Sstevel@tonic-gate 	 */
4447c478bd9Sstevel@tonic-gate 	pg = (struct mode_page *)saved;
4457c478bd9Sstevel@tonic-gate 	pg2 = (struct mode_page *)changeable;
4467c478bd9Sstevel@tonic-gate 	length = min(MODESENSE_PAGE_LEN(pg), MODESENSE_PAGE_LEN(pg2));
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate 	/*
4497c478bd9Sstevel@tonic-gate 	 * Try making this change to this page
4507c478bd9Sstevel@tonic-gate 	 */
4517c478bd9Sstevel@tonic-gate 	if (apply_chg_list(pageno, length, (uchar_t *)saved,
452*b12aaafbSToomas Soome 	    (uchar_t *)changeable, change_item)) {
4537c478bd9Sstevel@tonic-gate 		/*
4547c478bd9Sstevel@tonic-gate 		 * A change was made.  Do a mode select
4557c478bd9Sstevel@tonic-gate 		 * We always want to set the Page Format bit.
4567c478bd9Sstevel@tonic-gate 		 * Set the Save Page bit if the drive indicates
4577c478bd9Sstevel@tonic-gate 		 * that it can save this page.
4587c478bd9Sstevel@tonic-gate 		 */
4597c478bd9Sstevel@tonic-gate 		flags = MODE_SELECT_PF;
4607c478bd9Sstevel@tonic-gate 		if (pg->ps) {
4617c478bd9Sstevel@tonic-gate 			flags |= MODE_SELECT_SP;
4627c478bd9Sstevel@tonic-gate 		}
4637c478bd9Sstevel@tonic-gate 		pg->ps = 0;
4647c478bd9Sstevel@tonic-gate 		header.mode_header.length = 0;
4657c478bd9Sstevel@tonic-gate 		header.mode_header.device_specific = 0;
4667c478bd9Sstevel@tonic-gate 		if (uscsi_mode_select(cur_file, pageno, flags,
467*b12aaafbSToomas Soome 		    saved, length, &header)) {
4687c478bd9Sstevel@tonic-gate 			/*
4697c478bd9Sstevel@tonic-gate 			 * Failed - try not saving parameters,
4707c478bd9Sstevel@tonic-gate 			 * if possible.
4717c478bd9Sstevel@tonic-gate 			 */
4727c478bd9Sstevel@tonic-gate 			if (flags & MODE_SELECT_SP) {
4737c478bd9Sstevel@tonic-gate 				flags &= ~MODE_SELECT_SP;
4747c478bd9Sstevel@tonic-gate 				if (uscsi_mode_select(cur_file, pageno,
475*b12aaafbSToomas Soome 				    flags, saved, length, &header)) {
4767c478bd9Sstevel@tonic-gate 					result = 1;
4777c478bd9Sstevel@tonic-gate 				}
4787c478bd9Sstevel@tonic-gate 			} else {
4797c478bd9Sstevel@tonic-gate 				result = 1;
4807c478bd9Sstevel@tonic-gate 			}
4817c478bd9Sstevel@tonic-gate 		}
4827c478bd9Sstevel@tonic-gate 
4837c478bd9Sstevel@tonic-gate 		if (result) {
4847c478bd9Sstevel@tonic-gate 			fmt_print("\n\
4857c478bd9Sstevel@tonic-gate Mode select on page %x failed.\n", pageno);
4867c478bd9Sstevel@tonic-gate 		} else if ((flags & MODE_SELECT_SP) == 0) {
4877c478bd9Sstevel@tonic-gate 			fmt_print("\n\
4887c478bd9Sstevel@tonic-gate Mode select on page %x ok, but unable to save change permanently.\n", pageno);
4897c478bd9Sstevel@tonic-gate 		} else {
4907c478bd9Sstevel@tonic-gate 			fmt_print("\n\
4917c478bd9Sstevel@tonic-gate Mode select on page %x ok.\n", pageno);
4927c478bd9Sstevel@tonic-gate 		}
4937c478bd9Sstevel@tonic-gate 	} else {
4947c478bd9Sstevel@tonic-gate 		err_print("\nDevice cannot support this change\n");
4957c478bd9Sstevel@tonic-gate 	}
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate 	fmt_print("\n");
4987c478bd9Sstevel@tonic-gate 	return (result);
4997c478bd9Sstevel@tonic-gate }
5007c478bd9Sstevel@tonic-gate 
5017c478bd9Sstevel@tonic-gate 
5027c478bd9Sstevel@tonic-gate /*
5037c478bd9Sstevel@tonic-gate  * Format a device, without any of the standard mode selects.
5047c478bd9Sstevel@tonic-gate  * Ask if we should format with the P or the P&G lists.
5057c478bd9Sstevel@tonic-gate  */
5067c478bd9Sstevel@tonic-gate static int
do_format(void)507*b12aaafbSToomas Soome do_format(void)
5087c478bd9Sstevel@tonic-gate {
5097c478bd9Sstevel@tonic-gate 	struct uscsi_cmd	ucmd;
5107c478bd9Sstevel@tonic-gate 	union scsi_cdb		cdb;
5117c478bd9Sstevel@tonic-gate 	struct scsi_defect_hdr	defect_hdr;
5127c478bd9Sstevel@tonic-gate 	int			status;
5137c478bd9Sstevel@tonic-gate 	u_ioparam_t		ioparam;
5147c478bd9Sstevel@tonic-gate 	int			deflt;
5157c478bd9Sstevel@tonic-gate 	int			grown_list;
5167c478bd9Sstevel@tonic-gate 
5177c478bd9Sstevel@tonic-gate 	fmt_print("\n");
5187c478bd9Sstevel@tonic-gate 	/*
5197c478bd9Sstevel@tonic-gate 	 * Are there mounted partitions?
5207c478bd9Sstevel@tonic-gate 	 */
521342440ecSPrasad Singamsetty 	if (checkmount((diskaddr_t)-1, (diskaddr_t)-1)) {
5227c478bd9Sstevel@tonic-gate 		err_print("Cannot format disk with mounted partitions\n\n");
5237c478bd9Sstevel@tonic-gate 		return (-1);
5247c478bd9Sstevel@tonic-gate 	}
5257c478bd9Sstevel@tonic-gate 
5267c478bd9Sstevel@tonic-gate 	/*
5277c478bd9Sstevel@tonic-gate 	 * Is any of the partitions being used for swapping.
5287c478bd9Sstevel@tonic-gate 	 */
529342440ecSPrasad Singamsetty 	if (checkswap((diskaddr_t)-1, (diskaddr_t)-1)) {
5307c478bd9Sstevel@tonic-gate 		err_print("Cannot format disk while its partitions are \
5317c478bd9Sstevel@tonic-gate currently being used for swapping.\n\n");
5327c478bd9Sstevel@tonic-gate 		return (-1);
5337c478bd9Sstevel@tonic-gate 	}
5343e1bd7a2Ssjelinek 	/*
5353e1bd7a2Ssjelinek 	 * Are any being used for SVM, VxVM or live upgrade.
5363e1bd7a2Ssjelinek 	 */
5373e1bd7a2Ssjelinek 	if (checkdevinuse(cur_disk->disk_name, (diskaddr_t)-1,
5383e1bd7a2Ssjelinek 	    (diskaddr_t)-1, 0, 0)) {
5393e1bd7a2Ssjelinek 		err_print("Cannot format disk while its partitions are "
5403e1bd7a2Ssjelinek 		    "currently being used as described.\n");
5413e1bd7a2Ssjelinek 		return (-1);
5423e1bd7a2Ssjelinek 	}
5437c478bd9Sstevel@tonic-gate 
5447c478bd9Sstevel@tonic-gate 	/*
5457c478bd9Sstevel@tonic-gate 	 * Let the user choose between formatting with either
5467c478bd9Sstevel@tonic-gate 	 * the P, or the P&G lists.  Note that yes is 0, no is 1.
5477c478bd9Sstevel@tonic-gate 	 */
5487c478bd9Sstevel@tonic-gate 	deflt = 0;
5497c478bd9Sstevel@tonic-gate 	ioparam.io_charlist = confirm_list;
5507c478bd9Sstevel@tonic-gate 	grown_list = !input(FIO_MSTR, "Format with the Grown Defects list",
551342440ecSPrasad Singamsetty 	    '?', &ioparam, &deflt, DATA_INPUT);
5527c478bd9Sstevel@tonic-gate 
5537c478bd9Sstevel@tonic-gate 	/*
5547c478bd9Sstevel@tonic-gate 	 * Construct the uscsi format ioctl.
5557c478bd9Sstevel@tonic-gate 	 * To format with the P and G list, we set the fmtData
5567c478bd9Sstevel@tonic-gate 	 * and cmpLst bits to zero.  To format with just the
5577c478bd9Sstevel@tonic-gate 	 * P list, we set the fmtData bit (meaning that we will
5587c478bd9Sstevel@tonic-gate 	 * send down a defect list in the data phase) and the
5597c478bd9Sstevel@tonic-gate 	 * cmpLst bit (meaning that the list we send is the
5607c478bd9Sstevel@tonic-gate 	 * complete G list), and a defect list header with
5617c478bd9Sstevel@tonic-gate 	 * a defect list length of zero.
5627c478bd9Sstevel@tonic-gate 	 */
5637c478bd9Sstevel@tonic-gate 	(void) memset((char *)&ucmd, 0, sizeof (ucmd));
5647c478bd9Sstevel@tonic-gate 	(void) memset((char *)&cdb, 0, sizeof (union scsi_cdb));
5657c478bd9Sstevel@tonic-gate 	cdb.scc_cmd = SCMD_FORMAT;
5667c478bd9Sstevel@tonic-gate 	ucmd.uscsi_cdb = (caddr_t)&cdb;
5677c478bd9Sstevel@tonic-gate 	ucmd.uscsi_cdblen = CDB_GROUP0;
5687c478bd9Sstevel@tonic-gate 	if (!grown_list) {
5697c478bd9Sstevel@tonic-gate 		/*
5707c478bd9Sstevel@tonic-gate 		 * No G list.   Send empty defect list to replace it.
5717c478bd9Sstevel@tonic-gate 		 */
5727c478bd9Sstevel@tonic-gate 		cdb.cdb_opaque[1] = FPB_DATA | FPB_CMPLT | FPB_BFI;
5737c478bd9Sstevel@tonic-gate 		(void) memset((char *)&defect_hdr, 0, sizeof (defect_hdr));
5747c478bd9Sstevel@tonic-gate 		ucmd.uscsi_bufaddr = (caddr_t)&defect_hdr;
5757c478bd9Sstevel@tonic-gate 		ucmd.uscsi_buflen = sizeof (defect_hdr);
5767c478bd9Sstevel@tonic-gate 	}
5777c478bd9Sstevel@tonic-gate 
5787c478bd9Sstevel@tonic-gate 	/*
5797c478bd9Sstevel@tonic-gate 	 * Issue the format ioctl
5807c478bd9Sstevel@tonic-gate 	 */
5817c478bd9Sstevel@tonic-gate 	fmt_print("Formatting...\n");
5827c478bd9Sstevel@tonic-gate 	(void) fflush(stdout);
5837c478bd9Sstevel@tonic-gate 	status = uscsi_cmd(cur_file, &ucmd, F_NORMAL);
5847c478bd9Sstevel@tonic-gate 	fmt_print(status ? "Format failed\n\n" : "Format ok\n\n");
5857c478bd9Sstevel@tonic-gate 	return (status);
5867c478bd9Sstevel@tonic-gate }
5877c478bd9Sstevel@tonic-gate 
5887c478bd9Sstevel@tonic-gate 
5897c478bd9Sstevel@tonic-gate /*
5907c478bd9Sstevel@tonic-gate  * List common SCSI-2 mode pages
5917c478bd9Sstevel@tonic-gate  */
5927c478bd9Sstevel@tonic-gate static void
do_list(void)593*b12aaafbSToomas Soome do_list(void)
5947c478bd9Sstevel@tonic-gate {
5957c478bd9Sstevel@tonic-gate 	fmt_print("\n\
5967c478bd9Sstevel@tonic-gate Common SCSI-2 pages applicable to direct-access devices:\n\n");
5977c478bd9Sstevel@tonic-gate 	fmt_print("Page 0x1   - Read-Write Error Recovery Page\n");
5987c478bd9Sstevel@tonic-gate 	fmt_print("Page 0x2   - Disconnect-Reconnect Page\n");
5997c478bd9Sstevel@tonic-gate 	fmt_print("Page 0x3   - Format Device Page\n");
6007c478bd9Sstevel@tonic-gate 	fmt_print("Page 0x4   - Rigid Disk Geometry Page\n");
6017c478bd9Sstevel@tonic-gate 	fmt_print("Page 0x7   - Verify Error Recovery Page\n");
6027c478bd9Sstevel@tonic-gate 	fmt_print("Page 0x8   - Caching Page\n");
6037c478bd9Sstevel@tonic-gate 	fmt_print("Page 0xA   - Control Mode Page\n");
6047c478bd9Sstevel@tonic-gate 	fmt_print("\n");
6057c478bd9Sstevel@tonic-gate }
6067c478bd9Sstevel@tonic-gate 
6077c478bd9Sstevel@tonic-gate 
6087c478bd9Sstevel@tonic-gate /*
6097c478bd9Sstevel@tonic-gate  * Labels for the various fields of the scsi_inquiry structure
6107c478bd9Sstevel@tonic-gate  */
6117c478bd9Sstevel@tonic-gate static char *scsi_inquiry_labels[] = {
6127c478bd9Sstevel@tonic-gate 	"Vendor:                     ",
6137c478bd9Sstevel@tonic-gate 	"Product:                    ",
6147c478bd9Sstevel@tonic-gate 	"Revision:                   ",
6157c478bd9Sstevel@tonic-gate 	"Removable media:            ",
6167c478bd9Sstevel@tonic-gate 	"Device type:                ",
6177c478bd9Sstevel@tonic-gate 	"ISO version:                ",
6187c478bd9Sstevel@tonic-gate 	"ECMA version:               ",
6197c478bd9Sstevel@tonic-gate 	"ANSI version:               ",
6207c478bd9Sstevel@tonic-gate 	"Async event notification:   ",
6217c478bd9Sstevel@tonic-gate 	"Terminate i/o process msg:  ",
6227c478bd9Sstevel@tonic-gate 	"Response data format:       ",
6237c478bd9Sstevel@tonic-gate 	"Additional length:          ",
6247c478bd9Sstevel@tonic-gate 	"Relative addressing:        ",
6257c478bd9Sstevel@tonic-gate 	"32 bit transfers:           ",
6267c478bd9Sstevel@tonic-gate 	"16 bit transfers:           ",
6277c478bd9Sstevel@tonic-gate 	"Synchronous transfers:      ",
6287c478bd9Sstevel@tonic-gate 	"Linked commands:            ",
6297c478bd9Sstevel@tonic-gate 	"Command queueing:           ",
6307c478bd9Sstevel@tonic-gate 	"Soft reset option:          "
6317c478bd9Sstevel@tonic-gate };
6327c478bd9Sstevel@tonic-gate 
6337c478bd9Sstevel@tonic-gate 
6347c478bd9Sstevel@tonic-gate /*
6357c478bd9Sstevel@tonic-gate  * Dump the full inquiry as returned by the device
6367c478bd9Sstevel@tonic-gate  */
6377c478bd9Sstevel@tonic-gate static int
do_inquiry(void)638*b12aaafbSToomas Soome do_inquiry(void)
6397c478bd9Sstevel@tonic-gate {
6407c478bd9Sstevel@tonic-gate 	char			inqbuf[255];
6417c478bd9Sstevel@tonic-gate 	struct scsi_inquiry	*inq;
6427c478bd9Sstevel@tonic-gate 	char			**p;
6437c478bd9Sstevel@tonic-gate 
6447c478bd9Sstevel@tonic-gate 	inq = (struct scsi_inquiry *)inqbuf;
6457c478bd9Sstevel@tonic-gate 
6467c478bd9Sstevel@tonic-gate 	if (uscsi_inquiry(cur_file, inqbuf, sizeof (inqbuf))) {
6477c478bd9Sstevel@tonic-gate 		err_print("\nInquiry failed\n");
6487c478bd9Sstevel@tonic-gate 		return (1);
6497c478bd9Sstevel@tonic-gate 	}
6507c478bd9Sstevel@tonic-gate 
6517c478bd9Sstevel@tonic-gate 	fmt_print("\nInquiry:\n");
6527c478bd9Sstevel@tonic-gate 	/*
6537c478bd9Sstevel@tonic-gate 	 * The SCSI-2 spec defines "Additional length" as (n-4) bytes,
6547c478bd9Sstevel@tonic-gate 	 * where n is the last byte of the INQUIRY data.  Thus
6557c478bd9Sstevel@tonic-gate 	 * there are n+1 bytes of INQUIRY data.  We need to add 5 to
6567c478bd9Sstevel@tonic-gate 	 * inq_len in order to get all the INQUIRY data.
6577c478bd9Sstevel@tonic-gate 	 */
6587c478bd9Sstevel@tonic-gate 	dump("    ", inqbuf, inq->inq_len + 5, HEX_ASCII);
6597c478bd9Sstevel@tonic-gate 	fmt_print("\n");
6607c478bd9Sstevel@tonic-gate 
6617c478bd9Sstevel@tonic-gate 	p = scsi_inquiry_labels;
6627c478bd9Sstevel@tonic-gate 
6637c478bd9Sstevel@tonic-gate 	fmt_print("%s", *p++);
6647c478bd9Sstevel@tonic-gate 	print_buf(inq->inq_vid, sizeof (inq->inq_vid));
6657c478bd9Sstevel@tonic-gate 	fmt_print("\n%s", *p++);
6667c478bd9Sstevel@tonic-gate 	print_buf(inq->inq_pid, sizeof (inq->inq_pid));
6677c478bd9Sstevel@tonic-gate 	fmt_print("\n%s", *p++);
6687c478bd9Sstevel@tonic-gate 	print_buf(inq->inq_revision, sizeof (inq->inq_revision));
6697c478bd9Sstevel@tonic-gate 
6707c478bd9Sstevel@tonic-gate 	fmt_print("\n%s%s\n", *p++, inq->inq_rmb ? "yes" : "no");
6717c478bd9Sstevel@tonic-gate 	fmt_print("%s%d\n", *p++, inq->inq_qual);
6727c478bd9Sstevel@tonic-gate 	fmt_print("%s%d\n", *p++, inq->inq_iso);
6737c478bd9Sstevel@tonic-gate 	fmt_print("%s%d\n", *p++, inq->inq_ecma);
6747c478bd9Sstevel@tonic-gate 	fmt_print("%s%d\n", *p++, inq->inq_ansi);
6757c478bd9Sstevel@tonic-gate 	fmt_print("%s%s\n", *p++, inq->inq_aenc ? "yes" : "no");
6767c478bd9Sstevel@tonic-gate 	fmt_print("%s%s\n", *p++, inq->inq_trmiop ? "yes" : "no");
6777c478bd9Sstevel@tonic-gate 	fmt_print("%s%d\n", *p++, inq->inq_rdf);
6787c478bd9Sstevel@tonic-gate 	fmt_print("%s%d\n", *p++, inq->inq_len);
6797c478bd9Sstevel@tonic-gate 	fmt_print("%s%s\n", *p++, inq->inq_reladdr ? "yes" : "no");
6807c478bd9Sstevel@tonic-gate 	fmt_print("%s%s\n", *p++, inq->inq_wbus32 ? "yes" : "no");
6817c478bd9Sstevel@tonic-gate 	fmt_print("%s%s\n", *p++, inq->inq_wbus16 ? "yes" : "no");
6827c478bd9Sstevel@tonic-gate 	fmt_print("%s%s\n", *p++, inq->inq_sync ? "yes" : "no");
6837c478bd9Sstevel@tonic-gate 	fmt_print("%s%s\n", *p++, inq->inq_linked ? "yes" : "no");
6847c478bd9Sstevel@tonic-gate 	fmt_print("%s%s\n", *p++, inq->inq_cmdque ? "yes" : "no");
6857c478bd9Sstevel@tonic-gate 	fmt_print("%s%s\n", *p++, inq->inq_sftre ? "yes" : "no");
6867c478bd9Sstevel@tonic-gate 
6877c478bd9Sstevel@tonic-gate 	fmt_print("\n");
6887c478bd9Sstevel@tonic-gate 	return (0);
6897c478bd9Sstevel@tonic-gate }
6907c478bd9Sstevel@tonic-gate 
6917c478bd9Sstevel@tonic-gate 
6927c478bd9Sstevel@tonic-gate static void
do_apply(void)693*b12aaafbSToomas Soome do_apply(void)
6947c478bd9Sstevel@tonic-gate {
6957c478bd9Sstevel@tonic-gate 	if (change_list == NULL) {
6967c478bd9Sstevel@tonic-gate 		fmt_print("\nlist empty.\n");
6977c478bd9Sstevel@tonic-gate 	} else {
6987c478bd9Sstevel@tonic-gate 		(void) do_mode_select(change_list);
6997c478bd9Sstevel@tonic-gate 		free_change_list();
7007c478bd9Sstevel@tonic-gate 	}
7017c478bd9Sstevel@tonic-gate }
7027c478bd9Sstevel@tonic-gate 
7037c478bd9Sstevel@tonic-gate 
7047c478bd9Sstevel@tonic-gate static void
do_cancel(void)705*b12aaafbSToomas Soome do_cancel(void)
7067c478bd9Sstevel@tonic-gate {
7077c478bd9Sstevel@tonic-gate 	if (change_list == NULL) {
7087c478bd9Sstevel@tonic-gate 		fmt_print("\nlist empty.\n");
7097c478bd9Sstevel@tonic-gate 	} else {
7107c478bd9Sstevel@tonic-gate 		free_change_list();
7117c478bd9Sstevel@tonic-gate 	}
7127c478bd9Sstevel@tonic-gate }
7137c478bd9Sstevel@tonic-gate 
7147c478bd9Sstevel@tonic-gate 
7157c478bd9Sstevel@tonic-gate static void
do_display(void)716*b12aaafbSToomas Soome do_display(void)
7177c478bd9Sstevel@tonic-gate {
7187c478bd9Sstevel@tonic-gate 	struct chg_list	*cp;
7197c478bd9Sstevel@tonic-gate 
7207c478bd9Sstevel@tonic-gate 	if (change_list == NULL) {
7217c478bd9Sstevel@tonic-gate 		fmt_print("\nlist empty.\n");
7227c478bd9Sstevel@tonic-gate 	} else {
7237c478bd9Sstevel@tonic-gate 		fmt_print("\nPage 0x%x\n", current_page);
7247c478bd9Sstevel@tonic-gate 		for (cp = change_list; cp != NULL; cp = cp->next) {
7257c478bd9Sstevel@tonic-gate 			fmt_print("   b0x%x ", cp->byteno);
7267c478bd9Sstevel@tonic-gate 			switch (cp->mode) {
7277c478bd9Sstevel@tonic-gate 			case CHG_MODE_ABS:
7287c478bd9Sstevel@tonic-gate 				fmt_print("= 0x%x\n", cp->value);
7297c478bd9Sstevel@tonic-gate 				break;
7307c478bd9Sstevel@tonic-gate 			case CHG_MODE_SET:
7317c478bd9Sstevel@tonic-gate 				fmt_print("|= 0x%x\n", cp->value);
7327c478bd9Sstevel@tonic-gate 				break;
7337c478bd9Sstevel@tonic-gate 			case CHG_MODE_CLR:
7347c478bd9Sstevel@tonic-gate 				fmt_print("&= ~0x%x\n",
735342440ecSPrasad Singamsetty 				    (~(cp->value)) & 0xff);
7367c478bd9Sstevel@tonic-gate 				break;
7377c478bd9Sstevel@tonic-gate 			default:
7387c478bd9Sstevel@tonic-gate 				impossible("do_display");
7397c478bd9Sstevel@tonic-gate 				/*NOTREACHED*/
7407c478bd9Sstevel@tonic-gate 			}
7417c478bd9Sstevel@tonic-gate 		}
7427c478bd9Sstevel@tonic-gate 		fmt_print("\n");
7437c478bd9Sstevel@tonic-gate 	}
7447c478bd9Sstevel@tonic-gate }
7457c478bd9Sstevel@tonic-gate 
7467c478bd9Sstevel@tonic-gate 
7477c478bd9Sstevel@tonic-gate static int
parse_change_spec(char * full_input,char * input,int pageno,struct chg_list * chg_item)748*b12aaafbSToomas Soome parse_change_spec(char *full_input, char *input, int pageno,
749*b12aaafbSToomas Soome     struct chg_list *chg_item)
7507c478bd9Sstevel@tonic-gate {
7517c478bd9Sstevel@tonic-gate 	char		*p;
7527c478bd9Sstevel@tonic-gate 	int		tilde;
7537c478bd9Sstevel@tonic-gate 
7547c478bd9Sstevel@tonic-gate 	assert(*input == 'b');
7557c478bd9Sstevel@tonic-gate 
7567c478bd9Sstevel@tonic-gate 	chg_item->pageno = pageno;
7577c478bd9Sstevel@tonic-gate 	chg_item->next = NULL;
7587c478bd9Sstevel@tonic-gate 
7597c478bd9Sstevel@tonic-gate 	input++;
7607c478bd9Sstevel@tonic-gate 	chg_item->byteno = (int)strtol(input, &p, 0);
7617c478bd9Sstevel@tonic-gate 	if (p == input) {
7627c478bd9Sstevel@tonic-gate 		err_print("Syntax error: %s\n", full_input);
7637c478bd9Sstevel@tonic-gate 		return (0);
7647c478bd9Sstevel@tonic-gate 	}
7657c478bd9Sstevel@tonic-gate 	if (chg_item->byteno < 2) {
766*b12aaafbSToomas Soome 		err_print(" Unsupported byte offset: %d\n", chg_item->byteno);
7677c478bd9Sstevel@tonic-gate 		return (0);
7687c478bd9Sstevel@tonic-gate 	}
7697c478bd9Sstevel@tonic-gate 	for (input = p; *input == ' '; input++)
7707c478bd9Sstevel@tonic-gate 		;
7717c478bd9Sstevel@tonic-gate 	chg_item->mode = CHG_MODE_UNDEFINED;
7727c478bd9Sstevel@tonic-gate 	switch (*input++) {
7737c478bd9Sstevel@tonic-gate 	case '=':
7747c478bd9Sstevel@tonic-gate 		chg_item->mode = CHG_MODE_ABS;
7757c478bd9Sstevel@tonic-gate 		break;
7767c478bd9Sstevel@tonic-gate 	case '|':
7777c478bd9Sstevel@tonic-gate 		if (*input++ == '=') {
7787c478bd9Sstevel@tonic-gate 			chg_item->mode = CHG_MODE_SET;
7797c478bd9Sstevel@tonic-gate 		}
7807c478bd9Sstevel@tonic-gate 		break;
7817c478bd9Sstevel@tonic-gate 	case '&':
7827c478bd9Sstevel@tonic-gate 		if (*input++ == '=') {
7837c478bd9Sstevel@tonic-gate 			chg_item->mode = CHG_MODE_CLR;
7847c478bd9Sstevel@tonic-gate 		}
7857c478bd9Sstevel@tonic-gate 		break;
7867c478bd9Sstevel@tonic-gate 	}
7877c478bd9Sstevel@tonic-gate 	if (chg_item->mode == CHG_MODE_UNDEFINED) {
7887c478bd9Sstevel@tonic-gate 		err_print("Syntax error: %s\n", full_input);
7897c478bd9Sstevel@tonic-gate 		return (0);
7907c478bd9Sstevel@tonic-gate 	}
7917c478bd9Sstevel@tonic-gate 	for (; *input == ' '; input++)
7927c478bd9Sstevel@tonic-gate 		;
7937c478bd9Sstevel@tonic-gate 	if (*input == '~') {
7947c478bd9Sstevel@tonic-gate 		tilde = 1;
7957c478bd9Sstevel@tonic-gate 		for (input++; *input == ' '; input++)
7967c478bd9Sstevel@tonic-gate 			;
7977c478bd9Sstevel@tonic-gate 	} else {
7987c478bd9Sstevel@tonic-gate 		tilde = 0;
7997c478bd9Sstevel@tonic-gate 	}
8007c478bd9Sstevel@tonic-gate 	chg_item->value = (int)strtol(input, &p, 0);
8017c478bd9Sstevel@tonic-gate 	if (p == input || *p != 0) {
8027c478bd9Sstevel@tonic-gate 		err_print("Syntax error: %s\n", full_input);
8037c478bd9Sstevel@tonic-gate 		return (0);
8047c478bd9Sstevel@tonic-gate 	}
8057c478bd9Sstevel@tonic-gate 	/*
8067c478bd9Sstevel@tonic-gate 	 * Apply complement if selected.
8077c478bd9Sstevel@tonic-gate 	 * Constrain to a byte value.
8087c478bd9Sstevel@tonic-gate 	 */
8097c478bd9Sstevel@tonic-gate 	if (tilde) {
8107c478bd9Sstevel@tonic-gate 		chg_item->value = ~chg_item->value;
8117c478bd9Sstevel@tonic-gate 	}
8127c478bd9Sstevel@tonic-gate 	chg_item->value &= 0xff;
8137c478bd9Sstevel@tonic-gate 
8147c478bd9Sstevel@tonic-gate 	return (1);
8157c478bd9Sstevel@tonic-gate }
8167c478bd9Sstevel@tonic-gate 
8177c478bd9Sstevel@tonic-gate 
8187c478bd9Sstevel@tonic-gate static void
add_new_change_list_item(struct chg_list * chg_item)819*b12aaafbSToomas Soome add_new_change_list_item(struct chg_list *chg_item)
8207c478bd9Sstevel@tonic-gate {
8217c478bd9Sstevel@tonic-gate 	struct chg_list	*cp;
8227c478bd9Sstevel@tonic-gate 
8237c478bd9Sstevel@tonic-gate 	if (change_list == NULL) {
8247c478bd9Sstevel@tonic-gate 		change_list = chg_item;
8257c478bd9Sstevel@tonic-gate 	} else {
8267c478bd9Sstevel@tonic-gate 		for (cp = change_list; cp->next != NULL; cp = cp->next)
8277c478bd9Sstevel@tonic-gate 			;
8287c478bd9Sstevel@tonic-gate 		cp->next = chg_item;
8297c478bd9Sstevel@tonic-gate 	}
8307c478bd9Sstevel@tonic-gate 	chg_item->next = NULL;
8317c478bd9Sstevel@tonic-gate }
8327c478bd9Sstevel@tonic-gate 
8337c478bd9Sstevel@tonic-gate 
8347c478bd9Sstevel@tonic-gate static void
free_change_list(void)835*b12aaafbSToomas Soome free_change_list(void)
8367c478bd9Sstevel@tonic-gate {
8377c478bd9Sstevel@tonic-gate 	struct chg_list	*cp;
8387c478bd9Sstevel@tonic-gate 	struct chg_list	*cp2;
8397c478bd9Sstevel@tonic-gate 
8407c478bd9Sstevel@tonic-gate 	cp = change_list;
8417c478bd9Sstevel@tonic-gate 	while (cp != NULL) {
8427c478bd9Sstevel@tonic-gate 		cp2 = cp->next;
8437c478bd9Sstevel@tonic-gate 		destroy_data((char *)cp);
8447c478bd9Sstevel@tonic-gate 		cp = cp2;
8457c478bd9Sstevel@tonic-gate 	}
8467c478bd9Sstevel@tonic-gate 	change_list = NULL;
8477c478bd9Sstevel@tonic-gate }
8487c478bd9Sstevel@tonic-gate 
8497c478bd9Sstevel@tonic-gate 
8507c478bd9Sstevel@tonic-gate static void
do_default(char * input)851*b12aaafbSToomas Soome do_default(char *input)
8527c478bd9Sstevel@tonic-gate {
8537c478bd9Sstevel@tonic-gate 	char		*s = input;
8547c478bd9Sstevel@tonic-gate 	char		*p;
8557c478bd9Sstevel@tonic-gate 	int		n;
8567c478bd9Sstevel@tonic-gate 
8577c478bd9Sstevel@tonic-gate 	/*
8587c478bd9Sstevel@tonic-gate 	 * Reset current page indicator
8597c478bd9Sstevel@tonic-gate 	 */
8607c478bd9Sstevel@tonic-gate 	current_page = -1;
8617c478bd9Sstevel@tonic-gate 
8627c478bd9Sstevel@tonic-gate 	/*
8637c478bd9Sstevel@tonic-gate 	 * Skip the leading "default" command, which we
8647c478bd9Sstevel@tonic-gate 	 * must have, or we wouldn't have come here,
8657c478bd9Sstevel@tonic-gate 	 * and any white space.
8667c478bd9Sstevel@tonic-gate 	 */
8677c478bd9Sstevel@tonic-gate 	while (isspace(*s)) {
8687c478bd9Sstevel@tonic-gate 		s++;
8697c478bd9Sstevel@tonic-gate 	}
8707c478bd9Sstevel@tonic-gate 
8717c478bd9Sstevel@tonic-gate 	while (*s && isascii(*s) && isalpha(*s)) {
8727c478bd9Sstevel@tonic-gate 		s++;
8737c478bd9Sstevel@tonic-gate 	}
8747c478bd9Sstevel@tonic-gate 
8757c478bd9Sstevel@tonic-gate 	while (isspace(*s)) {
8767c478bd9Sstevel@tonic-gate 		s++;
8777c478bd9Sstevel@tonic-gate 	}
8787c478bd9Sstevel@tonic-gate 
8797c478bd9Sstevel@tonic-gate 	/*
8807c478bd9Sstevel@tonic-gate 	 * Subsequent modifier must be either "p<n>", or "all".
8817c478bd9Sstevel@tonic-gate 	 */
8827c478bd9Sstevel@tonic-gate 	if (*s == 'p') {
8837c478bd9Sstevel@tonic-gate 		s++;
8847c478bd9Sstevel@tonic-gate 		n = (int)strtol(s, &p, 0);
8857c478bd9Sstevel@tonic-gate 		if (p == s || *p != 0) {
8867c478bd9Sstevel@tonic-gate 			err_print("Syntax error: %s\n", input);
8877c478bd9Sstevel@tonic-gate 		} else {
8887c478bd9Sstevel@tonic-gate 			fmt_print("\n");
8897c478bd9Sstevel@tonic-gate 			(void) default_page(n);
8907c478bd9Sstevel@tonic-gate 			fmt_print("\n");
8917c478bd9Sstevel@tonic-gate 		}
8927c478bd9Sstevel@tonic-gate 	} else if (*s == 'a') {
8937c478bd9Sstevel@tonic-gate 		default_all_pages();
8947c478bd9Sstevel@tonic-gate 	} else {
8957c478bd9Sstevel@tonic-gate 		err_print("Syntax error: %s\n", input);
8967c478bd9Sstevel@tonic-gate 	}
8977c478bd9Sstevel@tonic-gate }
8987c478bd9Sstevel@tonic-gate 
8997c478bd9Sstevel@tonic-gate 
9007c478bd9Sstevel@tonic-gate static void
default_all_pages(void)901*b12aaafbSToomas Soome default_all_pages(void)
9027c478bd9Sstevel@tonic-gate {
9037c478bd9Sstevel@tonic-gate 	char			*p;
9047c478bd9Sstevel@tonic-gate 	struct mode_header	*mh;
9057c478bd9Sstevel@tonic-gate 	struct mode_page	*mp;
9067c478bd9Sstevel@tonic-gate 	int			n;
9077c478bd9Sstevel@tonic-gate 	struct uscsi_cmd	ucmd;
9087c478bd9Sstevel@tonic-gate 	union scsi_cdb		cdb;
9097c478bd9Sstevel@tonic-gate 	char			msbuf[MAX_MODE_SENSE_SIZE];
9107c478bd9Sstevel@tonic-gate 	int			nbytes = sizeof (msbuf);
9117c478bd9Sstevel@tonic-gate 	int			status;
9127c478bd9Sstevel@tonic-gate 
9137c478bd9Sstevel@tonic-gate 	/*
9147c478bd9Sstevel@tonic-gate 	 * Build and execute the uscsi ioctl.  Note that
9157c478bd9Sstevel@tonic-gate 	 * we cannot simply call uscsi_mode_sense() here,
9167c478bd9Sstevel@tonic-gate 	 * since that function attempts to valididate the
9177c478bd9Sstevel@tonic-gate 	 * returned data, and the page 0x3f has a unique
9187c478bd9Sstevel@tonic-gate 	 * format.
9197c478bd9Sstevel@tonic-gate 	 */
9207c478bd9Sstevel@tonic-gate 	nbytes = MAX_MODE_SENSE_SIZE;
9217c478bd9Sstevel@tonic-gate 	(void) memset(msbuf, 0, nbytes);
9227c478bd9Sstevel@tonic-gate 	(void) memset((char *)&ucmd, 0, sizeof (ucmd));
9237c478bd9Sstevel@tonic-gate 	(void) memset((char *)&cdb, 0, sizeof (union scsi_cdb));
9247c478bd9Sstevel@tonic-gate 	cdb.scc_cmd = SCMD_MODE_SENSE;
9257c478bd9Sstevel@tonic-gate 	FORMG0COUNT(&cdb, (uchar_t)nbytes);
9267c478bd9Sstevel@tonic-gate 	cdb.cdb_opaque[2] = MODE_SENSE_PC_DEFAULT | 0x3f;
9277c478bd9Sstevel@tonic-gate 	ucmd.uscsi_cdb = (caddr_t)&cdb;
9287c478bd9Sstevel@tonic-gate 	ucmd.uscsi_cdblen = CDB_GROUP0;
9297c478bd9Sstevel@tonic-gate 	ucmd.uscsi_bufaddr = msbuf;
9307c478bd9Sstevel@tonic-gate 	ucmd.uscsi_buflen = nbytes;
931342440ecSPrasad Singamsetty 	status = uscsi_cmd(cur_file, &ucmd, (option_msg) ? F_NORMAL : F_SILENT);
9327c478bd9Sstevel@tonic-gate 	if (status) {
9337c478bd9Sstevel@tonic-gate 		if (!option_msg) {
9347c478bd9Sstevel@tonic-gate 			err_print("\nMode sense page 0x3f failed\n");
9357c478bd9Sstevel@tonic-gate 		}
9367c478bd9Sstevel@tonic-gate 		return;
9377c478bd9Sstevel@tonic-gate 	}
9387c478bd9Sstevel@tonic-gate 
9397c478bd9Sstevel@tonic-gate 	fmt_print("\n");
9407c478bd9Sstevel@tonic-gate 
9417c478bd9Sstevel@tonic-gate 	/*
9427c478bd9Sstevel@tonic-gate 	 * Now parse the page 0x3f
9437c478bd9Sstevel@tonic-gate 	 */
9447c478bd9Sstevel@tonic-gate 	mh = (struct mode_header *)msbuf;
9457c478bd9Sstevel@tonic-gate 	nbytes = mh->length - sizeof (struct mode_header) -
946342440ecSPrasad Singamsetty 	    mh->bdesc_length + 1;
9477c478bd9Sstevel@tonic-gate 	p = msbuf + sizeof (struct mode_header) + mh->bdesc_length;
9487c478bd9Sstevel@tonic-gate 
9497c478bd9Sstevel@tonic-gate 	while (nbytes > 0) {
9507c478bd9Sstevel@tonic-gate 		mp = (struct mode_page *)p;
9517c478bd9Sstevel@tonic-gate 		n = mp->length + sizeof (struct mode_page);
9527c478bd9Sstevel@tonic-gate 		nbytes -= n;
9537c478bd9Sstevel@tonic-gate 		if (nbytes < 0)
9547c478bd9Sstevel@tonic-gate 			break;
9557c478bd9Sstevel@tonic-gate 		if (default_page(mp->code) == 0) {
9567c478bd9Sstevel@tonic-gate 			goto error;
9577c478bd9Sstevel@tonic-gate 		}
9587c478bd9Sstevel@tonic-gate 		p += n;
9597c478bd9Sstevel@tonic-gate 	}
9607c478bd9Sstevel@tonic-gate 
9617c478bd9Sstevel@tonic-gate 	if (nbytes < 0) {
9627c478bd9Sstevel@tonic-gate 		err_print("Mode sense page 0x3f formatted incorrectly:\n");
9637c478bd9Sstevel@tonic-gate 	}
9647c478bd9Sstevel@tonic-gate error:
9657c478bd9Sstevel@tonic-gate 	fmt_print("\n");
9667c478bd9Sstevel@tonic-gate }
9677c478bd9Sstevel@tonic-gate 
9687c478bd9Sstevel@tonic-gate 
9697c478bd9Sstevel@tonic-gate static int
default_page(int pageno)970*b12aaafbSToomas Soome default_page(int pageno)
9717c478bd9Sstevel@tonic-gate {
9727c478bd9Sstevel@tonic-gate 	struct scsi_ms_header	header;
9737c478bd9Sstevel@tonic-gate 	char			saved[MAX_MODE_SENSE_SIZE];
9747c478bd9Sstevel@tonic-gate 	char			current[MAX_MODE_SENSE_SIZE];
9757c478bd9Sstevel@tonic-gate 	char			dfault[MAX_MODE_SENSE_SIZE];
9767c478bd9Sstevel@tonic-gate 	struct mode_page	*sp;
9777c478bd9Sstevel@tonic-gate 	struct mode_page	*cp;
9787c478bd9Sstevel@tonic-gate 	struct mode_page	*dp;
9797c478bd9Sstevel@tonic-gate 	int			length;
9807c478bd9Sstevel@tonic-gate 	int			flags;
9817c478bd9Sstevel@tonic-gate 	int			i;
9827c478bd9Sstevel@tonic-gate 	int			need_mode_select;
9837c478bd9Sstevel@tonic-gate 
9847c478bd9Sstevel@tonic-gate 	/*
9857c478bd9Sstevel@tonic-gate 	 * Get default mode sense
9867c478bd9Sstevel@tonic-gate 	 */
9877c478bd9Sstevel@tonic-gate 	if (uscsi_mode_sense(cur_file, pageno, MODE_SENSE_PC_DEFAULT,
988*b12aaafbSToomas Soome 	    dfault, MAX_MODE_SENSE_SIZE, &header)) {
989*b12aaafbSToomas Soome 		err_print("Mode sense on page %x (dfault) failed\n", pageno);
9907c478bd9Sstevel@tonic-gate 		return (0);
9917c478bd9Sstevel@tonic-gate 	}
9927c478bd9Sstevel@tonic-gate 
9937c478bd9Sstevel@tonic-gate 	/*
9947c478bd9Sstevel@tonic-gate 	 * Get the current mode sense.
9957c478bd9Sstevel@tonic-gate 	 */
9967c478bd9Sstevel@tonic-gate 	if (uscsi_mode_sense(cur_file, pageno, MODE_SENSE_PC_CURRENT,
997*b12aaafbSToomas Soome 	    current, MAX_MODE_SENSE_SIZE, &header)) {
998*b12aaafbSToomas Soome 		err_print("Mode sense on page %x (current) failed\n", pageno);
9997c478bd9Sstevel@tonic-gate 		return (0);
10007c478bd9Sstevel@tonic-gate 	}
10017c478bd9Sstevel@tonic-gate 
10027c478bd9Sstevel@tonic-gate 	/*
10037c478bd9Sstevel@tonic-gate 	 * Get saved mode sense.  If this fails, assume it is
10047c478bd9Sstevel@tonic-gate 	 * the same as the current.
10057c478bd9Sstevel@tonic-gate 	 */
10067c478bd9Sstevel@tonic-gate 	if (uscsi_mode_sense(cur_file, pageno, MODE_SENSE_PC_SAVED,
1007*b12aaafbSToomas Soome 	    saved, MAX_MODE_SENSE_SIZE, &header)) {
10087c478bd9Sstevel@tonic-gate 		(void) memcpy(saved, current, MAX_MODE_SENSE_SIZE);
10097c478bd9Sstevel@tonic-gate 	}
10107c478bd9Sstevel@tonic-gate 
10117c478bd9Sstevel@tonic-gate 	/*
10127c478bd9Sstevel@tonic-gate 	 * Determine if we need a mode select on this page.
10137c478bd9Sstevel@tonic-gate 	 * Just deal with the intersection of the three pages.
10147c478bd9Sstevel@tonic-gate 	 */
10157c478bd9Sstevel@tonic-gate 	sp = (struct mode_page *)saved;
10167c478bd9Sstevel@tonic-gate 	cp = (struct mode_page *)current;
10177c478bd9Sstevel@tonic-gate 	dp = (struct mode_page *)dfault;
10187c478bd9Sstevel@tonic-gate 	length = min(MODESENSE_PAGE_LEN(sp), MODESENSE_PAGE_LEN(cp));
10197c478bd9Sstevel@tonic-gate 	length = min(length, MODESENSE_PAGE_LEN(dp));
10207c478bd9Sstevel@tonic-gate 
10217c478bd9Sstevel@tonic-gate 	need_mode_select = 0;
10227c478bd9Sstevel@tonic-gate 	for (i = 2; i < length; i++) {
10237c478bd9Sstevel@tonic-gate 		if (current[i] != dfault[i] || saved[i] != dfault[i]) {
10247c478bd9Sstevel@tonic-gate 			current[i] = dfault[i];
10257c478bd9Sstevel@tonic-gate 			need_mode_select = 1;
10267c478bd9Sstevel@tonic-gate 		}
10277c478bd9Sstevel@tonic-gate 	}
10287c478bd9Sstevel@tonic-gate 
10297c478bd9Sstevel@tonic-gate 	if (need_mode_select == 0) {
1030*b12aaafbSToomas Soome 		fmt_print("Defaulting page 0x%x: ok\n", pageno);
10317c478bd9Sstevel@tonic-gate 		return (1);
10327c478bd9Sstevel@tonic-gate 	}
10337c478bd9Sstevel@tonic-gate 
10347c478bd9Sstevel@tonic-gate 	/*
10357c478bd9Sstevel@tonic-gate 	 * A change was made.  Do a mode select
10367c478bd9Sstevel@tonic-gate 	 * We always want to set the Page Format bit.
10377c478bd9Sstevel@tonic-gate 	 * Set the Save Page bit if the drive indicates
10387c478bd9Sstevel@tonic-gate 	 * that it can save this page.
10397c478bd9Sstevel@tonic-gate 	 */
10407c478bd9Sstevel@tonic-gate 	length = MODESENSE_PAGE_LEN(cp);
10417c478bd9Sstevel@tonic-gate 	flags = MODE_SELECT_PF;
10427c478bd9Sstevel@tonic-gate 	if (cp->ps) {
10437c478bd9Sstevel@tonic-gate 		flags |= MODE_SELECT_SP;
10447c478bd9Sstevel@tonic-gate 	}
10457c478bd9Sstevel@tonic-gate 	cp->ps = 0;
10467c478bd9Sstevel@tonic-gate 	header.mode_header.length = 0;
10477c478bd9Sstevel@tonic-gate 	header.mode_header.device_specific = 0;
10487c478bd9Sstevel@tonic-gate 	if (uscsi_mode_select(cur_file, pageno, flags,
1049*b12aaafbSToomas Soome 	    current, length, &header)) {
10507c478bd9Sstevel@tonic-gate 		/*
10517c478bd9Sstevel@tonic-gate 		 * Failed - try not saving parameters,
10527c478bd9Sstevel@tonic-gate 		 * if possible.
10537c478bd9Sstevel@tonic-gate 		 */
10547c478bd9Sstevel@tonic-gate 		if (flags & MODE_SELECT_SP) {
10557c478bd9Sstevel@tonic-gate 			flags &= ~MODE_SELECT_SP;
10567c478bd9Sstevel@tonic-gate 			if (uscsi_mode_select(cur_file, pageno, flags,
1057*b12aaafbSToomas Soome 			    saved, length, &header)) {
10587c478bd9Sstevel@tonic-gate 				fmt_print("Defaulting page 0x%x: failed\n",
1059*b12aaafbSToomas Soome 				    pageno);
10607c478bd9Sstevel@tonic-gate 			} else {
1061*b12aaafbSToomas Soome 				fmt_print("Defaulting page 0x%x: ", pageno);
10627c478bd9Sstevel@tonic-gate 				fmt_print("cannot save page permanently\n");
10637c478bd9Sstevel@tonic-gate 			}
10647c478bd9Sstevel@tonic-gate 		} else {
10657c478bd9Sstevel@tonic-gate 			fmt_print("Defaulting page 0x%x: ", pageno);
10667c478bd9Sstevel@tonic-gate 			fmt_print("cannot save page permanently\n");
10677c478bd9Sstevel@tonic-gate 		}
10687c478bd9Sstevel@tonic-gate 	} else {
10697c478bd9Sstevel@tonic-gate 		fmt_print("Defaulting page 0x%x: mode select ok\n", pageno);
10707c478bd9Sstevel@tonic-gate 	}
10717c478bd9Sstevel@tonic-gate 
10727c478bd9Sstevel@tonic-gate 	return (1);
10737c478bd9Sstevel@tonic-gate }
1074