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
scsi_rdwr(dir,fd,blkno,secnt,bufaddr,flags,xfercntp)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 */
scsi_ck_format(void)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
scsi_format(start,end,list)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
scsi_raw_format(void)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
scsi_format_time()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
scsi_ms_page1(scsi2_flag)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
scsi_ms_page2(scsi2_flag)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
scsi_ms_page3(scsi2_flag)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
scsi_ms_page4(scsi2_flag)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
scsi_ms_page8(scsi2_flag)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
scsi_ms_page38(scsi2_flag)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
scsi_ex_man(list)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
scsi_ex_cur(list)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
scsi_ex_grown(list)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
scsi_read_defect_data(list,pglist_flags)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
scsi_repair(bn,flag)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
scsi_convert_list_to_new(list,def_list,list_format)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
uscsi_cmd(fd,ucmd,flags)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
uscsi_mode_sense(fd,page_code,page_control,page_data,page_size,header)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
uscsi_mode_select(fd,page_code,options,page_data,page_size,header)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
uscsi_inquiry(fd,inqbuf,inqbufsiz)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
uscsi_inquiry_page_86h(fd,inqbuf,inqbufsiz)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
uscsi_read_capacity_16(fd,capacity)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
uscsi_read_capacity(fd,capacity)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
uscsi_reserve_release(int fd,int cmd)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
scsi_dump_mode_sense_pages(page_control)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
scsi_printerr(ucmd,rq,rqlen)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
scsi_extract_sense_info_descr(struct scsi_descr_sense_hdr * sdsp,int rqlen)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 *
scsi_find_command_name(uint_t cmd)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
scsi_supported_page(int page)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
apply_chg_list(int pageno,int pagsiz,uchar_t * curbits,uchar_t * chgbits,struct chg_list * chglist)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
chg_list_affects_page(chglist,pageno)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
scsi_print_extended_sense(rq,rqlen)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
scsi_print_descr_sense(rq,rqlen)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
check_support_for_defects()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
scsi_format_without_defects()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 */
test_until_ready(int fd)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
get_cur_protection_type(struct scsi_capacity_16 * capacity)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