1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate 
23*0Sstevel@tonic-gate /*
24*0Sstevel@tonic-gate  * Copyright 1991-2003 Sun Microsystems, Inc.  All rights reserved.
25*0Sstevel@tonic-gate  * Use is subject to license terms.
26*0Sstevel@tonic-gate  */
27*0Sstevel@tonic-gate 
28*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
29*0Sstevel@tonic-gate 
30*0Sstevel@tonic-gate /*
31*0Sstevel@tonic-gate  * This file contains functions implementing the scsi menu commands.
32*0Sstevel@tonic-gate  *
33*0Sstevel@tonic-gate  * These functions are intended for expert use only, and provide
34*0Sstevel@tonic-gate  * a raw access to a scsi device's mode pages.  The ability to
35*0Sstevel@tonic-gate  * issue a raw format command is also provided, should a page be
36*0Sstevel@tonic-gate  * changed that requires a format.
37*0Sstevel@tonic-gate  */
38*0Sstevel@tonic-gate #include "global.h"
39*0Sstevel@tonic-gate #include <stdlib.h>
40*0Sstevel@tonic-gate #include <ctype.h>
41*0Sstevel@tonic-gate 
42*0Sstevel@tonic-gate #include "io.h"
43*0Sstevel@tonic-gate #include "menu.h"
44*0Sstevel@tonic-gate #include "misc.h"
45*0Sstevel@tonic-gate #include "menu_scsi.h"
46*0Sstevel@tonic-gate #include "ctlr_scsi.h"
47*0Sstevel@tonic-gate #include "startup.h"
48*0Sstevel@tonic-gate #include "checkmount.h"
49*0Sstevel@tonic-gate 
50*0Sstevel@tonic-gate 
51*0Sstevel@tonic-gate #ifdef	__STDC__
52*0Sstevel@tonic-gate /*
53*0Sstevel@tonic-gate  *	ANSI prototypes for local static functions
54*0Sstevel@tonic-gate  */
55*0Sstevel@tonic-gate static int	do_mode_sense(int);
56*0Sstevel@tonic-gate static int	do_mode_sense_all(void);
57*0Sstevel@tonic-gate static int	do_mode_select(struct chg_list *);
58*0Sstevel@tonic-gate static int	do_format(void);
59*0Sstevel@tonic-gate static void	do_list(void);
60*0Sstevel@tonic-gate static int	do_inquiry(void);
61*0Sstevel@tonic-gate static void	do_apply(void);
62*0Sstevel@tonic-gate static void	do_cancel(void);
63*0Sstevel@tonic-gate static void	do_display(void);
64*0Sstevel@tonic-gate static int	parse_change_spec(char *, char *, int, struct chg_list *);
65*0Sstevel@tonic-gate static void	add_new_change_list_item(struct chg_list *);
66*0Sstevel@tonic-gate static void	free_change_list(void);
67*0Sstevel@tonic-gate static void	do_default(char *);
68*0Sstevel@tonic-gate static void	default_all_pages(void);
69*0Sstevel@tonic-gate static int	default_page(int);
70*0Sstevel@tonic-gate #else
71*0Sstevel@tonic-gate static int	do_mode_sense();
72*0Sstevel@tonic-gate static int	do_mode_sense_all();
73*0Sstevel@tonic-gate static int	do_mode_select();
74*0Sstevel@tonic-gate static int	do_format();
75*0Sstevel@tonic-gate static void	do_list();
76*0Sstevel@tonic-gate static int	do_inquiry();
77*0Sstevel@tonic-gate static void	do_apply();
78*0Sstevel@tonic-gate static void	do_cancel();
79*0Sstevel@tonic-gate static void	do_display();
80*0Sstevel@tonic-gate static int	parse_change_spec();
81*0Sstevel@tonic-gate static void	add_new_change_list_item();
82*0Sstevel@tonic-gate static void	free_change_list();
83*0Sstevel@tonic-gate static void	do_default();
84*0Sstevel@tonic-gate static void	default_all_pages();
85*0Sstevel@tonic-gate static int	default_page();
86*0Sstevel@tonic-gate #endif	/* __STDC__ */
87*0Sstevel@tonic-gate 
88*0Sstevel@tonic-gate 
89*0Sstevel@tonic-gate /*
90*0Sstevel@tonic-gate  * Menu data for the SCSI menu display
91*0Sstevel@tonic-gate  */
92*0Sstevel@tonic-gate static char	*scsi_menu_strings[] = {
93*0Sstevel@tonic-gate 	"p<n>                   - display a mode sense page",
94*0Sstevel@tonic-gate 	"p<n> b<n> <op> [~]<n>  - change a byte and issue mode select",
95*0Sstevel@tonic-gate 	"b<n> <op> [~]<n>       - add an operation to the mode select list",
96*0Sstevel@tonic-gate 	"                             for the current page",
97*0Sstevel@tonic-gate 	"",
98*0Sstevel@tonic-gate 	"        where:  p<n> specifies the page with page code <n>",
99*0Sstevel@tonic-gate 	"                b<n> specifies byte <n> of the page",
100*0Sstevel@tonic-gate 	"                <op> can be one of the following operators:",
101*0Sstevel@tonic-gate 	"                     =    (set specified value)",
102*0Sstevel@tonic-gate 	"                     |=   (bitwise OR with current value)",
103*0Sstevel@tonic-gate 	"                     &=   (bitwise AND with current value)",
104*0Sstevel@tonic-gate 	"                <n> can be a decimal value in the range 0-255,",
105*0Sstevel@tonic-gate 	"                or two hexadecimal digits, in the form 0x<xx>.",
106*0Sstevel@tonic-gate 	"                [~] complements the specified value",
107*0Sstevel@tonic-gate 	"",
108*0Sstevel@tonic-gate 	"apply                  - apply mode select list",
109*0Sstevel@tonic-gate 	"cancel                 - cancel mode select list",
110*0Sstevel@tonic-gate 	"display                - display mode select list",
111*0Sstevel@tonic-gate 	"all                    - display all supported mode sense pages",
112*0Sstevel@tonic-gate 	"default p<n>           - mode select page <n> to default values",
113*0Sstevel@tonic-gate 	"default all            - mode select all pages to default values",
114*0Sstevel@tonic-gate 	"format                 - format without standard mode selects",
115*0Sstevel@tonic-gate 	"inquiry                - display device's inquiry response",
116*0Sstevel@tonic-gate 	"list                   - list common SCSI-2 mode pages",
117*0Sstevel@tonic-gate 	"!<cmd>                 - execute <cmd> , then return"
118*0Sstevel@tonic-gate };
119*0Sstevel@tonic-gate 
120*0Sstevel@tonic-gate #define	N_SCSI_STRINGS	(sizeof (scsi_menu_strings) / sizeof (char *))
121*0Sstevel@tonic-gate 
122*0Sstevel@tonic-gate /*
123*0Sstevel@tonic-gate  * Command types
124*0Sstevel@tonic-gate  */
125*0Sstevel@tonic-gate #define	CMD_ALL			0
126*0Sstevel@tonic-gate #define	CMD_FORMAT		1
127*0Sstevel@tonic-gate #define	CMD_QUIT		2
128*0Sstevel@tonic-gate #define	CMD_HELP		3
129*0Sstevel@tonic-gate #define	CMD_LIST		4
130*0Sstevel@tonic-gate #define	CMD_INQUIRY		5
131*0Sstevel@tonic-gate #define	CMD_APPLY		6
132*0Sstevel@tonic-gate #define	CMD_CANCEL		7
133*0Sstevel@tonic-gate #define	CMD_DISPLAY		8
134*0Sstevel@tonic-gate 
135*0Sstevel@tonic-gate /*
136*0Sstevel@tonic-gate  * SCSI menu commands for minimum recognition
137*0Sstevel@tonic-gate  */
138*0Sstevel@tonic-gate static struct slist	cmds_list[] = {
139*0Sstevel@tonic-gate 	{ "all",	NULL,	CMD_ALL },
140*0Sstevel@tonic-gate 	{ "format",	NULL,	CMD_FORMAT },
141*0Sstevel@tonic-gate 	{ "quit",	NULL,	CMD_QUIT },
142*0Sstevel@tonic-gate 	{ "help",	NULL,	CMD_HELP },
143*0Sstevel@tonic-gate 	{ "?",		NULL,	CMD_HELP },
144*0Sstevel@tonic-gate 	{ "list",	NULL,	CMD_LIST },
145*0Sstevel@tonic-gate 	{ "inquiry",	NULL,	CMD_INQUIRY },
146*0Sstevel@tonic-gate 	{ "apply",	NULL,	CMD_APPLY },
147*0Sstevel@tonic-gate 	{ "cancel",	NULL,	CMD_CANCEL },
148*0Sstevel@tonic-gate 	{ "display",	NULL,	CMD_DISPLAY },
149*0Sstevel@tonic-gate 	{ NULL	}
150*0Sstevel@tonic-gate };
151*0Sstevel@tonic-gate 
152*0Sstevel@tonic-gate /*
153*0Sstevel@tonic-gate  * Implied page for mode select change lists
154*0Sstevel@tonic-gate  */
155*0Sstevel@tonic-gate static	int		current_page;
156*0Sstevel@tonic-gate static	struct chg_list	*change_list;
157*0Sstevel@tonic-gate 
158*0Sstevel@tonic-gate /*
159*0Sstevel@tonic-gate  * Manage the SCSI menu.
160*0Sstevel@tonic-gate  * Parse input and dispatch to the appropriate functions.
161*0Sstevel@tonic-gate  * The commands we accept are not simple one-word commands,
162*0Sstevel@tonic-gate  * so we cannot use the standard format menu-handling functions.
163*0Sstevel@tonic-gate  */
164*0Sstevel@tonic-gate int
165*0Sstevel@tonic-gate c_scsi()
166*0Sstevel@tonic-gate {
167*0Sstevel@tonic-gate 	int			i;
168*0Sstevel@tonic-gate 	struct env		env;
169*0Sstevel@tonic-gate 	char			**menu;
170*0Sstevel@tonic-gate 	struct menu_item	scsi_menu[N_SCSI_STRINGS+1];
171*0Sstevel@tonic-gate 	struct chg_list		change_item;
172*0Sstevel@tonic-gate 	struct chg_list		*chg_item;
173*0Sstevel@tonic-gate 	char			s[MAXPATHLEN], nclean[MAXPATHLEN];
174*0Sstevel@tonic-gate 	char			*p;
175*0Sstevel@tonic-gate 	char			*p2;
176*0Sstevel@tonic-gate 	int			cmd;
177*0Sstevel@tonic-gate 	int			pageno;
178*0Sstevel@tonic-gate 	int			help = 1;
179*0Sstevel@tonic-gate 
180*0Sstevel@tonic-gate 	/*
181*0Sstevel@tonic-gate 	 * Warn casual users that maybe they should not be
182*0Sstevel@tonic-gate 	 * using this menu.
183*0Sstevel@tonic-gate 	 */
184*0Sstevel@tonic-gate 	fmt_print("\n"
185*0Sstevel@tonic-gate "Warning:  these functions are intended for expert use only, for\n"
186*0Sstevel@tonic-gate "debugging disk devices and for unusual configuration settings.\n"
187*0Sstevel@tonic-gate "It is recommended that you do not use this menu for normal disk\n"
188*0Sstevel@tonic-gate "configuration and formatting, unless you have explicit instructions,\n"
189*0Sstevel@tonic-gate "or know exactly what you are doing.\n");
190*0Sstevel@tonic-gate 
191*0Sstevel@tonic-gate 	/*
192*0Sstevel@tonic-gate 	 * Initialize change list and current page to empty
193*0Sstevel@tonic-gate 	 */
194*0Sstevel@tonic-gate 	current_page = -1;
195*0Sstevel@tonic-gate 	change_list = NULL;
196*0Sstevel@tonic-gate 
197*0Sstevel@tonic-gate 	/*
198*0Sstevel@tonic-gate 	 * Build and display the menu.
199*0Sstevel@tonic-gate 	 * we only use this for display purposes.
200*0Sstevel@tonic-gate 	 */
201*0Sstevel@tonic-gate 	for (i = 0; i < N_SCSI_STRINGS; i++) {
202*0Sstevel@tonic-gate 		scsi_menu[i].menu_cmd = scsi_menu_strings[i];
203*0Sstevel@tonic-gate 		scsi_menu[i].menu_func = NULL;
204*0Sstevel@tonic-gate 		scsi_menu[i].menu_state = true;
205*0Sstevel@tonic-gate 	}
206*0Sstevel@tonic-gate 	scsi_menu[i].menu_cmd = NULL;
207*0Sstevel@tonic-gate 	menu = create_menu_list(scsi_menu);
208*0Sstevel@tonic-gate 	/*
209*0Sstevel@tonic-gate 	 * Save the environment so a ctrl-C out of a command lands here.
210*0Sstevel@tonic-gate 	 */
211*0Sstevel@tonic-gate 	saveenv(env);
212*0Sstevel@tonic-gate 	for (;;) {
213*0Sstevel@tonic-gate 		if (help) {
214*0Sstevel@tonic-gate 			help = 0;
215*0Sstevel@tonic-gate 			fmt_print("\n\nSCSI MENU:\n");
216*0Sstevel@tonic-gate 			display_menu_list(menu);
217*0Sstevel@tonic-gate 		}
218*0Sstevel@tonic-gate 		/*
219*0Sstevel@tonic-gate 		 * Prompt and get next input line.  We don't use the
220*0Sstevel@tonic-gate 		 * standard input routine, since we need a little
221*0Sstevel@tonic-gate 		 * more flexibility in parsing the input.
222*0Sstevel@tonic-gate 		 */
223*0Sstevel@tonic-gate 		fmt_print("scsi> ");
224*0Sstevel@tonic-gate 		get_inputline(nclean, sizeof (nclean));
225*0Sstevel@tonic-gate 
226*0Sstevel@tonic-gate 		clean_token(s, nclean);
227*0Sstevel@tonic-gate 
228*0Sstevel@tonic-gate 		/*
229*0Sstevel@tonic-gate 		 * Mark the saved environment active so the user can now
230*0Sstevel@tonic-gate 		 * do a ctrl-C to get out of the command.
231*0Sstevel@tonic-gate 		 */
232*0Sstevel@tonic-gate 		useenv();
233*0Sstevel@tonic-gate 
234*0Sstevel@tonic-gate 		/*
235*0Sstevel@tonic-gate 		 * Figure out what the user chose
236*0Sstevel@tonic-gate 		 */
237*0Sstevel@tonic-gate 		i = find_value(cmds_list, s, &cmd);
238*0Sstevel@tonic-gate 		if (i == 1) {
239*0Sstevel@tonic-gate 			switch (cmd) {
240*0Sstevel@tonic-gate 			case CMD_ALL:
241*0Sstevel@tonic-gate 				(void) do_mode_sense_all();
242*0Sstevel@tonic-gate 				break;
243*0Sstevel@tonic-gate 			case CMD_FORMAT:
244*0Sstevel@tonic-gate 				(void) do_format();
245*0Sstevel@tonic-gate 				break;
246*0Sstevel@tonic-gate 			case CMD_QUIT:
247*0Sstevel@tonic-gate 				goto exit;
248*0Sstevel@tonic-gate 				/*NOTREACHED*/
249*0Sstevel@tonic-gate 			case CMD_HELP:
250*0Sstevel@tonic-gate 				fmt_print("\n\nSCSI MENU:\n");
251*0Sstevel@tonic-gate 				display_menu_list(menu);
252*0Sstevel@tonic-gate 				break;
253*0Sstevel@tonic-gate 			case CMD_LIST:
254*0Sstevel@tonic-gate 				do_list();
255*0Sstevel@tonic-gate 				break;
256*0Sstevel@tonic-gate 			case CMD_INQUIRY:
257*0Sstevel@tonic-gate 				(void) do_inquiry();
258*0Sstevel@tonic-gate 				break;
259*0Sstevel@tonic-gate 			case CMD_APPLY:
260*0Sstevel@tonic-gate 				do_apply();
261*0Sstevel@tonic-gate 				break;
262*0Sstevel@tonic-gate 			case CMD_CANCEL:
263*0Sstevel@tonic-gate 				do_cancel();
264*0Sstevel@tonic-gate 				break;
265*0Sstevel@tonic-gate 			case CMD_DISPLAY:
266*0Sstevel@tonic-gate 				do_display();
267*0Sstevel@tonic-gate 				break;
268*0Sstevel@tonic-gate 			}
269*0Sstevel@tonic-gate 		} else if (s[0] == 'd') {
270*0Sstevel@tonic-gate 			do_default(s);
271*0Sstevel@tonic-gate 		} else if (s[0] == 'p') {
272*0Sstevel@tonic-gate 			p = s + 1;
273*0Sstevel@tonic-gate 			pageno = (int)strtol(p, &p2, 0);
274*0Sstevel@tonic-gate 			if (p2 == p) {
275*0Sstevel@tonic-gate 				err_print("Syntax error: %s\n", s);
276*0Sstevel@tonic-gate 				goto error;
277*0Sstevel@tonic-gate 			}
278*0Sstevel@tonic-gate 			current_page = pageno;
279*0Sstevel@tonic-gate 			for (p = p2; *p == ' '; p++)
280*0Sstevel@tonic-gate 				;
281*0Sstevel@tonic-gate 			if (*p == 0) {
282*0Sstevel@tonic-gate 				(void) do_mode_sense(pageno);
283*0Sstevel@tonic-gate 			} else if (*p == 'b') {
284*0Sstevel@tonic-gate 				if (parse_change_spec(s, p, pageno,
285*0Sstevel@tonic-gate 						&change_item)) {
286*0Sstevel@tonic-gate 					(void) do_mode_select(&change_item);
287*0Sstevel@tonic-gate 				}
288*0Sstevel@tonic-gate 			}
289*0Sstevel@tonic-gate 		} else if (s[0] == 'b') {
290*0Sstevel@tonic-gate 				if (current_page == -1) {
291*0Sstevel@tonic-gate 					err_print("\
292*0Sstevel@tonic-gate Please display the page on which you'd like to do a mode select\n");
293*0Sstevel@tonic-gate 					goto error;
294*0Sstevel@tonic-gate 				}
295*0Sstevel@tonic-gate 				chg_item = (struct chg_list *)
296*0Sstevel@tonic-gate 					zalloc(sizeof (struct chg_list));
297*0Sstevel@tonic-gate 				if (parse_change_spec(s, s, current_page,
298*0Sstevel@tonic-gate 						chg_item)) {
299*0Sstevel@tonic-gate 					add_new_change_list_item(chg_item);
300*0Sstevel@tonic-gate 				} else {
301*0Sstevel@tonic-gate 					destroy_data((char *)chg_item);
302*0Sstevel@tonic-gate 				}
303*0Sstevel@tonic-gate 		} else if (s[0] == '!') {
304*0Sstevel@tonic-gate 			(void) execute_shell(&s[1]);
305*0Sstevel@tonic-gate 			help = 1;
306*0Sstevel@tonic-gate 		} else if (s[0] != 0) {
307*0Sstevel@tonic-gate 			err_print("Syntax error: %s\n", s);
308*0Sstevel@tonic-gate 		}
309*0Sstevel@tonic-gate error:
310*0Sstevel@tonic-gate 		/*
311*0Sstevel@tonic-gate 		 * Mark the saved environment inactive so ctrl-C doesn't
312*0Sstevel@tonic-gate 		 * work at the menu itself.
313*0Sstevel@tonic-gate 		 */
314*0Sstevel@tonic-gate 		unuseenv();
315*0Sstevel@tonic-gate 	}
316*0Sstevel@tonic-gate exit:
317*0Sstevel@tonic-gate 	/*
318*0Sstevel@tonic-gate 	 * Clean up the environment stack and free the menu
319*0Sstevel@tonic-gate 	 */
320*0Sstevel@tonic-gate 	clearenv();
321*0Sstevel@tonic-gate 	destroy_data((char *)menu);
322*0Sstevel@tonic-gate 
323*0Sstevel@tonic-gate 	/*
324*0Sstevel@tonic-gate 	 * Clean up the change list, if anything left over
325*0Sstevel@tonic-gate 	 */
326*0Sstevel@tonic-gate 	free_change_list();
327*0Sstevel@tonic-gate 
328*0Sstevel@tonic-gate 	/*
329*0Sstevel@tonic-gate 	 * Make sure user is prompted with previous menu
330*0Sstevel@tonic-gate 	 */
331*0Sstevel@tonic-gate 	last_menu++;
332*0Sstevel@tonic-gate 
333*0Sstevel@tonic-gate 	return (0);
334*0Sstevel@tonic-gate }
335*0Sstevel@tonic-gate 
336*0Sstevel@tonic-gate 
337*0Sstevel@tonic-gate /*
338*0Sstevel@tonic-gate  * Do a mode sense on a particular page, and dump the data.
339*0Sstevel@tonic-gate  * Get all the various flavors:  default, current, saved, changeable.
340*0Sstevel@tonic-gate  */
341*0Sstevel@tonic-gate static int
342*0Sstevel@tonic-gate do_mode_sense(pageno)
343*0Sstevel@tonic-gate 	int	pageno;
344*0Sstevel@tonic-gate {
345*0Sstevel@tonic-gate 	struct scsi_ms_header	header;
346*0Sstevel@tonic-gate 	struct mode_page	*pg;
347*0Sstevel@tonic-gate 	char			msbuf[MAX_MODE_SENSE_SIZE];
348*0Sstevel@tonic-gate 	int			result = 0;
349*0Sstevel@tonic-gate 
350*0Sstevel@tonic-gate 	char	*default_msg	= "default:     ";
351*0Sstevel@tonic-gate 	char	*saved_msg	= "saved:       ";
352*0Sstevel@tonic-gate 	char	*current_msg	= "current:     ";
353*0Sstevel@tonic-gate 	char	*changeable_msg	= "changeable:  ";
354*0Sstevel@tonic-gate 
355*0Sstevel@tonic-gate 
356*0Sstevel@tonic-gate 	pg = (struct mode_page *)msbuf;
357*0Sstevel@tonic-gate 
358*0Sstevel@tonic-gate 	fmt_print("\nPage 0x%x:\n", pageno);
359*0Sstevel@tonic-gate 	if (uscsi_mode_sense(cur_file, pageno, MODE_SENSE_PC_DEFAULT,
360*0Sstevel@tonic-gate 			msbuf, MAX_MODE_SENSE_SIZE, &header)) {
361*0Sstevel@tonic-gate 		err_print("%sfailed\n", default_msg);
362*0Sstevel@tonic-gate 		result = 1;
363*0Sstevel@tonic-gate 	} else {
364*0Sstevel@tonic-gate 		dump(default_msg, msbuf, MODESENSE_PAGE_LEN(pg),
365*0Sstevel@tonic-gate 			HEX_ONLY);
366*0Sstevel@tonic-gate 	}
367*0Sstevel@tonic-gate 
368*0Sstevel@tonic-gate 	if (uscsi_mode_sense(cur_file, pageno, MODE_SENSE_PC_CURRENT,
369*0Sstevel@tonic-gate 			msbuf, MAX_MODE_SENSE_SIZE, &header)) {
370*0Sstevel@tonic-gate 		err_print("%sfailed\n", current_msg);
371*0Sstevel@tonic-gate 		result = 1;
372*0Sstevel@tonic-gate 	} else {
373*0Sstevel@tonic-gate 		dump(current_msg, msbuf, MODESENSE_PAGE_LEN(pg),
374*0Sstevel@tonic-gate 			HEX_ONLY);
375*0Sstevel@tonic-gate 	}
376*0Sstevel@tonic-gate 
377*0Sstevel@tonic-gate 	if (uscsi_mode_sense(cur_file, pageno, MODE_SENSE_PC_SAVED,
378*0Sstevel@tonic-gate 			msbuf, MAX_MODE_SENSE_SIZE, &header)) {
379*0Sstevel@tonic-gate 		err_print("%sfailed\n", saved_msg);
380*0Sstevel@tonic-gate 		result = 1;
381*0Sstevel@tonic-gate 	} else {
382*0Sstevel@tonic-gate 		dump(saved_msg, msbuf, MODESENSE_PAGE_LEN(pg),
383*0Sstevel@tonic-gate 			HEX_ONLY);
384*0Sstevel@tonic-gate 	}
385*0Sstevel@tonic-gate 
386*0Sstevel@tonic-gate 	if (uscsi_mode_sense(cur_file, pageno, MODE_SENSE_PC_CHANGEABLE,
387*0Sstevel@tonic-gate 			msbuf, MAX_MODE_SENSE_SIZE, &header)) {
388*0Sstevel@tonic-gate 		err_print("%sfailed\n", changeable_msg);
389*0Sstevel@tonic-gate 		result = 1;
390*0Sstevel@tonic-gate 	} else {
391*0Sstevel@tonic-gate 		dump(changeable_msg, msbuf, MODESENSE_PAGE_LEN(pg),
392*0Sstevel@tonic-gate 			HEX_ONLY);
393*0Sstevel@tonic-gate 	}
394*0Sstevel@tonic-gate 
395*0Sstevel@tonic-gate 	fmt_print("\n");
396*0Sstevel@tonic-gate 	return (result);
397*0Sstevel@tonic-gate }
398*0Sstevel@tonic-gate 
399*0Sstevel@tonic-gate 
400*0Sstevel@tonic-gate /*
401*0Sstevel@tonic-gate  * Dump all the pages a device supports
402*0Sstevel@tonic-gate  */
403*0Sstevel@tonic-gate static int
404*0Sstevel@tonic-gate do_mode_sense_all()
405*0Sstevel@tonic-gate {
406*0Sstevel@tonic-gate 	int	result = 0;
407*0Sstevel@tonic-gate 
408*0Sstevel@tonic-gate 	if (scsi_dump_mode_sense_pages(MODE_SENSE_PC_DEFAULT)) {
409*0Sstevel@tonic-gate 		result = 1;
410*0Sstevel@tonic-gate 	}
411*0Sstevel@tonic-gate 	if (scsi_dump_mode_sense_pages(MODE_SENSE_PC_CURRENT)) {
412*0Sstevel@tonic-gate 		result = 1;
413*0Sstevel@tonic-gate 	}
414*0Sstevel@tonic-gate 	if (scsi_dump_mode_sense_pages(MODE_SENSE_PC_SAVED)) {
415*0Sstevel@tonic-gate 		result = 1;
416*0Sstevel@tonic-gate 	}
417*0Sstevel@tonic-gate 	if (scsi_dump_mode_sense_pages(MODE_SENSE_PC_CHANGEABLE)) {
418*0Sstevel@tonic-gate 		result = 1;
419*0Sstevel@tonic-gate 	}
420*0Sstevel@tonic-gate 	fmt_print("\n");
421*0Sstevel@tonic-gate 	return (result);
422*0Sstevel@tonic-gate }
423*0Sstevel@tonic-gate 
424*0Sstevel@tonic-gate 
425*0Sstevel@tonic-gate /*
426*0Sstevel@tonic-gate  * Get the current mode sense for a particular page, change
427*0Sstevel@tonic-gate  * a byte, and issue a mode select.  Note that we can only
428*0Sstevel@tonic-gate  * change a value if the device indicates that those bits
429*0Sstevel@tonic-gate  * are changeable.
430*0Sstevel@tonic-gate  */
431*0Sstevel@tonic-gate static int
432*0Sstevel@tonic-gate do_mode_select(change_item)
433*0Sstevel@tonic-gate 	struct chg_list	*change_item;
434*0Sstevel@tonic-gate {
435*0Sstevel@tonic-gate 	struct scsi_ms_header	header;
436*0Sstevel@tonic-gate 	char			saved[MAX_MODE_SENSE_SIZE];
437*0Sstevel@tonic-gate 	char			changeable[MAX_MODE_SENSE_SIZE];
438*0Sstevel@tonic-gate 	struct mode_page	*pg;
439*0Sstevel@tonic-gate 	struct mode_page	*pg2;
440*0Sstevel@tonic-gate 	int			length;
441*0Sstevel@tonic-gate 	int			pageno;
442*0Sstevel@tonic-gate 	int			flags;
443*0Sstevel@tonic-gate 	int			result = 0;
444*0Sstevel@tonic-gate 
445*0Sstevel@tonic-gate 	pageno = change_item->pageno;
446*0Sstevel@tonic-gate 
447*0Sstevel@tonic-gate 	/*
448*0Sstevel@tonic-gate 	 * Get changeable mode sense
449*0Sstevel@tonic-gate 	 */
450*0Sstevel@tonic-gate 	if (uscsi_mode_sense(cur_file, pageno, MODE_SENSE_PC_CHANGEABLE,
451*0Sstevel@tonic-gate 			changeable, MAX_MODE_SENSE_SIZE, &header)) {
452*0Sstevel@tonic-gate 		err_print("Mode sense on page %x (changeable) failed\n",
453*0Sstevel@tonic-gate 			pageno);
454*0Sstevel@tonic-gate 		return (1);
455*0Sstevel@tonic-gate 	}
456*0Sstevel@tonic-gate 
457*0Sstevel@tonic-gate 	/*
458*0Sstevel@tonic-gate 	 * Get saved mode sense.  If saved fails, use current values.
459*0Sstevel@tonic-gate 	 */
460*0Sstevel@tonic-gate 	if (uscsi_mode_sense(cur_file, pageno, MODE_SENSE_PC_SAVED,
461*0Sstevel@tonic-gate 			saved, MAX_MODE_SENSE_SIZE, &header)) {
462*0Sstevel@tonic-gate 		err_print("Mode sense on page %x (saved) failed\n",
463*0Sstevel@tonic-gate 			pageno);
464*0Sstevel@tonic-gate 		if (uscsi_mode_sense(cur_file, pageno, MODE_SENSE_PC_CURRENT,
465*0Sstevel@tonic-gate 				saved, MAX_MODE_SENSE_SIZE, &header)) {
466*0Sstevel@tonic-gate 			err_print("Mode sense on page %x (current) failed\n",
467*0Sstevel@tonic-gate 				pageno);
468*0Sstevel@tonic-gate 			return (1);
469*0Sstevel@tonic-gate 		} else {
470*0Sstevel@tonic-gate 			err_print("Using current values instead\n");
471*0Sstevel@tonic-gate 		}
472*0Sstevel@tonic-gate 	}
473*0Sstevel@tonic-gate 
474*0Sstevel@tonic-gate 	/*
475*0Sstevel@tonic-gate 	 * Use the intersection of the saved and changeable
476*0Sstevel@tonic-gate 	 */
477*0Sstevel@tonic-gate 	pg = (struct mode_page *)saved;
478*0Sstevel@tonic-gate 	pg2 = (struct mode_page *)changeable;
479*0Sstevel@tonic-gate 	length = min(MODESENSE_PAGE_LEN(pg), MODESENSE_PAGE_LEN(pg2));
480*0Sstevel@tonic-gate 
481*0Sstevel@tonic-gate 	/*
482*0Sstevel@tonic-gate 	 * Try making this change to this page
483*0Sstevel@tonic-gate 	 */
484*0Sstevel@tonic-gate 	if (apply_chg_list(pageno, length, (uchar_t *)saved,
485*0Sstevel@tonic-gate 			(uchar_t *)changeable, change_item)) {
486*0Sstevel@tonic-gate 		/*
487*0Sstevel@tonic-gate 		 * A change was made.  Do a mode select
488*0Sstevel@tonic-gate 		 * We always want to set the Page Format bit.
489*0Sstevel@tonic-gate 		 * Set the Save Page bit if the drive indicates
490*0Sstevel@tonic-gate 		 * that it can save this page.
491*0Sstevel@tonic-gate 		 */
492*0Sstevel@tonic-gate 		flags = MODE_SELECT_PF;
493*0Sstevel@tonic-gate 		if (pg->ps) {
494*0Sstevel@tonic-gate 			flags |= MODE_SELECT_SP;
495*0Sstevel@tonic-gate 		}
496*0Sstevel@tonic-gate 		pg->ps = 0;
497*0Sstevel@tonic-gate 		header.mode_header.length = 0;
498*0Sstevel@tonic-gate 		header.mode_header.device_specific = 0;
499*0Sstevel@tonic-gate 		if (uscsi_mode_select(cur_file, pageno, flags,
500*0Sstevel@tonic-gate 				saved, length, &header)) {
501*0Sstevel@tonic-gate 			/*
502*0Sstevel@tonic-gate 			 * Failed - try not saving parameters,
503*0Sstevel@tonic-gate 			 * if possible.
504*0Sstevel@tonic-gate 			 */
505*0Sstevel@tonic-gate 			if (flags & MODE_SELECT_SP) {
506*0Sstevel@tonic-gate 				flags &= ~MODE_SELECT_SP;
507*0Sstevel@tonic-gate 				if (uscsi_mode_select(cur_file, pageno,
508*0Sstevel@tonic-gate 						flags, saved,
509*0Sstevel@tonic-gate 						length, &header)) {
510*0Sstevel@tonic-gate 					result = 1;
511*0Sstevel@tonic-gate 				}
512*0Sstevel@tonic-gate 			} else {
513*0Sstevel@tonic-gate 				result = 1;
514*0Sstevel@tonic-gate 			}
515*0Sstevel@tonic-gate 		}
516*0Sstevel@tonic-gate 
517*0Sstevel@tonic-gate 		if (result) {
518*0Sstevel@tonic-gate 			fmt_print("\n\
519*0Sstevel@tonic-gate Mode select on page %x failed.\n", pageno);
520*0Sstevel@tonic-gate 		} else if ((flags & MODE_SELECT_SP) == 0) {
521*0Sstevel@tonic-gate 			fmt_print("\n\
522*0Sstevel@tonic-gate Mode select on page %x ok, but unable to save change permanently.\n", pageno);
523*0Sstevel@tonic-gate 		} else {
524*0Sstevel@tonic-gate 			fmt_print("\n\
525*0Sstevel@tonic-gate Mode select on page %x ok.\n", pageno);
526*0Sstevel@tonic-gate 		}
527*0Sstevel@tonic-gate 	} else {
528*0Sstevel@tonic-gate 		err_print("\nDevice cannot support this change\n");
529*0Sstevel@tonic-gate 	}
530*0Sstevel@tonic-gate 
531*0Sstevel@tonic-gate 	fmt_print("\n");
532*0Sstevel@tonic-gate 	return (result);
533*0Sstevel@tonic-gate }
534*0Sstevel@tonic-gate 
535*0Sstevel@tonic-gate 
536*0Sstevel@tonic-gate /*
537*0Sstevel@tonic-gate  * Format a device, without any of the standard mode selects.
538*0Sstevel@tonic-gate  * Ask if we should format with the P or the P&G lists.
539*0Sstevel@tonic-gate  */
540*0Sstevel@tonic-gate static int
541*0Sstevel@tonic-gate do_format()
542*0Sstevel@tonic-gate {
543*0Sstevel@tonic-gate 	struct uscsi_cmd	ucmd;
544*0Sstevel@tonic-gate 	union scsi_cdb		cdb;
545*0Sstevel@tonic-gate 	struct scsi_defect_hdr	defect_hdr;
546*0Sstevel@tonic-gate 	int			status;
547*0Sstevel@tonic-gate 	u_ioparam_t		ioparam;
548*0Sstevel@tonic-gate 	int			deflt;
549*0Sstevel@tonic-gate 	int			grown_list;
550*0Sstevel@tonic-gate 
551*0Sstevel@tonic-gate 	fmt_print("\n");
552*0Sstevel@tonic-gate 	/*
553*0Sstevel@tonic-gate 	 * Are there mounted partitions?
554*0Sstevel@tonic-gate 	 */
555*0Sstevel@tonic-gate 	if (checkmount((daddr_t)-1, (daddr_t)-1)) {
556*0Sstevel@tonic-gate 		err_print("Cannot format disk with mounted partitions\n\n");
557*0Sstevel@tonic-gate 		return (-1);
558*0Sstevel@tonic-gate 	}
559*0Sstevel@tonic-gate 
560*0Sstevel@tonic-gate 	/*
561*0Sstevel@tonic-gate 	 * Is any of the partitions being used for swapping.
562*0Sstevel@tonic-gate 	 */
563*0Sstevel@tonic-gate 	if (checkswap((daddr_t)-1, (daddr_t)-1)) {
564*0Sstevel@tonic-gate 		err_print("Cannot format disk while its partitions are \
565*0Sstevel@tonic-gate currently being used for swapping.\n\n");
566*0Sstevel@tonic-gate 		return (-1);
567*0Sstevel@tonic-gate 	}
568*0Sstevel@tonic-gate 
569*0Sstevel@tonic-gate 	/*
570*0Sstevel@tonic-gate 	 * Let the user choose between formatting with either
571*0Sstevel@tonic-gate 	 * the P, or the P&G lists.  Note that yes is 0, no is 1.
572*0Sstevel@tonic-gate 	 */
573*0Sstevel@tonic-gate 	deflt = 0;
574*0Sstevel@tonic-gate 	ioparam.io_charlist = confirm_list;
575*0Sstevel@tonic-gate 	grown_list = !input(FIO_MSTR, "Format with the Grown Defects list",
576*0Sstevel@tonic-gate 		'?', &ioparam, &deflt, DATA_INPUT);
577*0Sstevel@tonic-gate 
578*0Sstevel@tonic-gate 	/*
579*0Sstevel@tonic-gate 	 * Construct the uscsi format ioctl.
580*0Sstevel@tonic-gate 	 * To format with the P and G list, we set the fmtData
581*0Sstevel@tonic-gate 	 * and cmpLst bits to zero.  To format with just the
582*0Sstevel@tonic-gate 	 * P list, we set the fmtData bit (meaning that we will
583*0Sstevel@tonic-gate 	 * send down a defect list in the data phase) and the
584*0Sstevel@tonic-gate 	 * cmpLst bit (meaning that the list we send is the
585*0Sstevel@tonic-gate 	 * complete G list), and a defect list header with
586*0Sstevel@tonic-gate 	 * a defect list length of zero.
587*0Sstevel@tonic-gate 	 */
588*0Sstevel@tonic-gate 	(void) memset((char *)&ucmd, 0, sizeof (ucmd));
589*0Sstevel@tonic-gate 	(void) memset((char *)&cdb, 0, sizeof (union scsi_cdb));
590*0Sstevel@tonic-gate 	cdb.scc_cmd = SCMD_FORMAT;
591*0Sstevel@tonic-gate 	ucmd.uscsi_cdb = (caddr_t)&cdb;
592*0Sstevel@tonic-gate 	ucmd.uscsi_cdblen = CDB_GROUP0;
593*0Sstevel@tonic-gate 	if (!grown_list) {
594*0Sstevel@tonic-gate 		/*
595*0Sstevel@tonic-gate 		 * No G list.   Send empty defect list to replace it.
596*0Sstevel@tonic-gate 		 */
597*0Sstevel@tonic-gate 		cdb.cdb_opaque[1] = FPB_DATA | FPB_CMPLT | FPB_BFI;
598*0Sstevel@tonic-gate 		(void) memset((char *)&defect_hdr, 0, sizeof (defect_hdr));
599*0Sstevel@tonic-gate 		ucmd.uscsi_bufaddr = (caddr_t)&defect_hdr;
600*0Sstevel@tonic-gate 		ucmd.uscsi_buflen = sizeof (defect_hdr);
601*0Sstevel@tonic-gate 	}
602*0Sstevel@tonic-gate 
603*0Sstevel@tonic-gate 	/*
604*0Sstevel@tonic-gate 	 * Issue the format ioctl
605*0Sstevel@tonic-gate 	 */
606*0Sstevel@tonic-gate 	fmt_print("Formatting...\n");
607*0Sstevel@tonic-gate 	(void) fflush(stdout);
608*0Sstevel@tonic-gate 	status = uscsi_cmd(cur_file, &ucmd, F_NORMAL);
609*0Sstevel@tonic-gate 	fmt_print(status ? "Format failed\n\n" : "Format ok\n\n");
610*0Sstevel@tonic-gate 	return (status);
611*0Sstevel@tonic-gate }
612*0Sstevel@tonic-gate 
613*0Sstevel@tonic-gate 
614*0Sstevel@tonic-gate /*
615*0Sstevel@tonic-gate  * List common SCSI-2 mode pages
616*0Sstevel@tonic-gate  */
617*0Sstevel@tonic-gate static void
618*0Sstevel@tonic-gate do_list()
619*0Sstevel@tonic-gate {
620*0Sstevel@tonic-gate 	fmt_print("\n\
621*0Sstevel@tonic-gate Common SCSI-2 pages applicable to direct-access devices:\n\n");
622*0Sstevel@tonic-gate 	fmt_print("Page 0x1   - Read-Write Error Recovery Page\n");
623*0Sstevel@tonic-gate 	fmt_print("Page 0x2   - Disconnect-Reconnect Page\n");
624*0Sstevel@tonic-gate 	fmt_print("Page 0x3   - Format Device Page\n");
625*0Sstevel@tonic-gate 	fmt_print("Page 0x4   - Rigid Disk Geometry Page\n");
626*0Sstevel@tonic-gate 	fmt_print("Page 0x7   - Verify Error Recovery Page\n");
627*0Sstevel@tonic-gate 	fmt_print("Page 0x8   - Caching Page\n");
628*0Sstevel@tonic-gate 	fmt_print("Page 0xA   - Control Mode Page\n");
629*0Sstevel@tonic-gate 	fmt_print("\n");
630*0Sstevel@tonic-gate }
631*0Sstevel@tonic-gate 
632*0Sstevel@tonic-gate 
633*0Sstevel@tonic-gate /*
634*0Sstevel@tonic-gate  * Labels for the various fields of the scsi_inquiry structure
635*0Sstevel@tonic-gate  */
636*0Sstevel@tonic-gate static char *scsi_inquiry_labels[] = {
637*0Sstevel@tonic-gate 	"Vendor:                     ",
638*0Sstevel@tonic-gate 	"Product:                    ",
639*0Sstevel@tonic-gate 	"Revision:                   ",
640*0Sstevel@tonic-gate 	"Removable media:            ",
641*0Sstevel@tonic-gate 	"Device type:                ",
642*0Sstevel@tonic-gate 	"ISO version:                ",
643*0Sstevel@tonic-gate 	"ECMA version:               ",
644*0Sstevel@tonic-gate 	"ANSI version:               ",
645*0Sstevel@tonic-gate 	"Async event notification:   ",
646*0Sstevel@tonic-gate 	"Terminate i/o process msg:  ",
647*0Sstevel@tonic-gate 	"Response data format:       ",
648*0Sstevel@tonic-gate 	"Additional length:          ",
649*0Sstevel@tonic-gate 	"Relative addressing:        ",
650*0Sstevel@tonic-gate 	"32 bit transfers:           ",
651*0Sstevel@tonic-gate 	"16 bit transfers:           ",
652*0Sstevel@tonic-gate 	"Synchronous transfers:      ",
653*0Sstevel@tonic-gate 	"Linked commands:            ",
654*0Sstevel@tonic-gate 	"Command queueing:           ",
655*0Sstevel@tonic-gate 	"Soft reset option:          "
656*0Sstevel@tonic-gate };
657*0Sstevel@tonic-gate 
658*0Sstevel@tonic-gate 
659*0Sstevel@tonic-gate /*
660*0Sstevel@tonic-gate  * Dump the full inquiry as returned by the device
661*0Sstevel@tonic-gate  */
662*0Sstevel@tonic-gate static int
663*0Sstevel@tonic-gate do_inquiry()
664*0Sstevel@tonic-gate {
665*0Sstevel@tonic-gate 	char			inqbuf[255];
666*0Sstevel@tonic-gate 	struct scsi_inquiry	*inq;
667*0Sstevel@tonic-gate 	char			**p;
668*0Sstevel@tonic-gate 
669*0Sstevel@tonic-gate 	inq = (struct scsi_inquiry *)inqbuf;
670*0Sstevel@tonic-gate 
671*0Sstevel@tonic-gate 	if (uscsi_inquiry(cur_file, inqbuf, sizeof (inqbuf))) {
672*0Sstevel@tonic-gate 		err_print("\nInquiry failed\n");
673*0Sstevel@tonic-gate 		return (1);
674*0Sstevel@tonic-gate 	}
675*0Sstevel@tonic-gate 
676*0Sstevel@tonic-gate 	fmt_print("\nInquiry:\n");
677*0Sstevel@tonic-gate 	/*
678*0Sstevel@tonic-gate 	 * The SCSI-2 spec defines "Additional length" as (n-4) bytes,
679*0Sstevel@tonic-gate 	 * where n is the last byte of the INQUIRY data.  Thus
680*0Sstevel@tonic-gate 	 * there are n+1 bytes of INQUIRY data.  We need to add 5 to
681*0Sstevel@tonic-gate 	 * inq_len in order to get all the INQUIRY data.
682*0Sstevel@tonic-gate 	 */
683*0Sstevel@tonic-gate 	dump("    ", inqbuf, inq->inq_len + 5, HEX_ASCII);
684*0Sstevel@tonic-gate 	fmt_print("\n");
685*0Sstevel@tonic-gate 
686*0Sstevel@tonic-gate 	p = scsi_inquiry_labels;
687*0Sstevel@tonic-gate 
688*0Sstevel@tonic-gate 	fmt_print("%s", *p++);
689*0Sstevel@tonic-gate 	print_buf(inq->inq_vid, sizeof (inq->inq_vid));
690*0Sstevel@tonic-gate 	fmt_print("\n%s", *p++);
691*0Sstevel@tonic-gate 	print_buf(inq->inq_pid, sizeof (inq->inq_pid));
692*0Sstevel@tonic-gate 	fmt_print("\n%s", *p++);
693*0Sstevel@tonic-gate 	print_buf(inq->inq_revision, sizeof (inq->inq_revision));
694*0Sstevel@tonic-gate 
695*0Sstevel@tonic-gate 	fmt_print("\n%s%s\n", *p++, inq->inq_rmb ? "yes" : "no");
696*0Sstevel@tonic-gate 	fmt_print("%s%d\n", *p++, inq->inq_qual);
697*0Sstevel@tonic-gate 	fmt_print("%s%d\n", *p++, inq->inq_iso);
698*0Sstevel@tonic-gate 	fmt_print("%s%d\n", *p++, inq->inq_ecma);
699*0Sstevel@tonic-gate 	fmt_print("%s%d\n", *p++, inq->inq_ansi);
700*0Sstevel@tonic-gate 	fmt_print("%s%s\n", *p++, inq->inq_aenc ? "yes" : "no");
701*0Sstevel@tonic-gate 	fmt_print("%s%s\n", *p++, inq->inq_trmiop ? "yes" : "no");
702*0Sstevel@tonic-gate 	fmt_print("%s%d\n", *p++, inq->inq_rdf);
703*0Sstevel@tonic-gate 	fmt_print("%s%d\n", *p++, inq->inq_len);
704*0Sstevel@tonic-gate 	fmt_print("%s%s\n", *p++, inq->inq_reladdr ? "yes" : "no");
705*0Sstevel@tonic-gate 	fmt_print("%s%s\n", *p++, inq->inq_wbus32 ? "yes" : "no");
706*0Sstevel@tonic-gate 	fmt_print("%s%s\n", *p++, inq->inq_wbus16 ? "yes" : "no");
707*0Sstevel@tonic-gate 	fmt_print("%s%s\n", *p++, inq->inq_sync ? "yes" : "no");
708*0Sstevel@tonic-gate 	fmt_print("%s%s\n", *p++, inq->inq_linked ? "yes" : "no");
709*0Sstevel@tonic-gate 	fmt_print("%s%s\n", *p++, inq->inq_cmdque ? "yes" : "no");
710*0Sstevel@tonic-gate 	fmt_print("%s%s\n", *p++, inq->inq_sftre ? "yes" : "no");
711*0Sstevel@tonic-gate 
712*0Sstevel@tonic-gate 	fmt_print("\n");
713*0Sstevel@tonic-gate 	return (0);
714*0Sstevel@tonic-gate }
715*0Sstevel@tonic-gate 
716*0Sstevel@tonic-gate 
717*0Sstevel@tonic-gate static void
718*0Sstevel@tonic-gate do_apply()
719*0Sstevel@tonic-gate {
720*0Sstevel@tonic-gate 	if (change_list == NULL) {
721*0Sstevel@tonic-gate 		fmt_print("\nlist empty.\n");
722*0Sstevel@tonic-gate 	} else {
723*0Sstevel@tonic-gate 		(void) do_mode_select(change_list);
724*0Sstevel@tonic-gate 		free_change_list();
725*0Sstevel@tonic-gate 	}
726*0Sstevel@tonic-gate }
727*0Sstevel@tonic-gate 
728*0Sstevel@tonic-gate 
729*0Sstevel@tonic-gate static void
730*0Sstevel@tonic-gate do_cancel()
731*0Sstevel@tonic-gate {
732*0Sstevel@tonic-gate 	if (change_list == NULL) {
733*0Sstevel@tonic-gate 		fmt_print("\nlist empty.\n");
734*0Sstevel@tonic-gate 	} else {
735*0Sstevel@tonic-gate 		free_change_list();
736*0Sstevel@tonic-gate 	}
737*0Sstevel@tonic-gate }
738*0Sstevel@tonic-gate 
739*0Sstevel@tonic-gate 
740*0Sstevel@tonic-gate static void
741*0Sstevel@tonic-gate do_display()
742*0Sstevel@tonic-gate {
743*0Sstevel@tonic-gate 	struct chg_list	*cp;
744*0Sstevel@tonic-gate 
745*0Sstevel@tonic-gate 	if (change_list == NULL) {
746*0Sstevel@tonic-gate 		fmt_print("\nlist empty.\n");
747*0Sstevel@tonic-gate 	} else {
748*0Sstevel@tonic-gate 		fmt_print("\nPage 0x%x\n", current_page);
749*0Sstevel@tonic-gate 		for (cp = change_list; cp != NULL; cp = cp->next) {
750*0Sstevel@tonic-gate 			fmt_print("   b0x%x ", cp->byteno);
751*0Sstevel@tonic-gate 			switch (cp->mode) {
752*0Sstevel@tonic-gate 			case CHG_MODE_ABS:
753*0Sstevel@tonic-gate 				fmt_print("= 0x%x\n", cp->value);
754*0Sstevel@tonic-gate 				break;
755*0Sstevel@tonic-gate 			case CHG_MODE_SET:
756*0Sstevel@tonic-gate 				fmt_print("|= 0x%x\n", cp->value);
757*0Sstevel@tonic-gate 				break;
758*0Sstevel@tonic-gate 			case CHG_MODE_CLR:
759*0Sstevel@tonic-gate 				fmt_print("&= ~0x%x\n",
760*0Sstevel@tonic-gate 					(~(cp->value)) & 0xff);
761*0Sstevel@tonic-gate 				break;
762*0Sstevel@tonic-gate 			default:
763*0Sstevel@tonic-gate 				impossible("do_display");
764*0Sstevel@tonic-gate 				/*NOTREACHED*/
765*0Sstevel@tonic-gate 			}
766*0Sstevel@tonic-gate 		}
767*0Sstevel@tonic-gate 		fmt_print("\n");
768*0Sstevel@tonic-gate 	}
769*0Sstevel@tonic-gate }
770*0Sstevel@tonic-gate 
771*0Sstevel@tonic-gate 
772*0Sstevel@tonic-gate static int
773*0Sstevel@tonic-gate parse_change_spec(full_input, input, pageno, chg_item)
774*0Sstevel@tonic-gate 	char		*full_input;
775*0Sstevel@tonic-gate 	char		*input;
776*0Sstevel@tonic-gate 	int		pageno;
777*0Sstevel@tonic-gate 	struct chg_list	*chg_item;
778*0Sstevel@tonic-gate {
779*0Sstevel@tonic-gate 	char		*p;
780*0Sstevel@tonic-gate 	int		tilde;
781*0Sstevel@tonic-gate 
782*0Sstevel@tonic-gate 	assert(*input == 'b');
783*0Sstevel@tonic-gate 
784*0Sstevel@tonic-gate 	chg_item->pageno = pageno;
785*0Sstevel@tonic-gate 	chg_item->next = NULL;
786*0Sstevel@tonic-gate 
787*0Sstevel@tonic-gate 	input++;
788*0Sstevel@tonic-gate 	chg_item->byteno = (int)strtol(input, &p, 0);
789*0Sstevel@tonic-gate 	if (p == input) {
790*0Sstevel@tonic-gate 		err_print("Syntax error: %s\n", full_input);
791*0Sstevel@tonic-gate 		return (0);
792*0Sstevel@tonic-gate 	}
793*0Sstevel@tonic-gate 	if (chg_item->byteno < 2) {
794*0Sstevel@tonic-gate 		err_print(" Unsupported byte offset: %d\n",
795*0Sstevel@tonic-gate 			chg_item->byteno);
796*0Sstevel@tonic-gate 		return (0);
797*0Sstevel@tonic-gate 	}
798*0Sstevel@tonic-gate 	for (input = p; *input == ' '; input++)
799*0Sstevel@tonic-gate 		;
800*0Sstevel@tonic-gate 	chg_item->mode = CHG_MODE_UNDEFINED;
801*0Sstevel@tonic-gate 	switch (*input++) {
802*0Sstevel@tonic-gate 	case '=':
803*0Sstevel@tonic-gate 		chg_item->mode = CHG_MODE_ABS;
804*0Sstevel@tonic-gate 		break;
805*0Sstevel@tonic-gate 	case '|':
806*0Sstevel@tonic-gate 		if (*input++ == '=') {
807*0Sstevel@tonic-gate 			chg_item->mode = CHG_MODE_SET;
808*0Sstevel@tonic-gate 		}
809*0Sstevel@tonic-gate 		break;
810*0Sstevel@tonic-gate 	case '&':
811*0Sstevel@tonic-gate 		if (*input++ == '=') {
812*0Sstevel@tonic-gate 			chg_item->mode = CHG_MODE_CLR;
813*0Sstevel@tonic-gate 		}
814*0Sstevel@tonic-gate 		break;
815*0Sstevel@tonic-gate 	}
816*0Sstevel@tonic-gate 	if (chg_item->mode == CHG_MODE_UNDEFINED) {
817*0Sstevel@tonic-gate 		err_print("Syntax error: %s\n", full_input);
818*0Sstevel@tonic-gate 		return (0);
819*0Sstevel@tonic-gate 	}
820*0Sstevel@tonic-gate 	for (; *input == ' '; input++)
821*0Sstevel@tonic-gate 		;
822*0Sstevel@tonic-gate 	if (*input == '~') {
823*0Sstevel@tonic-gate 		tilde = 1;
824*0Sstevel@tonic-gate 		for (input++; *input == ' '; input++)
825*0Sstevel@tonic-gate 			;
826*0Sstevel@tonic-gate 	} else {
827*0Sstevel@tonic-gate 		tilde = 0;
828*0Sstevel@tonic-gate 	}
829*0Sstevel@tonic-gate 	chg_item->value = (int)strtol(input, &p, 0);
830*0Sstevel@tonic-gate 	if (p == input || *p != 0) {
831*0Sstevel@tonic-gate 		err_print("Syntax error: %s\n", full_input);
832*0Sstevel@tonic-gate 		return (0);
833*0Sstevel@tonic-gate 	}
834*0Sstevel@tonic-gate 	/*
835*0Sstevel@tonic-gate 	 * Apply complement if selected.
836*0Sstevel@tonic-gate 	 * Constrain to a byte value.
837*0Sstevel@tonic-gate 	 */
838*0Sstevel@tonic-gate 	if (tilde) {
839*0Sstevel@tonic-gate 		chg_item->value = ~chg_item->value;
840*0Sstevel@tonic-gate 	}
841*0Sstevel@tonic-gate 	chg_item->value &= 0xff;
842*0Sstevel@tonic-gate 
843*0Sstevel@tonic-gate 	return (1);
844*0Sstevel@tonic-gate }
845*0Sstevel@tonic-gate 
846*0Sstevel@tonic-gate 
847*0Sstevel@tonic-gate static void
848*0Sstevel@tonic-gate add_new_change_list_item(chg_item)
849*0Sstevel@tonic-gate 	struct chg_list		*chg_item;
850*0Sstevel@tonic-gate {
851*0Sstevel@tonic-gate 	struct chg_list	*cp;
852*0Sstevel@tonic-gate 
853*0Sstevel@tonic-gate 	if (change_list == NULL) {
854*0Sstevel@tonic-gate 		change_list = chg_item;
855*0Sstevel@tonic-gate 	} else {
856*0Sstevel@tonic-gate 		for (cp = change_list; cp->next != NULL; cp = cp->next)
857*0Sstevel@tonic-gate 			;
858*0Sstevel@tonic-gate 		cp->next = chg_item;
859*0Sstevel@tonic-gate 	}
860*0Sstevel@tonic-gate 	chg_item->next = NULL;
861*0Sstevel@tonic-gate }
862*0Sstevel@tonic-gate 
863*0Sstevel@tonic-gate 
864*0Sstevel@tonic-gate static void
865*0Sstevel@tonic-gate free_change_list()
866*0Sstevel@tonic-gate {
867*0Sstevel@tonic-gate 	struct chg_list	*cp;
868*0Sstevel@tonic-gate 	struct chg_list	*cp2;
869*0Sstevel@tonic-gate 
870*0Sstevel@tonic-gate 	cp = change_list;
871*0Sstevel@tonic-gate 	while (cp != NULL) {
872*0Sstevel@tonic-gate 		cp2 = cp->next;
873*0Sstevel@tonic-gate 		destroy_data((char *)cp);
874*0Sstevel@tonic-gate 		cp = cp2;
875*0Sstevel@tonic-gate 	}
876*0Sstevel@tonic-gate 	change_list = NULL;
877*0Sstevel@tonic-gate }
878*0Sstevel@tonic-gate 
879*0Sstevel@tonic-gate 
880*0Sstevel@tonic-gate static void
881*0Sstevel@tonic-gate do_default(input)
882*0Sstevel@tonic-gate 	char		*input;
883*0Sstevel@tonic-gate {
884*0Sstevel@tonic-gate 	char		*s = input;
885*0Sstevel@tonic-gate 	char		*p;
886*0Sstevel@tonic-gate 	int		n;
887*0Sstevel@tonic-gate 
888*0Sstevel@tonic-gate 	/*
889*0Sstevel@tonic-gate 	 * Reset current page indicator
890*0Sstevel@tonic-gate 	 */
891*0Sstevel@tonic-gate 	current_page = -1;
892*0Sstevel@tonic-gate 
893*0Sstevel@tonic-gate 	/*
894*0Sstevel@tonic-gate 	 * Skip the leading "default" command, which we
895*0Sstevel@tonic-gate 	 * must have, or we wouldn't have come here,
896*0Sstevel@tonic-gate 	 * and any white space.
897*0Sstevel@tonic-gate 	 */
898*0Sstevel@tonic-gate 	while (isspace(*s)) {
899*0Sstevel@tonic-gate 		s++;
900*0Sstevel@tonic-gate 	}
901*0Sstevel@tonic-gate 
902*0Sstevel@tonic-gate 	while (*s && isascii(*s) && isalpha(*s)) {
903*0Sstevel@tonic-gate 		s++;
904*0Sstevel@tonic-gate 	}
905*0Sstevel@tonic-gate 
906*0Sstevel@tonic-gate 	while (isspace(*s)) {
907*0Sstevel@tonic-gate 		s++;
908*0Sstevel@tonic-gate 	}
909*0Sstevel@tonic-gate 
910*0Sstevel@tonic-gate 	/*
911*0Sstevel@tonic-gate 	 * Subsequent modifier must be either "p<n>", or "all".
912*0Sstevel@tonic-gate 	 */
913*0Sstevel@tonic-gate 	if (*s == 'p') {
914*0Sstevel@tonic-gate 		s++;
915*0Sstevel@tonic-gate 		n = (int)strtol(s, &p, 0);
916*0Sstevel@tonic-gate 		if (p == s || *p != 0) {
917*0Sstevel@tonic-gate 			err_print("Syntax error: %s\n", input);
918*0Sstevel@tonic-gate 		} else {
919*0Sstevel@tonic-gate 			fmt_print("\n");
920*0Sstevel@tonic-gate 			(void) default_page(n);
921*0Sstevel@tonic-gate 			fmt_print("\n");
922*0Sstevel@tonic-gate 		}
923*0Sstevel@tonic-gate 	} else if (*s == 'a') {
924*0Sstevel@tonic-gate 		default_all_pages();
925*0Sstevel@tonic-gate 	} else {
926*0Sstevel@tonic-gate 		err_print("Syntax error: %s\n", input);
927*0Sstevel@tonic-gate 	}
928*0Sstevel@tonic-gate }
929*0Sstevel@tonic-gate 
930*0Sstevel@tonic-gate 
931*0Sstevel@tonic-gate static void
932*0Sstevel@tonic-gate default_all_pages()
933*0Sstevel@tonic-gate {
934*0Sstevel@tonic-gate 	char			*p;
935*0Sstevel@tonic-gate 	struct mode_header	*mh;
936*0Sstevel@tonic-gate 	struct mode_page	*mp;
937*0Sstevel@tonic-gate 	int			n;
938*0Sstevel@tonic-gate 	struct uscsi_cmd	ucmd;
939*0Sstevel@tonic-gate 	union scsi_cdb		cdb;
940*0Sstevel@tonic-gate 	char			msbuf[MAX_MODE_SENSE_SIZE];
941*0Sstevel@tonic-gate 	int			nbytes = sizeof (msbuf);
942*0Sstevel@tonic-gate 	int			status;
943*0Sstevel@tonic-gate 
944*0Sstevel@tonic-gate 	/*
945*0Sstevel@tonic-gate 	 * Build and execute the uscsi ioctl.  Note that
946*0Sstevel@tonic-gate 	 * we cannot simply call uscsi_mode_sense() here,
947*0Sstevel@tonic-gate 	 * since that function attempts to valididate the
948*0Sstevel@tonic-gate 	 * returned data, and the page 0x3f has a unique
949*0Sstevel@tonic-gate 	 * format.
950*0Sstevel@tonic-gate 	 */
951*0Sstevel@tonic-gate 	nbytes = MAX_MODE_SENSE_SIZE;
952*0Sstevel@tonic-gate 	(void) memset(msbuf, 0, nbytes);
953*0Sstevel@tonic-gate 	(void) memset((char *)&ucmd, 0, sizeof (ucmd));
954*0Sstevel@tonic-gate 	(void) memset((char *)&cdb, 0, sizeof (union scsi_cdb));
955*0Sstevel@tonic-gate 	cdb.scc_cmd = SCMD_MODE_SENSE;
956*0Sstevel@tonic-gate 	FORMG0COUNT(&cdb, (uchar_t)nbytes);
957*0Sstevel@tonic-gate 	cdb.cdb_opaque[2] = MODE_SENSE_PC_DEFAULT | 0x3f;
958*0Sstevel@tonic-gate 	ucmd.uscsi_cdb = (caddr_t)&cdb;
959*0Sstevel@tonic-gate 	ucmd.uscsi_cdblen = CDB_GROUP0;
960*0Sstevel@tonic-gate 	ucmd.uscsi_bufaddr = msbuf;
961*0Sstevel@tonic-gate 	ucmd.uscsi_buflen = nbytes;
962*0Sstevel@tonic-gate 	status = uscsi_cmd(cur_file, &ucmd,
963*0Sstevel@tonic-gate 		(option_msg) ? F_NORMAL : F_SILENT);
964*0Sstevel@tonic-gate 	if (status) {
965*0Sstevel@tonic-gate 		if (!option_msg) {
966*0Sstevel@tonic-gate 			err_print("\nMode sense page 0x3f failed\n");
967*0Sstevel@tonic-gate 		}
968*0Sstevel@tonic-gate 		return;
969*0Sstevel@tonic-gate 	}
970*0Sstevel@tonic-gate 
971*0Sstevel@tonic-gate 	fmt_print("\n");
972*0Sstevel@tonic-gate 
973*0Sstevel@tonic-gate 	/*
974*0Sstevel@tonic-gate 	 * Now parse the page 0x3f
975*0Sstevel@tonic-gate 	 */
976*0Sstevel@tonic-gate 	mh = (struct mode_header *)msbuf;
977*0Sstevel@tonic-gate 	nbytes = mh->length - sizeof (struct mode_header) -
978*0Sstevel@tonic-gate 			mh->bdesc_length + 1;
979*0Sstevel@tonic-gate 	p = msbuf + sizeof (struct mode_header) + mh->bdesc_length;
980*0Sstevel@tonic-gate 
981*0Sstevel@tonic-gate 	while (nbytes > 0) {
982*0Sstevel@tonic-gate 		mp = (struct mode_page *)p;
983*0Sstevel@tonic-gate 		n = mp->length + sizeof (struct mode_page);
984*0Sstevel@tonic-gate 		nbytes -= n;
985*0Sstevel@tonic-gate 		if (nbytes < 0)
986*0Sstevel@tonic-gate 			break;
987*0Sstevel@tonic-gate 		if (default_page(mp->code) == 0) {
988*0Sstevel@tonic-gate 			goto error;
989*0Sstevel@tonic-gate 		}
990*0Sstevel@tonic-gate 		p += n;
991*0Sstevel@tonic-gate 	}
992*0Sstevel@tonic-gate 
993*0Sstevel@tonic-gate 	if (nbytes < 0) {
994*0Sstevel@tonic-gate 		err_print("Mode sense page 0x3f formatted incorrectly:\n");
995*0Sstevel@tonic-gate 	}
996*0Sstevel@tonic-gate error:
997*0Sstevel@tonic-gate 	fmt_print("\n");
998*0Sstevel@tonic-gate }
999*0Sstevel@tonic-gate 
1000*0Sstevel@tonic-gate 
1001*0Sstevel@tonic-gate static int
1002*0Sstevel@tonic-gate default_page(pageno)
1003*0Sstevel@tonic-gate 	int		pageno;
1004*0Sstevel@tonic-gate {
1005*0Sstevel@tonic-gate 	struct scsi_ms_header	header;
1006*0Sstevel@tonic-gate 	char			saved[MAX_MODE_SENSE_SIZE];
1007*0Sstevel@tonic-gate 	char			current[MAX_MODE_SENSE_SIZE];
1008*0Sstevel@tonic-gate 	char			dfault[MAX_MODE_SENSE_SIZE];
1009*0Sstevel@tonic-gate 	struct mode_page	*sp;
1010*0Sstevel@tonic-gate 	struct mode_page	*cp;
1011*0Sstevel@tonic-gate 	struct mode_page	*dp;
1012*0Sstevel@tonic-gate 	int			length;
1013*0Sstevel@tonic-gate 	int			flags;
1014*0Sstevel@tonic-gate 	int			i;
1015*0Sstevel@tonic-gate 	int			need_mode_select;
1016*0Sstevel@tonic-gate 
1017*0Sstevel@tonic-gate 	/*
1018*0Sstevel@tonic-gate 	 * Get default mode sense
1019*0Sstevel@tonic-gate 	 */
1020*0Sstevel@tonic-gate 	if (uscsi_mode_sense(cur_file, pageno, MODE_SENSE_PC_DEFAULT,
1021*0Sstevel@tonic-gate 			dfault, MAX_MODE_SENSE_SIZE, &header)) {
1022*0Sstevel@tonic-gate 		err_print("Mode sense on page %x (dfault) failed\n",
1023*0Sstevel@tonic-gate 			pageno);
1024*0Sstevel@tonic-gate 		return (0);
1025*0Sstevel@tonic-gate 	}
1026*0Sstevel@tonic-gate 
1027*0Sstevel@tonic-gate 	/*
1028*0Sstevel@tonic-gate 	 * Get the current mode sense.
1029*0Sstevel@tonic-gate 	 */
1030*0Sstevel@tonic-gate 	if (uscsi_mode_sense(cur_file, pageno, MODE_SENSE_PC_CURRENT,
1031*0Sstevel@tonic-gate 			current, MAX_MODE_SENSE_SIZE, &header)) {
1032*0Sstevel@tonic-gate 		err_print("Mode sense on page %x (current) failed\n",
1033*0Sstevel@tonic-gate 			pageno);
1034*0Sstevel@tonic-gate 		return (0);
1035*0Sstevel@tonic-gate 	}
1036*0Sstevel@tonic-gate 
1037*0Sstevel@tonic-gate 	/*
1038*0Sstevel@tonic-gate 	 * Get saved mode sense.  If this fails, assume it is
1039*0Sstevel@tonic-gate 	 * the same as the current.
1040*0Sstevel@tonic-gate 	 */
1041*0Sstevel@tonic-gate 	if (uscsi_mode_sense(cur_file, pageno, MODE_SENSE_PC_SAVED,
1042*0Sstevel@tonic-gate 			saved, MAX_MODE_SENSE_SIZE, &header)) {
1043*0Sstevel@tonic-gate 		(void) memcpy(saved, current, MAX_MODE_SENSE_SIZE);
1044*0Sstevel@tonic-gate 	}
1045*0Sstevel@tonic-gate 
1046*0Sstevel@tonic-gate 	/*
1047*0Sstevel@tonic-gate 	 * Determine if we need a mode select on this page.
1048*0Sstevel@tonic-gate 	 * Just deal with the intersection of the three pages.
1049*0Sstevel@tonic-gate 	 */
1050*0Sstevel@tonic-gate 	sp = (struct mode_page *)saved;
1051*0Sstevel@tonic-gate 	cp = (struct mode_page *)current;
1052*0Sstevel@tonic-gate 	dp = (struct mode_page *)dfault;
1053*0Sstevel@tonic-gate 	length = min(MODESENSE_PAGE_LEN(sp), MODESENSE_PAGE_LEN(cp));
1054*0Sstevel@tonic-gate 	length = min(length, MODESENSE_PAGE_LEN(dp));
1055*0Sstevel@tonic-gate 
1056*0Sstevel@tonic-gate 	need_mode_select = 0;
1057*0Sstevel@tonic-gate 	for (i = 2; i < length; i++) {
1058*0Sstevel@tonic-gate 		if (current[i] != dfault[i] || saved[i] != dfault[i]) {
1059*0Sstevel@tonic-gate 			current[i] = dfault[i];
1060*0Sstevel@tonic-gate 			need_mode_select = 1;
1061*0Sstevel@tonic-gate 		}
1062*0Sstevel@tonic-gate 	}
1063*0Sstevel@tonic-gate 
1064*0Sstevel@tonic-gate 	if (need_mode_select == 0) {
1065*0Sstevel@tonic-gate 		fmt_print("Defaulting page 0x%x: ok\n",
1066*0Sstevel@tonic-gate 			pageno);
1067*0Sstevel@tonic-gate 		return (1);
1068*0Sstevel@tonic-gate 	}
1069*0Sstevel@tonic-gate 
1070*0Sstevel@tonic-gate 	/*
1071*0Sstevel@tonic-gate 	 * A change was made.  Do a mode select
1072*0Sstevel@tonic-gate 	 * We always want to set the Page Format bit.
1073*0Sstevel@tonic-gate 	 * Set the Save Page bit if the drive indicates
1074*0Sstevel@tonic-gate 	 * that it can save this page.
1075*0Sstevel@tonic-gate 	 */
1076*0Sstevel@tonic-gate 	length = MODESENSE_PAGE_LEN(cp);
1077*0Sstevel@tonic-gate 	flags = MODE_SELECT_PF;
1078*0Sstevel@tonic-gate 	if (cp->ps) {
1079*0Sstevel@tonic-gate 		flags |= MODE_SELECT_SP;
1080*0Sstevel@tonic-gate 	}
1081*0Sstevel@tonic-gate 	cp->ps = 0;
1082*0Sstevel@tonic-gate 	header.mode_header.length = 0;
1083*0Sstevel@tonic-gate 	header.mode_header.device_specific = 0;
1084*0Sstevel@tonic-gate 	if (uscsi_mode_select(cur_file, pageno, flags,
1085*0Sstevel@tonic-gate 			current, length, &header)) {
1086*0Sstevel@tonic-gate 		/*
1087*0Sstevel@tonic-gate 		 * Failed - try not saving parameters,
1088*0Sstevel@tonic-gate 		 * if possible.
1089*0Sstevel@tonic-gate 		 */
1090*0Sstevel@tonic-gate 		if (flags & MODE_SELECT_SP) {
1091*0Sstevel@tonic-gate 			flags &= ~MODE_SELECT_SP;
1092*0Sstevel@tonic-gate 			if (uscsi_mode_select(cur_file, pageno, flags,
1093*0Sstevel@tonic-gate 					saved, length, &header)) {
1094*0Sstevel@tonic-gate 				fmt_print("Defaulting page 0x%x: failed\n",
1095*0Sstevel@tonic-gate 					pageno);
1096*0Sstevel@tonic-gate 			} else {
1097*0Sstevel@tonic-gate 				fmt_print("Defaulting page 0x%x: ",
1098*0Sstevel@tonic-gate 					pageno);
1099*0Sstevel@tonic-gate 				fmt_print("cannot save page permanently\n");
1100*0Sstevel@tonic-gate 			}
1101*0Sstevel@tonic-gate 		} else {
1102*0Sstevel@tonic-gate 			fmt_print("Defaulting page 0x%x: ", pageno);
1103*0Sstevel@tonic-gate 			fmt_print("cannot save page permanently\n");
1104*0Sstevel@tonic-gate 		}
1105*0Sstevel@tonic-gate 	} else {
1106*0Sstevel@tonic-gate 		fmt_print("Defaulting page 0x%x: mode select ok\n", pageno);
1107*0Sstevel@tonic-gate 	}
1108*0Sstevel@tonic-gate 
1109*0Sstevel@tonic-gate 	return (1);
1110*0Sstevel@tonic-gate }
1111