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