17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5b210ab1cSbz211116 * Common Development and Distribution License (the "License"). 6b210ab1cSbz211116 * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*cf6efa00SRalph Turner - Sun UK - Contractor * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved. 237c478bd9Sstevel@tonic-gate */ 247c478bd9Sstevel@tonic-gate 257c478bd9Sstevel@tonic-gate /* 267c478bd9Sstevel@tonic-gate * This file contains the routines for embedded scsi disks 277c478bd9Sstevel@tonic-gate */ 287c478bd9Sstevel@tonic-gate #include "global.h" 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate #include <sys/types.h> 317c478bd9Sstevel@tonic-gate #include <sys/param.h> 327c478bd9Sstevel@tonic-gate #include <sys/ioctl.h> 337c478bd9Sstevel@tonic-gate #include <sys/uio.h> 347c478bd9Sstevel@tonic-gate #include <sys/fcntl.h> 357c478bd9Sstevel@tonic-gate #include <errno.h> 367c478bd9Sstevel@tonic-gate #include <memory.h> 377c478bd9Sstevel@tonic-gate #include <malloc.h> 387c478bd9Sstevel@tonic-gate #include <unistd.h> 397c478bd9Sstevel@tonic-gate #include <stdlib.h> 407c478bd9Sstevel@tonic-gate #include <values.h> 417c478bd9Sstevel@tonic-gate #include <sys/byteorder.h> 427c478bd9Sstevel@tonic-gate 437c478bd9Sstevel@tonic-gate 447c478bd9Sstevel@tonic-gate 457c478bd9Sstevel@tonic-gate #include "startup.h" 467c478bd9Sstevel@tonic-gate #include "scsi_com.h" 477c478bd9Sstevel@tonic-gate #include "misc.h" 487c478bd9Sstevel@tonic-gate #include "ctlr_scsi.h" 497c478bd9Sstevel@tonic-gate #include "analyze.h" 507c478bd9Sstevel@tonic-gate #include "param.h" 517c478bd9Sstevel@tonic-gate #include "io.h" 527c478bd9Sstevel@tonic-gate 537c478bd9Sstevel@tonic-gate 547c478bd9Sstevel@tonic-gate #ifndef DAD_MODE_CACHE_CCS 557c478bd9Sstevel@tonic-gate #define DAD_MODE_CACHE_CCS 0x38 567c478bd9Sstevel@tonic-gate #endif /* DAD_MODE_CACHE_CCS */ 577c478bd9Sstevel@tonic-gate 587c478bd9Sstevel@tonic-gate /* format defect header bits */ 597c478bd9Sstevel@tonic-gate #define FDH_FOV 0x80 607c478bd9Sstevel@tonic-gate #define FDH_IMMED 0x02 617c478bd9Sstevel@tonic-gate 627c478bd9Sstevel@tonic-gate #define SENSE_LEN 20 637c478bd9Sstevel@tonic-gate 647c478bd9Sstevel@tonic-gate #define RETRY_DELAY 5 657c478bd9Sstevel@tonic-gate 667c478bd9Sstevel@tonic-gate #define PROGRESS_INDICATION_BASE 65536 677c478bd9Sstevel@tonic-gate 687c478bd9Sstevel@tonic-gate #ifdef __STDC__ 697c478bd9Sstevel@tonic-gate /* 707c478bd9Sstevel@tonic-gate * Local prototypes for ANSI C compilers 717c478bd9Sstevel@tonic-gate */ 727c478bd9Sstevel@tonic-gate static int scsi_format(uint64_t, uint64_t, struct defect_list *); 737c478bd9Sstevel@tonic-gate static int scsi_raw_format(void); 747c478bd9Sstevel@tonic-gate static int scsi_ms_page8(int); 757c478bd9Sstevel@tonic-gate static int scsi_ms_page38(int); 767c478bd9Sstevel@tonic-gate static void scsi_convert_list_to_new(struct defect_list *, 777c478bd9Sstevel@tonic-gate struct scsi_defect_list *, int); 787c478bd9Sstevel@tonic-gate static char *scsi_find_command_name(uint_t); 797c478bd9Sstevel@tonic-gate static int chg_list_affects_page(struct chg_list *, int); 807c478bd9Sstevel@tonic-gate static void scsi_printerr(struct uscsi_cmd *, 817c478bd9Sstevel@tonic-gate struct scsi_extended_sense *, int); 827c478bd9Sstevel@tonic-gate static diskaddr_t 837c478bd9Sstevel@tonic-gate scsi_extract_sense_info_descr(struct scsi_descr_sense_hdr *sdsp, int rqlen); 847c478bd9Sstevel@tonic-gate 857c478bd9Sstevel@tonic-gate static void scsi_print_extended_sense(struct scsi_extended_sense *, int); 867c478bd9Sstevel@tonic-gate static void scsi_print_descr_sense(struct scsi_descr_sense_hdr *, int); 877c478bd9Sstevel@tonic-gate 887c478bd9Sstevel@tonic-gate static int test_until_ready(int fd); 897c478bd9Sstevel@tonic-gate static int uscsi_reserve_release(int, int); 907c478bd9Sstevel@tonic-gate static int check_support_for_defects(void); 917c478bd9Sstevel@tonic-gate static int scsi_format_without_defects(void); 927c478bd9Sstevel@tonic-gate static int scsi_ms_page1(int); 937c478bd9Sstevel@tonic-gate static int scsi_ms_page2(int); 947c478bd9Sstevel@tonic-gate static int scsi_ms_page3(int); 957c478bd9Sstevel@tonic-gate static int scsi_ms_page4(int); 967c478bd9Sstevel@tonic-gate static int scsi_repair(uint64_t, int); 977c478bd9Sstevel@tonic-gate static int scsi_read_defect_data(struct defect_list *, int); 987c478bd9Sstevel@tonic-gate static int scsi_ck_format(void); 997c478bd9Sstevel@tonic-gate 1007c478bd9Sstevel@tonic-gate #else /* __STDC__ */ 1017c478bd9Sstevel@tonic-gate 1027c478bd9Sstevel@tonic-gate static int scsi_format(); 1037c478bd9Sstevel@tonic-gate static int scsi_raw_format(); 1047c478bd9Sstevel@tonic-gate static int scsi_ms_page8(); 1057c478bd9Sstevel@tonic-gate static int scsi_ms_page38(); 1067c478bd9Sstevel@tonic-gate static void scsi_convert_list_to_new(); 1077c478bd9Sstevel@tonic-gate static char *scsi_find_command_name(); 1087c478bd9Sstevel@tonic-gate static int chg_list_affects_page(); 1097c478bd9Sstevel@tonic-gate static void scsi_printerr(); 1107c478bd9Sstevel@tonic-gate static diskaddr_t scsi_extract_sense_info_descr(); 1117c478bd9Sstevel@tonic-gate static void scsi_print_extended_sense(); 1127c478bd9Sstevel@tonic-gate static void scsi_print_descr_sense(); 1137c478bd9Sstevel@tonic-gate 1147c478bd9Sstevel@tonic-gate static int test_until_ready(); 1157c478bd9Sstevel@tonic-gate 1167c478bd9Sstevel@tonic-gate static int uscsi_reserve_release(); 1177c478bd9Sstevel@tonic-gate static int check_support_for_defects(); 1187c478bd9Sstevel@tonic-gate static int scsi_format_without_defects(); 1197c478bd9Sstevel@tonic-gate static int scsi_ms_page1(); 1207c478bd9Sstevel@tonic-gate static int scsi_ms_page2(); 1217c478bd9Sstevel@tonic-gate static int scsi_ms_page3(); 1227c478bd9Sstevel@tonic-gate static int scsi_ms_page4(); 1237c478bd9Sstevel@tonic-gate static int scsi_repair(); 1247c478bd9Sstevel@tonic-gate static int scsi_read_defect_data(); 1257c478bd9Sstevel@tonic-gate static int scsi_ck_format(); 1267c478bd9Sstevel@tonic-gate 1277c478bd9Sstevel@tonic-gate #endif /* __STDC__ */ 1287c478bd9Sstevel@tonic-gate 1297c478bd9Sstevel@tonic-gate 1307c478bd9Sstevel@tonic-gate 1317c478bd9Sstevel@tonic-gate struct ctlr_ops scsiops = { 1327c478bd9Sstevel@tonic-gate scsi_rdwr, 1337c478bd9Sstevel@tonic-gate scsi_ck_format, 1347c478bd9Sstevel@tonic-gate scsi_format, 1357c478bd9Sstevel@tonic-gate scsi_ex_man, 1367c478bd9Sstevel@tonic-gate scsi_ex_cur, 1377c478bd9Sstevel@tonic-gate scsi_repair, 1387c478bd9Sstevel@tonic-gate 0, 1397c478bd9Sstevel@tonic-gate }; 1407c478bd9Sstevel@tonic-gate 1417c478bd9Sstevel@tonic-gate #define SCMD_UNKNOWN 0xff 1427c478bd9Sstevel@tonic-gate 1437c478bd9Sstevel@tonic-gate /* 1447c478bd9Sstevel@tonic-gate * Names of commands. Must have SCMD_UNKNOWN at end of list. 1457c478bd9Sstevel@tonic-gate */ 1467c478bd9Sstevel@tonic-gate static struct scsi_command_name { 1477c478bd9Sstevel@tonic-gate uchar_t command; 1487c478bd9Sstevel@tonic-gate char *name; 1497c478bd9Sstevel@tonic-gate } scsi_command_names[] = { 1507c478bd9Sstevel@tonic-gate SCMD_FORMAT, "format", 1517c478bd9Sstevel@tonic-gate SCMD_READ, "read", 1527c478bd9Sstevel@tonic-gate SCMD_WRITE, "write", 1537c478bd9Sstevel@tonic-gate SCMD_READ|SCMD_GROUP1, "read", 1547c478bd9Sstevel@tonic-gate SCMD_WRITE|SCMD_GROUP1, "write", 1557c478bd9Sstevel@tonic-gate SCMD_INQUIRY, "inquiry", 1567c478bd9Sstevel@tonic-gate SCMD_MODE_SELECT, "mode select", 1577c478bd9Sstevel@tonic-gate SCMD_MODE_SENSE, "mode sense", 1587c478bd9Sstevel@tonic-gate SCMD_REASSIGN_BLOCK, "reassign block", 1597c478bd9Sstevel@tonic-gate SCMD_READ_DEFECT_LIST, "read defect list", 1607c478bd9Sstevel@tonic-gate SCMD_UNKNOWN, "unknown" 1617c478bd9Sstevel@tonic-gate }; 1627c478bd9Sstevel@tonic-gate 1637c478bd9Sstevel@tonic-gate 1647c478bd9Sstevel@tonic-gate /* 1657c478bd9Sstevel@tonic-gate * Strings for printing mode sense page control values 1667c478bd9Sstevel@tonic-gate */ 1677c478bd9Sstevel@tonic-gate static slist_t page_control_strings[] = { 1687c478bd9Sstevel@tonic-gate { "current", "", MODE_SENSE_PC_CURRENT }, 1697c478bd9Sstevel@tonic-gate { "changeable", "", MODE_SENSE_PC_CHANGEABLE }, 1707c478bd9Sstevel@tonic-gate { "default", "", MODE_SENSE_PC_DEFAULT }, 1717c478bd9Sstevel@tonic-gate { "saved", "", MODE_SENSE_PC_SAVED } 1727c478bd9Sstevel@tonic-gate }; 1737c478bd9Sstevel@tonic-gate 1747c478bd9Sstevel@tonic-gate /* 1757c478bd9Sstevel@tonic-gate * Strings for printing the mode select options 1767c478bd9Sstevel@tonic-gate */ 1777c478bd9Sstevel@tonic-gate static slist_t mode_select_strings[] = { 1787c478bd9Sstevel@tonic-gate { "", "", 0 }, 1797c478bd9Sstevel@tonic-gate { " (pf)", "", MODE_SELECT_PF }, 1807c478bd9Sstevel@tonic-gate { " (sp)", "", MODE_SELECT_SP }, 1817c478bd9Sstevel@tonic-gate { " (pf,sp)", "", MODE_SELECT_PF|MODE_SELECT_SP } 1827c478bd9Sstevel@tonic-gate }; 1837c478bd9Sstevel@tonic-gate 1847c478bd9Sstevel@tonic-gate static int scsi_format_revolutions = 5; 1857c478bd9Sstevel@tonic-gate static int scsi_format_timeout = 2*60*60; /* two hours */ 1867c478bd9Sstevel@tonic-gate 1877c478bd9Sstevel@tonic-gate /* 1887c478bd9Sstevel@tonic-gate * READ DEFECT DATA commands is optional as per SCSI-2 spec. 1897c478bd9Sstevel@tonic-gate * Hence check if the read_defect_data command fails with 1907c478bd9Sstevel@tonic-gate * Invalid Opcode so that we can give a more meaningful message 1917c478bd9Sstevel@tonic-gate * to the user. 1927c478bd9Sstevel@tonic-gate */ 1937c478bd9Sstevel@tonic-gate #define INVALID_OPCODE 0x20 1947c478bd9Sstevel@tonic-gate 1957c478bd9Sstevel@tonic-gate /* 1967c478bd9Sstevel@tonic-gate * Read or write the disk. 1977c478bd9Sstevel@tonic-gate */ 1987c478bd9Sstevel@tonic-gate int 1997c478bd9Sstevel@tonic-gate scsi_rdwr(dir, fd, blkno, secnt, bufaddr, flags, xfercntp) 2007c478bd9Sstevel@tonic-gate int dir; 2017c478bd9Sstevel@tonic-gate int fd; 2027c478bd9Sstevel@tonic-gate diskaddr_t blkno; 2037c478bd9Sstevel@tonic-gate int secnt; 2047c478bd9Sstevel@tonic-gate caddr_t bufaddr; 2057c478bd9Sstevel@tonic-gate int flags; 2067c478bd9Sstevel@tonic-gate int *xfercntp; 2077c478bd9Sstevel@tonic-gate { 2087c478bd9Sstevel@tonic-gate struct uscsi_cmd ucmd; 2097c478bd9Sstevel@tonic-gate union scsi_cdb cdb; 2107c478bd9Sstevel@tonic-gate int max_sectors; 2117c478bd9Sstevel@tonic-gate int rc = 0; 2127c478bd9Sstevel@tonic-gate 2137c478bd9Sstevel@tonic-gate /* 2147c478bd9Sstevel@tonic-gate * If the max xfercnt hasn't been determined start with BUF_SECTS 2157c478bd9Sstevel@tonic-gate * (currently 126 == 63K), otherwise use the xfercnt value 2167c478bd9Sstevel@tonic-gate * my caller saved from the previous invocation. 2177c478bd9Sstevel@tonic-gate */ 2187c478bd9Sstevel@tonic-gate if (xfercntp == NULL) { 2197c478bd9Sstevel@tonic-gate max_sectors = BUF_SECTS; 2207c478bd9Sstevel@tonic-gate } else if (*xfercntp == 0) { 2217c478bd9Sstevel@tonic-gate max_sectors = BUF_SECTS; 2227c478bd9Sstevel@tonic-gate *xfercntp = max_sectors; 2237c478bd9Sstevel@tonic-gate } else { 2247c478bd9Sstevel@tonic-gate max_sectors = *xfercntp; 2257c478bd9Sstevel@tonic-gate } 2267c478bd9Sstevel@tonic-gate 2277c478bd9Sstevel@tonic-gate /* 2287c478bd9Sstevel@tonic-gate * Build and execute the uscsi ioctl. We build a group0 2297c478bd9Sstevel@tonic-gate * or group1 command as necessary, since some targets 2307c478bd9Sstevel@tonic-gate * do not support group1 commands. 2317c478bd9Sstevel@tonic-gate */ 2327c478bd9Sstevel@tonic-gate while (secnt) { 2337c478bd9Sstevel@tonic-gate int nsectors; 2347c478bd9Sstevel@tonic-gate 2357c478bd9Sstevel@tonic-gate nsectors = (max_sectors < secnt) ? max_sectors : secnt; 2367c478bd9Sstevel@tonic-gate (void) memset((char *)&ucmd, 0, sizeof (ucmd)); 2377c478bd9Sstevel@tonic-gate (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb)); 2387c478bd9Sstevel@tonic-gate cdb.scc_cmd = (dir == DIR_READ) ? SCMD_READ : SCMD_WRITE; 2397c478bd9Sstevel@tonic-gate if (blkno < (2<<20) && nsectors <= 0xff) { 2407c478bd9Sstevel@tonic-gate FORMG0ADDR(&cdb, blkno); 2417c478bd9Sstevel@tonic-gate FORMG0COUNT(&cdb, nsectors); 2427c478bd9Sstevel@tonic-gate ucmd.uscsi_cdblen = CDB_GROUP0; 2437c478bd9Sstevel@tonic-gate } else { 2447c478bd9Sstevel@tonic-gate if (blkno > 0xffffffff) { 2457c478bd9Sstevel@tonic-gate FORMG4LONGADDR(&cdb, blkno); 2467c478bd9Sstevel@tonic-gate FORMG4COUNT(&cdb, nsectors); 2477c478bd9Sstevel@tonic-gate ucmd.uscsi_cdblen = CDB_GROUP4; 2487c478bd9Sstevel@tonic-gate cdb.scc_cmd |= SCMD_GROUP4; 2497c478bd9Sstevel@tonic-gate } else { 2507c478bd9Sstevel@tonic-gate FORMG1ADDR(&cdb, blkno); 2517c478bd9Sstevel@tonic-gate FORMG1COUNT(&cdb, nsectors); 2527c478bd9Sstevel@tonic-gate ucmd.uscsi_cdblen = CDB_GROUP1; 2537c478bd9Sstevel@tonic-gate cdb.scc_cmd |= SCMD_GROUP1; 2547c478bd9Sstevel@tonic-gate } 2557c478bd9Sstevel@tonic-gate } 2567c478bd9Sstevel@tonic-gate ucmd.uscsi_cdb = (caddr_t)&cdb; 2577c478bd9Sstevel@tonic-gate ucmd.uscsi_bufaddr = bufaddr; 25865908c77Syu, larry liu - Sun Microsystems - Beijing China ucmd.uscsi_buflen = nsectors * cur_blksz; 2597c478bd9Sstevel@tonic-gate rc = uscsi_cmd(fd, &ucmd, flags); 2607c478bd9Sstevel@tonic-gate 2617c478bd9Sstevel@tonic-gate if (rc != 0) 2627c478bd9Sstevel@tonic-gate break; 2637c478bd9Sstevel@tonic-gate 2647c478bd9Sstevel@tonic-gate /* 2657c478bd9Sstevel@tonic-gate * check if partial DMA breakup required 2667c478bd9Sstevel@tonic-gate * if so, reduce the request size by half and retry 2677c478bd9Sstevel@tonic-gate * the last request 2687c478bd9Sstevel@tonic-gate */ 2697c478bd9Sstevel@tonic-gate if (ucmd.uscsi_resid == ucmd.uscsi_buflen) { 2707c478bd9Sstevel@tonic-gate max_sectors >>= 1; 2717c478bd9Sstevel@tonic-gate if (max_sectors <= 0) { 2727c478bd9Sstevel@tonic-gate rc = -1; 2737c478bd9Sstevel@tonic-gate break; 2747c478bd9Sstevel@tonic-gate } 2757c478bd9Sstevel@tonic-gate continue; 2767c478bd9Sstevel@tonic-gate } 2777c478bd9Sstevel@tonic-gate if (ucmd.uscsi_resid != 0) { 2787c478bd9Sstevel@tonic-gate rc = -1; 2797c478bd9Sstevel@tonic-gate break; 2807c478bd9Sstevel@tonic-gate } 2817c478bd9Sstevel@tonic-gate 2827c478bd9Sstevel@tonic-gate blkno += nsectors; 2837c478bd9Sstevel@tonic-gate secnt -= nsectors; 28465908c77Syu, larry liu - Sun Microsystems - Beijing China bufaddr += nsectors * cur_blksz; 2857c478bd9Sstevel@tonic-gate } 2867c478bd9Sstevel@tonic-gate 2877c478bd9Sstevel@tonic-gate /* 2887c478bd9Sstevel@tonic-gate * If the xfercnt wasn't previously saved or if the 2897c478bd9Sstevel@tonic-gate * new value is smaller than the old value, save the 2907c478bd9Sstevel@tonic-gate * current value in my caller's save area. 2917c478bd9Sstevel@tonic-gate */ 2927c478bd9Sstevel@tonic-gate if (xfercntp != NULL && max_sectors < *xfercntp) { 2937c478bd9Sstevel@tonic-gate if (diag_msg) 2947c478bd9Sstevel@tonic-gate err_print("reducing xfercnt %d %d\n", 2957c478bd9Sstevel@tonic-gate *xfercntp, max_sectors); 2967c478bd9Sstevel@tonic-gate *xfercntp = max_sectors; 2977c478bd9Sstevel@tonic-gate } 2987c478bd9Sstevel@tonic-gate return (rc); 2997c478bd9Sstevel@tonic-gate } 3007c478bd9Sstevel@tonic-gate 3017c478bd9Sstevel@tonic-gate 3027c478bd9Sstevel@tonic-gate /* 3037c478bd9Sstevel@tonic-gate * Check to see if the disk has been formatted. 3047c478bd9Sstevel@tonic-gate * If we are able to read the first track, we conclude that 3057c478bd9Sstevel@tonic-gate * the disk has been formatted. 3067c478bd9Sstevel@tonic-gate */ 3077c478bd9Sstevel@tonic-gate #ifdef i386 3087c478bd9Sstevel@tonic-gate static int 3097c478bd9Sstevel@tonic-gate #else /* i386 */ 3107c478bd9Sstevel@tonic-gate static int 3117c478bd9Sstevel@tonic-gate #endif /* i386 */ 3127c478bd9Sstevel@tonic-gate scsi_ck_format(void) 3137c478bd9Sstevel@tonic-gate { 3147c478bd9Sstevel@tonic-gate int status; 3157c478bd9Sstevel@tonic-gate 3167c478bd9Sstevel@tonic-gate /* 3177c478bd9Sstevel@tonic-gate * Try to read the first four blocks. 3187c478bd9Sstevel@tonic-gate */ 319342440ecSPrasad Singamsetty status = scsi_rdwr(DIR_READ, cur_file, (diskaddr_t)0, 4, 320342440ecSPrasad Singamsetty (caddr_t)cur_buf, F_SILENT, NULL); 3217c478bd9Sstevel@tonic-gate return (!status); 3227c478bd9Sstevel@tonic-gate } 3237c478bd9Sstevel@tonic-gate 3247c478bd9Sstevel@tonic-gate 3257c478bd9Sstevel@tonic-gate /* 3267c478bd9Sstevel@tonic-gate * Format the disk, the whole disk, and nothing but the disk. 3277c478bd9Sstevel@tonic-gate */ 3287c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3297c478bd9Sstevel@tonic-gate static int 3307c478bd9Sstevel@tonic-gate scsi_format(start, end, list) 3317c478bd9Sstevel@tonic-gate uint64_t start; /* irrelevant for us */ 3327c478bd9Sstevel@tonic-gate uint64_t end; 3337c478bd9Sstevel@tonic-gate struct defect_list *list; 3347c478bd9Sstevel@tonic-gate { 3357c478bd9Sstevel@tonic-gate struct uscsi_cmd ucmd; 3367c478bd9Sstevel@tonic-gate union scsi_cdb cdb; 3377c478bd9Sstevel@tonic-gate int status; 3387c478bd9Sstevel@tonic-gate int flag; 3397c478bd9Sstevel@tonic-gate char rawbuf[MAX_MODE_SENSE_SIZE]; 3409ca9c420SSheng-Liang Eric Zhang struct scsi_inquiry *inq; 3419ca9c420SSheng-Liang Eric Zhang uint8_t fmt_prot_info; 3429ca9c420SSheng-Liang Eric Zhang uint8_t prot_field_usage; 3439ca9c420SSheng-Liang Eric Zhang uint8_t param_long_list = 1; 3449ca9c420SSheng-Liang Eric Zhang uint8_t fmt_long_param_header[8]; 3457c478bd9Sstevel@tonic-gate 3467c478bd9Sstevel@tonic-gate /* 3477c478bd9Sstevel@tonic-gate * Determine if the target appears to be SCSI-2 3487c478bd9Sstevel@tonic-gate * compliant. We handle mode sense/mode selects 3497c478bd9Sstevel@tonic-gate * a little differently, depending upon CCS/SCSI-2 3507c478bd9Sstevel@tonic-gate */ 3517c478bd9Sstevel@tonic-gate if (uscsi_inquiry(cur_file, rawbuf, sizeof (rawbuf))) { 3527c478bd9Sstevel@tonic-gate err_print("Inquiry failed\n"); 3537c478bd9Sstevel@tonic-gate return (-1); 3547c478bd9Sstevel@tonic-gate } 3557c478bd9Sstevel@tonic-gate inq = (struct scsi_inquiry *)rawbuf; 3567c478bd9Sstevel@tonic-gate flag = (inq->inq_rdf == RDF_SCSI2); 3577c478bd9Sstevel@tonic-gate 3587c478bd9Sstevel@tonic-gate /* 3597c478bd9Sstevel@tonic-gate * Reserve the scsi disk before performing mode select and 3607c478bd9Sstevel@tonic-gate * format operations. This will keep other hosts, if any, from 3617c478bd9Sstevel@tonic-gate * touching the disk while we are here. 3627c478bd9Sstevel@tonic-gate */ 3637c478bd9Sstevel@tonic-gate if (uscsi_reserve_release(cur_file, SCMD_RESERVE)) { 3647c478bd9Sstevel@tonic-gate err_print("Reserve failed\n"); 3657c478bd9Sstevel@tonic-gate return (-1); 3667c478bd9Sstevel@tonic-gate } 3677c478bd9Sstevel@tonic-gate 3687c478bd9Sstevel@tonic-gate /* 3697c478bd9Sstevel@tonic-gate * Set up the various SCSI parameters specified before 3707c478bd9Sstevel@tonic-gate * formatting the disk. Each routine handles the 37163360950Smp204432 * parameters relevant to a particular page. 3727c478bd9Sstevel@tonic-gate * If no parameters are specified for a page, there's 3737c478bd9Sstevel@tonic-gate * no need to do anything. Otherwise, issue a mode 3747c478bd9Sstevel@tonic-gate * sense for that page. If a specified parameter 3757c478bd9Sstevel@tonic-gate * differs from the drive's default value, and that 3767c478bd9Sstevel@tonic-gate * parameter is not fixed, then issue a mode select to 3777c478bd9Sstevel@tonic-gate * set the default value for the disk as specified 3787c478bd9Sstevel@tonic-gate * in format.dat. 3797c478bd9Sstevel@tonic-gate */ 3807c478bd9Sstevel@tonic-gate if (scsi_ms_page1(flag) || scsi_ms_page2(flag) || 3817c478bd9Sstevel@tonic-gate scsi_ms_page4(flag) || scsi_ms_page38(flag) || 3827c478bd9Sstevel@tonic-gate scsi_ms_page8(flag) || scsi_ms_page3(flag)) { 3837c478bd9Sstevel@tonic-gate (void) uscsi_reserve_release(cur_file, SCMD_RELEASE); 3847c478bd9Sstevel@tonic-gate return (-1); 3857c478bd9Sstevel@tonic-gate } 3867c478bd9Sstevel@tonic-gate 3877c478bd9Sstevel@tonic-gate /* 3887c478bd9Sstevel@tonic-gate * If we're debugging the drive, dump every page 3897c478bd9Sstevel@tonic-gate * the device supports, for thorough analysis. 3907c478bd9Sstevel@tonic-gate */ 3917c478bd9Sstevel@tonic-gate if (option_msg && diag_msg) { 3927c478bd9Sstevel@tonic-gate (void) scsi_dump_mode_sense_pages(MODE_SENSE_PC_DEFAULT); 3937c478bd9Sstevel@tonic-gate (void) scsi_dump_mode_sense_pages(MODE_SENSE_PC_CURRENT); 3947c478bd9Sstevel@tonic-gate (void) scsi_dump_mode_sense_pages(MODE_SENSE_PC_SAVED); 3957c478bd9Sstevel@tonic-gate (void) scsi_dump_mode_sense_pages(MODE_SENSE_PC_CHANGEABLE); 3967c478bd9Sstevel@tonic-gate err_print("\n"); 3977c478bd9Sstevel@tonic-gate } 3987c478bd9Sstevel@tonic-gate 3997c478bd9Sstevel@tonic-gate /* 4009ca9c420SSheng-Liang Eric Zhang * Determine the FMTPINFO field in format cdb, and the 4019ca9c420SSheng-Liang Eric Zhang * PROTECTION FIELD USAGE in the long parameter list, via 4029ca9c420SSheng-Liang Eric Zhang * the protection type input by users. 4039ca9c420SSheng-Liang Eric Zhang */ 4049ca9c420SSheng-Liang Eric Zhang switch (prot_type) { 4059ca9c420SSheng-Liang Eric Zhang case PROT_TYPE_0: 4069ca9c420SSheng-Liang Eric Zhang fmt_prot_info = 0x00; 4079ca9c420SSheng-Liang Eric Zhang prot_field_usage = 0x00; 4089ca9c420SSheng-Liang Eric Zhang break; 4099ca9c420SSheng-Liang Eric Zhang case PROT_TYPE_1: 4109ca9c420SSheng-Liang Eric Zhang fmt_prot_info = 0x02; 4119ca9c420SSheng-Liang Eric Zhang prot_field_usage = 0x00; 4129ca9c420SSheng-Liang Eric Zhang break; 4139ca9c420SSheng-Liang Eric Zhang case PROT_TYPE_2: 4149ca9c420SSheng-Liang Eric Zhang fmt_prot_info = 0x03; 4159ca9c420SSheng-Liang Eric Zhang prot_field_usage = 0x00; 4169ca9c420SSheng-Liang Eric Zhang break; 4179ca9c420SSheng-Liang Eric Zhang case PROT_TYPE_3: 4189ca9c420SSheng-Liang Eric Zhang fmt_prot_info = 0x03; 4199ca9c420SSheng-Liang Eric Zhang prot_field_usage = 0x01; 4209ca9c420SSheng-Liang Eric Zhang break; 4219ca9c420SSheng-Liang Eric Zhang default: 4229ca9c420SSheng-Liang Eric Zhang fmt_print("invalid protection type\n"); 4239ca9c420SSheng-Liang Eric Zhang return (-1); 4249ca9c420SSheng-Liang Eric Zhang } 4259ca9c420SSheng-Liang Eric Zhang 4269ca9c420SSheng-Liang Eric Zhang /* 4277c478bd9Sstevel@tonic-gate * Construct the uscsi format ioctl. The form depends 4287c478bd9Sstevel@tonic-gate * upon the defect list the user extracted. If s/he 4297c478bd9Sstevel@tonic-gate * extracted the "original" list, we format with only 4307c478bd9Sstevel@tonic-gate * the P (manufacturer's defect) list. Otherwise, we 4317c478bd9Sstevel@tonic-gate * format with both the P and the G (grown) list. 4327c478bd9Sstevel@tonic-gate * To format with the P and G list, we set the fmtData 4337c478bd9Sstevel@tonic-gate * bit, and send an empty list. To format with the 4347c478bd9Sstevel@tonic-gate * P list only, we also set the cmpLst bit, meaning 4357c478bd9Sstevel@tonic-gate * that the (empty) list we send down is the complete 4367c478bd9Sstevel@tonic-gate * G list, thereby discarding the old G list.. 4377c478bd9Sstevel@tonic-gate */ 4387c478bd9Sstevel@tonic-gate (void) memset((char *)&ucmd, 0, sizeof (ucmd)); 4397c478bd9Sstevel@tonic-gate (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb)); 4407c478bd9Sstevel@tonic-gate 4417c478bd9Sstevel@tonic-gate cdb.scc_cmd = SCMD_FORMAT; 4427c478bd9Sstevel@tonic-gate ucmd.uscsi_cdb = (caddr_t)&cdb; 4437c478bd9Sstevel@tonic-gate ucmd.uscsi_cdblen = CDB_GROUP0; 4447c478bd9Sstevel@tonic-gate cdb.cdb_opaque[1] = FPB_DATA; 4459ca9c420SSheng-Liang Eric Zhang 4469ca9c420SSheng-Liang Eric Zhang /* 4479ca9c420SSheng-Liang Eric Zhang * Use the long parameter header in format command, 4489ca9c420SSheng-Liang Eric Zhang * and set the FMTPINFO field., when type 1, 2, 3. 4499ca9c420SSheng-Liang Eric Zhang */ 4509ca9c420SSheng-Liang Eric Zhang cdb.cdb_opaque[1] |= (param_long_list << 5) | (fmt_prot_info << 6); 4519ca9c420SSheng-Liang Eric Zhang (void) memset((char *)fmt_long_param_header, 0, 4529ca9c420SSheng-Liang Eric Zhang sizeof (fmt_long_param_header)); 4539ca9c420SSheng-Liang Eric Zhang 4549ca9c420SSheng-Liang Eric Zhang /* 4559ca9c420SSheng-Liang Eric Zhang * Set the PROTECTION FIELD USAGE field in the long 4569ca9c420SSheng-Liang Eric Zhang * parameter list header, which combines with FMTINFO to 4579ca9c420SSheng-Liang Eric Zhang * determine the protection type. 4589ca9c420SSheng-Liang Eric Zhang * The PROTECTION INTERVAL EXPONET field is set default 0. 4599ca9c420SSheng-Liang Eric Zhang * So only one protection information interval is used 4609ca9c420SSheng-Liang Eric Zhang * in type 1, 2, 3. 4619ca9c420SSheng-Liang Eric Zhang */ 4629ca9c420SSheng-Liang Eric Zhang fmt_long_param_header[0] = prot_field_usage; 4639ca9c420SSheng-Liang Eric Zhang fmt_long_param_header[1] = FDH_FOV | FDH_IMMED; 4649ca9c420SSheng-Liang Eric Zhang ucmd.uscsi_bufaddr = (caddr_t)fmt_long_param_header; 4659ca9c420SSheng-Liang Eric Zhang ucmd.uscsi_buflen = sizeof (fmt_long_param_header); 4667c478bd9Sstevel@tonic-gate 4677c478bd9Sstevel@tonic-gate if ((list->list != NULL) && ((list->flags & LIST_PGLIST) == 0)) { 4687c478bd9Sstevel@tonic-gate /* 4697c478bd9Sstevel@tonic-gate * No G list. The empty list we send down 4707c478bd9Sstevel@tonic-gate * is the complete list. 4717c478bd9Sstevel@tonic-gate */ 4727c478bd9Sstevel@tonic-gate cdb.cdb_opaque[1] |= FPB_CMPLT; 4737c478bd9Sstevel@tonic-gate } 4747c478bd9Sstevel@tonic-gate 4757c478bd9Sstevel@tonic-gate /* 4767c478bd9Sstevel@tonic-gate * Issue the format ioctl 4777c478bd9Sstevel@tonic-gate */ 4787c478bd9Sstevel@tonic-gate fmt_print("Formatting...\n"); 4797c478bd9Sstevel@tonic-gate (void) fflush(stdout); 4807c478bd9Sstevel@tonic-gate status = uscsi_cmd(cur_file, &ucmd, 4817c478bd9Sstevel@tonic-gate (option_msg && diag_msg) ? F_NORMAL : F_SILENT); 4827c478bd9Sstevel@tonic-gate 4837c478bd9Sstevel@tonic-gate /* check if format with immed was successfully accepted */ 4847c478bd9Sstevel@tonic-gate if (status == 0) { 485*cf6efa00SRalph Turner - Sun UK - Contractor /* immed accepted poll to completion */ 4867c478bd9Sstevel@tonic-gate status = test_until_ready(cur_file); 4877c478bd9Sstevel@tonic-gate } else { 488*cf6efa00SRalph Turner - Sun UK - Contractor /* clear FOV and try again */ 489*cf6efa00SRalph Turner - Sun UK - Contractor (void) memset((char *)fmt_long_param_header, 0, 490*cf6efa00SRalph Turner - Sun UK - Contractor sizeof (fmt_long_param_header)); 491*cf6efa00SRalph Turner - Sun UK - Contractor fmt_long_param_header[0] = prot_field_usage; 492*cf6efa00SRalph Turner - Sun UK - Contractor fmt_long_param_header[1] = FDH_IMMED; 493*cf6efa00SRalph Turner - Sun UK - Contractor status = uscsi_cmd(cur_file, &ucmd, 494*cf6efa00SRalph Turner - Sun UK - Contractor (option_msg && diag_msg) ? F_NORMAL : F_SILENT); 495*cf6efa00SRalph Turner - Sun UK - Contractor if (status == 0) { 496*cf6efa00SRalph Turner - Sun UK - Contractor /* immed accepted, poll for progress */ 497*cf6efa00SRalph Turner - Sun UK - Contractor status = test_until_ready(cur_file); 498*cf6efa00SRalph Turner - Sun UK - Contractor } else { 499*cf6efa00SRalph Turner - Sun UK - Contractor /* 500*cf6efa00SRalph Turner - Sun UK - Contractor * clear defect header and try basecase format 501*cf6efa00SRalph Turner - Sun UK - Contractor * command will hang until format complete 502*cf6efa00SRalph Turner - Sun UK - Contractor */ 5039ca9c420SSheng-Liang Eric Zhang (void) memset((char *)fmt_long_param_header, 0, 5049ca9c420SSheng-Liang Eric Zhang sizeof (fmt_long_param_header)); 5059ca9c420SSheng-Liang Eric Zhang fmt_long_param_header[0] = prot_field_usage; 5067c478bd9Sstevel@tonic-gate status = uscsi_cmd(cur_file, &ucmd, 5077c478bd9Sstevel@tonic-gate (option_msg && diag_msg) ? F_NORMAL : F_SILENT); 5087c478bd9Sstevel@tonic-gate } 509*cf6efa00SRalph Turner - Sun UK - Contractor } 5107c478bd9Sstevel@tonic-gate 5117c478bd9Sstevel@tonic-gate /* format failure check */ 5127c478bd9Sstevel@tonic-gate if (status != 0) { 5137c478bd9Sstevel@tonic-gate /* 5147c478bd9Sstevel@tonic-gate * formatting failed with fmtdata = 1. 5157c478bd9Sstevel@tonic-gate * Check if defects list command is supported, if it 5167c478bd9Sstevel@tonic-gate * is not supported then use fmtdata = 0. 5177c478bd9Sstevel@tonic-gate * From SCSI Spec 5187c478bd9Sstevel@tonic-gate * A FmtData bit of zero indicates, the 5197c478bd9Sstevel@tonic-gate * source of defect information is not specified. 5207c478bd9Sstevel@tonic-gate * else 5217c478bd9Sstevel@tonic-gate * proceed to format using with mode selects. 5227c478bd9Sstevel@tonic-gate */ 5237c478bd9Sstevel@tonic-gate if (!(check_support_for_defects())) { 5247c478bd9Sstevel@tonic-gate status = scsi_format_without_defects(); 5257c478bd9Sstevel@tonic-gate } 5267c478bd9Sstevel@tonic-gate 5277c478bd9Sstevel@tonic-gate if (status != 0) { 5287c478bd9Sstevel@tonic-gate fmt_print("Format failed\n"); 5297c478bd9Sstevel@tonic-gate status = scsi_raw_format(); 5307c478bd9Sstevel@tonic-gate } 5317c478bd9Sstevel@tonic-gate } 5327c478bd9Sstevel@tonic-gate (void) uscsi_reserve_release(cur_file, SCMD_RELEASE); 5337c478bd9Sstevel@tonic-gate return (status); 5347c478bd9Sstevel@tonic-gate } 5357c478bd9Sstevel@tonic-gate 5367c478bd9Sstevel@tonic-gate /* 5377c478bd9Sstevel@tonic-gate * Format without any of the standard mode selects ignoring Grown defects list. 5387c478bd9Sstevel@tonic-gate */ 5397c478bd9Sstevel@tonic-gate static int 5407c478bd9Sstevel@tonic-gate scsi_raw_format(void) 5417c478bd9Sstevel@tonic-gate { 5427c478bd9Sstevel@tonic-gate struct uscsi_cmd ucmd; 5437c478bd9Sstevel@tonic-gate union scsi_cdb cdb; 5447c478bd9Sstevel@tonic-gate struct scsi_defect_hdr defect_hdr; 5457c478bd9Sstevel@tonic-gate int status; 5467c478bd9Sstevel@tonic-gate 5477c478bd9Sstevel@tonic-gate fmt_print("\n" 5487c478bd9Sstevel@tonic-gate "Retry of formatting operation without any of the standard\n" 5497c478bd9Sstevel@tonic-gate "mode selects and ignoring disk's Grown Defects list. The\n" 5507c478bd9Sstevel@tonic-gate "disk may be able to be reformatted this way if an earlier\n" 5517c478bd9Sstevel@tonic-gate "formatting operation was interrupted by a power failure or\n" 5527c478bd9Sstevel@tonic-gate "SCSI bus reset. The Grown Defects list will be recreated\n" 5537c478bd9Sstevel@tonic-gate "by format verification and surface analysis.\n\n"); 5547c478bd9Sstevel@tonic-gate 5557c478bd9Sstevel@tonic-gate if (check("Retry format without mode selects and Grown Defects list") 5567c478bd9Sstevel@tonic-gate != 0) { 5577c478bd9Sstevel@tonic-gate return (-1); 5587c478bd9Sstevel@tonic-gate } 5597c478bd9Sstevel@tonic-gate 5607c478bd9Sstevel@tonic-gate /* 5617c478bd9Sstevel@tonic-gate * Construct the uscsi format ioctl. 5627c478bd9Sstevel@tonic-gate * To format with the P and G list, we set the fmtData 5637c478bd9Sstevel@tonic-gate * and cmpLst bits to zero. To format with just the 5647c478bd9Sstevel@tonic-gate * P list, we set the fmtData bit (meaning that we will 5657c478bd9Sstevel@tonic-gate * send down a defect list in the data phase) and the 5667c478bd9Sstevel@tonic-gate * cmpLst bit (meaning that the list we send is the 5677c478bd9Sstevel@tonic-gate * complete G list), and a defect list header with 5687c478bd9Sstevel@tonic-gate * a defect list length of zero. 5697c478bd9Sstevel@tonic-gate */ 5707c478bd9Sstevel@tonic-gate (void) memset((char *)&ucmd, 0, sizeof (ucmd)); 5717c478bd9Sstevel@tonic-gate (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb)); 5727c478bd9Sstevel@tonic-gate (void) memset((char *)&defect_hdr, 0, sizeof (defect_hdr)); 5737c478bd9Sstevel@tonic-gate 5747c478bd9Sstevel@tonic-gate cdb.scc_cmd = SCMD_FORMAT; 5757c478bd9Sstevel@tonic-gate ucmd.uscsi_cdb = (caddr_t)&cdb; 5767c478bd9Sstevel@tonic-gate ucmd.uscsi_cdblen = CDB_GROUP0; 5777c478bd9Sstevel@tonic-gate /* No G list. Send empty defect list to replace it */ 5787c478bd9Sstevel@tonic-gate cdb.cdb_opaque[1] = FPB_DATA | FPB_CMPLT | FPB_BFI; 5797c478bd9Sstevel@tonic-gate ucmd.uscsi_bufaddr = (caddr_t)&defect_hdr; 5807c478bd9Sstevel@tonic-gate ucmd.uscsi_buflen = sizeof (defect_hdr); 5817c478bd9Sstevel@tonic-gate defect_hdr.descriptor = FDH_FOV | FDH_IMMED; 5827c478bd9Sstevel@tonic-gate 5837c478bd9Sstevel@tonic-gate /* 5847c478bd9Sstevel@tonic-gate * Issue the format ioctl 5857c478bd9Sstevel@tonic-gate */ 5867c478bd9Sstevel@tonic-gate fmt_print("Formatting...\n"); 5877c478bd9Sstevel@tonic-gate (void) fflush(stdout); 5887c478bd9Sstevel@tonic-gate status = uscsi_cmd(cur_file, &ucmd, F_NORMAL); 5897c478bd9Sstevel@tonic-gate 5907c478bd9Sstevel@tonic-gate /* check if format with immed was successfully accepted */ 5917c478bd9Sstevel@tonic-gate if (status == 0) { 5927c478bd9Sstevel@tonic-gate /* immed accepted pool to completion */ 5937c478bd9Sstevel@tonic-gate status = test_until_ready(cur_file); 5947c478bd9Sstevel@tonic-gate } else { 5957c478bd9Sstevel@tonic-gate /* clear defect header and try basecase format */ 5967c478bd9Sstevel@tonic-gate (void) memset((char *)&defect_hdr, 0, sizeof (defect_hdr)); 5977c478bd9Sstevel@tonic-gate status = uscsi_cmd(cur_file, &ucmd, F_NORMAL); 5987c478bd9Sstevel@tonic-gate } 5997c478bd9Sstevel@tonic-gate 6007c478bd9Sstevel@tonic-gate /* fmt_print(status ? "Format failed\n\n" : "Format ok\n\n"); */ 6017c478bd9Sstevel@tonic-gate return (status); 6027c478bd9Sstevel@tonic-gate } 6037c478bd9Sstevel@tonic-gate 6047c478bd9Sstevel@tonic-gate /* 6057c478bd9Sstevel@tonic-gate * Estimate the time required for format operation (See 1163770). 6067c478bd9Sstevel@tonic-gate * format time = (5_revs * p4_heads * p4_cylinders) / p4_rpm 6077c478bd9Sstevel@tonic-gate * 5 revolutions (correspond to format_time keyword in format.dat file) are: 6087c478bd9Sstevel@tonic-gate * 1 rev. for positioning 6097c478bd9Sstevel@tonic-gate * 2 rev. for writing the track 6107c478bd9Sstevel@tonic-gate * 1 rev. for positioning 6117c478bd9Sstevel@tonic-gate * 1 rev. for cerifying the data integrity of the track 6127c478bd9Sstevel@tonic-gate * The return value is a good estimate on the formatting time in minutes. 6137c478bd9Sstevel@tonic-gate * Caller should add 50% margin to cover defect management overhead. 6147c478bd9Sstevel@tonic-gate */ 6157c478bd9Sstevel@tonic-gate int 6167c478bd9Sstevel@tonic-gate scsi_format_time() 6177c478bd9Sstevel@tonic-gate { 6187c478bd9Sstevel@tonic-gate struct mode_geometry *page4; 6197c478bd9Sstevel@tonic-gate struct scsi_ms_header header; 6207c478bd9Sstevel@tonic-gate int status; 6217c478bd9Sstevel@tonic-gate int p4_cylinders, p4_heads, p4_rpm; 6227c478bd9Sstevel@tonic-gate int length; 6237c478bd9Sstevel@tonic-gate int format_time; 6247c478bd9Sstevel@tonic-gate union { 6257c478bd9Sstevel@tonic-gate struct mode_geometry page4; 6267c478bd9Sstevel@tonic-gate char rawbuf[MAX_MODE_SENSE_SIZE]; 6277c478bd9Sstevel@tonic-gate } u_page4; 6287c478bd9Sstevel@tonic-gate 6297c478bd9Sstevel@tonic-gate 6307c478bd9Sstevel@tonic-gate page4 = &u_page4.page4; 6317c478bd9Sstevel@tonic-gate (void) memset(&u_page4, 0, sizeof (u_page4)); 6327c478bd9Sstevel@tonic-gate 6337c478bd9Sstevel@tonic-gate /* 6347c478bd9Sstevel@tonic-gate * Issue a mode sense to determine the default parameters 6357c478bd9Sstevel@tonic-gate * If it fail, try to use the saved or current instead. 6367c478bd9Sstevel@tonic-gate */ 6377c478bd9Sstevel@tonic-gate status = uscsi_mode_sense(cur_file, DAD_MODE_GEOMETRY, 6387c478bd9Sstevel@tonic-gate MODE_SENSE_PC_DEFAULT, (caddr_t)page4, 6397c478bd9Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header); 6407c478bd9Sstevel@tonic-gate 6417c478bd9Sstevel@tonic-gate if (status) { 6427c478bd9Sstevel@tonic-gate status = uscsi_mode_sense(cur_file, DAD_MODE_GEOMETRY, 6437c478bd9Sstevel@tonic-gate MODE_SENSE_PC_SAVED, (caddr_t)page4, 6447c478bd9Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header); 6457c478bd9Sstevel@tonic-gate } 6467c478bd9Sstevel@tonic-gate if (status) { 6477c478bd9Sstevel@tonic-gate status = uscsi_mode_sense(cur_file, DAD_MODE_GEOMETRY, 6487c478bd9Sstevel@tonic-gate MODE_SENSE_PC_CURRENT, (caddr_t)page4, 6497c478bd9Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header); 6507c478bd9Sstevel@tonic-gate } 6517c478bd9Sstevel@tonic-gate if (status) { 6527c478bd9Sstevel@tonic-gate return (0); 6537c478bd9Sstevel@tonic-gate } 6547c478bd9Sstevel@tonic-gate 6557c478bd9Sstevel@tonic-gate /* 6567c478bd9Sstevel@tonic-gate * We only need the common subset between the CCS 6577c478bd9Sstevel@tonic-gate * and SCSI-2 structures, so we can treat both 6587c478bd9Sstevel@tonic-gate * cases identically. 6597c478bd9Sstevel@tonic-gate */ 6607c478bd9Sstevel@tonic-gate length = MODESENSE_PAGE_LEN(page4); 6617c478bd9Sstevel@tonic-gate if (length < MIN_PAGE4_LEN) { 6627c478bd9Sstevel@tonic-gate return (0); 6637c478bd9Sstevel@tonic-gate } 6647c478bd9Sstevel@tonic-gate 6657c478bd9Sstevel@tonic-gate page4->rpm = BE_16(page4->rpm); 6667c478bd9Sstevel@tonic-gate p4_cylinders = (page4->cyl_ub << 16) + (page4->cyl_mb << 8) + 6677c478bd9Sstevel@tonic-gate page4->cyl_lb; 6687c478bd9Sstevel@tonic-gate p4_heads = page4->heads; 6697c478bd9Sstevel@tonic-gate p4_rpm = page4->rpm; 6707c478bd9Sstevel@tonic-gate 6717c478bd9Sstevel@tonic-gate /* 6727c478bd9Sstevel@tonic-gate * Some drives report 0 for page4->rpm, adjust it to AVG_RPM, 3600. 6737c478bd9Sstevel@tonic-gate */ 6747c478bd9Sstevel@tonic-gate if (p4_rpm < MIN_RPM || p4_rpm > MAX_RPM) { 6757c478bd9Sstevel@tonic-gate err_print("Mode sense page(4) reports rpm value as %d," 6767c478bd9Sstevel@tonic-gate " adjusting it to %d\n", p4_rpm, AVG_RPM); 6777c478bd9Sstevel@tonic-gate p4_rpm = AVG_RPM; 6787c478bd9Sstevel@tonic-gate } 6797c478bd9Sstevel@tonic-gate 6807c478bd9Sstevel@tonic-gate if (p4_cylinders <= 0 || p4_heads <= 0) 6817c478bd9Sstevel@tonic-gate return (0); 6827c478bd9Sstevel@tonic-gate 6837c478bd9Sstevel@tonic-gate format_time = ((scsi_format_revolutions * p4_heads * 6847c478bd9Sstevel@tonic-gate p4_cylinders) + p4_rpm) / p4_rpm; 6857c478bd9Sstevel@tonic-gate 6867c478bd9Sstevel@tonic-gate if (option_msg && diag_msg) { 6877c478bd9Sstevel@tonic-gate err_print(" pcyl: %d\n", p4_cylinders); 6887c478bd9Sstevel@tonic-gate err_print(" heads: %d\n", p4_heads); 6897c478bd9Sstevel@tonic-gate err_print(" rpm: %d\n", p4_rpm); 6907c478bd9Sstevel@tonic-gate err_print("format_time: %d minutes\n", format_time); 6917c478bd9Sstevel@tonic-gate } 6927c478bd9Sstevel@tonic-gate return (format_time); 6937c478bd9Sstevel@tonic-gate } 6947c478bd9Sstevel@tonic-gate 6957c478bd9Sstevel@tonic-gate /* 6967c478bd9Sstevel@tonic-gate * Check disk error recovery parameters via mode sense. 6977c478bd9Sstevel@tonic-gate * Issue a mode select if we need to change something. 6987c478bd9Sstevel@tonic-gate */ 6997c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 7007c478bd9Sstevel@tonic-gate static int 7017c478bd9Sstevel@tonic-gate scsi_ms_page1(scsi2_flag) 7027c478bd9Sstevel@tonic-gate int scsi2_flag; 7037c478bd9Sstevel@tonic-gate { 7047c478bd9Sstevel@tonic-gate struct mode_err_recov *page1; 7057c478bd9Sstevel@tonic-gate struct mode_err_recov *fixed; 7067c478bd9Sstevel@tonic-gate struct scsi_ms_header header; 7077c478bd9Sstevel@tonic-gate struct scsi_ms_header fixed_hdr; 7087c478bd9Sstevel@tonic-gate int status; 7097c478bd9Sstevel@tonic-gate int tmp1, tmp2; 7107c478bd9Sstevel@tonic-gate int flag; 7117c478bd9Sstevel@tonic-gate int length; 7127c478bd9Sstevel@tonic-gate int sp_flags; 7137c478bd9Sstevel@tonic-gate union { 7147c478bd9Sstevel@tonic-gate struct mode_err_recov page1; 7157c478bd9Sstevel@tonic-gate char rawbuf[MAX_MODE_SENSE_SIZE]; 7167c478bd9Sstevel@tonic-gate } u_page1, u_fixed; 7177c478bd9Sstevel@tonic-gate 7187c478bd9Sstevel@tonic-gate 7197c478bd9Sstevel@tonic-gate page1 = &u_page1.page1; 7207c478bd9Sstevel@tonic-gate fixed = &u_fixed.page1; 7217c478bd9Sstevel@tonic-gate 7227c478bd9Sstevel@tonic-gate /* 7237c478bd9Sstevel@tonic-gate * If debugging, issue mode senses on the default and 7247c478bd9Sstevel@tonic-gate * current values. 7257c478bd9Sstevel@tonic-gate */ 7267c478bd9Sstevel@tonic-gate if (option_msg && diag_msg) { 7277c478bd9Sstevel@tonic-gate (void) uscsi_mode_sense(cur_file, DAD_MODE_ERR_RECOV, 7287c478bd9Sstevel@tonic-gate MODE_SENSE_PC_DEFAULT, (caddr_t)page1, 7297c478bd9Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header); 7307c478bd9Sstevel@tonic-gate (void) uscsi_mode_sense(cur_file, DAD_MODE_ERR_RECOV, 7317c478bd9Sstevel@tonic-gate MODE_SENSE_PC_CURRENT, (caddr_t)page1, 7327c478bd9Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header); 7337c478bd9Sstevel@tonic-gate } 7347c478bd9Sstevel@tonic-gate 7357c478bd9Sstevel@tonic-gate /* 7367c478bd9Sstevel@tonic-gate * Issue a mode sense to determine the saved parameters 7377c478bd9Sstevel@tonic-gate * If the saved values fail, use the current instead. 7387c478bd9Sstevel@tonic-gate */ 7397c478bd9Sstevel@tonic-gate status = uscsi_mode_sense(cur_file, DAD_MODE_ERR_RECOV, 7407c478bd9Sstevel@tonic-gate MODE_SENSE_PC_SAVED, (caddr_t)page1, 7417c478bd9Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header); 7427c478bd9Sstevel@tonic-gate if (status) { 7437c478bd9Sstevel@tonic-gate status = uscsi_mode_sense(cur_file, DAD_MODE_ERR_RECOV, 7447c478bd9Sstevel@tonic-gate MODE_SENSE_PC_CURRENT, (caddr_t)page1, 7457c478bd9Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header); 7467c478bd9Sstevel@tonic-gate if (status) { 7477c478bd9Sstevel@tonic-gate return (0); 7487c478bd9Sstevel@tonic-gate } 7497c478bd9Sstevel@tonic-gate } 7507c478bd9Sstevel@tonic-gate 7517c478bd9Sstevel@tonic-gate /* 7527c478bd9Sstevel@tonic-gate * We only need the common subset between the CCS 7537c478bd9Sstevel@tonic-gate * and SCSI-2 structures, so we can treat both 7547c478bd9Sstevel@tonic-gate * cases identically. Whatever the drive gives 7557c478bd9Sstevel@tonic-gate * us, we return to the drive in the mode select, 7567c478bd9Sstevel@tonic-gate * delta'ed by whatever we want to change. 7577c478bd9Sstevel@tonic-gate */ 7587c478bd9Sstevel@tonic-gate length = MODESENSE_PAGE_LEN(page1); 7597c478bd9Sstevel@tonic-gate if (length < MIN_PAGE1_LEN) { 7607c478bd9Sstevel@tonic-gate return (0); 7617c478bd9Sstevel@tonic-gate } 7627c478bd9Sstevel@tonic-gate 7637c478bd9Sstevel@tonic-gate /* 7647c478bd9Sstevel@tonic-gate * Ask for changeable parameters. 7657c478bd9Sstevel@tonic-gate */ 7667c478bd9Sstevel@tonic-gate status = uscsi_mode_sense(cur_file, DAD_MODE_ERR_RECOV, 7677c478bd9Sstevel@tonic-gate MODE_SENSE_PC_CHANGEABLE, (caddr_t)fixed, 7687c478bd9Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &fixed_hdr); 7697c478bd9Sstevel@tonic-gate if (status || MODESENSE_PAGE_LEN(fixed) < MIN_PAGE1_LEN) { 7707c478bd9Sstevel@tonic-gate return (0); 7717c478bd9Sstevel@tonic-gate } 7727c478bd9Sstevel@tonic-gate 7737c478bd9Sstevel@tonic-gate /* 7747c478bd9Sstevel@tonic-gate * We need to issue a mode select only if one or more 7757c478bd9Sstevel@tonic-gate * parameters need to be changed, and those parameters 7767c478bd9Sstevel@tonic-gate * are flagged by the drive as changeable. 7777c478bd9Sstevel@tonic-gate */ 7787c478bd9Sstevel@tonic-gate flag = 0; 7797c478bd9Sstevel@tonic-gate tmp1 = page1->read_retry_count; 7807c478bd9Sstevel@tonic-gate tmp2 = page1->write_retry_count; 7817c478bd9Sstevel@tonic-gate if (cur_dtype->dtype_options & SUP_READ_RETRIES && 7827c478bd9Sstevel@tonic-gate fixed->read_retry_count != 0) { 7837c478bd9Sstevel@tonic-gate flag |= (page1->read_retry_count != 7847c478bd9Sstevel@tonic-gate cur_dtype->dtype_read_retries); 7857c478bd9Sstevel@tonic-gate page1->read_retry_count = cur_dtype->dtype_read_retries; 7867c478bd9Sstevel@tonic-gate } 7877c478bd9Sstevel@tonic-gate if (length > 8) { 7887c478bd9Sstevel@tonic-gate if (cur_dtype->dtype_options & SUP_WRITE_RETRIES && 7897c478bd9Sstevel@tonic-gate fixed->write_retry_count != 0) { 7907c478bd9Sstevel@tonic-gate flag |= (page1->write_retry_count != 7917c478bd9Sstevel@tonic-gate cur_dtype->dtype_write_retries); 7927c478bd9Sstevel@tonic-gate page1->write_retry_count = 7937c478bd9Sstevel@tonic-gate cur_dtype->dtype_write_retries; 7947c478bd9Sstevel@tonic-gate } 7957c478bd9Sstevel@tonic-gate } 7967c478bd9Sstevel@tonic-gate /* 7977c478bd9Sstevel@tonic-gate * Report any changes so far... 7987c478bd9Sstevel@tonic-gate */ 7997c478bd9Sstevel@tonic-gate if (flag && option_msg) { 8007c478bd9Sstevel@tonic-gate fmt_print( 8017c478bd9Sstevel@tonic-gate "PAGE 1: read retries= %d (%d) write retries= %d (%d)\n", 8027c478bd9Sstevel@tonic-gate page1->read_retry_count, tmp1, 8037c478bd9Sstevel@tonic-gate page1->write_retry_count, tmp2); 8047c478bd9Sstevel@tonic-gate } 8057c478bd9Sstevel@tonic-gate /* 8067c478bd9Sstevel@tonic-gate * Apply any changes requested via the change list method 8077c478bd9Sstevel@tonic-gate */ 8087c478bd9Sstevel@tonic-gate flag |= apply_chg_list(DAD_MODE_ERR_RECOV, length, 8097c478bd9Sstevel@tonic-gate (uchar_t *)page1, (uchar_t *)fixed, 8107c478bd9Sstevel@tonic-gate cur_dtype->dtype_chglist); 8117c478bd9Sstevel@tonic-gate /* 8127c478bd9Sstevel@tonic-gate * If no changes required, do not issue a mode select 8137c478bd9Sstevel@tonic-gate */ 8147c478bd9Sstevel@tonic-gate if (flag == 0) { 8157c478bd9Sstevel@tonic-gate return (0); 8167c478bd9Sstevel@tonic-gate } 8177c478bd9Sstevel@tonic-gate /* 8187c478bd9Sstevel@tonic-gate * We always want to set the Page Format bit for mode 8197c478bd9Sstevel@tonic-gate * selects. Set the Save Page bit if the drive indicates 8207c478bd9Sstevel@tonic-gate * that it can save this page via the mode sense. 8217c478bd9Sstevel@tonic-gate */ 8227c478bd9Sstevel@tonic-gate sp_flags = MODE_SELECT_PF; 8237c478bd9Sstevel@tonic-gate if (page1->mode_page.ps) { 8247c478bd9Sstevel@tonic-gate sp_flags |= MODE_SELECT_SP; 8257c478bd9Sstevel@tonic-gate } 8267c478bd9Sstevel@tonic-gate page1->mode_page.ps = 0; 8277c478bd9Sstevel@tonic-gate header.mode_header.length = 0; 8287c478bd9Sstevel@tonic-gate header.mode_header.device_specific = 0; 8297c478bd9Sstevel@tonic-gate status = uscsi_mode_select(cur_file, DAD_MODE_ERR_RECOV, 8307c478bd9Sstevel@tonic-gate sp_flags, (caddr_t)page1, length, &header); 8317c478bd9Sstevel@tonic-gate if (status && (sp_flags & MODE_SELECT_SP)) { 8327c478bd9Sstevel@tonic-gate /* If failed, try not saving mode select params. */ 8337c478bd9Sstevel@tonic-gate sp_flags &= ~MODE_SELECT_SP; 8347c478bd9Sstevel@tonic-gate status = uscsi_mode_select(cur_file, DAD_MODE_ERR_RECOV, 8357c478bd9Sstevel@tonic-gate sp_flags, (caddr_t)page1, length, &header); 8367c478bd9Sstevel@tonic-gate } 8377c478bd9Sstevel@tonic-gate if (status && option_msg) { 8387c478bd9Sstevel@tonic-gate err_print("\ 8397c478bd9Sstevel@tonic-gate Warning: Using default error recovery parameters.\n\n"); 8407c478bd9Sstevel@tonic-gate } 8417c478bd9Sstevel@tonic-gate 8427c478bd9Sstevel@tonic-gate /* 8437c478bd9Sstevel@tonic-gate * If debugging, issue mode senses on the current and 8447c478bd9Sstevel@tonic-gate * saved values, so we can see the result of the mode 8457c478bd9Sstevel@tonic-gate * selects. 8467c478bd9Sstevel@tonic-gate */ 8477c478bd9Sstevel@tonic-gate if (option_msg && diag_msg) { 8487c478bd9Sstevel@tonic-gate (void) uscsi_mode_sense(cur_file, DAD_MODE_ERR_RECOV, 8497c478bd9Sstevel@tonic-gate MODE_SENSE_PC_CURRENT, (caddr_t)page1, 8507c478bd9Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header); 8517c478bd9Sstevel@tonic-gate (void) uscsi_mode_sense(cur_file, DAD_MODE_ERR_RECOV, 8527c478bd9Sstevel@tonic-gate MODE_SENSE_PC_SAVED, (caddr_t)page1, 8537c478bd9Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header); 8547c478bd9Sstevel@tonic-gate } 8557c478bd9Sstevel@tonic-gate 8567c478bd9Sstevel@tonic-gate return (0); 8577c478bd9Sstevel@tonic-gate } 8587c478bd9Sstevel@tonic-gate 8597c478bd9Sstevel@tonic-gate /* 8607c478bd9Sstevel@tonic-gate * Check disk disconnect/reconnect parameters via mode sense. 8617c478bd9Sstevel@tonic-gate * Issue a mode select if we need to change something. 8627c478bd9Sstevel@tonic-gate */ 8637c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 8647c478bd9Sstevel@tonic-gate static int 8657c478bd9Sstevel@tonic-gate scsi_ms_page2(scsi2_flag) 8667c478bd9Sstevel@tonic-gate int scsi2_flag; 8677c478bd9Sstevel@tonic-gate { 8687c478bd9Sstevel@tonic-gate struct mode_disco_reco *page2; 8697c478bd9Sstevel@tonic-gate struct mode_disco_reco *fixed; 8707c478bd9Sstevel@tonic-gate struct scsi_ms_header header; 8717c478bd9Sstevel@tonic-gate struct scsi_ms_header fixed_hdr; 8727c478bd9Sstevel@tonic-gate int status; 8737c478bd9Sstevel@tonic-gate int flag; 8747c478bd9Sstevel@tonic-gate int length; 8757c478bd9Sstevel@tonic-gate int sp_flags; 8767c478bd9Sstevel@tonic-gate union { 8777c478bd9Sstevel@tonic-gate struct mode_disco_reco page2; 8787c478bd9Sstevel@tonic-gate char rawbuf[MAX_MODE_SENSE_SIZE]; 8797c478bd9Sstevel@tonic-gate } u_page2, u_fixed; 8807c478bd9Sstevel@tonic-gate 8817c478bd9Sstevel@tonic-gate page2 = &u_page2.page2; 8827c478bd9Sstevel@tonic-gate fixed = &u_fixed.page2; 8837c478bd9Sstevel@tonic-gate 8847c478bd9Sstevel@tonic-gate /* 8857c478bd9Sstevel@tonic-gate * If debugging, issue mode senses on the default and 8867c478bd9Sstevel@tonic-gate * current values. 8877c478bd9Sstevel@tonic-gate */ 8887c478bd9Sstevel@tonic-gate if (option_msg && diag_msg) { 8897c478bd9Sstevel@tonic-gate (void) uscsi_mode_sense(cur_file, MODEPAGE_DISCO_RECO, 8907c478bd9Sstevel@tonic-gate MODE_SENSE_PC_DEFAULT, (caddr_t)page2, 8917c478bd9Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header); 8927c478bd9Sstevel@tonic-gate (void) uscsi_mode_sense(cur_file, MODEPAGE_DISCO_RECO, 8937c478bd9Sstevel@tonic-gate MODE_SENSE_PC_CURRENT, (caddr_t)page2, 8947c478bd9Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header); 8957c478bd9Sstevel@tonic-gate } 8967c478bd9Sstevel@tonic-gate 8977c478bd9Sstevel@tonic-gate /* 8987c478bd9Sstevel@tonic-gate * Issue a mode sense to determine the saved parameters 8997c478bd9Sstevel@tonic-gate * If the saved values fail, use the current instead. 9007c478bd9Sstevel@tonic-gate */ 9017c478bd9Sstevel@tonic-gate status = uscsi_mode_sense(cur_file, MODEPAGE_DISCO_RECO, 9027c478bd9Sstevel@tonic-gate MODE_SENSE_PC_SAVED, (caddr_t)page2, 9037c478bd9Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header); 9047c478bd9Sstevel@tonic-gate if (status) { 9057c478bd9Sstevel@tonic-gate status = uscsi_mode_sense(cur_file, MODEPAGE_DISCO_RECO, 9067c478bd9Sstevel@tonic-gate MODE_SENSE_PC_CURRENT, (caddr_t)page2, 9077c478bd9Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header); 9087c478bd9Sstevel@tonic-gate if (status) { 9097c478bd9Sstevel@tonic-gate return (0); 9107c478bd9Sstevel@tonic-gate } 9117c478bd9Sstevel@tonic-gate } 9127c478bd9Sstevel@tonic-gate 9137c478bd9Sstevel@tonic-gate /* 9147c478bd9Sstevel@tonic-gate * We only need the common subset between the CCS 9157c478bd9Sstevel@tonic-gate * and SCSI-2 structures, so we can treat both 9167c478bd9Sstevel@tonic-gate * cases identically. Whatever the drive gives 9177c478bd9Sstevel@tonic-gate * us, we return to the drive in the mode select, 9187c478bd9Sstevel@tonic-gate * delta'ed by whatever we want to change. 9197c478bd9Sstevel@tonic-gate */ 9207c478bd9Sstevel@tonic-gate length = MODESENSE_PAGE_LEN(page2); 9217c478bd9Sstevel@tonic-gate if (length < MIN_PAGE2_LEN) { 9227c478bd9Sstevel@tonic-gate return (0); 9237c478bd9Sstevel@tonic-gate } 9247c478bd9Sstevel@tonic-gate 9257c478bd9Sstevel@tonic-gate /* 9267c478bd9Sstevel@tonic-gate * Ask for changeable parameters. 9277c478bd9Sstevel@tonic-gate */ 9287c478bd9Sstevel@tonic-gate status = uscsi_mode_sense(cur_file, MODEPAGE_DISCO_RECO, 9297c478bd9Sstevel@tonic-gate MODE_SENSE_PC_CHANGEABLE, (caddr_t)fixed, 9307c478bd9Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &fixed_hdr); 9317c478bd9Sstevel@tonic-gate if (status || MODESENSE_PAGE_LEN(fixed) < MIN_PAGE2_LEN) { 9327c478bd9Sstevel@tonic-gate return (0); 9337c478bd9Sstevel@tonic-gate } 9347c478bd9Sstevel@tonic-gate 9357c478bd9Sstevel@tonic-gate /* 9367c478bd9Sstevel@tonic-gate * We need to issue a mode select only if one or more 9377c478bd9Sstevel@tonic-gate * parameters need to be changed, and those parameters 9387c478bd9Sstevel@tonic-gate * are flagged by the drive as changeable. 9397c478bd9Sstevel@tonic-gate */ 9407c478bd9Sstevel@tonic-gate flag = 0; 9417c478bd9Sstevel@tonic-gate /* 9427c478bd9Sstevel@tonic-gate * Apply any changes requested via the change list method 9437c478bd9Sstevel@tonic-gate */ 9447c478bd9Sstevel@tonic-gate flag |= apply_chg_list(MODEPAGE_DISCO_RECO, length, 9457c478bd9Sstevel@tonic-gate (uchar_t *)page2, (uchar_t *)fixed, 9467c478bd9Sstevel@tonic-gate cur_dtype->dtype_chglist); 9477c478bd9Sstevel@tonic-gate /* 9487c478bd9Sstevel@tonic-gate * If no changes required, do not issue a mode select 9497c478bd9Sstevel@tonic-gate */ 9507c478bd9Sstevel@tonic-gate if (flag == 0) { 9517c478bd9Sstevel@tonic-gate return (0); 9527c478bd9Sstevel@tonic-gate } 9537c478bd9Sstevel@tonic-gate /* 9547c478bd9Sstevel@tonic-gate * We always want to set the Page Format bit for mode 9557c478bd9Sstevel@tonic-gate * selects. Set the Save Page bit if the drive indicates 9567c478bd9Sstevel@tonic-gate * that it can save this page via the mode sense. 9577c478bd9Sstevel@tonic-gate */ 9587c478bd9Sstevel@tonic-gate sp_flags = MODE_SELECT_PF; 9597c478bd9Sstevel@tonic-gate if (page2->mode_page.ps) { 9607c478bd9Sstevel@tonic-gate sp_flags |= MODE_SELECT_SP; 9617c478bd9Sstevel@tonic-gate } 9627c478bd9Sstevel@tonic-gate page2->mode_page.ps = 0; 9637c478bd9Sstevel@tonic-gate header.mode_header.length = 0; 9647c478bd9Sstevel@tonic-gate header.mode_header.device_specific = 0; 9657c478bd9Sstevel@tonic-gate status = uscsi_mode_select(cur_file, MODEPAGE_DISCO_RECO, 9667c478bd9Sstevel@tonic-gate MODE_SELECT_SP, (caddr_t)page2, length, &header); 9677c478bd9Sstevel@tonic-gate if (status && (sp_flags & MODE_SELECT_SP)) { 9687c478bd9Sstevel@tonic-gate /* If failed, try not saving mode select params. */ 9697c478bd9Sstevel@tonic-gate sp_flags &= ~MODE_SELECT_SP; 9707c478bd9Sstevel@tonic-gate status = uscsi_mode_select(cur_file, MODEPAGE_DISCO_RECO, 9717c478bd9Sstevel@tonic-gate sp_flags, (caddr_t)page2, length, &header); 9727c478bd9Sstevel@tonic-gate } 9737c478bd9Sstevel@tonic-gate if (status && option_msg) { 9747c478bd9Sstevel@tonic-gate err_print("Warning: Using default .\n\n"); 9757c478bd9Sstevel@tonic-gate } 9767c478bd9Sstevel@tonic-gate 9777c478bd9Sstevel@tonic-gate /* 9787c478bd9Sstevel@tonic-gate * If debugging, issue mode senses on the current and 9797c478bd9Sstevel@tonic-gate * saved values, so we can see the result of the mode 9807c478bd9Sstevel@tonic-gate * selects. 9817c478bd9Sstevel@tonic-gate */ 9827c478bd9Sstevel@tonic-gate if (option_msg && diag_msg) { 9837c478bd9Sstevel@tonic-gate (void) uscsi_mode_sense(cur_file, MODEPAGE_DISCO_RECO, 9847c478bd9Sstevel@tonic-gate MODE_SENSE_PC_CURRENT, (caddr_t)page2, 9857c478bd9Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header); 9867c478bd9Sstevel@tonic-gate (void) uscsi_mode_sense(cur_file, MODEPAGE_DISCO_RECO, 9877c478bd9Sstevel@tonic-gate MODE_SENSE_PC_SAVED, (caddr_t)page2, 9887c478bd9Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header); 9897c478bd9Sstevel@tonic-gate } 9907c478bd9Sstevel@tonic-gate 9917c478bd9Sstevel@tonic-gate return (0); 9927c478bd9Sstevel@tonic-gate } 9937c478bd9Sstevel@tonic-gate 9947c478bd9Sstevel@tonic-gate /* 9957c478bd9Sstevel@tonic-gate * Check disk format parameters via mode sense. 9967c478bd9Sstevel@tonic-gate * Issue a mode select if we need to change something. 9977c478bd9Sstevel@tonic-gate */ 9987c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 9997c478bd9Sstevel@tonic-gate static int 10007c478bd9Sstevel@tonic-gate scsi_ms_page3(scsi2_flag) 10017c478bd9Sstevel@tonic-gate int scsi2_flag; 10027c478bd9Sstevel@tonic-gate { 10037c478bd9Sstevel@tonic-gate struct mode_format *page3; 10047c478bd9Sstevel@tonic-gate struct mode_format *fixed; 10057c478bd9Sstevel@tonic-gate struct scsi_ms_header header; 10067c478bd9Sstevel@tonic-gate struct scsi_ms_header fixed_hdr; 10077c478bd9Sstevel@tonic-gate int status; 10087c478bd9Sstevel@tonic-gate int tmp1, tmp2, tmp3; 10097c478bd9Sstevel@tonic-gate int tmp4, tmp5, tmp6; 10107c478bd9Sstevel@tonic-gate int flag; 10117c478bd9Sstevel@tonic-gate int length; 10127c478bd9Sstevel@tonic-gate int sp_flags; 10137c478bd9Sstevel@tonic-gate union { 10147c478bd9Sstevel@tonic-gate struct mode_format page3; 10157c478bd9Sstevel@tonic-gate char rawbuf[MAX_MODE_SENSE_SIZE]; 10167c478bd9Sstevel@tonic-gate } u_page3, u_fixed; 10177c478bd9Sstevel@tonic-gate 10187c478bd9Sstevel@tonic-gate 10197c478bd9Sstevel@tonic-gate page3 = &u_page3.page3; 10207c478bd9Sstevel@tonic-gate fixed = &u_fixed.page3; 10217c478bd9Sstevel@tonic-gate 10227c478bd9Sstevel@tonic-gate /* 10237c478bd9Sstevel@tonic-gate * If debugging, issue mode senses on the default and 10247c478bd9Sstevel@tonic-gate * current values. 10257c478bd9Sstevel@tonic-gate */ 10267c478bd9Sstevel@tonic-gate if (option_msg && diag_msg) { 10277c478bd9Sstevel@tonic-gate (void) uscsi_mode_sense(cur_file, DAD_MODE_FORMAT, 10287c478bd9Sstevel@tonic-gate MODE_SENSE_PC_DEFAULT, (caddr_t)page3, 10297c478bd9Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header); 10307c478bd9Sstevel@tonic-gate (void) uscsi_mode_sense(cur_file, DAD_MODE_FORMAT, 10317c478bd9Sstevel@tonic-gate MODE_SENSE_PC_CURRENT, (caddr_t)page3, 10327c478bd9Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header); 10337c478bd9Sstevel@tonic-gate } 10347c478bd9Sstevel@tonic-gate 10357c478bd9Sstevel@tonic-gate /* 10367c478bd9Sstevel@tonic-gate * Issue a mode sense to determine the saved parameters 10377c478bd9Sstevel@tonic-gate * If the saved values fail, use the current instead. 10387c478bd9Sstevel@tonic-gate */ 10397c478bd9Sstevel@tonic-gate status = uscsi_mode_sense(cur_file, DAD_MODE_FORMAT, 10407c478bd9Sstevel@tonic-gate MODE_SENSE_PC_SAVED, (caddr_t)page3, 10417c478bd9Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header); 10427c478bd9Sstevel@tonic-gate if (status) { 10437c478bd9Sstevel@tonic-gate status = uscsi_mode_sense(cur_file, DAD_MODE_FORMAT, 10447c478bd9Sstevel@tonic-gate MODE_SENSE_PC_CURRENT, (caddr_t)page3, 10457c478bd9Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header); 10467c478bd9Sstevel@tonic-gate if (status) { 10477c478bd9Sstevel@tonic-gate return (0); 10487c478bd9Sstevel@tonic-gate } 10497c478bd9Sstevel@tonic-gate } 10507c478bd9Sstevel@tonic-gate 10517c478bd9Sstevel@tonic-gate /* 10527c478bd9Sstevel@tonic-gate * We only need the common subset between the CCS 10537c478bd9Sstevel@tonic-gate * and SCSI-2 structures, so we can treat both 10547c478bd9Sstevel@tonic-gate * cases identically. Whatever the drive gives 10557c478bd9Sstevel@tonic-gate * us, we return to the drive in the mode select, 10567c478bd9Sstevel@tonic-gate * delta'ed by whatever we want to change. 10577c478bd9Sstevel@tonic-gate */ 10587c478bd9Sstevel@tonic-gate length = MODESENSE_PAGE_LEN(page3); 10597c478bd9Sstevel@tonic-gate if (length < MIN_PAGE3_LEN) { 10607c478bd9Sstevel@tonic-gate return (0); 10617c478bd9Sstevel@tonic-gate } 10627c478bd9Sstevel@tonic-gate 10637c478bd9Sstevel@tonic-gate /* 10647c478bd9Sstevel@tonic-gate * Ask for changeable parameters. 10657c478bd9Sstevel@tonic-gate */ 10667c478bd9Sstevel@tonic-gate status = uscsi_mode_sense(cur_file, DAD_MODE_FORMAT, 10677c478bd9Sstevel@tonic-gate MODE_SENSE_PC_CHANGEABLE, (caddr_t)fixed, 10687c478bd9Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &fixed_hdr); 10697c478bd9Sstevel@tonic-gate if (status || MODESENSE_PAGE_LEN(fixed) < MIN_PAGE3_LEN) { 10707c478bd9Sstevel@tonic-gate return (0); 10717c478bd9Sstevel@tonic-gate } 10727c478bd9Sstevel@tonic-gate 10737c478bd9Sstevel@tonic-gate /* 10747c478bd9Sstevel@tonic-gate * We need to issue a mode select only if one or more 10757c478bd9Sstevel@tonic-gate * parameters need to be changed, and those parameters 10767c478bd9Sstevel@tonic-gate * are flagged by the drive as changeable. 10777c478bd9Sstevel@tonic-gate */ 10787c478bd9Sstevel@tonic-gate tmp1 = page3->track_skew; 10797c478bd9Sstevel@tonic-gate tmp2 = page3->cylinder_skew; 10807c478bd9Sstevel@tonic-gate tmp3 = page3->sect_track; 10817c478bd9Sstevel@tonic-gate tmp4 = page3->tracks_per_zone; 10827c478bd9Sstevel@tonic-gate tmp5 = page3->alt_tracks_vol; 10837c478bd9Sstevel@tonic-gate tmp6 = page3->alt_sect_zone; 10847c478bd9Sstevel@tonic-gate 108565908c77Syu, larry liu - Sun Microsystems - Beijing China flag = (page3->data_bytes_sect != cur_blksz); 108665908c77Syu, larry liu - Sun Microsystems - Beijing China page3->data_bytes_sect = cur_blksz; 10877c478bd9Sstevel@tonic-gate 10887c478bd9Sstevel@tonic-gate flag |= (page3->interleave != 1); 10897c478bd9Sstevel@tonic-gate page3->interleave = 1; 10907c478bd9Sstevel@tonic-gate 10917c478bd9Sstevel@tonic-gate if (cur_dtype->dtype_options & SUP_CYLSKEW && 10927c478bd9Sstevel@tonic-gate fixed->cylinder_skew != 0) { 10937c478bd9Sstevel@tonic-gate flag |= (page3->cylinder_skew != cur_dtype->dtype_cyl_skew); 10947c478bd9Sstevel@tonic-gate page3->cylinder_skew = cur_dtype->dtype_cyl_skew; 10957c478bd9Sstevel@tonic-gate } 10967c478bd9Sstevel@tonic-gate if (cur_dtype->dtype_options & SUP_TRKSKEW && 10977c478bd9Sstevel@tonic-gate fixed->track_skew != 0) { 10987c478bd9Sstevel@tonic-gate flag |= (page3->track_skew != cur_dtype->dtype_trk_skew); 10997c478bd9Sstevel@tonic-gate page3->track_skew = cur_dtype->dtype_trk_skew; 11007c478bd9Sstevel@tonic-gate } 11017c478bd9Sstevel@tonic-gate if (cur_dtype->dtype_options & SUP_PSECT && 11027c478bd9Sstevel@tonic-gate fixed->sect_track != 0) { 11037c478bd9Sstevel@tonic-gate flag |= (page3->sect_track != psect); 11047c478bd9Sstevel@tonic-gate page3->sect_track = (ushort_t)psect; 11057c478bd9Sstevel@tonic-gate } 11067c478bd9Sstevel@tonic-gate if (cur_dtype->dtype_options & SUP_TRKS_ZONE && 11077c478bd9Sstevel@tonic-gate fixed->tracks_per_zone != 0) { 11087c478bd9Sstevel@tonic-gate flag |= (page3->tracks_per_zone != cur_dtype->dtype_trks_zone); 11097c478bd9Sstevel@tonic-gate page3->tracks_per_zone = cur_dtype->dtype_trks_zone; 11107c478bd9Sstevel@tonic-gate } 11117c478bd9Sstevel@tonic-gate if (cur_dtype->dtype_options & SUP_ASECT && 11127c478bd9Sstevel@tonic-gate fixed->alt_sect_zone != 0) { 11137c478bd9Sstevel@tonic-gate flag |= (page3->alt_sect_zone != cur_dtype->dtype_asect); 11147c478bd9Sstevel@tonic-gate page3->alt_sect_zone = cur_dtype->dtype_asect; 11157c478bd9Sstevel@tonic-gate } 11167c478bd9Sstevel@tonic-gate if (cur_dtype->dtype_options & SUP_ATRKS && 11177c478bd9Sstevel@tonic-gate fixed->alt_tracks_vol != 0) { 11187c478bd9Sstevel@tonic-gate flag |= (page3->alt_tracks_vol != cur_dtype->dtype_atrks); 11197c478bd9Sstevel@tonic-gate page3->alt_tracks_vol = cur_dtype->dtype_atrks; 11207c478bd9Sstevel@tonic-gate } 11217c478bd9Sstevel@tonic-gate /* 11227c478bd9Sstevel@tonic-gate * Notify user of any changes so far 11237c478bd9Sstevel@tonic-gate */ 11247c478bd9Sstevel@tonic-gate if (flag && option_msg) { 11257c478bd9Sstevel@tonic-gate fmt_print("PAGE 3: trk skew= %d (%d) cyl skew= %d (%d) ", 11267c478bd9Sstevel@tonic-gate page3->track_skew, tmp1, page3->cylinder_skew, tmp2); 11277c478bd9Sstevel@tonic-gate fmt_print("sects/trk= %d (%d)\n", page3->sect_track, tmp3); 11287c478bd9Sstevel@tonic-gate fmt_print(" trks/zone= %d (%d) alt trks= %d (%d) ", 11297c478bd9Sstevel@tonic-gate page3->tracks_per_zone, tmp4, 11307c478bd9Sstevel@tonic-gate page3->alt_tracks_vol, tmp5); 11317c478bd9Sstevel@tonic-gate fmt_print("alt sects/zone= %d (%d)\n", 11327c478bd9Sstevel@tonic-gate page3->alt_sect_zone, tmp6); 11337c478bd9Sstevel@tonic-gate } 11347c478bd9Sstevel@tonic-gate /* 11357c478bd9Sstevel@tonic-gate * Apply any changes requested via the change list method 11367c478bd9Sstevel@tonic-gate */ 11377c478bd9Sstevel@tonic-gate flag |= apply_chg_list(DAD_MODE_FORMAT, length, 11387c478bd9Sstevel@tonic-gate (uchar_t *)page3, (uchar_t *)fixed, 11397c478bd9Sstevel@tonic-gate cur_dtype->dtype_chglist); 11407c478bd9Sstevel@tonic-gate /* 11417c478bd9Sstevel@tonic-gate * If no changes required, do not issue a mode select 11427c478bd9Sstevel@tonic-gate */ 11437c478bd9Sstevel@tonic-gate if (flag == 0) { 11447c478bd9Sstevel@tonic-gate return (0); 11457c478bd9Sstevel@tonic-gate } 11467c478bd9Sstevel@tonic-gate /* 11477c478bd9Sstevel@tonic-gate * Issue a mode select 11487c478bd9Sstevel@tonic-gate */ 11497c478bd9Sstevel@tonic-gate /* 11507c478bd9Sstevel@tonic-gate * We always want to set the Page Format bit for mode 11517c478bd9Sstevel@tonic-gate * selects. Set the Save Page bit if the drive indicates 11527c478bd9Sstevel@tonic-gate * that it can save this page via the mode sense. 11537c478bd9Sstevel@tonic-gate */ 11547c478bd9Sstevel@tonic-gate sp_flags = MODE_SELECT_PF; 11557c478bd9Sstevel@tonic-gate if (page3->mode_page.ps) { 11567c478bd9Sstevel@tonic-gate sp_flags |= MODE_SELECT_SP; 11577c478bd9Sstevel@tonic-gate } 11587c478bd9Sstevel@tonic-gate page3->mode_page.ps = 0; 11597c478bd9Sstevel@tonic-gate header.mode_header.length = 0; 11607c478bd9Sstevel@tonic-gate header.mode_header.device_specific = 0; 11617c478bd9Sstevel@tonic-gate status = uscsi_mode_select(cur_file, DAD_MODE_FORMAT, 11627c478bd9Sstevel@tonic-gate MODE_SELECT_SP, (caddr_t)page3, length, &header); 11637c478bd9Sstevel@tonic-gate if (status && (sp_flags & MODE_SELECT_SP)) { 11647c478bd9Sstevel@tonic-gate /* If failed, try not saving mode select params. */ 11657c478bd9Sstevel@tonic-gate sp_flags &= ~MODE_SELECT_SP; 11667c478bd9Sstevel@tonic-gate status = uscsi_mode_select(cur_file, DAD_MODE_FORMAT, 11677c478bd9Sstevel@tonic-gate sp_flags, (caddr_t)page3, length, &header); 11687c478bd9Sstevel@tonic-gate } 11697c478bd9Sstevel@tonic-gate if (status && option_msg) { 11707c478bd9Sstevel@tonic-gate err_print("Warning: Using default drive format parameters.\n"); 11717c478bd9Sstevel@tonic-gate err_print("Warning: Drive format may not be correct.\n\n"); 11727c478bd9Sstevel@tonic-gate } 11737c478bd9Sstevel@tonic-gate 11747c478bd9Sstevel@tonic-gate /* 11757c478bd9Sstevel@tonic-gate * If debugging, issue mode senses on the current and 11767c478bd9Sstevel@tonic-gate * saved values, so we can see the result of the mode 11777c478bd9Sstevel@tonic-gate * selects. 11787c478bd9Sstevel@tonic-gate */ 11797c478bd9Sstevel@tonic-gate if (option_msg && diag_msg) { 11807c478bd9Sstevel@tonic-gate (void) uscsi_mode_sense(cur_file, DAD_MODE_FORMAT, 11817c478bd9Sstevel@tonic-gate MODE_SENSE_PC_CURRENT, (caddr_t)page3, 11827c478bd9Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header); 11837c478bd9Sstevel@tonic-gate (void) uscsi_mode_sense(cur_file, DAD_MODE_FORMAT, 11847c478bd9Sstevel@tonic-gate MODE_SENSE_PC_SAVED, (caddr_t)page3, 11857c478bd9Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header); 11867c478bd9Sstevel@tonic-gate } 11877c478bd9Sstevel@tonic-gate 11887c478bd9Sstevel@tonic-gate return (0); 11897c478bd9Sstevel@tonic-gate } 11907c478bd9Sstevel@tonic-gate 11917c478bd9Sstevel@tonic-gate /* 11927c478bd9Sstevel@tonic-gate * Check disk geometry parameters via mode sense. 11937c478bd9Sstevel@tonic-gate * Issue a mode select if we need to change something. 11947c478bd9Sstevel@tonic-gate */ 11957c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 11967c478bd9Sstevel@tonic-gate static int 11977c478bd9Sstevel@tonic-gate scsi_ms_page4(scsi2_flag) 11987c478bd9Sstevel@tonic-gate int scsi2_flag; 11997c478bd9Sstevel@tonic-gate { 12007c478bd9Sstevel@tonic-gate struct mode_geometry *page4; 12017c478bd9Sstevel@tonic-gate struct mode_geometry *fixed; 12027c478bd9Sstevel@tonic-gate struct scsi_ms_header header; 12037c478bd9Sstevel@tonic-gate struct scsi_ms_header fixed_hdr; 12047c478bd9Sstevel@tonic-gate int status; 12057c478bd9Sstevel@tonic-gate int tmp1, tmp2; 12067c478bd9Sstevel@tonic-gate int flag; 12077c478bd9Sstevel@tonic-gate int length; 12087c478bd9Sstevel@tonic-gate int sp_flags; 12097c478bd9Sstevel@tonic-gate union { 12107c478bd9Sstevel@tonic-gate struct mode_geometry page4; 12117c478bd9Sstevel@tonic-gate char rawbuf[MAX_MODE_SENSE_SIZE]; 12127c478bd9Sstevel@tonic-gate } u_page4, u_fixed; 12137c478bd9Sstevel@tonic-gate 12147c478bd9Sstevel@tonic-gate page4 = &u_page4.page4; 12157c478bd9Sstevel@tonic-gate fixed = &u_fixed.page4; 12167c478bd9Sstevel@tonic-gate 12177c478bd9Sstevel@tonic-gate /* 12187c478bd9Sstevel@tonic-gate * If debugging, issue mode senses on the default and 12197c478bd9Sstevel@tonic-gate * current values. 12207c478bd9Sstevel@tonic-gate */ 12217c478bd9Sstevel@tonic-gate if (option_msg && diag_msg) { 12227c478bd9Sstevel@tonic-gate (void) uscsi_mode_sense(cur_file, DAD_MODE_GEOMETRY, 12237c478bd9Sstevel@tonic-gate MODE_SENSE_PC_DEFAULT, (caddr_t)page4, 12247c478bd9Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header); 12257c478bd9Sstevel@tonic-gate (void) uscsi_mode_sense(cur_file, DAD_MODE_GEOMETRY, 12267c478bd9Sstevel@tonic-gate MODE_SENSE_PC_CURRENT, (caddr_t)page4, 12277c478bd9Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header); 12287c478bd9Sstevel@tonic-gate } 12297c478bd9Sstevel@tonic-gate 12307c478bd9Sstevel@tonic-gate /* 12317c478bd9Sstevel@tonic-gate * Issue a mode sense to determine the saved parameters 12327c478bd9Sstevel@tonic-gate * If the saved values fail, use the current instead. 12337c478bd9Sstevel@tonic-gate */ 12347c478bd9Sstevel@tonic-gate status = uscsi_mode_sense(cur_file, DAD_MODE_GEOMETRY, 12357c478bd9Sstevel@tonic-gate MODE_SENSE_PC_SAVED, (caddr_t)page4, 12367c478bd9Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header); 12377c478bd9Sstevel@tonic-gate if (status) { 12387c478bd9Sstevel@tonic-gate status = uscsi_mode_sense(cur_file, DAD_MODE_GEOMETRY, 12397c478bd9Sstevel@tonic-gate MODE_SENSE_PC_CURRENT, (caddr_t)page4, 12407c478bd9Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header); 12417c478bd9Sstevel@tonic-gate if (status) { 12427c478bd9Sstevel@tonic-gate return (0); 12437c478bd9Sstevel@tonic-gate } 12447c478bd9Sstevel@tonic-gate } 12457c478bd9Sstevel@tonic-gate 12467c478bd9Sstevel@tonic-gate /* 12477c478bd9Sstevel@tonic-gate * We only need the common subset between the CCS 12487c478bd9Sstevel@tonic-gate * and SCSI-2 structures, so we can treat both 12497c478bd9Sstevel@tonic-gate * cases identically. Whatever the drive gives 12507c478bd9Sstevel@tonic-gate * us, we return to the drive in the mode select, 12517c478bd9Sstevel@tonic-gate * delta'ed by whatever we want to change. 12527c478bd9Sstevel@tonic-gate */ 12537c478bd9Sstevel@tonic-gate length = MODESENSE_PAGE_LEN(page4); 12547c478bd9Sstevel@tonic-gate if (length < MIN_PAGE4_LEN) { 12557c478bd9Sstevel@tonic-gate return (0); 12567c478bd9Sstevel@tonic-gate } 12577c478bd9Sstevel@tonic-gate 12587c478bd9Sstevel@tonic-gate /* 12597c478bd9Sstevel@tonic-gate * Ask for changeable parameters. 12607c478bd9Sstevel@tonic-gate */ 12617c478bd9Sstevel@tonic-gate status = uscsi_mode_sense(cur_file, DAD_MODE_GEOMETRY, 12627c478bd9Sstevel@tonic-gate MODE_SENSE_PC_CHANGEABLE, (caddr_t)fixed, 12637c478bd9Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &fixed_hdr); 12647c478bd9Sstevel@tonic-gate if (status || MODESENSE_PAGE_LEN(fixed) < MIN_PAGE4_LEN) { 12657c478bd9Sstevel@tonic-gate return (0); 12667c478bd9Sstevel@tonic-gate } 12677c478bd9Sstevel@tonic-gate 12687c478bd9Sstevel@tonic-gate /* 12697c478bd9Sstevel@tonic-gate * We need to issue a mode select only if one or more 12707c478bd9Sstevel@tonic-gate * parameters need to be changed, and those parameters 12717c478bd9Sstevel@tonic-gate * are flagged by the drive as changeable. 12727c478bd9Sstevel@tonic-gate */ 12737c478bd9Sstevel@tonic-gate tmp1 = (page4->cyl_ub << 16) + (page4->cyl_mb << 8) + page4->cyl_lb; 12747c478bd9Sstevel@tonic-gate tmp2 = page4->heads; 12757c478bd9Sstevel@tonic-gate 12767c478bd9Sstevel@tonic-gate flag = 0; 12777c478bd9Sstevel@tonic-gate if ((cur_dtype->dtype_options & SUP_PHEAD) && fixed->heads != 0) { 12787c478bd9Sstevel@tonic-gate flag |= (page4->heads != phead); 12797c478bd9Sstevel@tonic-gate page4->heads = phead; 12807c478bd9Sstevel@tonic-gate } 12817c478bd9Sstevel@tonic-gate /* 12827c478bd9Sstevel@tonic-gate * Notify user of changes so far 12837c478bd9Sstevel@tonic-gate */ 12847c478bd9Sstevel@tonic-gate if (flag && option_msg) { 12857c478bd9Sstevel@tonic-gate fmt_print("PAGE 4: cylinders= %d heads= %d (%d)\n", 12867c478bd9Sstevel@tonic-gate tmp1, page4->heads, tmp2); 12877c478bd9Sstevel@tonic-gate } 12887c478bd9Sstevel@tonic-gate /* 12897c478bd9Sstevel@tonic-gate * Apply any changes requested via the change list method 12907c478bd9Sstevel@tonic-gate */ 12917c478bd9Sstevel@tonic-gate flag |= apply_chg_list(DAD_MODE_GEOMETRY, length, 12927c478bd9Sstevel@tonic-gate (uchar_t *)page4, (uchar_t *)fixed, 12937c478bd9Sstevel@tonic-gate cur_dtype->dtype_chglist); 12947c478bd9Sstevel@tonic-gate /* 12957c478bd9Sstevel@tonic-gate * If no changes required, do not issue a mode select 12967c478bd9Sstevel@tonic-gate */ 12977c478bd9Sstevel@tonic-gate if (flag == 0) { 12987c478bd9Sstevel@tonic-gate return (0); 12997c478bd9Sstevel@tonic-gate } 13007c478bd9Sstevel@tonic-gate /* 13017c478bd9Sstevel@tonic-gate * Issue a mode select 13027c478bd9Sstevel@tonic-gate */ 13037c478bd9Sstevel@tonic-gate /* 13047c478bd9Sstevel@tonic-gate * We always want to set the Page Format bit for mode 13057c478bd9Sstevel@tonic-gate * selects. Set the Save Page bit if the drive indicates 13067c478bd9Sstevel@tonic-gate * that it can save this page via the mode sense. 13077c478bd9Sstevel@tonic-gate */ 13087c478bd9Sstevel@tonic-gate sp_flags = MODE_SELECT_PF; 13097c478bd9Sstevel@tonic-gate if (page4->mode_page.ps) { 13107c478bd9Sstevel@tonic-gate sp_flags |= MODE_SELECT_SP; 13117c478bd9Sstevel@tonic-gate } 13127c478bd9Sstevel@tonic-gate page4->mode_page.ps = 0; 13137c478bd9Sstevel@tonic-gate header.mode_header.length = 0; 13147c478bd9Sstevel@tonic-gate header.mode_header.device_specific = 0; 13157c478bd9Sstevel@tonic-gate status = uscsi_mode_select(cur_file, DAD_MODE_GEOMETRY, 13167c478bd9Sstevel@tonic-gate MODE_SELECT_SP, (caddr_t)page4, length, &header); 13177c478bd9Sstevel@tonic-gate if (status && (sp_flags & MODE_SELECT_SP)) { 13187c478bd9Sstevel@tonic-gate /* If failed, try not saving mode select params. */ 13197c478bd9Sstevel@tonic-gate sp_flags &= ~MODE_SELECT_SP; 13207c478bd9Sstevel@tonic-gate status = uscsi_mode_select(cur_file, DAD_MODE_GEOMETRY, 13217c478bd9Sstevel@tonic-gate sp_flags, (caddr_t)page4, length, &header); 13227c478bd9Sstevel@tonic-gate } 13237c478bd9Sstevel@tonic-gate if (status && option_msg) { 13247c478bd9Sstevel@tonic-gate err_print("Warning: Using default drive geometry.\n\n"); 13257c478bd9Sstevel@tonic-gate } 13267c478bd9Sstevel@tonic-gate 13277c478bd9Sstevel@tonic-gate /* 13287c478bd9Sstevel@tonic-gate * If debugging, issue mode senses on the current and 13297c478bd9Sstevel@tonic-gate * saved values, so we can see the result of the mode 13307c478bd9Sstevel@tonic-gate * selects. 13317c478bd9Sstevel@tonic-gate */ 13327c478bd9Sstevel@tonic-gate if (option_msg && diag_msg) { 13337c478bd9Sstevel@tonic-gate (void) uscsi_mode_sense(cur_file, DAD_MODE_GEOMETRY, 13347c478bd9Sstevel@tonic-gate MODE_SENSE_PC_CURRENT, (caddr_t)page4, 13357c478bd9Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header); 13367c478bd9Sstevel@tonic-gate (void) uscsi_mode_sense(cur_file, DAD_MODE_GEOMETRY, 13377c478bd9Sstevel@tonic-gate MODE_SENSE_PC_SAVED, (caddr_t)page4, 13387c478bd9Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header); 13397c478bd9Sstevel@tonic-gate } 13407c478bd9Sstevel@tonic-gate 13417c478bd9Sstevel@tonic-gate return (0); 13427c478bd9Sstevel@tonic-gate } 13437c478bd9Sstevel@tonic-gate 13447c478bd9Sstevel@tonic-gate /* 13457c478bd9Sstevel@tonic-gate * Check SCSI-2 disk cache parameters via mode sense. 13467c478bd9Sstevel@tonic-gate * Issue a mode select if we need to change something. 13477c478bd9Sstevel@tonic-gate */ 13487c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 13497c478bd9Sstevel@tonic-gate static int 13507c478bd9Sstevel@tonic-gate scsi_ms_page8(scsi2_flag) 13517c478bd9Sstevel@tonic-gate int scsi2_flag; 13527c478bd9Sstevel@tonic-gate { 13537c478bd9Sstevel@tonic-gate struct mode_cache *page8; 13547c478bd9Sstevel@tonic-gate struct mode_cache *fixed; 13557c478bd9Sstevel@tonic-gate struct scsi_ms_header header; 13567c478bd9Sstevel@tonic-gate struct scsi_ms_header fixed_hdr; 13577c478bd9Sstevel@tonic-gate int status; 13587c478bd9Sstevel@tonic-gate int flag; 13597c478bd9Sstevel@tonic-gate int length; 13607c478bd9Sstevel@tonic-gate int sp_flags; 13617c478bd9Sstevel@tonic-gate union { 13627c478bd9Sstevel@tonic-gate struct mode_cache page8; 13637c478bd9Sstevel@tonic-gate char rawbuf[MAX_MODE_SENSE_SIZE]; 13647c478bd9Sstevel@tonic-gate } u_page8, u_fixed; 13657c478bd9Sstevel@tonic-gate 13667c478bd9Sstevel@tonic-gate page8 = &u_page8.page8; 13677c478bd9Sstevel@tonic-gate fixed = &u_fixed.page8; 13687c478bd9Sstevel@tonic-gate 13697c478bd9Sstevel@tonic-gate /* 13707c478bd9Sstevel@tonic-gate * Only SCSI-2 devices support this page 13717c478bd9Sstevel@tonic-gate */ 13727c478bd9Sstevel@tonic-gate if (!scsi2_flag) { 13737c478bd9Sstevel@tonic-gate return (0); 13747c478bd9Sstevel@tonic-gate } 13757c478bd9Sstevel@tonic-gate 13767c478bd9Sstevel@tonic-gate /* 13777c478bd9Sstevel@tonic-gate * If debugging, issue mode senses on the default and 13787c478bd9Sstevel@tonic-gate * current values. 13797c478bd9Sstevel@tonic-gate */ 13807c478bd9Sstevel@tonic-gate if (option_msg && diag_msg) { 13817c478bd9Sstevel@tonic-gate (void) uscsi_mode_sense(cur_file, DAD_MODE_CACHE, 13827c478bd9Sstevel@tonic-gate MODE_SENSE_PC_DEFAULT, (caddr_t)page8, 13837c478bd9Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header); 13847c478bd9Sstevel@tonic-gate (void) uscsi_mode_sense(cur_file, DAD_MODE_CACHE, 13857c478bd9Sstevel@tonic-gate MODE_SENSE_PC_CURRENT, (caddr_t)page8, 13867c478bd9Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header); 13877c478bd9Sstevel@tonic-gate } 13887c478bd9Sstevel@tonic-gate 13897c478bd9Sstevel@tonic-gate /* 13907c478bd9Sstevel@tonic-gate * Issue a mode sense to determine the saved parameters 13917c478bd9Sstevel@tonic-gate * If the saved values fail, use the current instead. 13927c478bd9Sstevel@tonic-gate */ 13937c478bd9Sstevel@tonic-gate status = uscsi_mode_sense(cur_file, DAD_MODE_CACHE, 13947c478bd9Sstevel@tonic-gate MODE_SENSE_PC_SAVED, (caddr_t)page8, 13957c478bd9Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header); 13967c478bd9Sstevel@tonic-gate if (status) { 13977c478bd9Sstevel@tonic-gate status = uscsi_mode_sense(cur_file, DAD_MODE_CACHE, 13987c478bd9Sstevel@tonic-gate MODE_SENSE_PC_CURRENT, (caddr_t)page8, 13997c478bd9Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header); 14007c478bd9Sstevel@tonic-gate if (status) { 14017c478bd9Sstevel@tonic-gate return (0); 14027c478bd9Sstevel@tonic-gate } 14037c478bd9Sstevel@tonic-gate } 14047c478bd9Sstevel@tonic-gate 14057c478bd9Sstevel@tonic-gate /* 14067c478bd9Sstevel@tonic-gate * We only need the common subset between the CCS 14077c478bd9Sstevel@tonic-gate * and SCSI-2 structures, so we can treat both 14087c478bd9Sstevel@tonic-gate * cases identically. Whatever the drive gives 14097c478bd9Sstevel@tonic-gate * us, we return to the drive in the mode select, 14107c478bd9Sstevel@tonic-gate * delta'ed by whatever we want to change. 14117c478bd9Sstevel@tonic-gate */ 14127c478bd9Sstevel@tonic-gate length = MODESENSE_PAGE_LEN(page8); 14137c478bd9Sstevel@tonic-gate if (length < MIN_PAGE8_LEN) { 14147c478bd9Sstevel@tonic-gate return (0); 14157c478bd9Sstevel@tonic-gate } 14167c478bd9Sstevel@tonic-gate 14177c478bd9Sstevel@tonic-gate /* 14187c478bd9Sstevel@tonic-gate * Ask for changeable parameters. 14197c478bd9Sstevel@tonic-gate */ 14207c478bd9Sstevel@tonic-gate status = uscsi_mode_sense(cur_file, DAD_MODE_CACHE, 14217c478bd9Sstevel@tonic-gate MODE_SENSE_PC_CHANGEABLE, (caddr_t)fixed, 14227c478bd9Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &fixed_hdr); 14237c478bd9Sstevel@tonic-gate if (status || MODESENSE_PAGE_LEN(fixed) < MIN_PAGE8_LEN) { 14247c478bd9Sstevel@tonic-gate return (0); 14257c478bd9Sstevel@tonic-gate } 14267c478bd9Sstevel@tonic-gate 14277c478bd9Sstevel@tonic-gate /* 14287c478bd9Sstevel@tonic-gate * We need to issue a mode select only if one or more 14297c478bd9Sstevel@tonic-gate * parameters need to be changed, and those parameters 14307c478bd9Sstevel@tonic-gate * are flagged by the drive as changeable. 14317c478bd9Sstevel@tonic-gate */ 14327c478bd9Sstevel@tonic-gate flag = 0; 14337c478bd9Sstevel@tonic-gate /* 14347c478bd9Sstevel@tonic-gate * Apply any changes requested via the change list method 14357c478bd9Sstevel@tonic-gate */ 14367c478bd9Sstevel@tonic-gate flag |= apply_chg_list(DAD_MODE_CACHE, length, 14377c478bd9Sstevel@tonic-gate (uchar_t *)page8, (uchar_t *)fixed, 14387c478bd9Sstevel@tonic-gate cur_dtype->dtype_chglist); 14397c478bd9Sstevel@tonic-gate /* 14407c478bd9Sstevel@tonic-gate * If no changes required, do not issue a mode select 14417c478bd9Sstevel@tonic-gate */ 14427c478bd9Sstevel@tonic-gate if (flag == 0) { 14437c478bd9Sstevel@tonic-gate return (0); 14447c478bd9Sstevel@tonic-gate } 14457c478bd9Sstevel@tonic-gate /* 14467c478bd9Sstevel@tonic-gate * Issue a mode select 14477c478bd9Sstevel@tonic-gate */ 14487c478bd9Sstevel@tonic-gate /* 14497c478bd9Sstevel@tonic-gate * We always want to set the Page Format bit for mode 14507c478bd9Sstevel@tonic-gate * selects. Set the Save Page bit if the drive indicates 14517c478bd9Sstevel@tonic-gate * that it can save this page via the mode sense. 14527c478bd9Sstevel@tonic-gate */ 14537c478bd9Sstevel@tonic-gate sp_flags = MODE_SELECT_PF; 14547c478bd9Sstevel@tonic-gate if (page8->mode_page.ps) { 14557c478bd9Sstevel@tonic-gate sp_flags |= MODE_SELECT_SP; 14567c478bd9Sstevel@tonic-gate } 14577c478bd9Sstevel@tonic-gate page8->mode_page.ps = 0; 14587c478bd9Sstevel@tonic-gate header.mode_header.length = 0; 14597c478bd9Sstevel@tonic-gate header.mode_header.device_specific = 0; 14607c478bd9Sstevel@tonic-gate status = uscsi_mode_select(cur_file, DAD_MODE_CACHE, 14617c478bd9Sstevel@tonic-gate sp_flags, (caddr_t)page8, length, &header); 14627c478bd9Sstevel@tonic-gate if (status && (sp_flags & MODE_SELECT_SP)) { 14637c478bd9Sstevel@tonic-gate /* If failed, try not saving mode select params. */ 14647c478bd9Sstevel@tonic-gate sp_flags &= ~MODE_SELECT_SP; 14657c478bd9Sstevel@tonic-gate status = uscsi_mode_select(cur_file, DAD_MODE_CACHE, 14667c478bd9Sstevel@tonic-gate sp_flags, (caddr_t)page8, length, &header); 14677c478bd9Sstevel@tonic-gate } 14687c478bd9Sstevel@tonic-gate if (status && option_msg) { 14697c478bd9Sstevel@tonic-gate err_print("\ 14707c478bd9Sstevel@tonic-gate Warning: Using default SCSI-2 cache parameters.\n\n"); 14717c478bd9Sstevel@tonic-gate } 14727c478bd9Sstevel@tonic-gate 14737c478bd9Sstevel@tonic-gate /* 14747c478bd9Sstevel@tonic-gate * If debugging, issue mode senses on the current and 14757c478bd9Sstevel@tonic-gate * saved values, so we can see the result of the mode 14767c478bd9Sstevel@tonic-gate * selects. 14777c478bd9Sstevel@tonic-gate */ 14787c478bd9Sstevel@tonic-gate if (option_msg && diag_msg) { 14797c478bd9Sstevel@tonic-gate (void) uscsi_mode_sense(cur_file, DAD_MODE_CACHE, 14807c478bd9Sstevel@tonic-gate MODE_SENSE_PC_CURRENT, (caddr_t)page8, 14817c478bd9Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header); 14827c478bd9Sstevel@tonic-gate (void) uscsi_mode_sense(cur_file, DAD_MODE_CACHE, 14837c478bd9Sstevel@tonic-gate MODE_SENSE_PC_SAVED, (caddr_t)page8, 14847c478bd9Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header); 14857c478bd9Sstevel@tonic-gate } 14867c478bd9Sstevel@tonic-gate 14877c478bd9Sstevel@tonic-gate return (0); 14887c478bd9Sstevel@tonic-gate } 14897c478bd9Sstevel@tonic-gate 14907c478bd9Sstevel@tonic-gate /* 14917c478bd9Sstevel@tonic-gate * Check CCS disk cache parameters via mode sense. 14927c478bd9Sstevel@tonic-gate * Issue a mode select if we need to change something. 14937c478bd9Sstevel@tonic-gate */ 14947c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 14957c478bd9Sstevel@tonic-gate static int 14967c478bd9Sstevel@tonic-gate scsi_ms_page38(scsi2_flag) 14977c478bd9Sstevel@tonic-gate int scsi2_flag; 14987c478bd9Sstevel@tonic-gate { 14997c478bd9Sstevel@tonic-gate struct mode_cache_ccs *page38; 15007c478bd9Sstevel@tonic-gate struct mode_cache_ccs *fixed; 15017c478bd9Sstevel@tonic-gate struct scsi_ms_header header; 15027c478bd9Sstevel@tonic-gate struct scsi_ms_header fixed_hdr; 15037c478bd9Sstevel@tonic-gate int status; 15047c478bd9Sstevel@tonic-gate int tmp1, tmp2, tmp3, tmp4; 15057c478bd9Sstevel@tonic-gate int flag; 15067c478bd9Sstevel@tonic-gate int length; 15077c478bd9Sstevel@tonic-gate int sp_flags; 15087c478bd9Sstevel@tonic-gate union { 15097c478bd9Sstevel@tonic-gate struct mode_cache_ccs page38; 15107c478bd9Sstevel@tonic-gate char rawbuf[MAX_MODE_SENSE_SIZE]; 15117c478bd9Sstevel@tonic-gate } u_page38, u_fixed; 15127c478bd9Sstevel@tonic-gate 15137c478bd9Sstevel@tonic-gate /* 15147c478bd9Sstevel@tonic-gate * First, determine if we need to look at page 38 at all. 15157c478bd9Sstevel@tonic-gate * Not all devices support it. 15167c478bd9Sstevel@tonic-gate */ 15177c478bd9Sstevel@tonic-gate if (((cur_dtype->dtype_options & (SUP_CACHE | SUP_PREFETCH | 15187c478bd9Sstevel@tonic-gate SUP_CACHE_MIN | SUP_CACHE_MAX)) == 0) && 15197c478bd9Sstevel@tonic-gate (!chg_list_affects_page(cur_dtype->dtype_chglist, 15207c478bd9Sstevel@tonic-gate 0x38))) { 15217c478bd9Sstevel@tonic-gate return (0); 15227c478bd9Sstevel@tonic-gate } 15237c478bd9Sstevel@tonic-gate 15247c478bd9Sstevel@tonic-gate page38 = &u_page38.page38; 15257c478bd9Sstevel@tonic-gate fixed = &u_fixed.page38; 15267c478bd9Sstevel@tonic-gate 15277c478bd9Sstevel@tonic-gate /* 15287c478bd9Sstevel@tonic-gate * If debugging, issue mode senses on the default and 15297c478bd9Sstevel@tonic-gate * current values. 15307c478bd9Sstevel@tonic-gate */ 15317c478bd9Sstevel@tonic-gate if (option_msg && diag_msg) { 15327c478bd9Sstevel@tonic-gate (void) uscsi_mode_sense(cur_file, DAD_MODE_CACHE_CCS, 15337c478bd9Sstevel@tonic-gate MODE_SENSE_PC_DEFAULT, (caddr_t)page38, 15347c478bd9Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header); 15357c478bd9Sstevel@tonic-gate (void) uscsi_mode_sense(cur_file, DAD_MODE_CACHE_CCS, 15367c478bd9Sstevel@tonic-gate MODE_SENSE_PC_CURRENT, (caddr_t)page38, 15377c478bd9Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header); 15387c478bd9Sstevel@tonic-gate } 15397c478bd9Sstevel@tonic-gate 15407c478bd9Sstevel@tonic-gate /* 15417c478bd9Sstevel@tonic-gate * Issue a mode sense to determine the saved parameters 15427c478bd9Sstevel@tonic-gate * If the saved values fail, use the current instead. 15437c478bd9Sstevel@tonic-gate */ 15447c478bd9Sstevel@tonic-gate status = uscsi_mode_sense(cur_file, DAD_MODE_CACHE_CCS, 15457c478bd9Sstevel@tonic-gate MODE_SENSE_PC_SAVED, (caddr_t)page38, 15467c478bd9Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header); 15477c478bd9Sstevel@tonic-gate if (status) { 15487c478bd9Sstevel@tonic-gate status = uscsi_mode_sense(cur_file, DAD_MODE_CACHE_CCS, 15497c478bd9Sstevel@tonic-gate MODE_SENSE_PC_CURRENT, (caddr_t)page38, 15507c478bd9Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header); 15517c478bd9Sstevel@tonic-gate if (status) { 15527c478bd9Sstevel@tonic-gate return (0); 15537c478bd9Sstevel@tonic-gate } 15547c478bd9Sstevel@tonic-gate } 15557c478bd9Sstevel@tonic-gate 15567c478bd9Sstevel@tonic-gate /* 15577c478bd9Sstevel@tonic-gate * We only need the common subset between the CCS 15587c478bd9Sstevel@tonic-gate * and SCSI-2 structures, so we can treat both 15597c478bd9Sstevel@tonic-gate * cases identically. Whatever the drive gives 15607c478bd9Sstevel@tonic-gate * us, we return to the drive in the mode select, 15617c478bd9Sstevel@tonic-gate * delta'ed by whatever we want to change. 15627c478bd9Sstevel@tonic-gate */ 15637c478bd9Sstevel@tonic-gate length = MODESENSE_PAGE_LEN(page38); 15647c478bd9Sstevel@tonic-gate if (length < MIN_PAGE38_LEN) { 15657c478bd9Sstevel@tonic-gate return (0); 15667c478bd9Sstevel@tonic-gate } 15677c478bd9Sstevel@tonic-gate 15687c478bd9Sstevel@tonic-gate /* 15697c478bd9Sstevel@tonic-gate * Ask for changeable parameters. 15707c478bd9Sstevel@tonic-gate */ 15717c478bd9Sstevel@tonic-gate status = uscsi_mode_sense(cur_file, DAD_MODE_CACHE_CCS, 15727c478bd9Sstevel@tonic-gate MODE_SENSE_PC_CHANGEABLE, (caddr_t)fixed, 15737c478bd9Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &fixed_hdr); 15747c478bd9Sstevel@tonic-gate if (status || MODESENSE_PAGE_LEN(fixed) < MIN_PAGE38_LEN) { 15757c478bd9Sstevel@tonic-gate return (0); 15767c478bd9Sstevel@tonic-gate } 15777c478bd9Sstevel@tonic-gate 15787c478bd9Sstevel@tonic-gate /* 15797c478bd9Sstevel@tonic-gate * We need to issue a mode select only if one or more 15807c478bd9Sstevel@tonic-gate * parameters need to be changed, and those parameters 15817c478bd9Sstevel@tonic-gate * are flagged by the drive as changeable. 15827c478bd9Sstevel@tonic-gate */ 15837c478bd9Sstevel@tonic-gate tmp1 = page38->mode; 15847c478bd9Sstevel@tonic-gate tmp2 = page38->threshold; 15857c478bd9Sstevel@tonic-gate tmp3 = page38->min_prefetch; 15867c478bd9Sstevel@tonic-gate tmp4 = page38->max_prefetch; 15877c478bd9Sstevel@tonic-gate 15887c478bd9Sstevel@tonic-gate flag = 0; 15897c478bd9Sstevel@tonic-gate if ((cur_dtype->dtype_options & SUP_CACHE) && 15907c478bd9Sstevel@tonic-gate (fixed->mode & cur_dtype->dtype_cache) == 15917c478bd9Sstevel@tonic-gate cur_dtype->dtype_cache) { 15927c478bd9Sstevel@tonic-gate flag |= (page38->mode != cur_dtype->dtype_cache); 15937c478bd9Sstevel@tonic-gate page38->mode = cur_dtype->dtype_cache; 15947c478bd9Sstevel@tonic-gate } 15957c478bd9Sstevel@tonic-gate if ((cur_dtype->dtype_options & SUP_PREFETCH) && 15967c478bd9Sstevel@tonic-gate (fixed->threshold & cur_dtype->dtype_threshold) == 15977c478bd9Sstevel@tonic-gate cur_dtype->dtype_threshold) { 15987c478bd9Sstevel@tonic-gate flag |= (page38->threshold != cur_dtype->dtype_threshold); 15997c478bd9Sstevel@tonic-gate page38->threshold = cur_dtype->dtype_threshold; 16007c478bd9Sstevel@tonic-gate } 16017c478bd9Sstevel@tonic-gate if ((cur_dtype->dtype_options & SUP_CACHE_MIN) && 16027c478bd9Sstevel@tonic-gate (fixed->min_prefetch & cur_dtype->dtype_prefetch_min) == 16037c478bd9Sstevel@tonic-gate cur_dtype->dtype_prefetch_min) { 16047c478bd9Sstevel@tonic-gate flag |= (page38->min_prefetch != cur_dtype->dtype_prefetch_min); 16057c478bd9Sstevel@tonic-gate page38->min_prefetch = cur_dtype->dtype_prefetch_min; 16067c478bd9Sstevel@tonic-gate } 16077c478bd9Sstevel@tonic-gate if ((cur_dtype->dtype_options & SUP_CACHE_MAX) && 16087c478bd9Sstevel@tonic-gate (fixed->max_prefetch & cur_dtype->dtype_prefetch_max) == 16097c478bd9Sstevel@tonic-gate cur_dtype->dtype_prefetch_max) { 16107c478bd9Sstevel@tonic-gate flag |= (page38->max_prefetch != cur_dtype->dtype_prefetch_max); 16117c478bd9Sstevel@tonic-gate page38->max_prefetch = cur_dtype->dtype_prefetch_max; 16127c478bd9Sstevel@tonic-gate } 16137c478bd9Sstevel@tonic-gate /* 16147c478bd9Sstevel@tonic-gate * Notify the user of changes up to this point 16157c478bd9Sstevel@tonic-gate */ 16167c478bd9Sstevel@tonic-gate if (flag && option_msg) { 16177c478bd9Sstevel@tonic-gate fmt_print("PAGE 38: cache mode= 0x%x (0x%x)\n", 16187c478bd9Sstevel@tonic-gate page38->mode, tmp1); 16197c478bd9Sstevel@tonic-gate fmt_print(" min. prefetch multiplier= %d ", 16207c478bd9Sstevel@tonic-gate page38->min_multiplier); 16217c478bd9Sstevel@tonic-gate fmt_print("max. prefetch multiplier= %d\n", 16227c478bd9Sstevel@tonic-gate page38->max_multiplier); 16237c478bd9Sstevel@tonic-gate fmt_print(" threshold= %d (%d) ", 16247c478bd9Sstevel@tonic-gate page38->threshold, tmp2); 16257c478bd9Sstevel@tonic-gate fmt_print("min. prefetch= %d (%d) ", 16267c478bd9Sstevel@tonic-gate page38->min_prefetch, tmp3); 16277c478bd9Sstevel@tonic-gate fmt_print("max. prefetch= %d (%d)\n", 16287c478bd9Sstevel@tonic-gate page38->max_prefetch, tmp4); 16297c478bd9Sstevel@tonic-gate } 16307c478bd9Sstevel@tonic-gate /* 16317c478bd9Sstevel@tonic-gate * Apply any changes requested via the change list method 16327c478bd9Sstevel@tonic-gate */ 16337c478bd9Sstevel@tonic-gate flag |= apply_chg_list(DAD_MODE_CACHE_CCS, length, 16347c478bd9Sstevel@tonic-gate (uchar_t *)page38, (uchar_t *)fixed, 16357c478bd9Sstevel@tonic-gate cur_dtype->dtype_chglist); 16367c478bd9Sstevel@tonic-gate /* 16377c478bd9Sstevel@tonic-gate * If no changes required, do not issue a mode select 16387c478bd9Sstevel@tonic-gate */ 16397c478bd9Sstevel@tonic-gate if (flag == 0) { 16407c478bd9Sstevel@tonic-gate return (0); 16417c478bd9Sstevel@tonic-gate } 16427c478bd9Sstevel@tonic-gate /* 16437c478bd9Sstevel@tonic-gate * Issue a mode select 16447c478bd9Sstevel@tonic-gate * 16457c478bd9Sstevel@tonic-gate * We always want to set the Page Format bit for mode 16467c478bd9Sstevel@tonic-gate * selects. Set the Save Page bit if the drive indicates 16477c478bd9Sstevel@tonic-gate * that it can save this page via the mode sense. 16487c478bd9Sstevel@tonic-gate */ 16497c478bd9Sstevel@tonic-gate sp_flags = MODE_SELECT_PF; 16507c478bd9Sstevel@tonic-gate if (page38->mode_page.ps) { 16517c478bd9Sstevel@tonic-gate sp_flags |= MODE_SELECT_SP; 16527c478bd9Sstevel@tonic-gate } 16537c478bd9Sstevel@tonic-gate page38->mode_page.ps = 0; 16547c478bd9Sstevel@tonic-gate header.mode_header.length = 0; 16557c478bd9Sstevel@tonic-gate header.mode_header.device_specific = 0; 16567c478bd9Sstevel@tonic-gate status = uscsi_mode_select(cur_file, DAD_MODE_CACHE_CCS, 16577c478bd9Sstevel@tonic-gate sp_flags, (caddr_t)page38, length, &header); 16587c478bd9Sstevel@tonic-gate if (status && (sp_flags & MODE_SELECT_SP)) { 16597c478bd9Sstevel@tonic-gate /* If failed, try not saving mode select params. */ 16607c478bd9Sstevel@tonic-gate sp_flags &= ~MODE_SELECT_SP; 16617c478bd9Sstevel@tonic-gate status = uscsi_mode_select(cur_file, DAD_MODE_CACHE_CCS, 16627c478bd9Sstevel@tonic-gate sp_flags, (caddr_t)page38, length, &header); 16637c478bd9Sstevel@tonic-gate } 16647c478bd9Sstevel@tonic-gate if (status && option_msg) { 16657c478bd9Sstevel@tonic-gate err_print("Warning: Using default CCS cache parameters.\n\n"); 16667c478bd9Sstevel@tonic-gate } 16677c478bd9Sstevel@tonic-gate 16687c478bd9Sstevel@tonic-gate /* 16697c478bd9Sstevel@tonic-gate * If debugging, issue mode senses on the current and 16707c478bd9Sstevel@tonic-gate * saved values, so we can see the result of the mode 16717c478bd9Sstevel@tonic-gate * selects. 16727c478bd9Sstevel@tonic-gate */ 16737c478bd9Sstevel@tonic-gate if (option_msg && diag_msg) { 16747c478bd9Sstevel@tonic-gate (void) uscsi_mode_sense(cur_file, DAD_MODE_CACHE_CCS, 16757c478bd9Sstevel@tonic-gate MODE_SENSE_PC_CURRENT, (caddr_t)page38, 16767c478bd9Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header); 16777c478bd9Sstevel@tonic-gate (void) uscsi_mode_sense(cur_file, DAD_MODE_CACHE_CCS, 16787c478bd9Sstevel@tonic-gate MODE_SENSE_PC_SAVED, (caddr_t)page38, 16797c478bd9Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header); 16807c478bd9Sstevel@tonic-gate } 16817c478bd9Sstevel@tonic-gate 16827c478bd9Sstevel@tonic-gate return (0); 16837c478bd9Sstevel@tonic-gate } 16847c478bd9Sstevel@tonic-gate 16857c478bd9Sstevel@tonic-gate 16867c478bd9Sstevel@tonic-gate /* 16877c478bd9Sstevel@tonic-gate * Extract the manufacturer's defect list. 16887c478bd9Sstevel@tonic-gate */ 16897c478bd9Sstevel@tonic-gate int 16907c478bd9Sstevel@tonic-gate scsi_ex_man(list) 16917c478bd9Sstevel@tonic-gate struct defect_list *list; 16927c478bd9Sstevel@tonic-gate { 16937c478bd9Sstevel@tonic-gate int i; 16947c478bd9Sstevel@tonic-gate 16957c478bd9Sstevel@tonic-gate i = scsi_read_defect_data(list, DLD_MAN_DEF_LIST); 16967c478bd9Sstevel@tonic-gate if (i != 0) 16977c478bd9Sstevel@tonic-gate return (i); 16987c478bd9Sstevel@tonic-gate list->flags &= ~LIST_PGLIST; 16997c478bd9Sstevel@tonic-gate return (0); 17007c478bd9Sstevel@tonic-gate } 17017c478bd9Sstevel@tonic-gate 17027c478bd9Sstevel@tonic-gate /* 17037c478bd9Sstevel@tonic-gate * Extract the current defect list. 17047c478bd9Sstevel@tonic-gate * For embedded scsi drives, this means both the manufacturer's (P) 17057c478bd9Sstevel@tonic-gate * and the grown (G) lists. 17067c478bd9Sstevel@tonic-gate */ 17077c478bd9Sstevel@tonic-gate int 17087c478bd9Sstevel@tonic-gate scsi_ex_cur(list) 17097c478bd9Sstevel@tonic-gate struct defect_list *list; 17107c478bd9Sstevel@tonic-gate { 17117c478bd9Sstevel@tonic-gate int i; 17127c478bd9Sstevel@tonic-gate 17137c478bd9Sstevel@tonic-gate i = scsi_read_defect_data(list, DLD_GROWN_DEF_LIST|DLD_MAN_DEF_LIST); 17147c478bd9Sstevel@tonic-gate if (i != 0) 17157c478bd9Sstevel@tonic-gate return (i); 17167c478bd9Sstevel@tonic-gate list->flags |= LIST_PGLIST; 17177c478bd9Sstevel@tonic-gate return (0); 17187c478bd9Sstevel@tonic-gate } 17197c478bd9Sstevel@tonic-gate 17207c478bd9Sstevel@tonic-gate 17217c478bd9Sstevel@tonic-gate /* 17227c478bd9Sstevel@tonic-gate * Extract the grown list only 17237c478bd9Sstevel@tonic-gate */ 17247c478bd9Sstevel@tonic-gate int 17257c478bd9Sstevel@tonic-gate scsi_ex_grown(list) 17267c478bd9Sstevel@tonic-gate struct defect_list *list; 17277c478bd9Sstevel@tonic-gate { 17287c478bd9Sstevel@tonic-gate int i; 17297c478bd9Sstevel@tonic-gate 17307c478bd9Sstevel@tonic-gate i = scsi_read_defect_data(list, DLD_GROWN_DEF_LIST); 17317c478bd9Sstevel@tonic-gate if (i != 0) 17327c478bd9Sstevel@tonic-gate return (i); 17337c478bd9Sstevel@tonic-gate list->flags |= LIST_PGLIST; 17347c478bd9Sstevel@tonic-gate return (0); 17357c478bd9Sstevel@tonic-gate } 17367c478bd9Sstevel@tonic-gate 17377c478bd9Sstevel@tonic-gate 17387c478bd9Sstevel@tonic-gate static int 17397c478bd9Sstevel@tonic-gate scsi_read_defect_data(list, pglist_flags) 17407c478bd9Sstevel@tonic-gate struct defect_list *list; 17417c478bd9Sstevel@tonic-gate int pglist_flags; 17427c478bd9Sstevel@tonic-gate { 17437c478bd9Sstevel@tonic-gate struct uscsi_cmd ucmd; 17447c478bd9Sstevel@tonic-gate char rqbuf[255]; 17457c478bd9Sstevel@tonic-gate union scsi_cdb cdb; 17467c478bd9Sstevel@tonic-gate struct scsi_defect_list *defects; 17477c478bd9Sstevel@tonic-gate struct scsi_defect_list def_list; 17487c478bd9Sstevel@tonic-gate struct scsi_defect_hdr *hdr; 17497c478bd9Sstevel@tonic-gate int status; 17507c478bd9Sstevel@tonic-gate int nbytes; 17517c478bd9Sstevel@tonic-gate int len; /* returned defect list length */ 17527c478bd9Sstevel@tonic-gate struct scsi_extended_sense *rq; 17537c478bd9Sstevel@tonic-gate 17547c478bd9Sstevel@tonic-gate hdr = (struct scsi_defect_hdr *)&def_list; 17557c478bd9Sstevel@tonic-gate 17567c478bd9Sstevel@tonic-gate /* 17577c478bd9Sstevel@tonic-gate * First get length of list by asking for the header only. 17587c478bd9Sstevel@tonic-gate */ 17597c478bd9Sstevel@tonic-gate (void) memset((char *)&def_list, 0, sizeof (def_list)); 17607c478bd9Sstevel@tonic-gate 17617c478bd9Sstevel@tonic-gate /* 17627c478bd9Sstevel@tonic-gate * Build and execute the uscsi ioctl 17637c478bd9Sstevel@tonic-gate */ 17647c478bd9Sstevel@tonic-gate (void) memset((char *)&ucmd, 0, sizeof (ucmd)); 17657c478bd9Sstevel@tonic-gate (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb)); 17667c478bd9Sstevel@tonic-gate (void) memset((char *)rqbuf, 0, 255); 17677c478bd9Sstevel@tonic-gate cdb.scc_cmd = SCMD_READ_DEFECT_LIST; 17687c478bd9Sstevel@tonic-gate FORMG1COUNT(&cdb, sizeof (struct scsi_defect_hdr)); 17697c478bd9Sstevel@tonic-gate cdb.cdb_opaque[2] = pglist_flags | DLD_BFI_FORMAT; 17707c478bd9Sstevel@tonic-gate ucmd.uscsi_cdb = (caddr_t)&cdb; 17717c478bd9Sstevel@tonic-gate ucmd.uscsi_cdblen = CDB_GROUP1; 17727c478bd9Sstevel@tonic-gate ucmd.uscsi_bufaddr = (caddr_t)hdr; 17737c478bd9Sstevel@tonic-gate ucmd.uscsi_buflen = sizeof (struct scsi_defect_hdr); 17747c478bd9Sstevel@tonic-gate ucmd.uscsi_rqbuf = rqbuf; 17757c478bd9Sstevel@tonic-gate ucmd.uscsi_rqlen = sizeof (rqbuf); 17767c478bd9Sstevel@tonic-gate ucmd.uscsi_rqresid = sizeof (rqbuf); 17777c478bd9Sstevel@tonic-gate rq = (struct scsi_extended_sense *)ucmd.uscsi_rqbuf; 17787c478bd9Sstevel@tonic-gate 17797c478bd9Sstevel@tonic-gate status = uscsi_cmd(cur_file, &ucmd, 17807c478bd9Sstevel@tonic-gate (option_msg && diag_msg) ? F_NORMAL : F_SILENT); 17817c478bd9Sstevel@tonic-gate 17827c478bd9Sstevel@tonic-gate if (status != 0) { 17837c478bd9Sstevel@tonic-gate /* 17847c478bd9Sstevel@tonic-gate * check if read_defect_list_is_supported. 17857c478bd9Sstevel@tonic-gate */ 17867c478bd9Sstevel@tonic-gate if (ucmd.uscsi_rqstatus == STATUS_GOOD && 17877c478bd9Sstevel@tonic-gate rq->es_key == KEY_ILLEGAL_REQUEST && 17887c478bd9Sstevel@tonic-gate rq->es_add_code == INVALID_OPCODE) { 17897c478bd9Sstevel@tonic-gate err_print("\nWARNING: Current Disk does not support" 17907c478bd9Sstevel@tonic-gate " defect lists. \n"); 17917c478bd9Sstevel@tonic-gate } else 17927c478bd9Sstevel@tonic-gate if (option_msg) { 17937c478bd9Sstevel@tonic-gate err_print("No %s defect list.\n", 17947c478bd9Sstevel@tonic-gate pglist_flags & DLD_GROWN_DEF_LIST ? 17957c478bd9Sstevel@tonic-gate "grown" : "manufacturer's"); 17967c478bd9Sstevel@tonic-gate } 17977c478bd9Sstevel@tonic-gate return (-1); 17987c478bd9Sstevel@tonic-gate } 17997c478bd9Sstevel@tonic-gate 18007c478bd9Sstevel@tonic-gate /* 18017c478bd9Sstevel@tonic-gate * Read the full list the second time 18027c478bd9Sstevel@tonic-gate */ 18037c478bd9Sstevel@tonic-gate hdr->length = BE_16(hdr->length); 18047c478bd9Sstevel@tonic-gate len = hdr->length; 18057c478bd9Sstevel@tonic-gate nbytes = len + sizeof (struct scsi_defect_hdr); 18067c478bd9Sstevel@tonic-gate 18077c478bd9Sstevel@tonic-gate defects = zalloc(nbytes); 18087c478bd9Sstevel@tonic-gate *(struct scsi_defect_hdr *)defects = *(struct scsi_defect_hdr *)hdr; 18097c478bd9Sstevel@tonic-gate 18107c478bd9Sstevel@tonic-gate (void) memset((char *)&ucmd, 0, sizeof (ucmd)); 18117c478bd9Sstevel@tonic-gate (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb)); 18127c478bd9Sstevel@tonic-gate cdb.scc_cmd = SCMD_READ_DEFECT_LIST; 18137c478bd9Sstevel@tonic-gate FORMG1COUNT(&cdb, nbytes); 18147c478bd9Sstevel@tonic-gate cdb.cdb_opaque[2] = pglist_flags | DLD_BFI_FORMAT; 18157c478bd9Sstevel@tonic-gate ucmd.uscsi_cdb = (caddr_t)&cdb; 18167c478bd9Sstevel@tonic-gate ucmd.uscsi_cdblen = CDB_GROUP1; 18177c478bd9Sstevel@tonic-gate ucmd.uscsi_bufaddr = (caddr_t)defects; 18187c478bd9Sstevel@tonic-gate ucmd.uscsi_buflen = nbytes; 18197c478bd9Sstevel@tonic-gate status = uscsi_cmd(cur_file, &ucmd, 18207c478bd9Sstevel@tonic-gate (option_msg && diag_msg) ? F_NORMAL : F_SILENT); 18217c478bd9Sstevel@tonic-gate 18227c478bd9Sstevel@tonic-gate if (status) { 18237c478bd9Sstevel@tonic-gate err_print("can't read defect list 2nd time"); 18247c478bd9Sstevel@tonic-gate destroy_data((char *)defects); 18257c478bd9Sstevel@tonic-gate return (-1); 18267c478bd9Sstevel@tonic-gate } 18277c478bd9Sstevel@tonic-gate 18287c478bd9Sstevel@tonic-gate defects->length = BE_16(defects->length); 18297c478bd9Sstevel@tonic-gate 18307c478bd9Sstevel@tonic-gate if (len != hdr->length) { 18317c478bd9Sstevel@tonic-gate err_print("not enough defects"); 18327c478bd9Sstevel@tonic-gate destroy_data((char *)defects); 18337c478bd9Sstevel@tonic-gate return (-1); 18347c478bd9Sstevel@tonic-gate } 18357c478bd9Sstevel@tonic-gate scsi_convert_list_to_new(list, (struct scsi_defect_list *)defects, 18367c478bd9Sstevel@tonic-gate DLD_BFI_FORMAT); 18377c478bd9Sstevel@tonic-gate destroy_data((char *)defects); 18387c478bd9Sstevel@tonic-gate return (0); 18397c478bd9Sstevel@tonic-gate } 18407c478bd9Sstevel@tonic-gate 18417c478bd9Sstevel@tonic-gate 18427c478bd9Sstevel@tonic-gate /* 18437c478bd9Sstevel@tonic-gate * Map a block. 18447c478bd9Sstevel@tonic-gate */ 18457c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 18467c478bd9Sstevel@tonic-gate static int 18477c478bd9Sstevel@tonic-gate scsi_repair(bn, flag) 18487c478bd9Sstevel@tonic-gate uint64_t bn; 18497c478bd9Sstevel@tonic-gate int flag; 18507c478bd9Sstevel@tonic-gate { 18517c478bd9Sstevel@tonic-gate struct uscsi_cmd ucmd; 18527c478bd9Sstevel@tonic-gate union scsi_cdb cdb; 18537c478bd9Sstevel@tonic-gate struct scsi_reassign_blk defect_list; 18547c478bd9Sstevel@tonic-gate 18557c478bd9Sstevel@tonic-gate /* 18567c478bd9Sstevel@tonic-gate * Build and execute the uscsi ioctl 18577c478bd9Sstevel@tonic-gate */ 18587c478bd9Sstevel@tonic-gate (void) memset((char *)&ucmd, 0, sizeof (ucmd)); 18597c478bd9Sstevel@tonic-gate (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb)); 18607c478bd9Sstevel@tonic-gate (void) memset((char *)&defect_list, 0, 18617c478bd9Sstevel@tonic-gate sizeof (struct scsi_reassign_blk)); 18627c478bd9Sstevel@tonic-gate cdb.scc_cmd = SCMD_REASSIGN_BLOCK; 18637c478bd9Sstevel@tonic-gate ucmd.uscsi_cdb = (caddr_t)&cdb; 18647c478bd9Sstevel@tonic-gate ucmd.uscsi_cdblen = CDB_GROUP0; 18657c478bd9Sstevel@tonic-gate ucmd.uscsi_bufaddr = (caddr_t)&defect_list; 18667c478bd9Sstevel@tonic-gate ucmd.uscsi_buflen = sizeof (struct scsi_reassign_blk); 18677c478bd9Sstevel@tonic-gate defect_list.length = sizeof (defect_list.defect); 18687c478bd9Sstevel@tonic-gate defect_list.length = BE_16(defect_list.length); 18697c478bd9Sstevel@tonic-gate defect_list.defect = bn; 18707c478bd9Sstevel@tonic-gate defect_list.defect = BE_32(defect_list.defect); 18717c478bd9Sstevel@tonic-gate return (uscsi_cmd(cur_file, &ucmd, 18727c478bd9Sstevel@tonic-gate (option_msg && diag_msg) ? F_NORMAL : F_SILENT)); 18737c478bd9Sstevel@tonic-gate } 18747c478bd9Sstevel@tonic-gate 18757c478bd9Sstevel@tonic-gate /* 18767c478bd9Sstevel@tonic-gate * Convert a SCSI-style defect list to our generic format. 18777c478bd9Sstevel@tonic-gate * We can handle different format lists. 18787c478bd9Sstevel@tonic-gate */ 18797c478bd9Sstevel@tonic-gate static void 18807c478bd9Sstevel@tonic-gate scsi_convert_list_to_new(list, def_list, list_format) 18817c478bd9Sstevel@tonic-gate struct defect_list *list; 18827c478bd9Sstevel@tonic-gate struct scsi_defect_list *def_list; 18837c478bd9Sstevel@tonic-gate int list_format; 18847c478bd9Sstevel@tonic-gate { 18857c478bd9Sstevel@tonic-gate register struct scsi_bfi_defect *old_defect, *old_defect1; 18867c478bd9Sstevel@tonic-gate register struct defect_entry *new_defect; 18877c478bd9Sstevel@tonic-gate register int len, new_len, obfi, nbfi; 18887c478bd9Sstevel@tonic-gate register int i; 18897c478bd9Sstevel@tonic-gate int old_cyl, new_cyl; 18907c478bd9Sstevel@tonic-gate unsigned char *cp; 18917c478bd9Sstevel@tonic-gate 18927c478bd9Sstevel@tonic-gate 18937c478bd9Sstevel@tonic-gate switch (list_format) { 18947c478bd9Sstevel@tonic-gate 18957c478bd9Sstevel@tonic-gate case DLD_BFI_FORMAT: 18967c478bd9Sstevel@tonic-gate /* 18977c478bd9Sstevel@tonic-gate * Allocate space for the rest of the list. 18987c478bd9Sstevel@tonic-gate */ 18997c478bd9Sstevel@tonic-gate len = def_list->length / sizeof (struct scsi_bfi_defect); 19007c478bd9Sstevel@tonic-gate old_defect = def_list->list; 19017c478bd9Sstevel@tonic-gate new_defect = (struct defect_entry *) 190265908c77Syu, larry liu - Sun Microsystems - Beijing China zalloc(deflist_size(cur_blksz, len) * 190365908c77Syu, larry liu - Sun Microsystems - Beijing China cur_blksz); 19047c478bd9Sstevel@tonic-gate 19057c478bd9Sstevel@tonic-gate list->header.magicno = (uint_t)DEFECT_MAGIC; 19067c478bd9Sstevel@tonic-gate list->list = new_defect; 19077c478bd9Sstevel@tonic-gate 19087c478bd9Sstevel@tonic-gate for (i = 0, new_len = 0; i < len; new_defect++, new_len++) { 19097c478bd9Sstevel@tonic-gate cp = (unsigned char *)old_defect; 19107c478bd9Sstevel@tonic-gate new_defect->cyl = (cp[0] << 16 | cp[1] << 8) | cp[2]; 19117c478bd9Sstevel@tonic-gate new_defect->head = old_defect->head; 19127c478bd9Sstevel@tonic-gate new_defect->bfi = (int)old_defect->bytes_from_index; 19137c478bd9Sstevel@tonic-gate new_defect->bfi = BE_32(new_defect->bfi); 19147c478bd9Sstevel@tonic-gate new_defect->nbits = 0; /* size of defect */ 19157c478bd9Sstevel@tonic-gate old_defect1 = old_defect++; 19167c478bd9Sstevel@tonic-gate i++; 19177c478bd9Sstevel@tonic-gate /* 19187c478bd9Sstevel@tonic-gate * Since we reached the end of the list, old_defect 19197c478bd9Sstevel@tonic-gate * now points to an invalid reference, since it got 19207c478bd9Sstevel@tonic-gate * incremented in the above operation. So we don't 19217c478bd9Sstevel@tonic-gate * need to proceed further. new_len needs to be 19227c478bd9Sstevel@tonic-gate * incremented to account for the last element. 19237c478bd9Sstevel@tonic-gate */ 19247c478bd9Sstevel@tonic-gate if (i == len) { 19257c478bd9Sstevel@tonic-gate new_len++; 19267c478bd9Sstevel@tonic-gate break; 19277c478bd9Sstevel@tonic-gate } 19287c478bd9Sstevel@tonic-gate obfi = new_defect->bfi; 19297c478bd9Sstevel@tonic-gate nbfi = (int)old_defect->bytes_from_index; 19307c478bd9Sstevel@tonic-gate nbfi = BE_32(nbfi); 19317c478bd9Sstevel@tonic-gate 19327c478bd9Sstevel@tonic-gate old_cyl = new_defect->cyl; 19337c478bd9Sstevel@tonic-gate cp = (unsigned char *)old_defect; 19347c478bd9Sstevel@tonic-gate new_cyl = (cp[0] << 16 | cp[1] << 8) | cp[2]; 19357c478bd9Sstevel@tonic-gate 19367c478bd9Sstevel@tonic-gate 19377c478bd9Sstevel@tonic-gate /* 19387c478bd9Sstevel@tonic-gate * Merge adjacent contiguous defect entries into one 19397c478bd9Sstevel@tonic-gate * and update the length of the defect 19407c478bd9Sstevel@tonic-gate */ 19417c478bd9Sstevel@tonic-gate while ((i < len) && 19427c478bd9Sstevel@tonic-gate (old_cyl == new_cyl) && 19437c478bd9Sstevel@tonic-gate (old_defect->head == old_defect1->head) && 19447c478bd9Sstevel@tonic-gate (nbfi == (obfi + BITSPERBYTE))) { 19457c478bd9Sstevel@tonic-gate old_defect1 = old_defect++; 19467c478bd9Sstevel@tonic-gate cp = (unsigned char *)old_defect; 19477c478bd9Sstevel@tonic-gate new_cyl = (cp[0] << 16 | cp[1] << 8) | cp[2]; 19487c478bd9Sstevel@tonic-gate obfi = (int)old_defect1->bytes_from_index; 19497c478bd9Sstevel@tonic-gate obfi = BE_32(obfi); 19507c478bd9Sstevel@tonic-gate nbfi = (int)old_defect->bytes_from_index; 19517c478bd9Sstevel@tonic-gate nbfi = BE_32(nbfi); 19527c478bd9Sstevel@tonic-gate new_defect->nbits += (8*BITSPERBYTE); 19537c478bd9Sstevel@tonic-gate i++; 19547c478bd9Sstevel@tonic-gate } 19557c478bd9Sstevel@tonic-gate } 19567c478bd9Sstevel@tonic-gate 19577c478bd9Sstevel@tonic-gate list->header.count = new_len; 19587c478bd9Sstevel@tonic-gate break; 19597c478bd9Sstevel@tonic-gate 19607c478bd9Sstevel@tonic-gate default: 19617c478bd9Sstevel@tonic-gate err_print("scsi_convert_list_to_new: can't deal with it\n"); 19627c478bd9Sstevel@tonic-gate exit(0); 19637c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 19647c478bd9Sstevel@tonic-gate } 19657c478bd9Sstevel@tonic-gate 19667c478bd9Sstevel@tonic-gate (void) checkdefsum(list, CK_MAKESUM); 19677c478bd9Sstevel@tonic-gate } 19687c478bd9Sstevel@tonic-gate 19697c478bd9Sstevel@tonic-gate 19707c478bd9Sstevel@tonic-gate 19717c478bd9Sstevel@tonic-gate /* 19727c478bd9Sstevel@tonic-gate * Execute a command and determine the result. 19737c478bd9Sstevel@tonic-gate * Uses the "uscsi" ioctl interface, which is 19747c478bd9Sstevel@tonic-gate * fully supported. 19757c478bd9Sstevel@tonic-gate * 19767c478bd9Sstevel@tonic-gate * If the user wants request sense data to be returned 19777c478bd9Sstevel@tonic-gate * in case of error then , the "uscsi_cmd" structure 19787c478bd9Sstevel@tonic-gate * should have the request sense buffer allocated in 19797c478bd9Sstevel@tonic-gate * uscsi_rqbuf. 19807c478bd9Sstevel@tonic-gate * 19817c478bd9Sstevel@tonic-gate */ 19827c478bd9Sstevel@tonic-gate int 19837c478bd9Sstevel@tonic-gate uscsi_cmd(fd, ucmd, flags) 19847c478bd9Sstevel@tonic-gate int fd; 19857c478bd9Sstevel@tonic-gate struct uscsi_cmd *ucmd; 19867c478bd9Sstevel@tonic-gate int flags; 19877c478bd9Sstevel@tonic-gate { 19887c478bd9Sstevel@tonic-gate struct scsi_extended_sense *rq; 19897c478bd9Sstevel@tonic-gate char rqbuf[255]; 19907c478bd9Sstevel@tonic-gate int status; 19917c478bd9Sstevel@tonic-gate int rqlen; 19927c478bd9Sstevel@tonic-gate int timeout = 0; 19937c478bd9Sstevel@tonic-gate 19947c478bd9Sstevel@tonic-gate /* 19957c478bd9Sstevel@tonic-gate * Set function flags for driver. 19967c478bd9Sstevel@tonic-gate */ 19977c478bd9Sstevel@tonic-gate ucmd->uscsi_flags = USCSI_ISOLATE; 19987c478bd9Sstevel@tonic-gate if (flags & F_SILENT) { 19997c478bd9Sstevel@tonic-gate ucmd->uscsi_flags |= USCSI_SILENT; 20007c478bd9Sstevel@tonic-gate } 20017c478bd9Sstevel@tonic-gate if (flags & F_RQENABLE) { 20027c478bd9Sstevel@tonic-gate ucmd->uscsi_flags |= USCSI_RQENABLE; 20037c478bd9Sstevel@tonic-gate } 20047c478bd9Sstevel@tonic-gate 20057c478bd9Sstevel@tonic-gate /* 20067c478bd9Sstevel@tonic-gate * If this command will perform a read, set the USCSI_READ flag 20077c478bd9Sstevel@tonic-gate */ 20087c478bd9Sstevel@tonic-gate if (ucmd->uscsi_buflen > 0) { 20097c478bd9Sstevel@tonic-gate /* 20107c478bd9Sstevel@tonic-gate * uscsi_cdb is declared as a caddr_t, so any CDB 20117c478bd9Sstevel@tonic-gate * command byte with the MSB set will result in a 20127c478bd9Sstevel@tonic-gate * compiler error unless we cast to an unsigned value. 20137c478bd9Sstevel@tonic-gate */ 20147c478bd9Sstevel@tonic-gate switch ((uint8_t)ucmd->uscsi_cdb[0]) { 20157c478bd9Sstevel@tonic-gate case SCMD_READ: 20167c478bd9Sstevel@tonic-gate case SCMD_READ|SCMD_GROUP1: 20177c478bd9Sstevel@tonic-gate case SCMD_READ|SCMD_GROUP4: 20187c478bd9Sstevel@tonic-gate case SCMD_MODE_SENSE: 20197c478bd9Sstevel@tonic-gate case SCMD_INQUIRY: 20207c478bd9Sstevel@tonic-gate case SCMD_READ_DEFECT_LIST: 20217c478bd9Sstevel@tonic-gate case SCMD_READ_CAPACITY: 20227c478bd9Sstevel@tonic-gate case SCMD_SVC_ACTION_IN_G4: 20237c478bd9Sstevel@tonic-gate ucmd->uscsi_flags |= USCSI_READ; 20247c478bd9Sstevel@tonic-gate break; 20257c478bd9Sstevel@tonic-gate } 20267c478bd9Sstevel@tonic-gate } 20277c478bd9Sstevel@tonic-gate 20287c478bd9Sstevel@tonic-gate /* 20297c478bd9Sstevel@tonic-gate * Set timeout: 30 seconds for all commands except format 20307c478bd9Sstevel@tonic-gate */ 20317c478bd9Sstevel@tonic-gate switch (ucmd->uscsi_cdb[0]) { 20327c478bd9Sstevel@tonic-gate case SCMD_FORMAT: 20337c478bd9Sstevel@tonic-gate if (ucmd->uscsi_timeout == 0) { 20347c478bd9Sstevel@tonic-gate ucmd->uscsi_timeout = scsi_format_timeout; 20357c478bd9Sstevel@tonic-gate /* 20367c478bd9Sstevel@tonic-gate * Get the timeout value computed using page4 geometry. 20377c478bd9Sstevel@tonic-gate * add 50% margin to cover defect management overhead. 20387c478bd9Sstevel@tonic-gate * add another 50% margin to have a safe timeout. 20397c478bd9Sstevel@tonic-gate * If it exceeds 2 hours then use this value. 20407c478bd9Sstevel@tonic-gate */ 20417c478bd9Sstevel@tonic-gate if ((timeout = scsi_format_time()) > 0) { 20427c478bd9Sstevel@tonic-gate timeout *= 60; /* convert to seconds */ 20437c478bd9Sstevel@tonic-gate timeout += timeout; 20447c478bd9Sstevel@tonic-gate /* 20457c478bd9Sstevel@tonic-gate * formatting drives with huge capacity 20467c478bd9Sstevel@tonic-gate * will cause these heuristics to come 20477c478bd9Sstevel@tonic-gate * up with times that overflow ~9 hours 20487c478bd9Sstevel@tonic-gate */ 20497c478bd9Sstevel@tonic-gate if (timeout > SHRT_MAX) 20507c478bd9Sstevel@tonic-gate timeout = SHRT_MAX; 20517c478bd9Sstevel@tonic-gate if (timeout > scsi_format_timeout) 20527c478bd9Sstevel@tonic-gate ucmd->uscsi_timeout = timeout; 20537c478bd9Sstevel@tonic-gate } 20547c478bd9Sstevel@tonic-gate } 20557c478bd9Sstevel@tonic-gate if (option_msg && diag_msg) { 20567c478bd9Sstevel@tonic-gate err_print("format_timeout set to %d seconds, %d" 20577c478bd9Sstevel@tonic-gate " required\n", ucmd->uscsi_timeout, timeout); 20587c478bd9Sstevel@tonic-gate } 20597c478bd9Sstevel@tonic-gate break; 20607c478bd9Sstevel@tonic-gate 20617c478bd9Sstevel@tonic-gate default: 20627c478bd9Sstevel@tonic-gate ucmd->uscsi_timeout = 30; /* 30 seconds */ 20637c478bd9Sstevel@tonic-gate break; 20647c478bd9Sstevel@tonic-gate } 20657c478bd9Sstevel@tonic-gate 20667c478bd9Sstevel@tonic-gate /* 20677c478bd9Sstevel@tonic-gate * Set up Request Sense buffer 20687c478bd9Sstevel@tonic-gate */ 20697c478bd9Sstevel@tonic-gate ucmd->uscsi_flags |= USCSI_RQENABLE; 20707c478bd9Sstevel@tonic-gate 20717c478bd9Sstevel@tonic-gate if (ucmd->uscsi_rqbuf == NULL) { 20727c478bd9Sstevel@tonic-gate ucmd->uscsi_rqbuf = rqbuf; 20737c478bd9Sstevel@tonic-gate ucmd->uscsi_rqlen = sizeof (rqbuf); 20747c478bd9Sstevel@tonic-gate ucmd->uscsi_rqresid = sizeof (rqbuf); 20757c478bd9Sstevel@tonic-gate } 20767c478bd9Sstevel@tonic-gate ucmd->uscsi_rqstatus = IMPOSSIBLE_SCSI_STATUS; 20777c478bd9Sstevel@tonic-gate 20787c478bd9Sstevel@tonic-gate /* 20797c478bd9Sstevel@tonic-gate * Clear global error state 20807c478bd9Sstevel@tonic-gate */ 20817c478bd9Sstevel@tonic-gate media_error = 0; 20827c478bd9Sstevel@tonic-gate 20837c478bd9Sstevel@tonic-gate /* 20847c478bd9Sstevel@tonic-gate * Execute the ioctl 20857c478bd9Sstevel@tonic-gate */ 20867c478bd9Sstevel@tonic-gate status = ioctl(fd, USCSICMD, ucmd); 20877c478bd9Sstevel@tonic-gate if (status == 0 && ucmd->uscsi_status == 0) { 20887c478bd9Sstevel@tonic-gate return (status); 20897c478bd9Sstevel@tonic-gate } 20907c478bd9Sstevel@tonic-gate 20917c478bd9Sstevel@tonic-gate /* 20927c478bd9Sstevel@tonic-gate * Check the status and return appropriate errors if the disk is 20937c478bd9Sstevel@tonic-gate * unavailable (could be formatting) or reserved (by other host). 20947c478bd9Sstevel@tonic-gate * In either case we can not talk to the disk now. 20957c478bd9Sstevel@tonic-gate */ 20967c478bd9Sstevel@tonic-gate if (status == -1 && errno == EAGAIN) { 20977c478bd9Sstevel@tonic-gate disk_error = DISK_STAT_UNAVAILABLE; 20987c478bd9Sstevel@tonic-gate return (DSK_UNAVAILABLE); 20997c478bd9Sstevel@tonic-gate } 21007c478bd9Sstevel@tonic-gate if ((ucmd->uscsi_status & STATUS_MASK) == STATUS_RESERVATION_CONFLICT) { 21017c478bd9Sstevel@tonic-gate disk_error = DISK_STAT_RESERVED; 21027c478bd9Sstevel@tonic-gate return (DSK_RESERVED); 21037c478bd9Sstevel@tonic-gate } 21047c478bd9Sstevel@tonic-gate /* 21057c478bd9Sstevel@tonic-gate * Check for physically removed or completely unresponsive drive 21067c478bd9Sstevel@tonic-gate */ 21077c478bd9Sstevel@tonic-gate if (status == -1 && !ucmd->uscsi_status && errno == EIO) { 21087c478bd9Sstevel@tonic-gate disk_error = DISK_STAT_UNAVAILABLE; 21097c478bd9Sstevel@tonic-gate return (DSK_UNAVAILABLE); 21107c478bd9Sstevel@tonic-gate } 21117c478bd9Sstevel@tonic-gate 21127c478bd9Sstevel@tonic-gate /* 21137c478bd9Sstevel@tonic-gate * If an automatic Request Sense gave us valid 21147c478bd9Sstevel@tonic-gate * info about the error, we may be able to use 21157c478bd9Sstevel@tonic-gate * that to print a reasonable error msg. 21167c478bd9Sstevel@tonic-gate */ 21177c478bd9Sstevel@tonic-gate if (ucmd->uscsi_rqstatus == IMPOSSIBLE_SCSI_STATUS) { 21187c478bd9Sstevel@tonic-gate if (option_msg && diag_msg) { 21197c478bd9Sstevel@tonic-gate err_print("No request sense for command %s\n", 21207c478bd9Sstevel@tonic-gate scsi_find_command_name(ucmd->uscsi_cdb[0])); 21217c478bd9Sstevel@tonic-gate } 21227c478bd9Sstevel@tonic-gate return (-1); 21237c478bd9Sstevel@tonic-gate } 21247c478bd9Sstevel@tonic-gate if (ucmd->uscsi_rqstatus != STATUS_GOOD) { 21257c478bd9Sstevel@tonic-gate if (option_msg && diag_msg) { 21267c478bd9Sstevel@tonic-gate err_print("Request sense status for command %s: 0x%x\n", 21277c478bd9Sstevel@tonic-gate scsi_find_command_name(ucmd->uscsi_cdb[0]), 21287c478bd9Sstevel@tonic-gate ucmd->uscsi_rqstatus); 21297c478bd9Sstevel@tonic-gate } 21307c478bd9Sstevel@tonic-gate return (-1); 21317c478bd9Sstevel@tonic-gate } 21327c478bd9Sstevel@tonic-gate rq = (struct scsi_extended_sense *)ucmd->uscsi_rqbuf; 21337c478bd9Sstevel@tonic-gate rqlen = ucmd->uscsi_rqlen - ucmd->uscsi_rqresid; 21347c478bd9Sstevel@tonic-gate if ((((int)rq->es_add_len) + 8) < MIN_REQUEST_SENSE_LEN || 21357c478bd9Sstevel@tonic-gate rq->es_class != CLASS_EXTENDED_SENSE || 21367c478bd9Sstevel@tonic-gate rqlen < MIN_REQUEST_SENSE_LEN) { 21377c478bd9Sstevel@tonic-gate if (option_msg) { 21387c478bd9Sstevel@tonic-gate err_print("Request sense for command %s failed\n", 21397c478bd9Sstevel@tonic-gate scsi_find_command_name(ucmd->uscsi_cdb[0])); 21407c478bd9Sstevel@tonic-gate } 21417c478bd9Sstevel@tonic-gate if (option_msg && diag_msg) { 21427c478bd9Sstevel@tonic-gate err_print("Sense data:\n"); 21437c478bd9Sstevel@tonic-gate dump("", (caddr_t)rqbuf, rqlen, HEX_ONLY); 21447c478bd9Sstevel@tonic-gate } 2145b210ab1cSbz211116 if (errno == EIO) { 2146b210ab1cSbz211116 disk_error = DISK_STAT_UNAVAILABLE; 2147b210ab1cSbz211116 return (DSK_UNAVAILABLE); 2148b210ab1cSbz211116 } else { 21497c478bd9Sstevel@tonic-gate return (-1); 21507c478bd9Sstevel@tonic-gate } 2151b210ab1cSbz211116 } 21527c478bd9Sstevel@tonic-gate 21537c478bd9Sstevel@tonic-gate /* 21547c478bd9Sstevel@tonic-gate * If the failed command is a Mode Select, and the 21557c478bd9Sstevel@tonic-gate * target is indicating that it has rounded one of 21567c478bd9Sstevel@tonic-gate * the mode select parameters, as defined in the SCSI-2 21577c478bd9Sstevel@tonic-gate * specification, then we should accept the command 21587c478bd9Sstevel@tonic-gate * as successful. 21597c478bd9Sstevel@tonic-gate */ 21607c478bd9Sstevel@tonic-gate if (ucmd->uscsi_cdb[0] == SCMD_MODE_SELECT) { 21617c478bd9Sstevel@tonic-gate if (rq->es_key == KEY_RECOVERABLE_ERROR && 21627c478bd9Sstevel@tonic-gate rq->es_add_code == ROUNDED_PARAMETER && 21637c478bd9Sstevel@tonic-gate rq->es_qual_code == 0) { 21647c478bd9Sstevel@tonic-gate return (0); 21657c478bd9Sstevel@tonic-gate } 21667c478bd9Sstevel@tonic-gate } 21677c478bd9Sstevel@tonic-gate 21687c478bd9Sstevel@tonic-gate switch (rq->es_key) { 21697c478bd9Sstevel@tonic-gate case KEY_NOT_READY: 21707c478bd9Sstevel@tonic-gate disk_error = DISK_STAT_NOTREADY; 21717c478bd9Sstevel@tonic-gate break; 21727c478bd9Sstevel@tonic-gate case KEY_DATA_PROTECT: 21737c478bd9Sstevel@tonic-gate disk_error = DISK_STAT_DATA_PROTECT; 21747c478bd9Sstevel@tonic-gate break; 21757c478bd9Sstevel@tonic-gate } 21767c478bd9Sstevel@tonic-gate 21777c478bd9Sstevel@tonic-gate if (flags & F_ALLERRS) { 21787c478bd9Sstevel@tonic-gate media_error = (rq->es_key == KEY_MEDIUM_ERROR); 21797c478bd9Sstevel@tonic-gate } 21807c478bd9Sstevel@tonic-gate if (!(flags & F_SILENT) || option_msg) { 21817c478bd9Sstevel@tonic-gate scsi_printerr(ucmd, rq, rqlen); 21827c478bd9Sstevel@tonic-gate } 21837c478bd9Sstevel@tonic-gate if ((rq->es_key != KEY_RECOVERABLE_ERROR) || (flags & F_ALLERRS)) { 21847c478bd9Sstevel@tonic-gate return (-1); 21857c478bd9Sstevel@tonic-gate } 2186b210ab1cSbz211116 2187b210ab1cSbz211116 if (status == -1 && errno == EIO) { 2188b210ab1cSbz211116 disk_error = DISK_STAT_UNAVAILABLE; 2189b210ab1cSbz211116 return (DSK_UNAVAILABLE); 2190b210ab1cSbz211116 } 2191b210ab1cSbz211116 21927c478bd9Sstevel@tonic-gate return (0); 21937c478bd9Sstevel@tonic-gate } 21947c478bd9Sstevel@tonic-gate 21957c478bd9Sstevel@tonic-gate 21967c478bd9Sstevel@tonic-gate /* 21977c478bd9Sstevel@tonic-gate * Execute a uscsi mode sense command. 21987c478bd9Sstevel@tonic-gate * This can only be used to return one page at a time. 21997c478bd9Sstevel@tonic-gate * Return the mode header/block descriptor and the actual 22007c478bd9Sstevel@tonic-gate * page data separately - this allows us to support 22017c478bd9Sstevel@tonic-gate * devices which return either 0 or 1 block descriptors. 22027c478bd9Sstevel@tonic-gate * Whatever a device gives us in the mode header/block descriptor 22037c478bd9Sstevel@tonic-gate * will be returned to it upon subsequent mode selects. 22047c478bd9Sstevel@tonic-gate */ 22057c478bd9Sstevel@tonic-gate int 22067c478bd9Sstevel@tonic-gate uscsi_mode_sense(fd, page_code, page_control, page_data, page_size, header) 22077c478bd9Sstevel@tonic-gate int fd; /* file descriptor */ 22087c478bd9Sstevel@tonic-gate int page_code; /* requested page number */ 22097c478bd9Sstevel@tonic-gate int page_control; /* current, changeable, etc. */ 22107c478bd9Sstevel@tonic-gate caddr_t page_data; /* place received data here */ 22117c478bd9Sstevel@tonic-gate int page_size; /* size of page_data */ 22127c478bd9Sstevel@tonic-gate struct scsi_ms_header *header; /* mode header/block descriptor */ 22137c478bd9Sstevel@tonic-gate { 22147c478bd9Sstevel@tonic-gate caddr_t mode_sense_buf; 22157c478bd9Sstevel@tonic-gate struct mode_header *hdr; 22167c478bd9Sstevel@tonic-gate struct mode_page *pg; 22177c478bd9Sstevel@tonic-gate int nbytes; 22187c478bd9Sstevel@tonic-gate struct uscsi_cmd ucmd; 22197c478bd9Sstevel@tonic-gate union scsi_cdb cdb; 22207c478bd9Sstevel@tonic-gate int status; 22217c478bd9Sstevel@tonic-gate int maximum; 22227c478bd9Sstevel@tonic-gate 22237c478bd9Sstevel@tonic-gate assert(page_size >= 0 && page_size < 256); 22247c478bd9Sstevel@tonic-gate assert(page_control == MODE_SENSE_PC_CURRENT || 22257c478bd9Sstevel@tonic-gate page_control == MODE_SENSE_PC_CHANGEABLE || 22267c478bd9Sstevel@tonic-gate page_control == MODE_SENSE_PC_DEFAULT || 22277c478bd9Sstevel@tonic-gate page_control == MODE_SENSE_PC_SAVED); 22287c478bd9Sstevel@tonic-gate /* 22297c478bd9Sstevel@tonic-gate * Allocate a buffer for the mode sense headers 22307c478bd9Sstevel@tonic-gate * and mode sense data itself. 22317c478bd9Sstevel@tonic-gate */ 22327c478bd9Sstevel@tonic-gate nbytes = sizeof (struct block_descriptor) + 22337c478bd9Sstevel@tonic-gate sizeof (struct mode_header) + page_size; 22347c478bd9Sstevel@tonic-gate nbytes = page_size; 22357c478bd9Sstevel@tonic-gate if ((mode_sense_buf = malloc((uint_t)nbytes)) == NULL) { 22367c478bd9Sstevel@tonic-gate err_print("cannot malloc %d bytes\n", nbytes); 22377c478bd9Sstevel@tonic-gate return (-1); 22387c478bd9Sstevel@tonic-gate } 22397c478bd9Sstevel@tonic-gate 22407c478bd9Sstevel@tonic-gate /* 22417c478bd9Sstevel@tonic-gate * Build and execute the uscsi ioctl 22427c478bd9Sstevel@tonic-gate */ 22437c478bd9Sstevel@tonic-gate (void) memset(mode_sense_buf, 0, nbytes); 22447c478bd9Sstevel@tonic-gate (void) memset((char *)&ucmd, 0, sizeof (ucmd)); 22457c478bd9Sstevel@tonic-gate (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb)); 22467c478bd9Sstevel@tonic-gate cdb.scc_cmd = SCMD_MODE_SENSE; 22477c478bd9Sstevel@tonic-gate FORMG0COUNT(&cdb, (uchar_t)nbytes); 22487c478bd9Sstevel@tonic-gate cdb.cdb_opaque[2] = page_control | page_code; 22497c478bd9Sstevel@tonic-gate ucmd.uscsi_cdb = (caddr_t)&cdb; 22507c478bd9Sstevel@tonic-gate ucmd.uscsi_cdblen = CDB_GROUP0; 22517c478bd9Sstevel@tonic-gate ucmd.uscsi_bufaddr = mode_sense_buf; 22527c478bd9Sstevel@tonic-gate ucmd.uscsi_buflen = nbytes; 22537c478bd9Sstevel@tonic-gate status = uscsi_cmd(fd, &ucmd, 22547c478bd9Sstevel@tonic-gate (option_msg && diag_msg) ? F_NORMAL : F_SILENT); 22557c478bd9Sstevel@tonic-gate if (status) { 22567c478bd9Sstevel@tonic-gate if (option_msg) { 22577c478bd9Sstevel@tonic-gate err_print("Mode sense page 0x%x failed\n", 22587c478bd9Sstevel@tonic-gate page_code); 22597c478bd9Sstevel@tonic-gate } 22607c478bd9Sstevel@tonic-gate free(mode_sense_buf); 22617c478bd9Sstevel@tonic-gate return (-1); 22627c478bd9Sstevel@tonic-gate } 22637c478bd9Sstevel@tonic-gate 22647c478bd9Sstevel@tonic-gate /* 22657c478bd9Sstevel@tonic-gate * Verify that the returned data looks reasonabled, 22667c478bd9Sstevel@tonic-gate * find the actual page data, and copy it into the 22677c478bd9Sstevel@tonic-gate * user's buffer. Copy the mode_header and block_descriptor 22687c478bd9Sstevel@tonic-gate * into the header structure, which can then be used to 22697c478bd9Sstevel@tonic-gate * return the same data to the drive when issuing a mode select. 22707c478bd9Sstevel@tonic-gate */ 22717c478bd9Sstevel@tonic-gate hdr = (struct mode_header *)mode_sense_buf; 22727c478bd9Sstevel@tonic-gate (void) memset((caddr_t)header, 0, sizeof (struct scsi_ms_header)); 22737c478bd9Sstevel@tonic-gate if (hdr->bdesc_length != sizeof (struct block_descriptor) && 22747c478bd9Sstevel@tonic-gate hdr->bdesc_length != 0) { 22757c478bd9Sstevel@tonic-gate if (option_msg) { 22767c478bd9Sstevel@tonic-gate err_print("\ 22777c478bd9Sstevel@tonic-gate \nMode sense page 0x%x: block descriptor length %d incorrect\n", 22787c478bd9Sstevel@tonic-gate page_code, hdr->bdesc_length); 22797c478bd9Sstevel@tonic-gate if (diag_msg) 22807c478bd9Sstevel@tonic-gate dump("Mode sense: ", mode_sense_buf, 22817c478bd9Sstevel@tonic-gate nbytes, HEX_ONLY); 22827c478bd9Sstevel@tonic-gate } 22837c478bd9Sstevel@tonic-gate free(mode_sense_buf); 22847c478bd9Sstevel@tonic-gate return (-1); 22857c478bd9Sstevel@tonic-gate } 22867c478bd9Sstevel@tonic-gate (void) memcpy((caddr_t)header, mode_sense_buf, 22877c478bd9Sstevel@tonic-gate (int) (sizeof (struct mode_header) + hdr->bdesc_length)); 22887c478bd9Sstevel@tonic-gate pg = (struct mode_page *)((ulong_t)mode_sense_buf + 22897c478bd9Sstevel@tonic-gate sizeof (struct mode_header) + hdr->bdesc_length); 22907c478bd9Sstevel@tonic-gate if (pg->code != page_code) { 22917c478bd9Sstevel@tonic-gate if (option_msg) { 22927c478bd9Sstevel@tonic-gate err_print("\ 22937c478bd9Sstevel@tonic-gate \nMode sense page 0x%x: incorrect page code 0x%x\n", 22947c478bd9Sstevel@tonic-gate page_code, pg->code); 22957c478bd9Sstevel@tonic-gate if (diag_msg) 22967c478bd9Sstevel@tonic-gate dump("Mode sense: ", mode_sense_buf, 22977c478bd9Sstevel@tonic-gate nbytes, HEX_ONLY); 22987c478bd9Sstevel@tonic-gate } 22997c478bd9Sstevel@tonic-gate free(mode_sense_buf); 23007c478bd9Sstevel@tonic-gate return (-1); 23017c478bd9Sstevel@tonic-gate } 23027c478bd9Sstevel@tonic-gate /* 23037c478bd9Sstevel@tonic-gate * Accept up to "page_size" bytes of mode sense data. 23047c478bd9Sstevel@tonic-gate * This allows us to accept both CCS and SCSI-2 23057c478bd9Sstevel@tonic-gate * structures, as long as we request the greater 23067c478bd9Sstevel@tonic-gate * of the two. 23077c478bd9Sstevel@tonic-gate */ 23087c478bd9Sstevel@tonic-gate maximum = page_size - sizeof (struct mode_page) - hdr->bdesc_length; 23097c478bd9Sstevel@tonic-gate if (((int)pg->length) > maximum) { 23107c478bd9Sstevel@tonic-gate if (option_msg) { 23117c478bd9Sstevel@tonic-gate err_print("\ 23127c478bd9Sstevel@tonic-gate Mode sense page 0x%x: incorrect page length %d - expected max %d\n", 23137c478bd9Sstevel@tonic-gate page_code, pg->length, maximum); 23147c478bd9Sstevel@tonic-gate if (diag_msg) 23157c478bd9Sstevel@tonic-gate dump("Mode sense: ", mode_sense_buf, 23167c478bd9Sstevel@tonic-gate nbytes, HEX_ONLY); 23177c478bd9Sstevel@tonic-gate } 23187c478bd9Sstevel@tonic-gate free(mode_sense_buf); 23197c478bd9Sstevel@tonic-gate return (-1); 23207c478bd9Sstevel@tonic-gate } 23217c478bd9Sstevel@tonic-gate 23227c478bd9Sstevel@tonic-gate (void) memcpy(page_data, (caddr_t)pg, MODESENSE_PAGE_LEN(pg)); 23237c478bd9Sstevel@tonic-gate 23247c478bd9Sstevel@tonic-gate if (option_msg && diag_msg) { 23257c478bd9Sstevel@tonic-gate char *pc = find_string(page_control_strings, page_control); 23267c478bd9Sstevel@tonic-gate err_print("\nMode sense page 0x%x (%s):\n", page_code, 23277c478bd9Sstevel@tonic-gate pc != NULL ? pc : ""); 23287c478bd9Sstevel@tonic-gate dump("header: ", (caddr_t)header, 23297c478bd9Sstevel@tonic-gate sizeof (struct scsi_ms_header), HEX_ONLY); 23307c478bd9Sstevel@tonic-gate dump("data: ", page_data, 23317c478bd9Sstevel@tonic-gate MODESENSE_PAGE_LEN(pg), HEX_ONLY); 23327c478bd9Sstevel@tonic-gate } 23337c478bd9Sstevel@tonic-gate 23347c478bd9Sstevel@tonic-gate free(mode_sense_buf); 23357c478bd9Sstevel@tonic-gate return (0); 23367c478bd9Sstevel@tonic-gate } 23377c478bd9Sstevel@tonic-gate 23387c478bd9Sstevel@tonic-gate 23397c478bd9Sstevel@tonic-gate /* 23407c478bd9Sstevel@tonic-gate * Execute a uscsi mode select command. 23417c478bd9Sstevel@tonic-gate */ 23427c478bd9Sstevel@tonic-gate int 23437c478bd9Sstevel@tonic-gate uscsi_mode_select(fd, page_code, options, page_data, page_size, header) 23447c478bd9Sstevel@tonic-gate int fd; /* file descriptor */ 23457c478bd9Sstevel@tonic-gate int page_code; /* mode select page */ 23467c478bd9Sstevel@tonic-gate int options; /* save page/page format */ 23477c478bd9Sstevel@tonic-gate caddr_t page_data; /* place received data here */ 23487c478bd9Sstevel@tonic-gate int page_size; /* size of page_data */ 23497c478bd9Sstevel@tonic-gate struct scsi_ms_header *header; /* mode header/block descriptor */ 23507c478bd9Sstevel@tonic-gate { 23517c478bd9Sstevel@tonic-gate caddr_t mode_select_buf; 23527c478bd9Sstevel@tonic-gate int nbytes; 23537c478bd9Sstevel@tonic-gate struct uscsi_cmd ucmd; 23547c478bd9Sstevel@tonic-gate union scsi_cdb cdb; 23557c478bd9Sstevel@tonic-gate int status; 23567c478bd9Sstevel@tonic-gate 23577c478bd9Sstevel@tonic-gate assert(((struct mode_page *)page_data)->ps == 0); 23587c478bd9Sstevel@tonic-gate assert(header->mode_header.length == 0); 23597c478bd9Sstevel@tonic-gate assert(header->mode_header.device_specific == 0); 23607c478bd9Sstevel@tonic-gate assert((options & ~(MODE_SELECT_SP|MODE_SELECT_PF)) == 0); 23617c478bd9Sstevel@tonic-gate 23627c478bd9Sstevel@tonic-gate /* 23637c478bd9Sstevel@tonic-gate * Allocate a buffer for the mode select header and data 23647c478bd9Sstevel@tonic-gate */ 23657c478bd9Sstevel@tonic-gate nbytes = sizeof (struct block_descriptor) + 23667c478bd9Sstevel@tonic-gate sizeof (struct mode_header) + page_size; 23677c478bd9Sstevel@tonic-gate if ((mode_select_buf = malloc((uint_t)nbytes)) == NULL) { 23687c478bd9Sstevel@tonic-gate err_print("cannot malloc %d bytes\n", nbytes); 23697c478bd9Sstevel@tonic-gate return (-1); 23707c478bd9Sstevel@tonic-gate } 23717c478bd9Sstevel@tonic-gate 23727c478bd9Sstevel@tonic-gate /* 23737c478bd9Sstevel@tonic-gate * Build the mode select data out of the header and page data 23747c478bd9Sstevel@tonic-gate * This allows us to support devices which return either 23757c478bd9Sstevel@tonic-gate * 0 or 1 block descriptors. 23767c478bd9Sstevel@tonic-gate */ 23777c478bd9Sstevel@tonic-gate (void) memset(mode_select_buf, 0, nbytes); 23787c478bd9Sstevel@tonic-gate nbytes = sizeof (struct mode_header); 23797c478bd9Sstevel@tonic-gate if (header->mode_header.bdesc_length == 23807c478bd9Sstevel@tonic-gate sizeof (struct block_descriptor)) { 23817c478bd9Sstevel@tonic-gate nbytes += sizeof (struct block_descriptor); 23827c478bd9Sstevel@tonic-gate } 23837c478bd9Sstevel@tonic-gate 23847c478bd9Sstevel@tonic-gate /* 23857c478bd9Sstevel@tonic-gate * Dump the structures if anyone's interested 23867c478bd9Sstevel@tonic-gate */ 23877c478bd9Sstevel@tonic-gate if (option_msg && diag_msg) { 23887c478bd9Sstevel@tonic-gate char *s; 23897c478bd9Sstevel@tonic-gate s = find_string(mode_select_strings, 23907c478bd9Sstevel@tonic-gate options & (MODE_SELECT_SP|MODE_SELECT_PF)); 23917c478bd9Sstevel@tonic-gate err_print("\nMode select page 0x%x%s:\n", page_code, 23927c478bd9Sstevel@tonic-gate s != NULL ? s : ""); 23937c478bd9Sstevel@tonic-gate dump("header: ", (caddr_t)header, 23947c478bd9Sstevel@tonic-gate nbytes, HEX_ONLY); 23957c478bd9Sstevel@tonic-gate dump("data: ", (caddr_t)page_data, 23967c478bd9Sstevel@tonic-gate page_size, HEX_ONLY); 23977c478bd9Sstevel@tonic-gate } 23987c478bd9Sstevel@tonic-gate 23997c478bd9Sstevel@tonic-gate /* 24007c478bd9Sstevel@tonic-gate * Fix the code for byte ordering 24017c478bd9Sstevel@tonic-gate */ 24027c478bd9Sstevel@tonic-gate 24037c478bd9Sstevel@tonic-gate switch (page_code) { 24047c478bd9Sstevel@tonic-gate case DAD_MODE_ERR_RECOV: 24057c478bd9Sstevel@tonic-gate { 24067c478bd9Sstevel@tonic-gate struct mode_err_recov *pd; 24077c478bd9Sstevel@tonic-gate pd = (struct mode_err_recov *)(void *)page_data; 24087c478bd9Sstevel@tonic-gate pd->recovery_time_limit = BE_16(pd->recovery_time_limit); 24097c478bd9Sstevel@tonic-gate break; 24107c478bd9Sstevel@tonic-gate } 24117c478bd9Sstevel@tonic-gate case MODEPAGE_DISCO_RECO: 24127c478bd9Sstevel@tonic-gate { 24137c478bd9Sstevel@tonic-gate struct mode_disco_reco *pd; 24147c478bd9Sstevel@tonic-gate pd = (struct mode_disco_reco *)(void *)page_data; 24157c478bd9Sstevel@tonic-gate pd->bus_inactivity_limit = BE_16(pd->bus_inactivity_limit); 24167c478bd9Sstevel@tonic-gate pd->disconect_time_limit = BE_16(pd->disconect_time_limit); 24177c478bd9Sstevel@tonic-gate pd->connect_time_limit = BE_16(pd->connect_time_limit); 24187c478bd9Sstevel@tonic-gate pd->max_burst_size = BE_16(pd->max_burst_size); 24197c478bd9Sstevel@tonic-gate break; 24207c478bd9Sstevel@tonic-gate } 24217c478bd9Sstevel@tonic-gate case DAD_MODE_FORMAT: 24227c478bd9Sstevel@tonic-gate { 24237c478bd9Sstevel@tonic-gate struct mode_format *pd; 24247c478bd9Sstevel@tonic-gate pd = (struct mode_format *)(void *)page_data; 24257c478bd9Sstevel@tonic-gate pd->tracks_per_zone = BE_16(pd->tracks_per_zone); 24267c478bd9Sstevel@tonic-gate pd->alt_sect_zone = BE_16(pd->alt_sect_zone); 24277c478bd9Sstevel@tonic-gate pd->alt_tracks_zone = BE_16(pd->alt_tracks_zone); 24287c478bd9Sstevel@tonic-gate pd->alt_tracks_vol = BE_16(pd->alt_tracks_vol); 24297c478bd9Sstevel@tonic-gate pd->sect_track = BE_16(pd->sect_track); 24307c478bd9Sstevel@tonic-gate pd->data_bytes_sect = BE_16(pd->data_bytes_sect); 24317c478bd9Sstevel@tonic-gate pd->interleave = BE_16(pd->interleave); 24327c478bd9Sstevel@tonic-gate pd->track_skew = BE_16(pd->track_skew); 24337c478bd9Sstevel@tonic-gate pd->cylinder_skew = BE_16(pd->cylinder_skew); 24347c478bd9Sstevel@tonic-gate break; 24357c478bd9Sstevel@tonic-gate } 24367c478bd9Sstevel@tonic-gate case DAD_MODE_GEOMETRY: 24377c478bd9Sstevel@tonic-gate { 24387c478bd9Sstevel@tonic-gate struct mode_geometry *pd; 24397c478bd9Sstevel@tonic-gate pd = (struct mode_geometry *)(void *)page_data; 24407c478bd9Sstevel@tonic-gate pd->step_rate = BE_16(pd->step_rate); 24417c478bd9Sstevel@tonic-gate pd->rpm = BE_16(pd->rpm); 24427c478bd9Sstevel@tonic-gate break; 24437c478bd9Sstevel@tonic-gate } 24447c478bd9Sstevel@tonic-gate case DAD_MODE_CACHE: 24457c478bd9Sstevel@tonic-gate { 24467c478bd9Sstevel@tonic-gate struct mode_cache *pd; 24477c478bd9Sstevel@tonic-gate pd = (struct mode_cache *)(void *)page_data; 24487c478bd9Sstevel@tonic-gate pd->dis_prefetch_len = BE_16(pd->dis_prefetch_len); 24497c478bd9Sstevel@tonic-gate pd->min_prefetch = BE_16(pd->min_prefetch); 24507c478bd9Sstevel@tonic-gate pd->max_prefetch = BE_16(pd->max_prefetch); 24517c478bd9Sstevel@tonic-gate pd->prefetch_ceiling = BE_16(pd->prefetch_ceiling); 24527c478bd9Sstevel@tonic-gate break; 24537c478bd9Sstevel@tonic-gate } 24547c478bd9Sstevel@tonic-gate case MODEPAGE_PDEVICE: 24557c478bd9Sstevel@tonic-gate { 24567c478bd9Sstevel@tonic-gate struct mode_pdevice *pd; 24577c478bd9Sstevel@tonic-gate pd = (struct mode_pdevice *)(void *)page_data; 24587c478bd9Sstevel@tonic-gate pd->if_ident = BE_16(pd->if_ident); 24597c478bd9Sstevel@tonic-gate break; 24607c478bd9Sstevel@tonic-gate } 24617c478bd9Sstevel@tonic-gate case MODEPAGE_CTRL_MODE: 24627c478bd9Sstevel@tonic-gate { 24637c478bd9Sstevel@tonic-gate struct mode_control *pd; 24647c478bd9Sstevel@tonic-gate pd = (struct mode_control *)(void *)page_data; 24657c478bd9Sstevel@tonic-gate pd->ready_aen_holdoff = BE_16(pd->ready_aen_holdoff); 24667c478bd9Sstevel@tonic-gate break; 24677c478bd9Sstevel@tonic-gate } 24687c478bd9Sstevel@tonic-gate } 24697c478bd9Sstevel@tonic-gate 24707c478bd9Sstevel@tonic-gate /* 24717c478bd9Sstevel@tonic-gate * Put the header and data together 24727c478bd9Sstevel@tonic-gate */ 24737c478bd9Sstevel@tonic-gate (void) memcpy(mode_select_buf, (caddr_t)header, nbytes); 24747c478bd9Sstevel@tonic-gate (void) memcpy(mode_select_buf + nbytes, page_data, page_size); 24757c478bd9Sstevel@tonic-gate nbytes += page_size; 24767c478bd9Sstevel@tonic-gate 24777c478bd9Sstevel@tonic-gate /* 24787c478bd9Sstevel@tonic-gate * Build and execute the uscsi ioctl 24797c478bd9Sstevel@tonic-gate */ 24807c478bd9Sstevel@tonic-gate (void) memset((char *)&ucmd, 0, sizeof (ucmd)); 24817c478bd9Sstevel@tonic-gate (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb)); 24827c478bd9Sstevel@tonic-gate cdb.scc_cmd = SCMD_MODE_SELECT; 24837c478bd9Sstevel@tonic-gate FORMG0COUNT(&cdb, (uchar_t)nbytes); 24847c478bd9Sstevel@tonic-gate cdb.cdb_opaque[1] = (uchar_t)options; 24857c478bd9Sstevel@tonic-gate ucmd.uscsi_cdb = (caddr_t)&cdb; 24867c478bd9Sstevel@tonic-gate ucmd.uscsi_cdblen = CDB_GROUP0; 24877c478bd9Sstevel@tonic-gate ucmd.uscsi_bufaddr = mode_select_buf; 24887c478bd9Sstevel@tonic-gate ucmd.uscsi_buflen = nbytes; 24897c478bd9Sstevel@tonic-gate status = uscsi_cmd(fd, &ucmd, 24907c478bd9Sstevel@tonic-gate (option_msg && diag_msg) ? F_NORMAL : F_SILENT); 24917c478bd9Sstevel@tonic-gate 24927c478bd9Sstevel@tonic-gate if (status && option_msg) { 24937c478bd9Sstevel@tonic-gate err_print("Mode select page 0x%x failed\n", page_code); 24947c478bd9Sstevel@tonic-gate } 24957c478bd9Sstevel@tonic-gate 24967c478bd9Sstevel@tonic-gate free(mode_select_buf); 24977c478bd9Sstevel@tonic-gate return (status); 24987c478bd9Sstevel@tonic-gate } 24997c478bd9Sstevel@tonic-gate 25007c478bd9Sstevel@tonic-gate 25017c478bd9Sstevel@tonic-gate /* 25027c478bd9Sstevel@tonic-gate * Execute a uscsi inquiry command and return the 25037c478bd9Sstevel@tonic-gate * resulting data. 25047c478bd9Sstevel@tonic-gate */ 25057c478bd9Sstevel@tonic-gate int 25067c478bd9Sstevel@tonic-gate uscsi_inquiry(fd, inqbuf, inqbufsiz) 25077c478bd9Sstevel@tonic-gate int fd; 25087c478bd9Sstevel@tonic-gate caddr_t inqbuf; 25097c478bd9Sstevel@tonic-gate int inqbufsiz; 25107c478bd9Sstevel@tonic-gate { 25117c478bd9Sstevel@tonic-gate struct uscsi_cmd ucmd; 25127c478bd9Sstevel@tonic-gate union scsi_cdb cdb; 25137c478bd9Sstevel@tonic-gate struct scsi_inquiry *inq; 25147c478bd9Sstevel@tonic-gate int n; 25157c478bd9Sstevel@tonic-gate int status; 25167c478bd9Sstevel@tonic-gate 25177c478bd9Sstevel@tonic-gate assert(inqbufsiz >= sizeof (struct scsi_inquiry) && 25187c478bd9Sstevel@tonic-gate inqbufsiz < 256); 25197c478bd9Sstevel@tonic-gate 25207c478bd9Sstevel@tonic-gate /* 25217c478bd9Sstevel@tonic-gate * Build and execute the uscsi ioctl 25227c478bd9Sstevel@tonic-gate */ 25237c478bd9Sstevel@tonic-gate (void) memset((char *)inqbuf, 0, inqbufsiz); 25247c478bd9Sstevel@tonic-gate (void) memset((char *)&ucmd, 0, sizeof (ucmd)); 25257c478bd9Sstevel@tonic-gate (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb)); 25267c478bd9Sstevel@tonic-gate cdb.scc_cmd = SCMD_INQUIRY; 25277c478bd9Sstevel@tonic-gate FORMG0COUNT(&cdb, (uchar_t)inqbufsiz); 25287c478bd9Sstevel@tonic-gate ucmd.uscsi_cdb = (caddr_t)&cdb; 25297c478bd9Sstevel@tonic-gate ucmd.uscsi_cdblen = CDB_GROUP0; 25307c478bd9Sstevel@tonic-gate ucmd.uscsi_bufaddr = (caddr_t)inqbuf; 25317c478bd9Sstevel@tonic-gate ucmd.uscsi_buflen = inqbufsiz; 25327c478bd9Sstevel@tonic-gate status = uscsi_cmd(fd, &ucmd, 25337c478bd9Sstevel@tonic-gate (option_msg && diag_msg) ? F_NORMAL : F_SILENT); 25347c478bd9Sstevel@tonic-gate if (status) { 25357c478bd9Sstevel@tonic-gate if (option_msg) { 25367c478bd9Sstevel@tonic-gate err_print("Inquiry failed\n"); 25377c478bd9Sstevel@tonic-gate } 25387c478bd9Sstevel@tonic-gate } else if (option_msg && diag_msg) { 25397c478bd9Sstevel@tonic-gate /* 25407c478bd9Sstevel@tonic-gate * Dump the inquiry data if anyone's interested 25417c478bd9Sstevel@tonic-gate */ 25427c478bd9Sstevel@tonic-gate inq = (struct scsi_inquiry *)inqbuf; 25437c478bd9Sstevel@tonic-gate n = (int)inq->inq_len + 4; 25447c478bd9Sstevel@tonic-gate n = min(n, inqbufsiz); 25457c478bd9Sstevel@tonic-gate err_print("Inquiry:\n"); 25467c478bd9Sstevel@tonic-gate dump("", (caddr_t)inqbuf, n, HEX_ASCII); 25477c478bd9Sstevel@tonic-gate } 25487c478bd9Sstevel@tonic-gate return (status); 25497c478bd9Sstevel@tonic-gate } 25507c478bd9Sstevel@tonic-gate 25519ca9c420SSheng-Liang Eric Zhang /* 25529ca9c420SSheng-Liang Eric Zhang * Execute a uscsi inquiry command with page code 86h 25539ca9c420SSheng-Liang Eric Zhang */ 25549ca9c420SSheng-Liang Eric Zhang int 25559ca9c420SSheng-Liang Eric Zhang uscsi_inquiry_page_86h(fd, inqbuf, inqbufsiz) 25569ca9c420SSheng-Liang Eric Zhang int fd; 25579ca9c420SSheng-Liang Eric Zhang caddr_t inqbuf; 25589ca9c420SSheng-Liang Eric Zhang int inqbufsiz; 25599ca9c420SSheng-Liang Eric Zhang { 25609ca9c420SSheng-Liang Eric Zhang struct uscsi_cmd ucmd; 25619ca9c420SSheng-Liang Eric Zhang union scsi_cdb cdb; 25629ca9c420SSheng-Liang Eric Zhang int status; 25639ca9c420SSheng-Liang Eric Zhang 25649ca9c420SSheng-Liang Eric Zhang assert(inqbuf); 25659ca9c420SSheng-Liang Eric Zhang assert(inqbufsiz >= sizeof (struct scsi_inquiry) && 25669ca9c420SSheng-Liang Eric Zhang inqbufsiz < 256); 25679ca9c420SSheng-Liang Eric Zhang /* 25689ca9c420SSheng-Liang Eric Zhang * Build and execute uscsi ioctl 25699ca9c420SSheng-Liang Eric Zhang */ 25709ca9c420SSheng-Liang Eric Zhang (void) memset((char *)inqbuf, 0, inqbufsiz); 25719ca9c420SSheng-Liang Eric Zhang (void) memset((char *)&ucmd, 0, sizeof (ucmd)); 25729ca9c420SSheng-Liang Eric Zhang (void) memset((char *)&cdb, 0, sizeof (cdb)); 25739ca9c420SSheng-Liang Eric Zhang cdb.scc_cmd = SCMD_INQUIRY; 25749ca9c420SSheng-Liang Eric Zhang FORMG0COUNT(&cdb, (uchar_t)inqbufsiz); 25759ca9c420SSheng-Liang Eric Zhang cdb.cdb_opaque[1] |= 0x01; 25769ca9c420SSheng-Liang Eric Zhang cdb.cdb_opaque[2] = 0x86; 25779ca9c420SSheng-Liang Eric Zhang ucmd.uscsi_cdb = (caddr_t)&cdb; 25789ca9c420SSheng-Liang Eric Zhang ucmd.uscsi_cdblen = CDB_GROUP0; 25799ca9c420SSheng-Liang Eric Zhang ucmd.uscsi_bufaddr = (caddr_t)inqbuf; 25809ca9c420SSheng-Liang Eric Zhang ucmd.uscsi_buflen = inqbufsiz; 25819ca9c420SSheng-Liang Eric Zhang 25829ca9c420SSheng-Liang Eric Zhang status = uscsi_cmd(fd, &ucmd, 25839ca9c420SSheng-Liang Eric Zhang (option_msg && diag_msg) ? F_NORMAL : F_SILENT); 25849ca9c420SSheng-Liang Eric Zhang 25859ca9c420SSheng-Liang Eric Zhang if (status) { 25869ca9c420SSheng-Liang Eric Zhang if (option_msg) { 25879ca9c420SSheng-Liang Eric Zhang err_print("Inquriy with page_86h failed\n"); 25889ca9c420SSheng-Liang Eric Zhang } 25899ca9c420SSheng-Liang Eric Zhang } 25909ca9c420SSheng-Liang Eric Zhang return (status); 25919ca9c420SSheng-Liang Eric Zhang } 25927c478bd9Sstevel@tonic-gate 25937c478bd9Sstevel@tonic-gate /* 25947c478bd9Sstevel@tonic-gate * Return the Read Capacity information 25957c478bd9Sstevel@tonic-gate */ 25967c478bd9Sstevel@tonic-gate int 25979ca9c420SSheng-Liang Eric Zhang uscsi_read_capacity_16(fd, capacity) 25989ca9c420SSheng-Liang Eric Zhang int fd; 25999ca9c420SSheng-Liang Eric Zhang struct scsi_capacity_16 *capacity; 26009ca9c420SSheng-Liang Eric Zhang { 26019ca9c420SSheng-Liang Eric Zhang struct uscsi_cmd ucmd; 26029ca9c420SSheng-Liang Eric Zhang union scsi_cdb cdb; 26039ca9c420SSheng-Liang Eric Zhang int status; 26049ca9c420SSheng-Liang Eric Zhang 26059ca9c420SSheng-Liang Eric Zhang (void) memset((char *)capacity, 0, sizeof (struct scsi_capacity_16)); 26069ca9c420SSheng-Liang Eric Zhang (void) memset((char *)&ucmd, 0, sizeof (ucmd)); 26079ca9c420SSheng-Liang Eric Zhang (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb)); 26089ca9c420SSheng-Liang Eric Zhang 26099ca9c420SSheng-Liang Eric Zhang ucmd.uscsi_cdb = (caddr_t)&cdb; 26109ca9c420SSheng-Liang Eric Zhang ucmd.uscsi_cdblen = CDB_GROUP4; 26119ca9c420SSheng-Liang Eric Zhang ucmd.uscsi_bufaddr = (caddr_t)capacity; 26129ca9c420SSheng-Liang Eric Zhang ucmd.uscsi_buflen = sizeof (struct scsi_capacity_16); 26139ca9c420SSheng-Liang Eric Zhang 26149ca9c420SSheng-Liang Eric Zhang /* 26159ca9c420SSheng-Liang Eric Zhang * Read Capacity (16) is a Service Action In command. One 26169ca9c420SSheng-Liang Eric Zhang * command byte (0x9E) is overloaded for multiple operations, 26179ca9c420SSheng-Liang Eric Zhang * with the second CDB byte specifying the desired operation 26189ca9c420SSheng-Liang Eric Zhang */ 26199ca9c420SSheng-Liang Eric Zhang cdb.scc_cmd = SCMD_SVC_ACTION_IN_G4; 26209ca9c420SSheng-Liang Eric Zhang cdb.cdb_opaque[1] = SSVC_ACTION_READ_CAPACITY_G4; 26219ca9c420SSheng-Liang Eric Zhang 26229ca9c420SSheng-Liang Eric Zhang /* 26239ca9c420SSheng-Liang Eric Zhang * Fill in allocation length field 26249ca9c420SSheng-Liang Eric Zhang */ 26259ca9c420SSheng-Liang Eric Zhang cdb.cdb_opaque[10] = 26269ca9c420SSheng-Liang Eric Zhang (uchar_t)((ucmd.uscsi_buflen & 0xff000000) >> 24); 26279ca9c420SSheng-Liang Eric Zhang cdb.cdb_opaque[11] = 26289ca9c420SSheng-Liang Eric Zhang (uchar_t)((ucmd.uscsi_buflen & 0x00ff0000) >> 16); 26299ca9c420SSheng-Liang Eric Zhang cdb.cdb_opaque[12] = 26309ca9c420SSheng-Liang Eric Zhang (uchar_t)((ucmd.uscsi_buflen & 0x0000ff00) >> 8); 26319ca9c420SSheng-Liang Eric Zhang cdb.cdb_opaque[13] = 26329ca9c420SSheng-Liang Eric Zhang (uchar_t)(ucmd.uscsi_buflen & 0x000000ff); 26339ca9c420SSheng-Liang Eric Zhang 26349ca9c420SSheng-Liang Eric Zhang status = uscsi_cmd(fd, &ucmd, 26359ca9c420SSheng-Liang Eric Zhang (option_msg && diag_msg) ? F_NORMAL : F_SILENT); 26369ca9c420SSheng-Liang Eric Zhang 26379ca9c420SSheng-Liang Eric Zhang if (status) { 26389ca9c420SSheng-Liang Eric Zhang if (option_msg) { 26399ca9c420SSheng-Liang Eric Zhang err_print("Read capacity 16 failed\n"); 26409ca9c420SSheng-Liang Eric Zhang } 26419ca9c420SSheng-Liang Eric Zhang } else if (option_msg && diag_msg) { 26429ca9c420SSheng-Liang Eric Zhang /* 26439ca9c420SSheng-Liang Eric Zhang * Dump the capacity data if anyone's interested 26449ca9c420SSheng-Liang Eric Zhang */ 26459ca9c420SSheng-Liang Eric Zhang dump("Capacity: ", (caddr_t)capacity, 26469ca9c420SSheng-Liang Eric Zhang sizeof (struct scsi_capacity_16), HEX_ONLY); 26479ca9c420SSheng-Liang Eric Zhang } 26489ca9c420SSheng-Liang Eric Zhang 26499ca9c420SSheng-Liang Eric Zhang capacity->sc_capacity = BE_64(capacity->sc_capacity); 26509ca9c420SSheng-Liang Eric Zhang capacity->sc_lbasize = BE_32(capacity->sc_lbasize); 26519ca9c420SSheng-Liang Eric Zhang 26529ca9c420SSheng-Liang Eric Zhang return (status); 26539ca9c420SSheng-Liang Eric Zhang } 26549ca9c420SSheng-Liang Eric Zhang 26559ca9c420SSheng-Liang Eric Zhang int 26567c478bd9Sstevel@tonic-gate uscsi_read_capacity(fd, capacity) 26577c478bd9Sstevel@tonic-gate int fd; 26587c478bd9Sstevel@tonic-gate struct scsi_capacity_16 *capacity; 26597c478bd9Sstevel@tonic-gate { 26607c478bd9Sstevel@tonic-gate struct uscsi_cmd ucmd; 26617c478bd9Sstevel@tonic-gate union scsi_cdb cdb; 26627c478bd9Sstevel@tonic-gate int status; 26637c478bd9Sstevel@tonic-gate struct scsi_capacity cap_old; 26647c478bd9Sstevel@tonic-gate 26657c478bd9Sstevel@tonic-gate /* 26667c478bd9Sstevel@tonic-gate * Build and execute the uscsi ioctl 26677c478bd9Sstevel@tonic-gate */ 26687c478bd9Sstevel@tonic-gate (void) memset((char *)capacity, 0, sizeof (struct scsi_capacity_16)); 26697c478bd9Sstevel@tonic-gate (void) memset((char *)&cap_old, 0, sizeof (struct scsi_capacity)); 26707c478bd9Sstevel@tonic-gate (void) memset((char *)&ucmd, 0, sizeof (ucmd)); 26717c478bd9Sstevel@tonic-gate (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb)); 26727c478bd9Sstevel@tonic-gate cdb.scc_cmd = SCMD_READ_CAPACITY; 26737c478bd9Sstevel@tonic-gate ucmd.uscsi_cdb = (caddr_t)&cdb; 26747c478bd9Sstevel@tonic-gate ucmd.uscsi_cdblen = CDB_GROUP1; 26757c478bd9Sstevel@tonic-gate ucmd.uscsi_bufaddr = (caddr_t)&cap_old; 26767c478bd9Sstevel@tonic-gate ucmd.uscsi_buflen = sizeof (struct scsi_capacity); 26777c478bd9Sstevel@tonic-gate status = uscsi_cmd(fd, &ucmd, 26787c478bd9Sstevel@tonic-gate (option_msg && diag_msg) ? F_NORMAL : F_SILENT); 26797c478bd9Sstevel@tonic-gate 26807c478bd9Sstevel@tonic-gate if (cap_old.capacity == UINT_MAX32) { 26817c478bd9Sstevel@tonic-gate /* 26827c478bd9Sstevel@tonic-gate * A capacity of 0xffffffff in response to a 26837c478bd9Sstevel@tonic-gate * READ CAPACITY 10 indicates that the lun 26847c478bd9Sstevel@tonic-gate * is too large to report the size in a 32 bit 26857c478bd9Sstevel@tonic-gate * value, and a READ CAPACITY 16 is required 26867c478bd9Sstevel@tonic-gate * to get the correct size. 26877c478bd9Sstevel@tonic-gate */ 26887c478bd9Sstevel@tonic-gate (void) memset((char *)&ucmd, 0, sizeof (ucmd)); 26897c478bd9Sstevel@tonic-gate (void) memset((char *)&cdb, 0, 26907c478bd9Sstevel@tonic-gate sizeof (union scsi_cdb)); 26917c478bd9Sstevel@tonic-gate 26927c478bd9Sstevel@tonic-gate ucmd.uscsi_cdb = (caddr_t)&cdb; 26937c478bd9Sstevel@tonic-gate ucmd.uscsi_cdblen = CDB_GROUP4; 26947c478bd9Sstevel@tonic-gate ucmd.uscsi_bufaddr = (caddr_t)capacity; 26957c478bd9Sstevel@tonic-gate ucmd.uscsi_buflen = sizeof (struct scsi_capacity_16); 26967c478bd9Sstevel@tonic-gate 26977c478bd9Sstevel@tonic-gate /* 26987c478bd9Sstevel@tonic-gate * Read Capacity (16) is a Service Action In command. One 26997c478bd9Sstevel@tonic-gate * command byte (0x9E) is overloaded for multiple operations, 27007c478bd9Sstevel@tonic-gate * with the second CDB byte specifying the desired operation 27017c478bd9Sstevel@tonic-gate */ 27027c478bd9Sstevel@tonic-gate cdb.scc_cmd = SCMD_SVC_ACTION_IN_G4; 27037c478bd9Sstevel@tonic-gate cdb.cdb_opaque[1] = SSVC_ACTION_READ_CAPACITY_G4; 27047c478bd9Sstevel@tonic-gate 27057c478bd9Sstevel@tonic-gate /* 27067c478bd9Sstevel@tonic-gate * Fill in allocation length field 27077c478bd9Sstevel@tonic-gate */ 27087c478bd9Sstevel@tonic-gate cdb.cdb_opaque[10] = 27097c478bd9Sstevel@tonic-gate (uchar_t)((ucmd.uscsi_buflen & 0xff000000) >> 24); 27107c478bd9Sstevel@tonic-gate cdb.cdb_opaque[11] = 27117c478bd9Sstevel@tonic-gate (uchar_t)((ucmd.uscsi_buflen & 0x00ff0000) >> 16); 27127c478bd9Sstevel@tonic-gate cdb.cdb_opaque[12] = 27137c478bd9Sstevel@tonic-gate (uchar_t)((ucmd.uscsi_buflen & 0x0000ff00) >> 8); 27147c478bd9Sstevel@tonic-gate cdb.cdb_opaque[13] = 27157c478bd9Sstevel@tonic-gate (uchar_t)(ucmd.uscsi_buflen & 0x000000ff); 27167c478bd9Sstevel@tonic-gate 27177c478bd9Sstevel@tonic-gate status = uscsi_cmd(fd, &ucmd, 27187c478bd9Sstevel@tonic-gate (option_msg && diag_msg) ? F_NORMAL : F_SILENT); 27197c478bd9Sstevel@tonic-gate } 27207c478bd9Sstevel@tonic-gate 27217c478bd9Sstevel@tonic-gate if (status) { 27227c478bd9Sstevel@tonic-gate if (option_msg) { 27237c478bd9Sstevel@tonic-gate /* 27247c478bd9Sstevel@tonic-gate * Indicate which of the commands failed 27257c478bd9Sstevel@tonic-gate */ 27267c478bd9Sstevel@tonic-gate if (cdb.scc_cmd == SCMD_READ_CAPACITY) { 27277c478bd9Sstevel@tonic-gate err_print("Read capacity failed\n"); 27287c478bd9Sstevel@tonic-gate } else { 27297c478bd9Sstevel@tonic-gate err_print("Read capacity 16 failed\n"); 27307c478bd9Sstevel@tonic-gate } 27317c478bd9Sstevel@tonic-gate } 27327c478bd9Sstevel@tonic-gate } else if (option_msg && diag_msg) { 27337c478bd9Sstevel@tonic-gate /* 27347c478bd9Sstevel@tonic-gate * Dump the capacity data if anyone's interested 27357c478bd9Sstevel@tonic-gate */ 27368007dbcdSlh195018 if (cap_old.capacity == UINT_MAX32) { 27377c478bd9Sstevel@tonic-gate dump("Capacity: ", (caddr_t)capacity, 27387c478bd9Sstevel@tonic-gate sizeof (struct scsi_capacity_16), HEX_ONLY); 27398007dbcdSlh195018 } else { 27408007dbcdSlh195018 dump("Capacity: ", (caddr_t)&cap_old, 27418007dbcdSlh195018 sizeof (struct scsi_capacity), HEX_ONLY); 27427c478bd9Sstevel@tonic-gate } 27438007dbcdSlh195018 } 27448007dbcdSlh195018 27458007dbcdSlh195018 if (cap_old.capacity == UINT_MAX32) { 27468007dbcdSlh195018 capacity->sc_capacity = BE_64(capacity->sc_capacity); 27478007dbcdSlh195018 capacity->sc_lbasize = BE_32(capacity->sc_lbasize); 27488007dbcdSlh195018 } else { 27498007dbcdSlh195018 capacity->sc_capacity = (uint64_t)BE_32(cap_old.capacity); 27508007dbcdSlh195018 capacity->sc_lbasize = BE_32(cap_old.lbasize); 27518007dbcdSlh195018 } 27528007dbcdSlh195018 27537c478bd9Sstevel@tonic-gate return (status); 27547c478bd9Sstevel@tonic-gate } 27557c478bd9Sstevel@tonic-gate 27567c478bd9Sstevel@tonic-gate 27577c478bd9Sstevel@tonic-gate /* 27587c478bd9Sstevel@tonic-gate * Reserve the current disk 27597c478bd9Sstevel@tonic-gate */ 27607c478bd9Sstevel@tonic-gate static int 27617c478bd9Sstevel@tonic-gate uscsi_reserve_release(int fd, int cmd) 27627c478bd9Sstevel@tonic-gate { 27637c478bd9Sstevel@tonic-gate int status = 0; 27647c478bd9Sstevel@tonic-gate #ifdef sparc 27657c478bd9Sstevel@tonic-gate struct uscsi_cmd ucmd; 27667c478bd9Sstevel@tonic-gate union scsi_cdb cdb; 27677c478bd9Sstevel@tonic-gate 27687c478bd9Sstevel@tonic-gate /* 27697c478bd9Sstevel@tonic-gate * Build and execute the uscsi ioctl 27707c478bd9Sstevel@tonic-gate */ 27717c478bd9Sstevel@tonic-gate (void) memset((char *)&ucmd, 0, sizeof (ucmd)); 27727c478bd9Sstevel@tonic-gate (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb)); 27737c478bd9Sstevel@tonic-gate cdb.scc_cmd = (cmd == SCMD_RESERVE) ? SCMD_RESERVE : SCMD_RELEASE; 27747c478bd9Sstevel@tonic-gate ucmd.uscsi_cdb = (caddr_t)&cdb; 27757c478bd9Sstevel@tonic-gate ucmd.uscsi_cdblen = CDB_GROUP0; 27767c478bd9Sstevel@tonic-gate status = uscsi_cmd(fd, &ucmd, 27777c478bd9Sstevel@tonic-gate (option_msg && diag_msg) ? F_NORMAL : F_SILENT); 27787c478bd9Sstevel@tonic-gate 27797c478bd9Sstevel@tonic-gate if (status) { 27807c478bd9Sstevel@tonic-gate /* 27817c478bd9Sstevel@tonic-gate * Reserve/Release(6) failed. 27827c478bd9Sstevel@tonic-gate * Try Reserve/Release(10) , if it succeeds then 27837c478bd9Sstevel@tonic-gate * return success. 27847c478bd9Sstevel@tonic-gate */ 27857c478bd9Sstevel@tonic-gate (void) memset((char *)&ucmd, 0, sizeof (ucmd)); 27867c478bd9Sstevel@tonic-gate (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb)); 27877c478bd9Sstevel@tonic-gate ucmd.uscsi_cdb = (caddr_t)&cdb; 27887c478bd9Sstevel@tonic-gate cdb.scc_cmd = (cmd == SCMD_RESERVE) ? 27897c478bd9Sstevel@tonic-gate SCMD_RESERVE_G1 : SCMD_RELEASE_G1; 27907c478bd9Sstevel@tonic-gate ucmd.uscsi_cdblen = CDB_GROUP1; 27917c478bd9Sstevel@tonic-gate status = uscsi_cmd(fd, &ucmd, 27927c478bd9Sstevel@tonic-gate (option_msg && diag_msg) ? F_NORMAL : F_SILENT); 27937c478bd9Sstevel@tonic-gate if (status) { 27947c478bd9Sstevel@tonic-gate if (option_msg) { 27957c478bd9Sstevel@tonic-gate err_print("%s failed\n", (cmd == SCMD_RESERVE) ? 27967c478bd9Sstevel@tonic-gate "Reserve" : "Release"); 27977c478bd9Sstevel@tonic-gate } 27987c478bd9Sstevel@tonic-gate } 27997c478bd9Sstevel@tonic-gate } 28007c478bd9Sstevel@tonic-gate #else /* not sparc */ 28017c478bd9Sstevel@tonic-gate 28027c478bd9Sstevel@tonic-gate #ifdef lint 28037c478bd9Sstevel@tonic-gate fd = fd; 28047c478bd9Sstevel@tonic-gate cmd = cmd; 28057c478bd9Sstevel@tonic-gate #endif /* lint */ 28067c478bd9Sstevel@tonic-gate 28077c478bd9Sstevel@tonic-gate #endif /* not sparc */ 28087c478bd9Sstevel@tonic-gate 28097c478bd9Sstevel@tonic-gate return (status); 28107c478bd9Sstevel@tonic-gate } 28117c478bd9Sstevel@tonic-gate 28127c478bd9Sstevel@tonic-gate int 28137c478bd9Sstevel@tonic-gate scsi_dump_mode_sense_pages(page_control) 28147c478bd9Sstevel@tonic-gate int page_control; 28157c478bd9Sstevel@tonic-gate { 28167c478bd9Sstevel@tonic-gate struct uscsi_cmd ucmd; 28177c478bd9Sstevel@tonic-gate union scsi_cdb cdb; 28187c478bd9Sstevel@tonic-gate char *msbuf; 28197c478bd9Sstevel@tonic-gate int nbytes; 28207c478bd9Sstevel@tonic-gate char *pc_str; 28217c478bd9Sstevel@tonic-gate int status; 28227c478bd9Sstevel@tonic-gate struct mode_header *mh; 28237c478bd9Sstevel@tonic-gate char *p; 28247c478bd9Sstevel@tonic-gate struct mode_page *mp; 28257c478bd9Sstevel@tonic-gate int n; 28267c478bd9Sstevel@tonic-gate char s[16]; 28277c478bd9Sstevel@tonic-gate int result = 0; 28287c478bd9Sstevel@tonic-gate 28297c478bd9Sstevel@tonic-gate pc_str = find_string(page_control_strings, page_control); 28307c478bd9Sstevel@tonic-gate 28317c478bd9Sstevel@tonic-gate /* 28327c478bd9Sstevel@tonic-gate * Allocate memory for the mode sense buffer. 28337c478bd9Sstevel@tonic-gate */ 28347c478bd9Sstevel@tonic-gate nbytes = 255; 28357c478bd9Sstevel@tonic-gate msbuf = (char *)zalloc(nbytes); 28367c478bd9Sstevel@tonic-gate 28377c478bd9Sstevel@tonic-gate /* 28387c478bd9Sstevel@tonic-gate * Build and execute the uscsi ioctl 28397c478bd9Sstevel@tonic-gate */ 28407c478bd9Sstevel@tonic-gate (void) memset(msbuf, 0, nbytes); 28417c478bd9Sstevel@tonic-gate (void) memset((char *)&ucmd, 0, sizeof (ucmd)); 28427c478bd9Sstevel@tonic-gate (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb)); 28437c478bd9Sstevel@tonic-gate cdb.scc_cmd = SCMD_MODE_SENSE; 28447c478bd9Sstevel@tonic-gate FORMG0COUNT(&cdb, (uchar_t)nbytes); 28457c478bd9Sstevel@tonic-gate cdb.cdb_opaque[2] = page_control | 0x3f; 28467c478bd9Sstevel@tonic-gate ucmd.uscsi_cdb = (caddr_t)&cdb; 28477c478bd9Sstevel@tonic-gate ucmd.uscsi_cdblen = CDB_GROUP0; 28487c478bd9Sstevel@tonic-gate ucmd.uscsi_bufaddr = msbuf; 28497c478bd9Sstevel@tonic-gate ucmd.uscsi_buflen = nbytes; 28507c478bd9Sstevel@tonic-gate status = uscsi_cmd(cur_file, &ucmd, 28517c478bd9Sstevel@tonic-gate (option_msg && diag_msg) ? F_NORMAL : F_SILENT); 28527c478bd9Sstevel@tonic-gate if (status) { 28537c478bd9Sstevel@tonic-gate err_print("\nMode sense page 0x3f (%s) failed\n", 28547c478bd9Sstevel@tonic-gate pc_str); 28557c478bd9Sstevel@tonic-gate result = 1; 28567c478bd9Sstevel@tonic-gate } else { 28577c478bd9Sstevel@tonic-gate err_print("\nMode sense pages (%s):\n", pc_str); 28587c478bd9Sstevel@tonic-gate mh = (struct mode_header *)msbuf; 28597c478bd9Sstevel@tonic-gate nbytes = mh->length - sizeof (struct mode_header) - 28607c478bd9Sstevel@tonic-gate mh->bdesc_length + 1; 28617c478bd9Sstevel@tonic-gate p = msbuf + sizeof (struct mode_header) + 28627c478bd9Sstevel@tonic-gate mh->bdesc_length; 28637c478bd9Sstevel@tonic-gate dump(" ", msbuf, sizeof (struct mode_header) + 28647c478bd9Sstevel@tonic-gate (int)mh->bdesc_length, HEX_ONLY); 28657c478bd9Sstevel@tonic-gate while (nbytes > 0) { 28667c478bd9Sstevel@tonic-gate mp = (struct mode_page *)p; 28677c478bd9Sstevel@tonic-gate n = mp->length + sizeof (struct mode_page); 28687c478bd9Sstevel@tonic-gate nbytes -= n; 28697c478bd9Sstevel@tonic-gate if (nbytes < 0) 28707c478bd9Sstevel@tonic-gate break; 28717c478bd9Sstevel@tonic-gate (void) sprintf(s, " %3x: ", mp->code); 28727c478bd9Sstevel@tonic-gate dump(s, p, n, HEX_ONLY); 28737c478bd9Sstevel@tonic-gate p += n; 28747c478bd9Sstevel@tonic-gate } 28757c478bd9Sstevel@tonic-gate if (nbytes < 0) { 28767c478bd9Sstevel@tonic-gate err_print(" Sense data formatted incorrectly:\n"); 28777c478bd9Sstevel@tonic-gate dump(" ", msbuf, (int)mh->length+1, HEX_ONLY); 28787c478bd9Sstevel@tonic-gate result = 1; 28797c478bd9Sstevel@tonic-gate } 28807c478bd9Sstevel@tonic-gate err_print("\n"); 28817c478bd9Sstevel@tonic-gate } 28827c478bd9Sstevel@tonic-gate 28837c478bd9Sstevel@tonic-gate free(msbuf); 28847c478bd9Sstevel@tonic-gate return (result); 28857c478bd9Sstevel@tonic-gate } 28867c478bd9Sstevel@tonic-gate 28877c478bd9Sstevel@tonic-gate 28887c478bd9Sstevel@tonic-gate static void 28897c478bd9Sstevel@tonic-gate scsi_printerr(ucmd, rq, rqlen) 28907c478bd9Sstevel@tonic-gate struct uscsi_cmd *ucmd; 28917c478bd9Sstevel@tonic-gate struct scsi_extended_sense *rq; 28927c478bd9Sstevel@tonic-gate int rqlen; 28937c478bd9Sstevel@tonic-gate { 28947c478bd9Sstevel@tonic-gate diskaddr_t blkno; 28957c478bd9Sstevel@tonic-gate struct scsi_descr_sense_hdr *sdsp = 28967c478bd9Sstevel@tonic-gate (struct scsi_descr_sense_hdr *)rq; 28977c478bd9Sstevel@tonic-gate 28987c478bd9Sstevel@tonic-gate switch (rq->es_key) { 28997c478bd9Sstevel@tonic-gate case KEY_NO_SENSE: 29007c478bd9Sstevel@tonic-gate err_print("No sense error"); 29017c478bd9Sstevel@tonic-gate break; 29027c478bd9Sstevel@tonic-gate case KEY_RECOVERABLE_ERROR: 29037c478bd9Sstevel@tonic-gate err_print("Recoverable error"); 29047c478bd9Sstevel@tonic-gate break; 29057c478bd9Sstevel@tonic-gate case KEY_NOT_READY: 29067c478bd9Sstevel@tonic-gate err_print("Not ready error"); 29077c478bd9Sstevel@tonic-gate break; 29087c478bd9Sstevel@tonic-gate case KEY_MEDIUM_ERROR: 29097c478bd9Sstevel@tonic-gate err_print("Medium error"); 29107c478bd9Sstevel@tonic-gate break; 29117c478bd9Sstevel@tonic-gate case KEY_HARDWARE_ERROR: 29127c478bd9Sstevel@tonic-gate err_print("Hardware error"); 29137c478bd9Sstevel@tonic-gate break; 29147c478bd9Sstevel@tonic-gate case KEY_ILLEGAL_REQUEST: 29157c478bd9Sstevel@tonic-gate err_print("Illegal request"); 29167c478bd9Sstevel@tonic-gate break; 29177c478bd9Sstevel@tonic-gate case KEY_UNIT_ATTENTION: 29187c478bd9Sstevel@tonic-gate err_print("Unit attention error"); 29197c478bd9Sstevel@tonic-gate break; 29207c478bd9Sstevel@tonic-gate case KEY_WRITE_PROTECT: 29217c478bd9Sstevel@tonic-gate err_print("Write protect error"); 29227c478bd9Sstevel@tonic-gate break; 29237c478bd9Sstevel@tonic-gate case KEY_BLANK_CHECK: 29247c478bd9Sstevel@tonic-gate err_print("Blank check error"); 29257c478bd9Sstevel@tonic-gate break; 29267c478bd9Sstevel@tonic-gate case KEY_VENDOR_UNIQUE: 29277c478bd9Sstevel@tonic-gate err_print("Vendor unique error"); 29287c478bd9Sstevel@tonic-gate break; 29297c478bd9Sstevel@tonic-gate case KEY_COPY_ABORTED: 29307c478bd9Sstevel@tonic-gate err_print("Copy aborted error"); 29317c478bd9Sstevel@tonic-gate break; 29327c478bd9Sstevel@tonic-gate case KEY_ABORTED_COMMAND: 29337c478bd9Sstevel@tonic-gate err_print("Aborted command"); 29347c478bd9Sstevel@tonic-gate break; 29357c478bd9Sstevel@tonic-gate case KEY_EQUAL: 29367c478bd9Sstevel@tonic-gate err_print("Equal error"); 29377c478bd9Sstevel@tonic-gate break; 29387c478bd9Sstevel@tonic-gate case KEY_VOLUME_OVERFLOW: 29397c478bd9Sstevel@tonic-gate err_print("Volume overflow"); 29407c478bd9Sstevel@tonic-gate break; 29417c478bd9Sstevel@tonic-gate case KEY_MISCOMPARE: 29427c478bd9Sstevel@tonic-gate err_print("Miscompare error"); 29437c478bd9Sstevel@tonic-gate break; 29447c478bd9Sstevel@tonic-gate case KEY_RESERVED: 29457c478bd9Sstevel@tonic-gate err_print("Reserved error"); 29467c478bd9Sstevel@tonic-gate break; 29477c478bd9Sstevel@tonic-gate default: 29487c478bd9Sstevel@tonic-gate err_print("Unknown error"); 29497c478bd9Sstevel@tonic-gate break; 29507c478bd9Sstevel@tonic-gate } 29517c478bd9Sstevel@tonic-gate 29527c478bd9Sstevel@tonic-gate err_print(" during %s", scsi_find_command_name(ucmd->uscsi_cdb[0])); 29537c478bd9Sstevel@tonic-gate 29547c478bd9Sstevel@tonic-gate /* 29557c478bd9Sstevel@tonic-gate * Get asc, ascq and info field from sense data. There are two 29567c478bd9Sstevel@tonic-gate * possible formats (fixed sense data and descriptor sense data) 29577c478bd9Sstevel@tonic-gate * depending on the value of es_code. 29587c478bd9Sstevel@tonic-gate */ 29597c478bd9Sstevel@tonic-gate switch (rq->es_code) { 29607c478bd9Sstevel@tonic-gate case CODE_FMT_DESCR_CURRENT: 29617c478bd9Sstevel@tonic-gate case CODE_FMT_DESCR_DEFERRED: 29627c478bd9Sstevel@tonic-gate blkno = 29637c478bd9Sstevel@tonic-gate (diskaddr_t)scsi_extract_sense_info_descr(sdsp, rqlen); 29647c478bd9Sstevel@tonic-gate if (blkno != (diskaddr_t)-1) { 29657c478bd9Sstevel@tonic-gate err_print(": block %lld (0x%llx) (", blkno, blkno); 29667c478bd9Sstevel@tonic-gate pr_dblock(err_print, blkno); 29677c478bd9Sstevel@tonic-gate err_print(")"); 29687c478bd9Sstevel@tonic-gate } 29697c478bd9Sstevel@tonic-gate 29707c478bd9Sstevel@tonic-gate err_print("\n"); 29717c478bd9Sstevel@tonic-gate 29727c478bd9Sstevel@tonic-gate err_print("ASC: 0x%x ASCQ: 0x%x\n", 29737c478bd9Sstevel@tonic-gate sdsp->ds_add_code, sdsp->ds_qual_code); 29747c478bd9Sstevel@tonic-gate break; 29757c478bd9Sstevel@tonic-gate case CODE_FMT_FIXED_CURRENT: 29767c478bd9Sstevel@tonic-gate case CODE_FMT_FIXED_DEFERRED: 29777c478bd9Sstevel@tonic-gate default: 29787c478bd9Sstevel@tonic-gate if (rq->es_valid) { 29797c478bd9Sstevel@tonic-gate blkno = (rq->es_info_1 << 24) | 29807c478bd9Sstevel@tonic-gate (rq->es_info_2 << 16) | 29817c478bd9Sstevel@tonic-gate (rq->es_info_3 << 8) | rq->es_info_4; 29827c478bd9Sstevel@tonic-gate err_print(": block %lld (0x%llx) (", blkno, blkno); 29837c478bd9Sstevel@tonic-gate pr_dblock(err_print, blkno); 29847c478bd9Sstevel@tonic-gate err_print(")"); 29857c478bd9Sstevel@tonic-gate } 29867c478bd9Sstevel@tonic-gate 29877c478bd9Sstevel@tonic-gate err_print("\n"); 29887c478bd9Sstevel@tonic-gate 29897c478bd9Sstevel@tonic-gate if (rq->es_add_len >= 6) { 29907c478bd9Sstevel@tonic-gate err_print("ASC: 0x%x ASCQ: 0x%x\n", 29917c478bd9Sstevel@tonic-gate rq->es_add_code, rq->es_qual_code); 29927c478bd9Sstevel@tonic-gate } 29937c478bd9Sstevel@tonic-gate break; 29947c478bd9Sstevel@tonic-gate } 29957c478bd9Sstevel@tonic-gate 29967c478bd9Sstevel@tonic-gate if (option_msg && diag_msg) { 29977c478bd9Sstevel@tonic-gate if (rq->es_key == KEY_ILLEGAL_REQUEST) { 29987c478bd9Sstevel@tonic-gate dump("cmd: ", (caddr_t)ucmd, 29997c478bd9Sstevel@tonic-gate sizeof (struct uscsi_cmd), HEX_ONLY); 30007c478bd9Sstevel@tonic-gate dump("cdb: ", (caddr_t)ucmd->uscsi_cdb, 30017c478bd9Sstevel@tonic-gate ucmd->uscsi_cdblen, HEX_ONLY); 30027c478bd9Sstevel@tonic-gate } 30037c478bd9Sstevel@tonic-gate dump("sense: ", (caddr_t)rq, rqlen, HEX_ONLY); 30047c478bd9Sstevel@tonic-gate } 30057c478bd9Sstevel@tonic-gate 30067c478bd9Sstevel@tonic-gate if (option_msg) { 30077c478bd9Sstevel@tonic-gate switch (rq->es_code) { 30087c478bd9Sstevel@tonic-gate case CODE_FMT_DESCR_CURRENT: 30097c478bd9Sstevel@tonic-gate case CODE_FMT_DESCR_DEFERRED: 30107c478bd9Sstevel@tonic-gate scsi_print_descr_sense(sdsp, rqlen); 30117c478bd9Sstevel@tonic-gate break; 30127c478bd9Sstevel@tonic-gate case CODE_FMT_FIXED_CURRENT: 30137c478bd9Sstevel@tonic-gate case CODE_FMT_FIXED_DEFERRED: 30147c478bd9Sstevel@tonic-gate default: 30157c478bd9Sstevel@tonic-gate scsi_print_extended_sense(rq, rqlen); 30167c478bd9Sstevel@tonic-gate break; 30177c478bd9Sstevel@tonic-gate } 30187c478bd9Sstevel@tonic-gate } 30197c478bd9Sstevel@tonic-gate } 30207c478bd9Sstevel@tonic-gate 30217c478bd9Sstevel@tonic-gate /* 30227c478bd9Sstevel@tonic-gate * Retrieve "information" field from descriptor format 30237c478bd9Sstevel@tonic-gate * sense data. Iterates through each sense descriptor 30247c478bd9Sstevel@tonic-gate * looking for the information descriptor and returns 30257c478bd9Sstevel@tonic-gate * the information field from that descriptor. 30267c478bd9Sstevel@tonic-gate */ 30277c478bd9Sstevel@tonic-gate static diskaddr_t 30287c478bd9Sstevel@tonic-gate scsi_extract_sense_info_descr(struct scsi_descr_sense_hdr *sdsp, int rqlen) 30297c478bd9Sstevel@tonic-gate { 30307c478bd9Sstevel@tonic-gate diskaddr_t result; 30317c478bd9Sstevel@tonic-gate uint8_t *descr_offset; 30327c478bd9Sstevel@tonic-gate int valid_sense_length; 30337c478bd9Sstevel@tonic-gate struct scsi_information_sense_descr *isd; 30347c478bd9Sstevel@tonic-gate 30357c478bd9Sstevel@tonic-gate /* 30367c478bd9Sstevel@tonic-gate * Initialize result to -1 indicating there is no information 30377c478bd9Sstevel@tonic-gate * descriptor 30387c478bd9Sstevel@tonic-gate */ 30397c478bd9Sstevel@tonic-gate result = (diskaddr_t)-1; 30407c478bd9Sstevel@tonic-gate 30417c478bd9Sstevel@tonic-gate /* 30427c478bd9Sstevel@tonic-gate * The first descriptor will immediately follow the header 30437c478bd9Sstevel@tonic-gate */ 30447c478bd9Sstevel@tonic-gate descr_offset = (uint8_t *)(sdsp+1); /* Pointer arithmetic */ 30457c478bd9Sstevel@tonic-gate 30467c478bd9Sstevel@tonic-gate /* 30477c478bd9Sstevel@tonic-gate * Calculate the amount of valid sense data 30487c478bd9Sstevel@tonic-gate */ 30497c478bd9Sstevel@tonic-gate valid_sense_length = 30507c478bd9Sstevel@tonic-gate min((sizeof (struct scsi_descr_sense_hdr) + 30517c478bd9Sstevel@tonic-gate sdsp->ds_addl_sense_length), 30527c478bd9Sstevel@tonic-gate rqlen); 30537c478bd9Sstevel@tonic-gate 30547c478bd9Sstevel@tonic-gate /* 30557c478bd9Sstevel@tonic-gate * Iterate through the list of descriptors, stopping when we 30567c478bd9Sstevel@tonic-gate * run out of sense data 30577c478bd9Sstevel@tonic-gate */ 30587c478bd9Sstevel@tonic-gate while ((descr_offset + sizeof (struct scsi_information_sense_descr)) <= 30597c478bd9Sstevel@tonic-gate (uint8_t *)sdsp + valid_sense_length) { 30607c478bd9Sstevel@tonic-gate /* 30617c478bd9Sstevel@tonic-gate * Check if this is an information descriptor. We can 30627c478bd9Sstevel@tonic-gate * use the scsi_information_sense_descr structure as a 30637c478bd9Sstevel@tonic-gate * template sense the first two fields are always the 30647c478bd9Sstevel@tonic-gate * same 30657c478bd9Sstevel@tonic-gate */ 30667c478bd9Sstevel@tonic-gate isd = (struct scsi_information_sense_descr *)descr_offset; 30677c478bd9Sstevel@tonic-gate if (isd->isd_descr_type == DESCR_INFORMATION) { 30687c478bd9Sstevel@tonic-gate /* 30697c478bd9Sstevel@tonic-gate * Found an information descriptor. Copy the 30707c478bd9Sstevel@tonic-gate * information field. There will only be one 30717c478bd9Sstevel@tonic-gate * information descriptor so we can stop looking. 30727c478bd9Sstevel@tonic-gate */ 30737c478bd9Sstevel@tonic-gate result = 30747c478bd9Sstevel@tonic-gate (((diskaddr_t)isd->isd_information[0] << 56) | 30757c478bd9Sstevel@tonic-gate ((diskaddr_t)isd->isd_information[1] << 48) | 30767c478bd9Sstevel@tonic-gate ((diskaddr_t)isd->isd_information[2] << 40) | 30777c478bd9Sstevel@tonic-gate ((diskaddr_t)isd->isd_information[3] << 32) | 30787c478bd9Sstevel@tonic-gate ((diskaddr_t)isd->isd_information[4] << 24) | 30797c478bd9Sstevel@tonic-gate ((diskaddr_t)isd->isd_information[5] << 16) | 30807c478bd9Sstevel@tonic-gate ((diskaddr_t)isd->isd_information[6] << 8) | 30817c478bd9Sstevel@tonic-gate ((diskaddr_t)isd->isd_information[7])); 30827c478bd9Sstevel@tonic-gate break; 30837c478bd9Sstevel@tonic-gate } 30847c478bd9Sstevel@tonic-gate 30857c478bd9Sstevel@tonic-gate /* 30867c478bd9Sstevel@tonic-gate * Get pointer to the next descriptor. The "additional 30877c478bd9Sstevel@tonic-gate * length" field holds the length of the descriptor except 30887c478bd9Sstevel@tonic-gate * for the "type" and "additional length" fields, so 30897c478bd9Sstevel@tonic-gate * we need to add 2 to get the total length. 30907c478bd9Sstevel@tonic-gate */ 30917c478bd9Sstevel@tonic-gate descr_offset += (isd->isd_addl_length + 2); 30927c478bd9Sstevel@tonic-gate } 30937c478bd9Sstevel@tonic-gate 30947c478bd9Sstevel@tonic-gate return (result); 30957c478bd9Sstevel@tonic-gate } 30967c478bd9Sstevel@tonic-gate 30977c478bd9Sstevel@tonic-gate /* 30987c478bd9Sstevel@tonic-gate * Return a pointer to a string telling us the name of the command. 30997c478bd9Sstevel@tonic-gate */ 31007c478bd9Sstevel@tonic-gate static char * 31017c478bd9Sstevel@tonic-gate scsi_find_command_name(uint_t cmd) 31027c478bd9Sstevel@tonic-gate { 31037c478bd9Sstevel@tonic-gate struct scsi_command_name *c; 31047c478bd9Sstevel@tonic-gate 31057c478bd9Sstevel@tonic-gate for (c = scsi_command_names; c->command != SCMD_UNKNOWN; c++) 31067c478bd9Sstevel@tonic-gate if (c->command == cmd) 31077c478bd9Sstevel@tonic-gate break; 31087c478bd9Sstevel@tonic-gate return (c->name); 31097c478bd9Sstevel@tonic-gate } 31107c478bd9Sstevel@tonic-gate 31117c478bd9Sstevel@tonic-gate 31127c478bd9Sstevel@tonic-gate /* 31137c478bd9Sstevel@tonic-gate * Return true if we support a particular mode page 31147c478bd9Sstevel@tonic-gate */ 31157c478bd9Sstevel@tonic-gate int 31167c478bd9Sstevel@tonic-gate scsi_supported_page(int page) { 31177c478bd9Sstevel@tonic-gate return (page == 1 || page == 2 || page == 3 || page == 4 || 31187c478bd9Sstevel@tonic-gate page == 8 || page == 0x38); 31197c478bd9Sstevel@tonic-gate } 31207c478bd9Sstevel@tonic-gate 31217c478bd9Sstevel@tonic-gate 31227c478bd9Sstevel@tonic-gate int 31237c478bd9Sstevel@tonic-gate apply_chg_list(int pageno, int pagsiz, uchar_t *curbits, 31247c478bd9Sstevel@tonic-gate uchar_t *chgbits, struct chg_list *chglist) 31257c478bd9Sstevel@tonic-gate { 31267c478bd9Sstevel@tonic-gate uchar_t c; 31277c478bd9Sstevel@tonic-gate int i; 31287c478bd9Sstevel@tonic-gate int m; 31297c478bd9Sstevel@tonic-gate int delta; 31307c478bd9Sstevel@tonic-gate int changed = 0; 31317c478bd9Sstevel@tonic-gate 31327c478bd9Sstevel@tonic-gate while (chglist != NULL) { 31337c478bd9Sstevel@tonic-gate if (chglist->pageno == pageno && 31347c478bd9Sstevel@tonic-gate chglist->byteno < pagsiz) { 31357c478bd9Sstevel@tonic-gate i = chglist->byteno; 31367c478bd9Sstevel@tonic-gate c = curbits[i]; 31377c478bd9Sstevel@tonic-gate switch (chglist->mode) { 31387c478bd9Sstevel@tonic-gate case CHG_MODE_SET: 31397c478bd9Sstevel@tonic-gate c |= (uchar_t)chglist->value; 31407c478bd9Sstevel@tonic-gate break; 31417c478bd9Sstevel@tonic-gate case CHG_MODE_CLR: 31427c478bd9Sstevel@tonic-gate c &= (uchar_t)chglist->value; 31437c478bd9Sstevel@tonic-gate break; 31447c478bd9Sstevel@tonic-gate case CHG_MODE_ABS: 31457c478bd9Sstevel@tonic-gate c = (uchar_t)chglist->value; 31467c478bd9Sstevel@tonic-gate break; 31477c478bd9Sstevel@tonic-gate } 31487c478bd9Sstevel@tonic-gate /* 31497c478bd9Sstevel@tonic-gate * Figure out which bits changed, and 31507c478bd9Sstevel@tonic-gate * are marked as changeable. If this 31517c478bd9Sstevel@tonic-gate * result actually differs from the 31527c478bd9Sstevel@tonic-gate * current value, update the current 31537c478bd9Sstevel@tonic-gate * value, and note that a mode select 31547c478bd9Sstevel@tonic-gate * should be done. 31557c478bd9Sstevel@tonic-gate */ 31567c478bd9Sstevel@tonic-gate delta = c ^ curbits[i]; 31577c478bd9Sstevel@tonic-gate for (m = 0x01; m < 0x100; m <<= 1) { 31587c478bd9Sstevel@tonic-gate if ((delta & m) && (chgbits[i] & m)) { 31597c478bd9Sstevel@tonic-gate curbits[i] ^= m; 31607c478bd9Sstevel@tonic-gate changed = 1; 31617c478bd9Sstevel@tonic-gate } 31627c478bd9Sstevel@tonic-gate } 31637c478bd9Sstevel@tonic-gate } 31647c478bd9Sstevel@tonic-gate chglist = chglist->next; 31657c478bd9Sstevel@tonic-gate } 31667c478bd9Sstevel@tonic-gate 31677c478bd9Sstevel@tonic-gate return (changed); 31687c478bd9Sstevel@tonic-gate } 31697c478bd9Sstevel@tonic-gate 31707c478bd9Sstevel@tonic-gate 31717c478bd9Sstevel@tonic-gate /* 31727c478bd9Sstevel@tonic-gate * Return whether a given page is affected by an item on 31737c478bd9Sstevel@tonic-gate * the change list. 31747c478bd9Sstevel@tonic-gate */ 31757c478bd9Sstevel@tonic-gate static int 31767c478bd9Sstevel@tonic-gate chg_list_affects_page(chglist, pageno) 31777c478bd9Sstevel@tonic-gate struct chg_list *chglist; 31787c478bd9Sstevel@tonic-gate int pageno; 31797c478bd9Sstevel@tonic-gate { 31807c478bd9Sstevel@tonic-gate while (chglist != NULL) { 31817c478bd9Sstevel@tonic-gate if (chglist->pageno == pageno) { 31827c478bd9Sstevel@tonic-gate return (1); 31837c478bd9Sstevel@tonic-gate } 31847c478bd9Sstevel@tonic-gate chglist = chglist->next; 31857c478bd9Sstevel@tonic-gate } 31867c478bd9Sstevel@tonic-gate 31877c478bd9Sstevel@tonic-gate return (0); 31887c478bd9Sstevel@tonic-gate } 31897c478bd9Sstevel@tonic-gate 31907c478bd9Sstevel@tonic-gate 31917c478bd9Sstevel@tonic-gate /* 31927c478bd9Sstevel@tonic-gate * Labels for the various fields of the scsi_extended_sense structure 31937c478bd9Sstevel@tonic-gate */ 31947c478bd9Sstevel@tonic-gate static char *scsi_extended_sense_labels[] = { 31957c478bd9Sstevel@tonic-gate "Request sense valid: ", 31967c478bd9Sstevel@tonic-gate "Error class and code: ", 31977c478bd9Sstevel@tonic-gate "Segment number: ", 31987c478bd9Sstevel@tonic-gate "Filemark: ", 31997c478bd9Sstevel@tonic-gate "End-of-medium: ", 32007c478bd9Sstevel@tonic-gate "Incorrect length indicator: ", 32017c478bd9Sstevel@tonic-gate "Sense key: ", 32027c478bd9Sstevel@tonic-gate "Information field: ", 32037c478bd9Sstevel@tonic-gate "Additional sense length: ", 32047c478bd9Sstevel@tonic-gate "Command-specific information: ", 32057c478bd9Sstevel@tonic-gate "Additional sense code: ", 32067c478bd9Sstevel@tonic-gate "Additional sense code qualifier: ", 32077c478bd9Sstevel@tonic-gate "Field replaceable unit code: ", 32087c478bd9Sstevel@tonic-gate "Sense-key specific: ", 32097c478bd9Sstevel@tonic-gate "Additional sense bytes: " 32107c478bd9Sstevel@tonic-gate }; 32117c478bd9Sstevel@tonic-gate 32127c478bd9Sstevel@tonic-gate 32137c478bd9Sstevel@tonic-gate /* 32147c478bd9Sstevel@tonic-gate * Display the full scsi_extended_sense as returned by the device 32157c478bd9Sstevel@tonic-gate */ 32167c478bd9Sstevel@tonic-gate static void 32177c478bd9Sstevel@tonic-gate scsi_print_extended_sense(rq, rqlen) 32187c478bd9Sstevel@tonic-gate struct scsi_extended_sense *rq; 32197c478bd9Sstevel@tonic-gate int rqlen; 32207c478bd9Sstevel@tonic-gate { 32217c478bd9Sstevel@tonic-gate char **p; 32227c478bd9Sstevel@tonic-gate 32237c478bd9Sstevel@tonic-gate p = scsi_extended_sense_labels; 32247c478bd9Sstevel@tonic-gate if (rqlen < (sizeof (*rq) - 2) || !rq->es_valid) { 32257c478bd9Sstevel@tonic-gate /* 32267c478bd9Sstevel@tonic-gate * target should be capable of returning at least 18 32277c478bd9Sstevel@tonic-gate * bytes of data, i.e upto rq->es_skey_specific field. 32287c478bd9Sstevel@tonic-gate * The additional sense bytes (2 or more ...) are optional. 32297c478bd9Sstevel@tonic-gate */ 32307c478bd9Sstevel@tonic-gate return; 32317c478bd9Sstevel@tonic-gate } 32327c478bd9Sstevel@tonic-gate 32337c478bd9Sstevel@tonic-gate fmt_print("\n%s%s\n", *p++, rq->es_valid ? "yes" : "no"); 32347c478bd9Sstevel@tonic-gate fmt_print("%s0x%02x\n", *p++, (rq->es_class << 4) + rq->es_code); 32357c478bd9Sstevel@tonic-gate fmt_print("%s%d\n", *p++, rq->es_segnum); 32367c478bd9Sstevel@tonic-gate fmt_print("%s%s\n", *p++, rq->es_filmk ? "yes" : "no"); 32377c478bd9Sstevel@tonic-gate fmt_print("%s%s\n", *p++, rq->es_eom ? "yes" : "no"); 32387c478bd9Sstevel@tonic-gate fmt_print("%s%s\n", *p++, rq->es_ili ? "yes" : "no"); 32397c478bd9Sstevel@tonic-gate fmt_print("%s%d\n", *p++, rq->es_key); 32407c478bd9Sstevel@tonic-gate 32417c478bd9Sstevel@tonic-gate fmt_print("%s0x%02x 0x%02x 0x%02x 0x%02x\n", *p++, rq->es_info_1, 32427c478bd9Sstevel@tonic-gate rq->es_info_2, rq->es_info_3, rq->es_info_4); 32437c478bd9Sstevel@tonic-gate fmt_print("%s%d\n", *p++, rq->es_add_len); 32447c478bd9Sstevel@tonic-gate fmt_print("%s0x%02x 0x%02x 0x%02x 0x%02x\n", *p++, rq->es_cmd_info[0], 32457c478bd9Sstevel@tonic-gate rq->es_cmd_info[1], rq->es_cmd_info[2], rq->es_cmd_info[3]); 32467c478bd9Sstevel@tonic-gate fmt_print("%s0x%02x = %d\n", *p++, rq->es_add_code, rq->es_add_code); 32477c478bd9Sstevel@tonic-gate fmt_print("%s0x%02x = %d\n", *p++, rq->es_qual_code, rq->es_qual_code); 32487c478bd9Sstevel@tonic-gate fmt_print("%s%d\n", *p++, rq->es_fru_code); 32497c478bd9Sstevel@tonic-gate fmt_print("%s0x%02x 0x%02x 0x%02x\n", *p++, rq->es_skey_specific[0], 32507c478bd9Sstevel@tonic-gate rq->es_skey_specific[1], rq->es_skey_specific[2]); 32517c478bd9Sstevel@tonic-gate if (rqlen >= sizeof (*rq)) { 32527c478bd9Sstevel@tonic-gate fmt_print("%s0x%02x 0x%02x%s\n", *p, rq->es_add_info[0], 32537c478bd9Sstevel@tonic-gate rq->es_add_info[1], (rqlen > sizeof (*rq)) ? " ..." : ""); 32547c478bd9Sstevel@tonic-gate } 32557c478bd9Sstevel@tonic-gate 32567c478bd9Sstevel@tonic-gate fmt_print("\n"); 32577c478bd9Sstevel@tonic-gate } 32587c478bd9Sstevel@tonic-gate 32597c478bd9Sstevel@tonic-gate /* 32607c478bd9Sstevel@tonic-gate * Labels for the various fields of the scsi_descr_sense_hdr structure 32617c478bd9Sstevel@tonic-gate */ 32627c478bd9Sstevel@tonic-gate static char *scsi_descr_sense_labels[] = { 32637c478bd9Sstevel@tonic-gate "Error class and code: ", 32647c478bd9Sstevel@tonic-gate "Sense key: ", 32657c478bd9Sstevel@tonic-gate "Additional sense length: ", 32667c478bd9Sstevel@tonic-gate "Additional sense code: ", 32677c478bd9Sstevel@tonic-gate "Additional sense code qualifier: ", 32687c478bd9Sstevel@tonic-gate "Additional sense bytes: " 32697c478bd9Sstevel@tonic-gate }; 32707c478bd9Sstevel@tonic-gate 32717c478bd9Sstevel@tonic-gate 32727c478bd9Sstevel@tonic-gate /* 32737c478bd9Sstevel@tonic-gate * Display the full descriptor sense data as returned by the device 32747c478bd9Sstevel@tonic-gate */ 32757c478bd9Sstevel@tonic-gate 32767c478bd9Sstevel@tonic-gate static void 32777c478bd9Sstevel@tonic-gate scsi_print_descr_sense(rq, rqlen) 32787c478bd9Sstevel@tonic-gate struct scsi_descr_sense_hdr *rq; 32797c478bd9Sstevel@tonic-gate int rqlen; 32807c478bd9Sstevel@tonic-gate { 32817c478bd9Sstevel@tonic-gate char **p; 32827c478bd9Sstevel@tonic-gate uint8_t *descr_offset; 32837c478bd9Sstevel@tonic-gate int valid_sense_length; 32847c478bd9Sstevel@tonic-gate struct scsi_information_sense_descr *isd; 32857c478bd9Sstevel@tonic-gate 32867c478bd9Sstevel@tonic-gate p = scsi_descr_sense_labels; 32877c478bd9Sstevel@tonic-gate if (rqlen < sizeof (struct scsi_descr_sense_hdr)) { 32887c478bd9Sstevel@tonic-gate /* 32897c478bd9Sstevel@tonic-gate * target must return at least 8 bytes of data 32907c478bd9Sstevel@tonic-gate */ 32917c478bd9Sstevel@tonic-gate return; 32927c478bd9Sstevel@tonic-gate } 32937c478bd9Sstevel@tonic-gate 32947c478bd9Sstevel@tonic-gate /* Print descriptor sense header */ 32957c478bd9Sstevel@tonic-gate fmt_print("%s0x%02x\n", *p++, (rq->ds_class << 4) + rq->ds_code); 32967c478bd9Sstevel@tonic-gate fmt_print("%s%d\n", *p++, rq->ds_key); 32977c478bd9Sstevel@tonic-gate 32987c478bd9Sstevel@tonic-gate fmt_print("%s%d\n", *p++, rq->ds_addl_sense_length); 32997c478bd9Sstevel@tonic-gate fmt_print("%s0x%02x = %d\n", *p++, rq->ds_add_code, rq->ds_add_code); 33007c478bd9Sstevel@tonic-gate fmt_print("%s0x%02x = %d\n", *p++, rq->ds_qual_code, rq->ds_qual_code); 33017c478bd9Sstevel@tonic-gate fmt_print("\n"); 33027c478bd9Sstevel@tonic-gate 33037c478bd9Sstevel@tonic-gate /* 33047c478bd9Sstevel@tonic-gate * Now print any sense descriptors. The first descriptor will 33057c478bd9Sstevel@tonic-gate * immediately follow the header 33067c478bd9Sstevel@tonic-gate */ 33077c478bd9Sstevel@tonic-gate descr_offset = (uint8_t *)(rq+1); /* Pointer arithmetic */ 33087c478bd9Sstevel@tonic-gate 33097c478bd9Sstevel@tonic-gate /* 33107c478bd9Sstevel@tonic-gate * Calculate the amount of valid sense data 33117c478bd9Sstevel@tonic-gate */ 33127c478bd9Sstevel@tonic-gate valid_sense_length = 33137c478bd9Sstevel@tonic-gate min((sizeof (struct scsi_descr_sense_hdr) + 33147c478bd9Sstevel@tonic-gate rq->ds_addl_sense_length), rqlen); 33157c478bd9Sstevel@tonic-gate 33167c478bd9Sstevel@tonic-gate /* 33177c478bd9Sstevel@tonic-gate * Iterate through the list of descriptors, stopping when we 33187c478bd9Sstevel@tonic-gate * run out of sense data. Descriptor format is: 33197c478bd9Sstevel@tonic-gate * 33207c478bd9Sstevel@tonic-gate * <Descriptor type> <Descriptor length> <Descriptor data> ... 33217c478bd9Sstevel@tonic-gate */ 33227c478bd9Sstevel@tonic-gate while ((descr_offset + *(descr_offset + 1)) <= 33237c478bd9Sstevel@tonic-gate (uint8_t *)rq + valid_sense_length) { 33247c478bd9Sstevel@tonic-gate /* 33257c478bd9Sstevel@tonic-gate * Determine descriptor type. We can use the 33267c478bd9Sstevel@tonic-gate * scsi_information_sense_descr structure as a 33277c478bd9Sstevel@tonic-gate * template since the first two fields are always the 33287c478bd9Sstevel@tonic-gate * same. 33297c478bd9Sstevel@tonic-gate */ 33307c478bd9Sstevel@tonic-gate isd = (struct scsi_information_sense_descr *)descr_offset; 33317c478bd9Sstevel@tonic-gate switch (isd->isd_descr_type) { 33327c478bd9Sstevel@tonic-gate case DESCR_INFORMATION: { 33337c478bd9Sstevel@tonic-gate uint64_t information; 33347c478bd9Sstevel@tonic-gate 33357c478bd9Sstevel@tonic-gate information = 33367c478bd9Sstevel@tonic-gate (((uint64_t)isd->isd_information[0] << 56) | 33377c478bd9Sstevel@tonic-gate ((uint64_t)isd->isd_information[1] << 48) | 33387c478bd9Sstevel@tonic-gate ((uint64_t)isd->isd_information[2] << 40) | 33397c478bd9Sstevel@tonic-gate ((uint64_t)isd->isd_information[3] << 32) | 33407c478bd9Sstevel@tonic-gate ((uint64_t)isd->isd_information[4] << 24) | 33417c478bd9Sstevel@tonic-gate ((uint64_t)isd->isd_information[5] << 16) | 33427c478bd9Sstevel@tonic-gate ((uint64_t)isd->isd_information[6] << 8) | 33437c478bd9Sstevel@tonic-gate ((uint64_t)isd->isd_information[7])); 33447c478bd9Sstevel@tonic-gate fmt_print("Information field: " 33457c478bd9Sstevel@tonic-gate "%0llx\n", information); 33467c478bd9Sstevel@tonic-gate break; 33477c478bd9Sstevel@tonic-gate } 33487c478bd9Sstevel@tonic-gate case DESCR_COMMAND_SPECIFIC: { 33497c478bd9Sstevel@tonic-gate struct scsi_cmd_specific_sense_descr *c = 33507c478bd9Sstevel@tonic-gate (struct scsi_cmd_specific_sense_descr *)isd; 33517c478bd9Sstevel@tonic-gate uint64_t cmd_specific; 33527c478bd9Sstevel@tonic-gate 33537c478bd9Sstevel@tonic-gate cmd_specific = 33547c478bd9Sstevel@tonic-gate (((uint64_t)c->css_cmd_specific_info[0] << 56) | 33557c478bd9Sstevel@tonic-gate ((uint64_t)c->css_cmd_specific_info[1] << 48) | 33567c478bd9Sstevel@tonic-gate ((uint64_t)c->css_cmd_specific_info[2] << 40) | 33577c478bd9Sstevel@tonic-gate ((uint64_t)c->css_cmd_specific_info[3] << 32) | 33587c478bd9Sstevel@tonic-gate ((uint64_t)c->css_cmd_specific_info[4] << 24) | 33597c478bd9Sstevel@tonic-gate ((uint64_t)c->css_cmd_specific_info[5] << 16) | 33607c478bd9Sstevel@tonic-gate ((uint64_t)c->css_cmd_specific_info[6] << 8) | 33617c478bd9Sstevel@tonic-gate ((uint64_t)c->css_cmd_specific_info[7])); 33627c478bd9Sstevel@tonic-gate fmt_print("Command-specific information: " 33637c478bd9Sstevel@tonic-gate "%0llx\n", cmd_specific); 33647c478bd9Sstevel@tonic-gate break; 33657c478bd9Sstevel@tonic-gate } 33667c478bd9Sstevel@tonic-gate case DESCR_SENSE_KEY_SPECIFIC: { 33677c478bd9Sstevel@tonic-gate struct scsi_sk_specific_sense_descr *ssd = 33687c478bd9Sstevel@tonic-gate (struct scsi_sk_specific_sense_descr *)isd; 33697c478bd9Sstevel@tonic-gate uint8_t *sk_spec_ptr = (uint8_t *)&ssd->sss_data; 33707c478bd9Sstevel@tonic-gate fmt_print("Sense-key specific: " 33717c478bd9Sstevel@tonic-gate "0x%02x 0x%02x 0x%02x\n", sk_spec_ptr[0], 33727c478bd9Sstevel@tonic-gate sk_spec_ptr[1], sk_spec_ptr[2]); 33737c478bd9Sstevel@tonic-gate break; 33747c478bd9Sstevel@tonic-gate } 33757c478bd9Sstevel@tonic-gate case DESCR_FRU: { 33767c478bd9Sstevel@tonic-gate struct scsi_fru_sense_descr *fsd = 33777c478bd9Sstevel@tonic-gate (struct scsi_fru_sense_descr *)isd; 33787c478bd9Sstevel@tonic-gate fmt_print("Field replaceable unit code: " 33797c478bd9Sstevel@tonic-gate "%d\n", fsd->fs_fru_code); 33807c478bd9Sstevel@tonic-gate break; 33817c478bd9Sstevel@tonic-gate } 33827c478bd9Sstevel@tonic-gate case DESCR_BLOCK_COMMANDS: { 33837c478bd9Sstevel@tonic-gate struct scsi_block_cmd_sense_descr *bsd = 33847c478bd9Sstevel@tonic-gate (struct scsi_block_cmd_sense_descr *)isd; 33857c478bd9Sstevel@tonic-gate fmt_print("Incorrect length indicator: " 33867c478bd9Sstevel@tonic-gate "%s\n", bsd->bcs_ili ? "yes" : "no"); 33877c478bd9Sstevel@tonic-gate break; 33887c478bd9Sstevel@tonic-gate } 33897c478bd9Sstevel@tonic-gate default: 33907c478bd9Sstevel@tonic-gate /* Ignore */ 33917c478bd9Sstevel@tonic-gate break; 33927c478bd9Sstevel@tonic-gate } 33937c478bd9Sstevel@tonic-gate 33947c478bd9Sstevel@tonic-gate /* 33957c478bd9Sstevel@tonic-gate * Get pointer to the next descriptor. The "additional 33967c478bd9Sstevel@tonic-gate * length" field holds the length of the descriptor except 33977c478bd9Sstevel@tonic-gate * for the "type" and "additional length" fields, so 33987c478bd9Sstevel@tonic-gate * we need to add 2 to get the total length. 33997c478bd9Sstevel@tonic-gate */ 34007c478bd9Sstevel@tonic-gate descr_offset += (isd->isd_addl_length + 2); 34017c478bd9Sstevel@tonic-gate } 34027c478bd9Sstevel@tonic-gate 34037c478bd9Sstevel@tonic-gate fmt_print("\n"); 34047c478bd9Sstevel@tonic-gate } 34057c478bd9Sstevel@tonic-gate 34067c478bd9Sstevel@tonic-gate /* 34077c478bd9Sstevel@tonic-gate * Function checks if READ DEFECT DATA command is supported 34087c478bd9Sstevel@tonic-gate * on the current disk. 34097c478bd9Sstevel@tonic-gate */ 34107c478bd9Sstevel@tonic-gate static int 34117c478bd9Sstevel@tonic-gate check_support_for_defects() 34127c478bd9Sstevel@tonic-gate { 34137c478bd9Sstevel@tonic-gate struct uscsi_cmd ucmd; 34147c478bd9Sstevel@tonic-gate union scsi_cdb cdb; 34157c478bd9Sstevel@tonic-gate struct scsi_defect_list def_list; 34167c478bd9Sstevel@tonic-gate struct scsi_defect_hdr *hdr; 34177c478bd9Sstevel@tonic-gate int status; 34187c478bd9Sstevel@tonic-gate char rqbuf[255]; 34197c478bd9Sstevel@tonic-gate struct scsi_extended_sense *rq; 34207c478bd9Sstevel@tonic-gate 34217c478bd9Sstevel@tonic-gate hdr = (struct scsi_defect_hdr *)&def_list; 34227c478bd9Sstevel@tonic-gate 34237c478bd9Sstevel@tonic-gate /* 34247c478bd9Sstevel@tonic-gate * First get length of list by asking for the header only. 34257c478bd9Sstevel@tonic-gate */ 34267c478bd9Sstevel@tonic-gate (void) memset((char *)&def_list, 0, sizeof (def_list)); 34277c478bd9Sstevel@tonic-gate 34287c478bd9Sstevel@tonic-gate /* 34297c478bd9Sstevel@tonic-gate * Build and execute the uscsi ioctl 34307c478bd9Sstevel@tonic-gate */ 34317c478bd9Sstevel@tonic-gate (void) memset((char *)&ucmd, 0, sizeof (ucmd)); 34327c478bd9Sstevel@tonic-gate (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb)); 34337c478bd9Sstevel@tonic-gate (void) memset((char *)rqbuf, 0, 255); 34347c478bd9Sstevel@tonic-gate cdb.scc_cmd = SCMD_READ_DEFECT_LIST; 34357c478bd9Sstevel@tonic-gate FORMG1COUNT(&cdb, sizeof (struct scsi_defect_hdr)); 34367c478bd9Sstevel@tonic-gate cdb.cdb_opaque[2] = DLD_MAN_DEF_LIST | DLD_BFI_FORMAT; 34377c478bd9Sstevel@tonic-gate ucmd.uscsi_cdb = (caddr_t)&cdb; 34387c478bd9Sstevel@tonic-gate ucmd.uscsi_cdblen = CDB_GROUP1; 34397c478bd9Sstevel@tonic-gate ucmd.uscsi_bufaddr = (caddr_t)hdr; 34407c478bd9Sstevel@tonic-gate ucmd.uscsi_buflen = sizeof (struct scsi_defect_hdr); 34417c478bd9Sstevel@tonic-gate ucmd.uscsi_rqbuf = rqbuf; 34427c478bd9Sstevel@tonic-gate ucmd.uscsi_rqlen = sizeof (rqbuf); 34437c478bd9Sstevel@tonic-gate ucmd.uscsi_rqresid = sizeof (rqbuf); 34447c478bd9Sstevel@tonic-gate rq = (struct scsi_extended_sense *)ucmd.uscsi_rqbuf; 34457c478bd9Sstevel@tonic-gate 34467c478bd9Sstevel@tonic-gate status = uscsi_cmd(cur_file, &ucmd, 34477c478bd9Sstevel@tonic-gate (option_msg && diag_msg) ? F_NORMAL : F_SILENT); 34487c478bd9Sstevel@tonic-gate 34497c478bd9Sstevel@tonic-gate if (status != 0) { 34507c478bd9Sstevel@tonic-gate /* 34517c478bd9Sstevel@tonic-gate * check if read_defect_list_is_supported. 34527c478bd9Sstevel@tonic-gate */ 34537c478bd9Sstevel@tonic-gate if (ucmd.uscsi_rqstatus == STATUS_GOOD && 34547c478bd9Sstevel@tonic-gate rq->es_key == KEY_ILLEGAL_REQUEST && 34557c478bd9Sstevel@tonic-gate rq->es_add_code == INVALID_OPCODE) 34567c478bd9Sstevel@tonic-gate return (0); 34577c478bd9Sstevel@tonic-gate } 34587c478bd9Sstevel@tonic-gate return (1); 34597c478bd9Sstevel@tonic-gate } 34607c478bd9Sstevel@tonic-gate 34617c478bd9Sstevel@tonic-gate /* 34627c478bd9Sstevel@tonic-gate * Format the disk, the whole disk, and nothing but the disk. 34637c478bd9Sstevel@tonic-gate * Function will be called only for disks 34647c478bd9Sstevel@tonic-gate * which do not support read defect list command. 34657c478bd9Sstevel@tonic-gate */ 34667c478bd9Sstevel@tonic-gate static int 34677c478bd9Sstevel@tonic-gate scsi_format_without_defects() 34687c478bd9Sstevel@tonic-gate { 34697c478bd9Sstevel@tonic-gate struct uscsi_cmd ucmd; 34707c478bd9Sstevel@tonic-gate union scsi_cdb cdb; 34717c478bd9Sstevel@tonic-gate struct scsi_defect_hdr defect_hdr; 34727c478bd9Sstevel@tonic-gate int status; 34737c478bd9Sstevel@tonic-gate 34747c478bd9Sstevel@tonic-gate /* 34757c478bd9Sstevel@tonic-gate * Construct the uscsi format ioctl. 34767c478bd9Sstevel@tonic-gate * Use fmtdata = 0 , indicating the no source of 34777c478bd9Sstevel@tonic-gate * defects information is provided . 34787c478bd9Sstevel@tonic-gate * Function will be called only for disks 34797c478bd9Sstevel@tonic-gate * which do not support read defect list command. 34807c478bd9Sstevel@tonic-gate */ 34817c478bd9Sstevel@tonic-gate (void) memset((char *)&ucmd, 0, sizeof (ucmd)); 34827c478bd9Sstevel@tonic-gate (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb)); 34837c478bd9Sstevel@tonic-gate (void) memset((char *)&defect_hdr, 0, sizeof (defect_hdr)); 34847c478bd9Sstevel@tonic-gate cdb.scc_cmd = SCMD_FORMAT; 34857c478bd9Sstevel@tonic-gate ucmd.uscsi_cdb = (caddr_t)&cdb; 34867c478bd9Sstevel@tonic-gate ucmd.uscsi_cdblen = CDB_GROUP0; 34877c478bd9Sstevel@tonic-gate ucmd.uscsi_bufaddr = (caddr_t)&defect_hdr; 34887c478bd9Sstevel@tonic-gate ucmd.uscsi_buflen = sizeof (defect_hdr); 34897c478bd9Sstevel@tonic-gate cdb.cdb_opaque[1] = 0; 34907c478bd9Sstevel@tonic-gate /* 34917c478bd9Sstevel@tonic-gate * Issue the format ioctl 34927c478bd9Sstevel@tonic-gate */ 34937c478bd9Sstevel@tonic-gate status = uscsi_cmd(cur_file, &ucmd, 34947c478bd9Sstevel@tonic-gate (option_msg && diag_msg) ? F_NORMAL : F_SILENT); 34957c478bd9Sstevel@tonic-gate return (status); 34967c478bd9Sstevel@tonic-gate } 34977c478bd9Sstevel@tonic-gate 34987c478bd9Sstevel@tonic-gate /* 34997c478bd9Sstevel@tonic-gate * Name: test_until_ready 35007c478bd9Sstevel@tonic-gate * 35017c478bd9Sstevel@tonic-gate * Description: This function is used by scsi_format and 35027c478bd9Sstevel@tonic-gate * scsi_format_raw to poll the device while the FORMAT 35037c478bd9Sstevel@tonic-gate * UNIT cdb in in progress. 35047c478bd9Sstevel@tonic-gate * 35057c478bd9Sstevel@tonic-gate * Parameters: 35067c478bd9Sstevel@tonic-gate * file descriptor to poll 35077c478bd9Sstevel@tonic-gate * 35087c478bd9Sstevel@tonic-gate * Returns: 35097c478bd9Sstevel@tonic-gate * 0 - good status 35107c478bd9Sstevel@tonic-gate * !0 - bad status 35117c478bd9Sstevel@tonic-gate */ 35127c478bd9Sstevel@tonic-gate static int test_until_ready(int fd) { 35137c478bd9Sstevel@tonic-gate int status = 1; 35147c478bd9Sstevel@tonic-gate struct uscsi_cmd ucmd; 35157c478bd9Sstevel@tonic-gate union scsi_cdb cdb; 35167c478bd9Sstevel@tonic-gate struct scsi_extended_sense sense; 35177c478bd9Sstevel@tonic-gate time_t start, check, time_left; 35187c478bd9Sstevel@tonic-gate uint16_t progress; 35197c478bd9Sstevel@tonic-gate int hour, min, sec; 35207c478bd9Sstevel@tonic-gate 35217c478bd9Sstevel@tonic-gate (void) memset((char *)&ucmd, 0, sizeof (ucmd)); 35227c478bd9Sstevel@tonic-gate (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb)); 35237c478bd9Sstevel@tonic-gate 35247c478bd9Sstevel@tonic-gate ucmd.uscsi_cdb = (caddr_t)&cdb; 35257c478bd9Sstevel@tonic-gate ucmd.uscsi_cdblen = CDB_GROUP0; 35267c478bd9Sstevel@tonic-gate ucmd.uscsi_rqbuf = (caddr_t)&sense; 35277c478bd9Sstevel@tonic-gate ucmd.uscsi_rqlen = SENSE_LEN; 35287c478bd9Sstevel@tonic-gate 35297c478bd9Sstevel@tonic-gate start = check = time((time_t *)0); 35307c478bd9Sstevel@tonic-gate 35317c478bd9Sstevel@tonic-gate /* Loop sending TEST UNIT READY until format is complete */ 35327c478bd9Sstevel@tonic-gate while (status) { 35337c478bd9Sstevel@tonic-gate /* clear last request sense data */ 35347c478bd9Sstevel@tonic-gate ucmd.uscsi_rqstatus = 0; 35357c478bd9Sstevel@tonic-gate ucmd.uscsi_rqresid = 0; 35367c478bd9Sstevel@tonic-gate (void) memset((char *)&sense, 0, SENSE_LEN); 35377c478bd9Sstevel@tonic-gate 35387c478bd9Sstevel@tonic-gate /* issue test unit ready */ 35397c478bd9Sstevel@tonic-gate status = uscsi_cmd(fd, &ucmd, F_SILENT 35407c478bd9Sstevel@tonic-gate | F_RQENABLE); 35417c478bd9Sstevel@tonic-gate 35427c478bd9Sstevel@tonic-gate check = time((time_t *)0); 35437c478bd9Sstevel@tonic-gate 35447c478bd9Sstevel@tonic-gate /* If device returns not ready we get EIO */ 35457c478bd9Sstevel@tonic-gate if (status != 0 && errno == EIO) { 35467c478bd9Sstevel@tonic-gate /* Check SKSV if progress indication is avail */ 35477c478bd9Sstevel@tonic-gate if (sense.es_skey_specific[0] == 0x80) { 35487c478bd9Sstevel@tonic-gate /* Store progress indication */ 35497c478bd9Sstevel@tonic-gate progress = ((uint16_t)sense. 35507c478bd9Sstevel@tonic-gate es_skey_specific[1]) << 8; 35517c478bd9Sstevel@tonic-gate progress |= (uint16_t)sense. 35527c478bd9Sstevel@tonic-gate es_skey_specific[2]; 35537c478bd9Sstevel@tonic-gate progress = (uint16_t)(((float)progress / 35547c478bd9Sstevel@tonic-gate (float)PROGRESS_INDICATION_BASE)*100); 35557c478bd9Sstevel@tonic-gate 35567c478bd9Sstevel@tonic-gate fmt_print("\015"); 35577c478bd9Sstevel@tonic-gate 35587c478bd9Sstevel@tonic-gate /* 35597c478bd9Sstevel@tonic-gate * check to see if we can estimate 35607c478bd9Sstevel@tonic-gate * time remaining - wait until the format 35617c478bd9Sstevel@tonic-gate * is at least 5 percent complete to avoid 35627c478bd9Sstevel@tonic-gate * wildly-fluctuating time estimates 35637c478bd9Sstevel@tonic-gate */ 35647c478bd9Sstevel@tonic-gate if ((check - start) <= 0 || progress <= 5) { 35657c478bd9Sstevel@tonic-gate /* unable to estimate */ 35667c478bd9Sstevel@tonic-gate fmt_print(" %02d%% complete ", 35677c478bd9Sstevel@tonic-gate progress); 35687c478bd9Sstevel@tonic-gate } else { 35697c478bd9Sstevel@tonic-gate /* display with estimated time */ 35707c478bd9Sstevel@tonic-gate time_left = (time_t)(((float)(check 35717c478bd9Sstevel@tonic-gate - start) / (float)progress) * 35727c478bd9Sstevel@tonic-gate (float)(100 - progress)); 35737c478bd9Sstevel@tonic-gate sec = time_left % 60; 35747c478bd9Sstevel@tonic-gate min = (time_left / 60) % 60; 35757c478bd9Sstevel@tonic-gate hour = time_left / 3600; 35767c478bd9Sstevel@tonic-gate 35777c478bd9Sstevel@tonic-gate fmt_print(" %02d%% complete " 35787c478bd9Sstevel@tonic-gate "(%02d:%02d:%02d remaining) ", 35797c478bd9Sstevel@tonic-gate progress, hour, min, sec); 35807c478bd9Sstevel@tonic-gate } 35817c478bd9Sstevel@tonic-gate /* flush or the screen will not update */ 35827c478bd9Sstevel@tonic-gate (void) fflush(stdout); 35837c478bd9Sstevel@tonic-gate } 35847c478bd9Sstevel@tonic-gate } else { 35857c478bd9Sstevel@tonic-gate /* format not in progress */ 35867c478bd9Sstevel@tonic-gate if (option_msg) { 35877c478bd9Sstevel@tonic-gate fmt_print("\nRequest Sense ASC=0x%x ASCQ=0x%x", 35887c478bd9Sstevel@tonic-gate sense.es_add_code, sense.es_qual_code); 35897c478bd9Sstevel@tonic-gate } 35907c478bd9Sstevel@tonic-gate break; 35917c478bd9Sstevel@tonic-gate } 35927c478bd9Sstevel@tonic-gate 35937c478bd9Sstevel@tonic-gate /* delay so we don't waste cpu time */ 35947c478bd9Sstevel@tonic-gate (void) sleep(RETRY_DELAY); 35957c478bd9Sstevel@tonic-gate } 35967c478bd9Sstevel@tonic-gate return (status); 35977c478bd9Sstevel@tonic-gate } 35989ca9c420SSheng-Liang Eric Zhang 35999ca9c420SSheng-Liang Eric Zhang /* 36009ca9c420SSheng-Liang Eric Zhang * Get the current protection type from the PROT_EN and P_TYPE 36019ca9c420SSheng-Liang Eric Zhang */ 36029ca9c420SSheng-Liang Eric Zhang uint8_t 36039ca9c420SSheng-Liang Eric Zhang get_cur_protection_type(struct scsi_capacity_16 *capacity) 36049ca9c420SSheng-Liang Eric Zhang { 36059ca9c420SSheng-Liang Eric Zhang uint8_t cp13; 36069ca9c420SSheng-Liang Eric Zhang uint8_t prot_en; 36079ca9c420SSheng-Liang Eric Zhang uint8_t p_type; 36089ca9c420SSheng-Liang Eric Zhang 36099ca9c420SSheng-Liang Eric Zhang cp13 = ((capacity->sc_rsvd0 & 0x3f) << 2) 36109ca9c420SSheng-Liang Eric Zhang | ((capacity->sc_prot_en & 0x01) << 1) 36119ca9c420SSheng-Liang Eric Zhang | (capacity->sc_rto_en & 0x01); 36129ca9c420SSheng-Liang Eric Zhang prot_en = cp13 & 0x01; 36139ca9c420SSheng-Liang Eric Zhang if (prot_en == 0) { 36149ca9c420SSheng-Liang Eric Zhang p_type = 0; 36159ca9c420SSheng-Liang Eric Zhang } else { 36169ca9c420SSheng-Liang Eric Zhang p_type = (cp13 << 4) >> 5; 36179ca9c420SSheng-Liang Eric Zhang p_type += 1; 36189ca9c420SSheng-Liang Eric Zhang } 36199ca9c420SSheng-Liang Eric Zhang return (p_type); 36209ca9c420SSheng-Liang Eric Zhang } 3621