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