10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
56765Sbz211116 * Common Development and Distribution License (the "License").
66765Sbz211116 * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
22*12930SRalph.Turner@Sun.COM * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved.
230Sstevel@tonic-gate */
240Sstevel@tonic-gate
250Sstevel@tonic-gate /*
260Sstevel@tonic-gate * This file contains the routines for embedded scsi disks
270Sstevel@tonic-gate */
280Sstevel@tonic-gate #include "global.h"
290Sstevel@tonic-gate
300Sstevel@tonic-gate #include <sys/types.h>
310Sstevel@tonic-gate #include <sys/param.h>
320Sstevel@tonic-gate #include <sys/ioctl.h>
330Sstevel@tonic-gate #include <sys/uio.h>
340Sstevel@tonic-gate #include <sys/fcntl.h>
350Sstevel@tonic-gate #include <errno.h>
360Sstevel@tonic-gate #include <memory.h>
370Sstevel@tonic-gate #include <malloc.h>
380Sstevel@tonic-gate #include <unistd.h>
390Sstevel@tonic-gate #include <stdlib.h>
400Sstevel@tonic-gate #include <values.h>
410Sstevel@tonic-gate #include <sys/byteorder.h>
420Sstevel@tonic-gate
430Sstevel@tonic-gate
440Sstevel@tonic-gate
450Sstevel@tonic-gate #include "startup.h"
460Sstevel@tonic-gate #include "scsi_com.h"
470Sstevel@tonic-gate #include "misc.h"
480Sstevel@tonic-gate #include "ctlr_scsi.h"
490Sstevel@tonic-gate #include "analyze.h"
500Sstevel@tonic-gate #include "param.h"
510Sstevel@tonic-gate #include "io.h"
520Sstevel@tonic-gate
530Sstevel@tonic-gate
540Sstevel@tonic-gate #ifndef DAD_MODE_CACHE_CCS
550Sstevel@tonic-gate #define DAD_MODE_CACHE_CCS 0x38
560Sstevel@tonic-gate #endif /* DAD_MODE_CACHE_CCS */
570Sstevel@tonic-gate
580Sstevel@tonic-gate /* format defect header bits */
590Sstevel@tonic-gate #define FDH_FOV 0x80
600Sstevel@tonic-gate #define FDH_IMMED 0x02
610Sstevel@tonic-gate
620Sstevel@tonic-gate #define SENSE_LEN 20
630Sstevel@tonic-gate
640Sstevel@tonic-gate #define RETRY_DELAY 5
650Sstevel@tonic-gate
660Sstevel@tonic-gate #define PROGRESS_INDICATION_BASE 65536
670Sstevel@tonic-gate
680Sstevel@tonic-gate #ifdef __STDC__
690Sstevel@tonic-gate /*
700Sstevel@tonic-gate * Local prototypes for ANSI C compilers
710Sstevel@tonic-gate */
720Sstevel@tonic-gate static int scsi_format(uint64_t, uint64_t, struct defect_list *);
730Sstevel@tonic-gate static int scsi_raw_format(void);
740Sstevel@tonic-gate static int scsi_ms_page8(int);
750Sstevel@tonic-gate static int scsi_ms_page38(int);
760Sstevel@tonic-gate static void scsi_convert_list_to_new(struct defect_list *,
770Sstevel@tonic-gate struct scsi_defect_list *, int);
780Sstevel@tonic-gate static char *scsi_find_command_name(uint_t);
790Sstevel@tonic-gate static int chg_list_affects_page(struct chg_list *, int);
800Sstevel@tonic-gate static void scsi_printerr(struct uscsi_cmd *,
810Sstevel@tonic-gate struct scsi_extended_sense *, int);
820Sstevel@tonic-gate static diskaddr_t
830Sstevel@tonic-gate scsi_extract_sense_info_descr(struct scsi_descr_sense_hdr *sdsp, int rqlen);
840Sstevel@tonic-gate
850Sstevel@tonic-gate static void scsi_print_extended_sense(struct scsi_extended_sense *, int);
860Sstevel@tonic-gate static void scsi_print_descr_sense(struct scsi_descr_sense_hdr *, int);
870Sstevel@tonic-gate
880Sstevel@tonic-gate static int test_until_ready(int fd);
890Sstevel@tonic-gate static int uscsi_reserve_release(int, int);
900Sstevel@tonic-gate static int check_support_for_defects(void);
910Sstevel@tonic-gate static int scsi_format_without_defects(void);
920Sstevel@tonic-gate static int scsi_ms_page1(int);
930Sstevel@tonic-gate static int scsi_ms_page2(int);
940Sstevel@tonic-gate static int scsi_ms_page3(int);
950Sstevel@tonic-gate static int scsi_ms_page4(int);
960Sstevel@tonic-gate static int scsi_repair(uint64_t, int);
970Sstevel@tonic-gate static int scsi_read_defect_data(struct defect_list *, int);
980Sstevel@tonic-gate static int scsi_ck_format(void);
990Sstevel@tonic-gate
1000Sstevel@tonic-gate #else /* __STDC__ */
1010Sstevel@tonic-gate
1020Sstevel@tonic-gate static int scsi_format();
1030Sstevel@tonic-gate static int scsi_raw_format();
1040Sstevel@tonic-gate static int scsi_ms_page8();
1050Sstevel@tonic-gate static int scsi_ms_page38();
1060Sstevel@tonic-gate static void scsi_convert_list_to_new();
1070Sstevel@tonic-gate static char *scsi_find_command_name();
1080Sstevel@tonic-gate static int chg_list_affects_page();
1090Sstevel@tonic-gate static void scsi_printerr();
1100Sstevel@tonic-gate static diskaddr_t scsi_extract_sense_info_descr();
1110Sstevel@tonic-gate static void scsi_print_extended_sense();
1120Sstevel@tonic-gate static void scsi_print_descr_sense();
1130Sstevel@tonic-gate
1140Sstevel@tonic-gate static int test_until_ready();
1150Sstevel@tonic-gate
1160Sstevel@tonic-gate static int uscsi_reserve_release();
1170Sstevel@tonic-gate static int check_support_for_defects();
1180Sstevel@tonic-gate static int scsi_format_without_defects();
1190Sstevel@tonic-gate static int scsi_ms_page1();
1200Sstevel@tonic-gate static int scsi_ms_page2();
1210Sstevel@tonic-gate static int scsi_ms_page3();
1220Sstevel@tonic-gate static int scsi_ms_page4();
1230Sstevel@tonic-gate static int scsi_repair();
1240Sstevel@tonic-gate static int scsi_read_defect_data();
1250Sstevel@tonic-gate static int scsi_ck_format();
1260Sstevel@tonic-gate
1270Sstevel@tonic-gate #endif /* __STDC__ */
1280Sstevel@tonic-gate
1290Sstevel@tonic-gate
1300Sstevel@tonic-gate
1310Sstevel@tonic-gate struct ctlr_ops scsiops = {
1320Sstevel@tonic-gate scsi_rdwr,
1330Sstevel@tonic-gate scsi_ck_format,
1340Sstevel@tonic-gate scsi_format,
1350Sstevel@tonic-gate scsi_ex_man,
1360Sstevel@tonic-gate scsi_ex_cur,
1370Sstevel@tonic-gate scsi_repair,
1380Sstevel@tonic-gate 0,
1390Sstevel@tonic-gate };
1400Sstevel@tonic-gate
1410Sstevel@tonic-gate #define SCMD_UNKNOWN 0xff
1420Sstevel@tonic-gate
1430Sstevel@tonic-gate /*
1440Sstevel@tonic-gate * Names of commands. Must have SCMD_UNKNOWN at end of list.
1450Sstevel@tonic-gate */
1460Sstevel@tonic-gate static struct scsi_command_name {
1470Sstevel@tonic-gate uchar_t command;
1480Sstevel@tonic-gate char *name;
1490Sstevel@tonic-gate } scsi_command_names[] = {
1500Sstevel@tonic-gate SCMD_FORMAT, "format",
1510Sstevel@tonic-gate SCMD_READ, "read",
1520Sstevel@tonic-gate SCMD_WRITE, "write",
1530Sstevel@tonic-gate SCMD_READ|SCMD_GROUP1, "read",
1540Sstevel@tonic-gate SCMD_WRITE|SCMD_GROUP1, "write",
1550Sstevel@tonic-gate SCMD_INQUIRY, "inquiry",
1560Sstevel@tonic-gate SCMD_MODE_SELECT, "mode select",
1570Sstevel@tonic-gate SCMD_MODE_SENSE, "mode sense",
1580Sstevel@tonic-gate SCMD_REASSIGN_BLOCK, "reassign block",
1590Sstevel@tonic-gate SCMD_READ_DEFECT_LIST, "read defect list",
1600Sstevel@tonic-gate SCMD_UNKNOWN, "unknown"
1610Sstevel@tonic-gate };
1620Sstevel@tonic-gate
1630Sstevel@tonic-gate
1640Sstevel@tonic-gate /*
1650Sstevel@tonic-gate * Strings for printing mode sense page control values
1660Sstevel@tonic-gate */
1670Sstevel@tonic-gate static slist_t page_control_strings[] = {
1680Sstevel@tonic-gate { "current", "", MODE_SENSE_PC_CURRENT },
1690Sstevel@tonic-gate { "changeable", "", MODE_SENSE_PC_CHANGEABLE },
1700Sstevel@tonic-gate { "default", "", MODE_SENSE_PC_DEFAULT },
1710Sstevel@tonic-gate { "saved", "", MODE_SENSE_PC_SAVED }
1720Sstevel@tonic-gate };
1730Sstevel@tonic-gate
1740Sstevel@tonic-gate /*
1750Sstevel@tonic-gate * Strings for printing the mode select options
1760Sstevel@tonic-gate */
1770Sstevel@tonic-gate static slist_t mode_select_strings[] = {
1780Sstevel@tonic-gate { "", "", 0 },
1790Sstevel@tonic-gate { " (pf)", "", MODE_SELECT_PF },
1800Sstevel@tonic-gate { " (sp)", "", MODE_SELECT_SP },
1810Sstevel@tonic-gate { " (pf,sp)", "", MODE_SELECT_PF|MODE_SELECT_SP }
1820Sstevel@tonic-gate };
1830Sstevel@tonic-gate
1840Sstevel@tonic-gate static int scsi_format_revolutions = 5;
1850Sstevel@tonic-gate static int scsi_format_timeout = 2*60*60; /* two hours */
1860Sstevel@tonic-gate
1870Sstevel@tonic-gate /*
1880Sstevel@tonic-gate * READ DEFECT DATA commands is optional as per SCSI-2 spec.
1890Sstevel@tonic-gate * Hence check if the read_defect_data command fails with
1900Sstevel@tonic-gate * Invalid Opcode so that we can give a more meaningful message
1910Sstevel@tonic-gate * to the user.
1920Sstevel@tonic-gate */
1930Sstevel@tonic-gate #define INVALID_OPCODE 0x20
1940Sstevel@tonic-gate
1950Sstevel@tonic-gate /*
1960Sstevel@tonic-gate * Read or write the disk.
1970Sstevel@tonic-gate */
1980Sstevel@tonic-gate int
scsi_rdwr(dir,fd,blkno,secnt,bufaddr,flags,xfercntp)1990Sstevel@tonic-gate scsi_rdwr(dir, fd, blkno, secnt, bufaddr, flags, xfercntp)
2000Sstevel@tonic-gate int dir;
2010Sstevel@tonic-gate int fd;
2020Sstevel@tonic-gate diskaddr_t blkno;
2030Sstevel@tonic-gate int secnt;
2040Sstevel@tonic-gate caddr_t bufaddr;
2050Sstevel@tonic-gate int flags;
2060Sstevel@tonic-gate int *xfercntp;
2070Sstevel@tonic-gate {
2080Sstevel@tonic-gate struct uscsi_cmd ucmd;
2090Sstevel@tonic-gate union scsi_cdb cdb;
2100Sstevel@tonic-gate int max_sectors;
2110Sstevel@tonic-gate int rc = 0;
2120Sstevel@tonic-gate
2130Sstevel@tonic-gate /*
2140Sstevel@tonic-gate * If the max xfercnt hasn't been determined start with BUF_SECTS
2150Sstevel@tonic-gate * (currently 126 == 63K), otherwise use the xfercnt value
2160Sstevel@tonic-gate * my caller saved from the previous invocation.
2170Sstevel@tonic-gate */
2180Sstevel@tonic-gate if (xfercntp == NULL) {
2190Sstevel@tonic-gate max_sectors = BUF_SECTS;
2200Sstevel@tonic-gate } else if (*xfercntp == 0) {
2210Sstevel@tonic-gate max_sectors = BUF_SECTS;
2220Sstevel@tonic-gate *xfercntp = max_sectors;
2230Sstevel@tonic-gate } else {
2240Sstevel@tonic-gate max_sectors = *xfercntp;
2250Sstevel@tonic-gate }
2260Sstevel@tonic-gate
2270Sstevel@tonic-gate /*
2280Sstevel@tonic-gate * Build and execute the uscsi ioctl. We build a group0
2290Sstevel@tonic-gate * or group1 command as necessary, since some targets
2300Sstevel@tonic-gate * do not support group1 commands.
2310Sstevel@tonic-gate */
2320Sstevel@tonic-gate while (secnt) {
2330Sstevel@tonic-gate int nsectors;
2340Sstevel@tonic-gate
2350Sstevel@tonic-gate nsectors = (max_sectors < secnt) ? max_sectors : secnt;
2360Sstevel@tonic-gate (void) memset((char *)&ucmd, 0, sizeof (ucmd));
2370Sstevel@tonic-gate (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb));
2380Sstevel@tonic-gate cdb.scc_cmd = (dir == DIR_READ) ? SCMD_READ : SCMD_WRITE;
2390Sstevel@tonic-gate if (blkno < (2<<20) && nsectors <= 0xff) {
2400Sstevel@tonic-gate FORMG0ADDR(&cdb, blkno);
2410Sstevel@tonic-gate FORMG0COUNT(&cdb, nsectors);
2420Sstevel@tonic-gate ucmd.uscsi_cdblen = CDB_GROUP0;
2430Sstevel@tonic-gate } else {
2440Sstevel@tonic-gate if (blkno > 0xffffffff) {
2450Sstevel@tonic-gate FORMG4LONGADDR(&cdb, blkno);
2460Sstevel@tonic-gate FORMG4COUNT(&cdb, nsectors);
2470Sstevel@tonic-gate ucmd.uscsi_cdblen = CDB_GROUP4;
2480Sstevel@tonic-gate cdb.scc_cmd |= SCMD_GROUP4;
2490Sstevel@tonic-gate } else {
2500Sstevel@tonic-gate FORMG1ADDR(&cdb, blkno);
2510Sstevel@tonic-gate FORMG1COUNT(&cdb, nsectors);
2520Sstevel@tonic-gate ucmd.uscsi_cdblen = CDB_GROUP1;
2530Sstevel@tonic-gate cdb.scc_cmd |= SCMD_GROUP1;
2540Sstevel@tonic-gate }
2550Sstevel@tonic-gate }
2560Sstevel@tonic-gate ucmd.uscsi_cdb = (caddr_t)&cdb;
2570Sstevel@tonic-gate ucmd.uscsi_bufaddr = bufaddr;
2589889SLarry.Liu@Sun.COM ucmd.uscsi_buflen = nsectors * cur_blksz;
2590Sstevel@tonic-gate rc = uscsi_cmd(fd, &ucmd, flags);
2600Sstevel@tonic-gate
2610Sstevel@tonic-gate if (rc != 0)
2620Sstevel@tonic-gate break;
2630Sstevel@tonic-gate
2640Sstevel@tonic-gate /*
2650Sstevel@tonic-gate * check if partial DMA breakup required
2660Sstevel@tonic-gate * if so, reduce the request size by half and retry
2670Sstevel@tonic-gate * the last request
2680Sstevel@tonic-gate */
2690Sstevel@tonic-gate if (ucmd.uscsi_resid == ucmd.uscsi_buflen) {
2700Sstevel@tonic-gate max_sectors >>= 1;
2710Sstevel@tonic-gate if (max_sectors <= 0) {
2720Sstevel@tonic-gate rc = -1;
2730Sstevel@tonic-gate break;
2740Sstevel@tonic-gate }
2750Sstevel@tonic-gate continue;
2760Sstevel@tonic-gate }
2770Sstevel@tonic-gate if (ucmd.uscsi_resid != 0) {
2780Sstevel@tonic-gate rc = -1;
2790Sstevel@tonic-gate break;
2800Sstevel@tonic-gate }
2810Sstevel@tonic-gate
2820Sstevel@tonic-gate blkno += nsectors;
2830Sstevel@tonic-gate secnt -= nsectors;
2849889SLarry.Liu@Sun.COM bufaddr += nsectors * cur_blksz;
2850Sstevel@tonic-gate }
2860Sstevel@tonic-gate
2870Sstevel@tonic-gate /*
2880Sstevel@tonic-gate * If the xfercnt wasn't previously saved or if the
2890Sstevel@tonic-gate * new value is smaller than the old value, save the
2900Sstevel@tonic-gate * current value in my caller's save area.
2910Sstevel@tonic-gate */
2920Sstevel@tonic-gate if (xfercntp != NULL && max_sectors < *xfercntp) {
2930Sstevel@tonic-gate if (diag_msg)
2940Sstevel@tonic-gate err_print("reducing xfercnt %d %d\n",
2950Sstevel@tonic-gate *xfercntp, max_sectors);
2960Sstevel@tonic-gate *xfercntp = max_sectors;
2970Sstevel@tonic-gate }
2980Sstevel@tonic-gate return (rc);
2990Sstevel@tonic-gate }
3000Sstevel@tonic-gate
3010Sstevel@tonic-gate
3020Sstevel@tonic-gate /*
3030Sstevel@tonic-gate * Check to see if the disk has been formatted.
3040Sstevel@tonic-gate * If we are able to read the first track, we conclude that
3050Sstevel@tonic-gate * the disk has been formatted.
3060Sstevel@tonic-gate */
3070Sstevel@tonic-gate #ifdef i386
3080Sstevel@tonic-gate static int
3090Sstevel@tonic-gate #else /* i386 */
3100Sstevel@tonic-gate static int
3110Sstevel@tonic-gate #endif /* i386 */
scsi_ck_format(void)3120Sstevel@tonic-gate scsi_ck_format(void)
3130Sstevel@tonic-gate {
3140Sstevel@tonic-gate int status;
3150Sstevel@tonic-gate
3160Sstevel@tonic-gate /*
3170Sstevel@tonic-gate * Try to read the first four blocks.
3180Sstevel@tonic-gate */
3197563SPrasad.Singamsetty@Sun.COM status = scsi_rdwr(DIR_READ, cur_file, (diskaddr_t)0, 4,
3209889SLarry.Liu@Sun.COM (caddr_t)cur_buf, F_SILENT, NULL);
3210Sstevel@tonic-gate return (!status);
3220Sstevel@tonic-gate }
3230Sstevel@tonic-gate
3240Sstevel@tonic-gate
3250Sstevel@tonic-gate /*
3260Sstevel@tonic-gate * Format the disk, the whole disk, and nothing but the disk.
3270Sstevel@tonic-gate */
3280Sstevel@tonic-gate /*ARGSUSED*/
3290Sstevel@tonic-gate static int
scsi_format(start,end,list)3300Sstevel@tonic-gate scsi_format(start, end, list)
3310Sstevel@tonic-gate uint64_t start; /* irrelevant for us */
3320Sstevel@tonic-gate uint64_t end;
3330Sstevel@tonic-gate struct defect_list *list;
3340Sstevel@tonic-gate {
3350Sstevel@tonic-gate struct uscsi_cmd ucmd;
3360Sstevel@tonic-gate union scsi_cdb cdb;
3370Sstevel@tonic-gate int status;
3380Sstevel@tonic-gate int flag;
33912594SShengliang.Zhang@Sun.COM char rawbuf[MAX_MODE_SENSE_SIZE];
3400Sstevel@tonic-gate struct scsi_inquiry *inq;
34112594SShengliang.Zhang@Sun.COM uint8_t fmt_prot_info;
34212594SShengliang.Zhang@Sun.COM uint8_t prot_field_usage;
34312594SShengliang.Zhang@Sun.COM uint8_t param_long_list = 1;
34412594SShengliang.Zhang@Sun.COM uint8_t fmt_long_param_header[8];
3450Sstevel@tonic-gate
3460Sstevel@tonic-gate /*
3470Sstevel@tonic-gate * Determine if the target appears to be SCSI-2
3480Sstevel@tonic-gate * compliant. We handle mode sense/mode selects
3490Sstevel@tonic-gate * a little differently, depending upon CCS/SCSI-2
3500Sstevel@tonic-gate */
3510Sstevel@tonic-gate if (uscsi_inquiry(cur_file, rawbuf, sizeof (rawbuf))) {
3520Sstevel@tonic-gate err_print("Inquiry failed\n");
3530Sstevel@tonic-gate return (-1);
3540Sstevel@tonic-gate }
3550Sstevel@tonic-gate inq = (struct scsi_inquiry *)rawbuf;
3560Sstevel@tonic-gate flag = (inq->inq_rdf == RDF_SCSI2);
3570Sstevel@tonic-gate
3580Sstevel@tonic-gate /*
3590Sstevel@tonic-gate * Reserve the scsi disk before performing mode select and
3600Sstevel@tonic-gate * format operations. This will keep other hosts, if any, from
3610Sstevel@tonic-gate * touching the disk while we are here.
3620Sstevel@tonic-gate */
3630Sstevel@tonic-gate if (uscsi_reserve_release(cur_file, SCMD_RESERVE)) {
3640Sstevel@tonic-gate err_print("Reserve failed\n");
3650Sstevel@tonic-gate return (-1);
3660Sstevel@tonic-gate }
3670Sstevel@tonic-gate
3680Sstevel@tonic-gate /*
3690Sstevel@tonic-gate * Set up the various SCSI parameters specified before
3700Sstevel@tonic-gate * formatting the disk. Each routine handles the
3713517Smp204432 * parameters relevant to a particular page.
3720Sstevel@tonic-gate * If no parameters are specified for a page, there's
3730Sstevel@tonic-gate * no need to do anything. Otherwise, issue a mode
3740Sstevel@tonic-gate * sense for that page. If a specified parameter
3750Sstevel@tonic-gate * differs from the drive's default value, and that
3760Sstevel@tonic-gate * parameter is not fixed, then issue a mode select to
3770Sstevel@tonic-gate * set the default value for the disk as specified
3780Sstevel@tonic-gate * in format.dat.
3790Sstevel@tonic-gate */
3800Sstevel@tonic-gate if (scsi_ms_page1(flag) || scsi_ms_page2(flag) ||
3810Sstevel@tonic-gate scsi_ms_page4(flag) || scsi_ms_page38(flag) ||
3820Sstevel@tonic-gate scsi_ms_page8(flag) || scsi_ms_page3(flag)) {
3830Sstevel@tonic-gate (void) uscsi_reserve_release(cur_file, SCMD_RELEASE);
3840Sstevel@tonic-gate return (-1);
3850Sstevel@tonic-gate }
3860Sstevel@tonic-gate
3870Sstevel@tonic-gate /*
3880Sstevel@tonic-gate * If we're debugging the drive, dump every page
3890Sstevel@tonic-gate * the device supports, for thorough analysis.
3900Sstevel@tonic-gate */
3910Sstevel@tonic-gate if (option_msg && diag_msg) {
3920Sstevel@tonic-gate (void) scsi_dump_mode_sense_pages(MODE_SENSE_PC_DEFAULT);
3930Sstevel@tonic-gate (void) scsi_dump_mode_sense_pages(MODE_SENSE_PC_CURRENT);
3940Sstevel@tonic-gate (void) scsi_dump_mode_sense_pages(MODE_SENSE_PC_SAVED);
3950Sstevel@tonic-gate (void) scsi_dump_mode_sense_pages(MODE_SENSE_PC_CHANGEABLE);
3960Sstevel@tonic-gate err_print("\n");
3970Sstevel@tonic-gate }
3980Sstevel@tonic-gate
3990Sstevel@tonic-gate /*
40012594SShengliang.Zhang@Sun.COM * Determine the FMTPINFO field in format cdb, and the
40112594SShengliang.Zhang@Sun.COM * PROTECTION FIELD USAGE in the long parameter list, via
40212594SShengliang.Zhang@Sun.COM * the protection type input by users.
40312594SShengliang.Zhang@Sun.COM */
40412594SShengliang.Zhang@Sun.COM switch (prot_type) {
40512594SShengliang.Zhang@Sun.COM case PROT_TYPE_0:
40612594SShengliang.Zhang@Sun.COM fmt_prot_info = 0x00;
40712594SShengliang.Zhang@Sun.COM prot_field_usage = 0x00;
40812594SShengliang.Zhang@Sun.COM break;
40912594SShengliang.Zhang@Sun.COM case PROT_TYPE_1:
41012594SShengliang.Zhang@Sun.COM fmt_prot_info = 0x02;
41112594SShengliang.Zhang@Sun.COM prot_field_usage = 0x00;
41212594SShengliang.Zhang@Sun.COM break;
41312594SShengliang.Zhang@Sun.COM case PROT_TYPE_2:
41412594SShengliang.Zhang@Sun.COM fmt_prot_info = 0x03;
41512594SShengliang.Zhang@Sun.COM prot_field_usage = 0x00;
41612594SShengliang.Zhang@Sun.COM break;
41712594SShengliang.Zhang@Sun.COM case PROT_TYPE_3:
41812594SShengliang.Zhang@Sun.COM fmt_prot_info = 0x03;
41912594SShengliang.Zhang@Sun.COM prot_field_usage = 0x01;
42012594SShengliang.Zhang@Sun.COM break;
42112594SShengliang.Zhang@Sun.COM default:
42212594SShengliang.Zhang@Sun.COM fmt_print("invalid protection type\n");
42312594SShengliang.Zhang@Sun.COM return (-1);
42412594SShengliang.Zhang@Sun.COM }
42512594SShengliang.Zhang@Sun.COM
42612594SShengliang.Zhang@Sun.COM /*
4270Sstevel@tonic-gate * Construct the uscsi format ioctl. The form depends
4280Sstevel@tonic-gate * upon the defect list the user extracted. If s/he
4290Sstevel@tonic-gate * extracted the "original" list, we format with only
4300Sstevel@tonic-gate * the P (manufacturer's defect) list. Otherwise, we
4310Sstevel@tonic-gate * format with both the P and the G (grown) list.
4320Sstevel@tonic-gate * To format with the P and G list, we set the fmtData
4330Sstevel@tonic-gate * bit, and send an empty list. To format with the
4340Sstevel@tonic-gate * P list only, we also set the cmpLst bit, meaning
4350Sstevel@tonic-gate * that the (empty) list we send down is the complete
4360Sstevel@tonic-gate * G list, thereby discarding the old G list..
4370Sstevel@tonic-gate */
4380Sstevel@tonic-gate (void) memset((char *)&ucmd, 0, sizeof (ucmd));
4390Sstevel@tonic-gate (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb));
4400Sstevel@tonic-gate
4410Sstevel@tonic-gate cdb.scc_cmd = SCMD_FORMAT;
4420Sstevel@tonic-gate ucmd.uscsi_cdb = (caddr_t)&cdb;
4430Sstevel@tonic-gate ucmd.uscsi_cdblen = CDB_GROUP0;
4440Sstevel@tonic-gate cdb.cdb_opaque[1] = FPB_DATA;
44512594SShengliang.Zhang@Sun.COM
44612594SShengliang.Zhang@Sun.COM /*
44712594SShengliang.Zhang@Sun.COM * Use the long parameter header in format command,
44812594SShengliang.Zhang@Sun.COM * and set the FMTPINFO field., when type 1, 2, 3.
44912594SShengliang.Zhang@Sun.COM */
45012594SShengliang.Zhang@Sun.COM cdb.cdb_opaque[1] |= (param_long_list << 5) | (fmt_prot_info << 6);
45112594SShengliang.Zhang@Sun.COM (void) memset((char *)fmt_long_param_header, 0,
45212594SShengliang.Zhang@Sun.COM sizeof (fmt_long_param_header));
45312594SShengliang.Zhang@Sun.COM
45412594SShengliang.Zhang@Sun.COM /*
45512594SShengliang.Zhang@Sun.COM * Set the PROTECTION FIELD USAGE field in the long
45612594SShengliang.Zhang@Sun.COM * parameter list header, which combines with FMTINFO to
45712594SShengliang.Zhang@Sun.COM * determine the protection type.
45812594SShengliang.Zhang@Sun.COM * The PROTECTION INTERVAL EXPONET field is set default 0.
45912594SShengliang.Zhang@Sun.COM * So only one protection information interval is used
46012594SShengliang.Zhang@Sun.COM * in type 1, 2, 3.
46112594SShengliang.Zhang@Sun.COM */
46212594SShengliang.Zhang@Sun.COM fmt_long_param_header[0] = prot_field_usage;
46312594SShengliang.Zhang@Sun.COM fmt_long_param_header[1] = FDH_FOV | FDH_IMMED;
46412594SShengliang.Zhang@Sun.COM ucmd.uscsi_bufaddr = (caddr_t)fmt_long_param_header;
46512594SShengliang.Zhang@Sun.COM ucmd.uscsi_buflen = sizeof (fmt_long_param_header);
4660Sstevel@tonic-gate
4670Sstevel@tonic-gate if ((list->list != NULL) && ((list->flags & LIST_PGLIST) == 0)) {
4680Sstevel@tonic-gate /*
4690Sstevel@tonic-gate * No G list. The empty list we send down
4700Sstevel@tonic-gate * is the complete list.
4710Sstevel@tonic-gate */
4720Sstevel@tonic-gate cdb.cdb_opaque[1] |= FPB_CMPLT;
4730Sstevel@tonic-gate }
4740Sstevel@tonic-gate
4750Sstevel@tonic-gate /*
4760Sstevel@tonic-gate * Issue the format ioctl
4770Sstevel@tonic-gate */
4780Sstevel@tonic-gate fmt_print("Formatting...\n");
4790Sstevel@tonic-gate (void) fflush(stdout);
4800Sstevel@tonic-gate status = uscsi_cmd(cur_file, &ucmd,
4810Sstevel@tonic-gate (option_msg && diag_msg) ? F_NORMAL : F_SILENT);
4820Sstevel@tonic-gate
4830Sstevel@tonic-gate /* check if format with immed was successfully accepted */
4840Sstevel@tonic-gate if (status == 0) {
485*12930SRalph.Turner@Sun.COM /* immed accepted poll to completion */
4860Sstevel@tonic-gate status = test_until_ready(cur_file);
4870Sstevel@tonic-gate } else {
488*12930SRalph.Turner@Sun.COM /* clear FOV and try again */
48912594SShengliang.Zhang@Sun.COM (void) memset((char *)fmt_long_param_header, 0,
49012594SShengliang.Zhang@Sun.COM sizeof (fmt_long_param_header));
49112594SShengliang.Zhang@Sun.COM fmt_long_param_header[0] = prot_field_usage;
492*12930SRalph.Turner@Sun.COM fmt_long_param_header[1] = FDH_IMMED;
4930Sstevel@tonic-gate status = uscsi_cmd(cur_file, &ucmd,
494*12930SRalph.Turner@Sun.COM (option_msg && diag_msg) ? F_NORMAL : F_SILENT);
495*12930SRalph.Turner@Sun.COM if (status == 0) {
496*12930SRalph.Turner@Sun.COM /* immed accepted, poll for progress */
497*12930SRalph.Turner@Sun.COM status = test_until_ready(cur_file);
498*12930SRalph.Turner@Sun.COM } else {
499*12930SRalph.Turner@Sun.COM /*
500*12930SRalph.Turner@Sun.COM * clear defect header and try basecase format
501*12930SRalph.Turner@Sun.COM * command will hang until format complete
502*12930SRalph.Turner@Sun.COM */
503*12930SRalph.Turner@Sun.COM (void) memset((char *)fmt_long_param_header, 0,
504*12930SRalph.Turner@Sun.COM sizeof (fmt_long_param_header));
505*12930SRalph.Turner@Sun.COM fmt_long_param_header[0] = prot_field_usage;
506*12930SRalph.Turner@Sun.COM status = uscsi_cmd(cur_file, &ucmd,
507*12930SRalph.Turner@Sun.COM (option_msg && diag_msg) ? F_NORMAL : F_SILENT);
508*12930SRalph.Turner@Sun.COM }
5090Sstevel@tonic-gate }
5100Sstevel@tonic-gate
5110Sstevel@tonic-gate /* format failure check */
5120Sstevel@tonic-gate if (status != 0) {
5130Sstevel@tonic-gate /*
5140Sstevel@tonic-gate * formatting failed with fmtdata = 1.
5150Sstevel@tonic-gate * Check if defects list command is supported, if it
5160Sstevel@tonic-gate * is not supported then use fmtdata = 0.
5170Sstevel@tonic-gate * From SCSI Spec
5180Sstevel@tonic-gate * A FmtData bit of zero indicates, the
5190Sstevel@tonic-gate * source of defect information is not specified.
5200Sstevel@tonic-gate * else
5210Sstevel@tonic-gate * proceed to format using with mode selects.
5220Sstevel@tonic-gate */
5230Sstevel@tonic-gate if (!(check_support_for_defects())) {
5240Sstevel@tonic-gate status = scsi_format_without_defects();
5250Sstevel@tonic-gate }
5260Sstevel@tonic-gate
5270Sstevel@tonic-gate if (status != 0) {
5280Sstevel@tonic-gate fmt_print("Format failed\n");
5290Sstevel@tonic-gate status = scsi_raw_format();
5300Sstevel@tonic-gate }
5310Sstevel@tonic-gate }
5320Sstevel@tonic-gate (void) uscsi_reserve_release(cur_file, SCMD_RELEASE);
5330Sstevel@tonic-gate return (status);
5340Sstevel@tonic-gate }
5350Sstevel@tonic-gate
5360Sstevel@tonic-gate /*
5370Sstevel@tonic-gate * Format without any of the standard mode selects ignoring Grown defects list.
5380Sstevel@tonic-gate */
5390Sstevel@tonic-gate static int
scsi_raw_format(void)5400Sstevel@tonic-gate scsi_raw_format(void)
5410Sstevel@tonic-gate {
5420Sstevel@tonic-gate struct uscsi_cmd ucmd;
5430Sstevel@tonic-gate union scsi_cdb cdb;
5440Sstevel@tonic-gate struct scsi_defect_hdr defect_hdr;
5450Sstevel@tonic-gate int status;
5460Sstevel@tonic-gate
5470Sstevel@tonic-gate fmt_print("\n"
5480Sstevel@tonic-gate "Retry of formatting operation without any of the standard\n"
5490Sstevel@tonic-gate "mode selects and ignoring disk's Grown Defects list. The\n"
5500Sstevel@tonic-gate "disk may be able to be reformatted this way if an earlier\n"
5510Sstevel@tonic-gate "formatting operation was interrupted by a power failure or\n"
5520Sstevel@tonic-gate "SCSI bus reset. The Grown Defects list will be recreated\n"
5530Sstevel@tonic-gate "by format verification and surface analysis.\n\n");
5540Sstevel@tonic-gate
5550Sstevel@tonic-gate if (check("Retry format without mode selects and Grown Defects list")
5569889SLarry.Liu@Sun.COM != 0) {
5570Sstevel@tonic-gate return (-1);
5580Sstevel@tonic-gate }
5590Sstevel@tonic-gate
5600Sstevel@tonic-gate /*
5610Sstevel@tonic-gate * Construct the uscsi format ioctl.
5620Sstevel@tonic-gate * To format with the P and G list, we set the fmtData
5630Sstevel@tonic-gate * and cmpLst bits to zero. To format with just the
5640Sstevel@tonic-gate * P list, we set the fmtData bit (meaning that we will
5650Sstevel@tonic-gate * send down a defect list in the data phase) and the
5660Sstevel@tonic-gate * cmpLst bit (meaning that the list we send is the
5670Sstevel@tonic-gate * complete G list), and a defect list header with
5680Sstevel@tonic-gate * a defect list length of zero.
5690Sstevel@tonic-gate */
5700Sstevel@tonic-gate (void) memset((char *)&ucmd, 0, sizeof (ucmd));
5710Sstevel@tonic-gate (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb));
5720Sstevel@tonic-gate (void) memset((char *)&defect_hdr, 0, sizeof (defect_hdr));
5730Sstevel@tonic-gate
5740Sstevel@tonic-gate cdb.scc_cmd = SCMD_FORMAT;
5750Sstevel@tonic-gate ucmd.uscsi_cdb = (caddr_t)&cdb;
5760Sstevel@tonic-gate ucmd.uscsi_cdblen = CDB_GROUP0;
5770Sstevel@tonic-gate /* No G list. Send empty defect list to replace it */
5780Sstevel@tonic-gate cdb.cdb_opaque[1] = FPB_DATA | FPB_CMPLT | FPB_BFI;
5790Sstevel@tonic-gate ucmd.uscsi_bufaddr = (caddr_t)&defect_hdr;
5800Sstevel@tonic-gate ucmd.uscsi_buflen = sizeof (defect_hdr);
5810Sstevel@tonic-gate defect_hdr.descriptor = FDH_FOV | FDH_IMMED;
5820Sstevel@tonic-gate
5830Sstevel@tonic-gate /*
5840Sstevel@tonic-gate * Issue the format ioctl
5850Sstevel@tonic-gate */
5860Sstevel@tonic-gate fmt_print("Formatting...\n");
5870Sstevel@tonic-gate (void) fflush(stdout);
5880Sstevel@tonic-gate status = uscsi_cmd(cur_file, &ucmd, F_NORMAL);
5890Sstevel@tonic-gate
5900Sstevel@tonic-gate /* check if format with immed was successfully accepted */
5910Sstevel@tonic-gate if (status == 0) {
5920Sstevel@tonic-gate /* immed accepted pool to completion */
5930Sstevel@tonic-gate status = test_until_ready(cur_file);
5940Sstevel@tonic-gate } else {
5950Sstevel@tonic-gate /* clear defect header and try basecase format */
5960Sstevel@tonic-gate (void) memset((char *)&defect_hdr, 0, sizeof (defect_hdr));
5970Sstevel@tonic-gate status = uscsi_cmd(cur_file, &ucmd, F_NORMAL);
5980Sstevel@tonic-gate }
5990Sstevel@tonic-gate
6000Sstevel@tonic-gate /* fmt_print(status ? "Format failed\n\n" : "Format ok\n\n"); */
6010Sstevel@tonic-gate return (status);
6020Sstevel@tonic-gate }
6030Sstevel@tonic-gate
6040Sstevel@tonic-gate /*
6050Sstevel@tonic-gate * Estimate the time required for format operation (See 1163770).
6060Sstevel@tonic-gate * format time = (5_revs * p4_heads * p4_cylinders) / p4_rpm
6070Sstevel@tonic-gate * 5 revolutions (correspond to format_time keyword in format.dat file) are:
6080Sstevel@tonic-gate * 1 rev. for positioning
6090Sstevel@tonic-gate * 2 rev. for writing the track
6100Sstevel@tonic-gate * 1 rev. for positioning
6110Sstevel@tonic-gate * 1 rev. for cerifying the data integrity of the track
6120Sstevel@tonic-gate * The return value is a good estimate on the formatting time in minutes.
6130Sstevel@tonic-gate * Caller should add 50% margin to cover defect management overhead.
6140Sstevel@tonic-gate */
6150Sstevel@tonic-gate int
scsi_format_time()6160Sstevel@tonic-gate scsi_format_time()
6170Sstevel@tonic-gate {
6180Sstevel@tonic-gate struct mode_geometry *page4;
6190Sstevel@tonic-gate struct scsi_ms_header header;
6200Sstevel@tonic-gate int status;
6210Sstevel@tonic-gate int p4_cylinders, p4_heads, p4_rpm;
6220Sstevel@tonic-gate int length;
6230Sstevel@tonic-gate int format_time;
6240Sstevel@tonic-gate union {
6250Sstevel@tonic-gate struct mode_geometry page4;
6260Sstevel@tonic-gate char rawbuf[MAX_MODE_SENSE_SIZE];
6270Sstevel@tonic-gate } u_page4;
6280Sstevel@tonic-gate
6290Sstevel@tonic-gate
6300Sstevel@tonic-gate page4 = &u_page4.page4;
6310Sstevel@tonic-gate (void) memset(&u_page4, 0, sizeof (u_page4));
6320Sstevel@tonic-gate
6330Sstevel@tonic-gate /*
6340Sstevel@tonic-gate * Issue a mode sense to determine the default parameters
6350Sstevel@tonic-gate * If it fail, try to use the saved or current instead.
6360Sstevel@tonic-gate */
6370Sstevel@tonic-gate status = uscsi_mode_sense(cur_file, DAD_MODE_GEOMETRY,
6389889SLarry.Liu@Sun.COM MODE_SENSE_PC_DEFAULT, (caddr_t)page4,
6399889SLarry.Liu@Sun.COM MAX_MODE_SENSE_SIZE, &header);
6400Sstevel@tonic-gate
6410Sstevel@tonic-gate if (status) {
6420Sstevel@tonic-gate status = uscsi_mode_sense(cur_file, DAD_MODE_GEOMETRY,
6439889SLarry.Liu@Sun.COM MODE_SENSE_PC_SAVED, (caddr_t)page4,
6449889SLarry.Liu@Sun.COM MAX_MODE_SENSE_SIZE, &header);
6450Sstevel@tonic-gate }
6460Sstevel@tonic-gate if (status) {
6470Sstevel@tonic-gate status = uscsi_mode_sense(cur_file, DAD_MODE_GEOMETRY,
6489889SLarry.Liu@Sun.COM MODE_SENSE_PC_CURRENT, (caddr_t)page4,
6499889SLarry.Liu@Sun.COM MAX_MODE_SENSE_SIZE, &header);
6500Sstevel@tonic-gate }
6510Sstevel@tonic-gate if (status) {
6520Sstevel@tonic-gate return (0);
6530Sstevel@tonic-gate }
6540Sstevel@tonic-gate
6550Sstevel@tonic-gate /*
6560Sstevel@tonic-gate * We only need the common subset between the CCS
6570Sstevel@tonic-gate * and SCSI-2 structures, so we can treat both
6580Sstevel@tonic-gate * cases identically.
6590Sstevel@tonic-gate */
6600Sstevel@tonic-gate length = MODESENSE_PAGE_LEN(page4);
6610Sstevel@tonic-gate if (length < MIN_PAGE4_LEN) {
6620Sstevel@tonic-gate return (0);
6630Sstevel@tonic-gate }
6640Sstevel@tonic-gate
6650Sstevel@tonic-gate page4->rpm = BE_16(page4->rpm);
6660Sstevel@tonic-gate p4_cylinders = (page4->cyl_ub << 16) + (page4->cyl_mb << 8) +
6679889SLarry.Liu@Sun.COM page4->cyl_lb;
6680Sstevel@tonic-gate p4_heads = page4->heads;
6690Sstevel@tonic-gate p4_rpm = page4->rpm;
6700Sstevel@tonic-gate
6710Sstevel@tonic-gate /*
6720Sstevel@tonic-gate * Some drives report 0 for page4->rpm, adjust it to AVG_RPM, 3600.
6730Sstevel@tonic-gate */
6740Sstevel@tonic-gate if (p4_rpm < MIN_RPM || p4_rpm > MAX_RPM) {
6750Sstevel@tonic-gate err_print("Mode sense page(4) reports rpm value as %d,"
6769889SLarry.Liu@Sun.COM " adjusting it to %d\n", p4_rpm, AVG_RPM);
6770Sstevel@tonic-gate p4_rpm = AVG_RPM;
6780Sstevel@tonic-gate }
6790Sstevel@tonic-gate
6800Sstevel@tonic-gate if (p4_cylinders <= 0 || p4_heads <= 0)
6810Sstevel@tonic-gate return (0);
6820Sstevel@tonic-gate
6830Sstevel@tonic-gate format_time = ((scsi_format_revolutions * p4_heads *
6849889SLarry.Liu@Sun.COM p4_cylinders) + p4_rpm) / p4_rpm;
6850Sstevel@tonic-gate
6860Sstevel@tonic-gate if (option_msg && diag_msg) {
6870Sstevel@tonic-gate err_print(" pcyl: %d\n", p4_cylinders);
6880Sstevel@tonic-gate err_print(" heads: %d\n", p4_heads);
6890Sstevel@tonic-gate err_print(" rpm: %d\n", p4_rpm);
6900Sstevel@tonic-gate err_print("format_time: %d minutes\n", format_time);
6910Sstevel@tonic-gate }
6920Sstevel@tonic-gate return (format_time);
6930Sstevel@tonic-gate }
6940Sstevel@tonic-gate
6950Sstevel@tonic-gate /*
6960Sstevel@tonic-gate * Check disk error recovery parameters via mode sense.
6970Sstevel@tonic-gate * Issue a mode select if we need to change something.
6980Sstevel@tonic-gate */
6990Sstevel@tonic-gate /*ARGSUSED*/
7000Sstevel@tonic-gate static int
scsi_ms_page1(scsi2_flag)7010Sstevel@tonic-gate scsi_ms_page1(scsi2_flag)
7020Sstevel@tonic-gate int scsi2_flag;
7030Sstevel@tonic-gate {
7040Sstevel@tonic-gate struct mode_err_recov *page1;
7050Sstevel@tonic-gate struct mode_err_recov *fixed;
7060Sstevel@tonic-gate struct scsi_ms_header header;
7070Sstevel@tonic-gate struct scsi_ms_header fixed_hdr;
7080Sstevel@tonic-gate int status;
7090Sstevel@tonic-gate int tmp1, tmp2;
7100Sstevel@tonic-gate int flag;
7110Sstevel@tonic-gate int length;
7120Sstevel@tonic-gate int sp_flags;
7130Sstevel@tonic-gate union {
7140Sstevel@tonic-gate struct mode_err_recov page1;
7150Sstevel@tonic-gate char rawbuf[MAX_MODE_SENSE_SIZE];
7160Sstevel@tonic-gate } u_page1, u_fixed;
7170Sstevel@tonic-gate
7180Sstevel@tonic-gate
7190Sstevel@tonic-gate page1 = &u_page1.page1;
7200Sstevel@tonic-gate fixed = &u_fixed.page1;
7210Sstevel@tonic-gate
7220Sstevel@tonic-gate /*
7230Sstevel@tonic-gate * If debugging, issue mode senses on the default and
7240Sstevel@tonic-gate * current values.
7250Sstevel@tonic-gate */
7260Sstevel@tonic-gate if (option_msg && diag_msg) {
7270Sstevel@tonic-gate (void) uscsi_mode_sense(cur_file, DAD_MODE_ERR_RECOV,
7280Sstevel@tonic-gate MODE_SENSE_PC_DEFAULT, (caddr_t)page1,
7290Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header);
7300Sstevel@tonic-gate (void) uscsi_mode_sense(cur_file, DAD_MODE_ERR_RECOV,
7310Sstevel@tonic-gate MODE_SENSE_PC_CURRENT, (caddr_t)page1,
7320Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header);
7330Sstevel@tonic-gate }
7340Sstevel@tonic-gate
7350Sstevel@tonic-gate /*
7360Sstevel@tonic-gate * Issue a mode sense to determine the saved parameters
7370Sstevel@tonic-gate * If the saved values fail, use the current instead.
7380Sstevel@tonic-gate */
7390Sstevel@tonic-gate status = uscsi_mode_sense(cur_file, DAD_MODE_ERR_RECOV,
7400Sstevel@tonic-gate MODE_SENSE_PC_SAVED, (caddr_t)page1,
7410Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header);
7420Sstevel@tonic-gate if (status) {
7430Sstevel@tonic-gate status = uscsi_mode_sense(cur_file, DAD_MODE_ERR_RECOV,
7440Sstevel@tonic-gate MODE_SENSE_PC_CURRENT, (caddr_t)page1,
7450Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header);
7460Sstevel@tonic-gate if (status) {
7470Sstevel@tonic-gate return (0);
7480Sstevel@tonic-gate }
7490Sstevel@tonic-gate }
7500Sstevel@tonic-gate
7510Sstevel@tonic-gate /*
7520Sstevel@tonic-gate * We only need the common subset between the CCS
7530Sstevel@tonic-gate * and SCSI-2 structures, so we can treat both
7540Sstevel@tonic-gate * cases identically. Whatever the drive gives
7550Sstevel@tonic-gate * us, we return to the drive in the mode select,
7560Sstevel@tonic-gate * delta'ed by whatever we want to change.
7570Sstevel@tonic-gate */
7580Sstevel@tonic-gate length = MODESENSE_PAGE_LEN(page1);
7590Sstevel@tonic-gate if (length < MIN_PAGE1_LEN) {
7600Sstevel@tonic-gate return (0);
7610Sstevel@tonic-gate }
7620Sstevel@tonic-gate
7630Sstevel@tonic-gate /*
7640Sstevel@tonic-gate * Ask for changeable parameters.
7650Sstevel@tonic-gate */
7660Sstevel@tonic-gate status = uscsi_mode_sense(cur_file, DAD_MODE_ERR_RECOV,
7670Sstevel@tonic-gate MODE_SENSE_PC_CHANGEABLE, (caddr_t)fixed,
7680Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &fixed_hdr);
7690Sstevel@tonic-gate if (status || MODESENSE_PAGE_LEN(fixed) < MIN_PAGE1_LEN) {
7700Sstevel@tonic-gate return (0);
7710Sstevel@tonic-gate }
7720Sstevel@tonic-gate
7730Sstevel@tonic-gate /*
7740Sstevel@tonic-gate * We need to issue a mode select only if one or more
7750Sstevel@tonic-gate * parameters need to be changed, and those parameters
7760Sstevel@tonic-gate * are flagged by the drive as changeable.
7770Sstevel@tonic-gate */
7780Sstevel@tonic-gate flag = 0;
7790Sstevel@tonic-gate tmp1 = page1->read_retry_count;
7800Sstevel@tonic-gate tmp2 = page1->write_retry_count;
7810Sstevel@tonic-gate if (cur_dtype->dtype_options & SUP_READ_RETRIES &&
7820Sstevel@tonic-gate fixed->read_retry_count != 0) {
7830Sstevel@tonic-gate flag |= (page1->read_retry_count !=
7840Sstevel@tonic-gate cur_dtype->dtype_read_retries);
7850Sstevel@tonic-gate page1->read_retry_count = cur_dtype->dtype_read_retries;
7860Sstevel@tonic-gate }
7870Sstevel@tonic-gate if (length > 8) {
7880Sstevel@tonic-gate if (cur_dtype->dtype_options & SUP_WRITE_RETRIES &&
7890Sstevel@tonic-gate fixed->write_retry_count != 0) {
7900Sstevel@tonic-gate flag |= (page1->write_retry_count !=
7910Sstevel@tonic-gate cur_dtype->dtype_write_retries);
7920Sstevel@tonic-gate page1->write_retry_count =
7930Sstevel@tonic-gate cur_dtype->dtype_write_retries;
7940Sstevel@tonic-gate }
7950Sstevel@tonic-gate }
7960Sstevel@tonic-gate /*
7970Sstevel@tonic-gate * Report any changes so far...
7980Sstevel@tonic-gate */
7990Sstevel@tonic-gate if (flag && option_msg) {
8000Sstevel@tonic-gate fmt_print(
8010Sstevel@tonic-gate "PAGE 1: read retries= %d (%d) write retries= %d (%d)\n",
8020Sstevel@tonic-gate page1->read_retry_count, tmp1,
8030Sstevel@tonic-gate page1->write_retry_count, tmp2);
8040Sstevel@tonic-gate }
8050Sstevel@tonic-gate /*
8060Sstevel@tonic-gate * Apply any changes requested via the change list method
8070Sstevel@tonic-gate */
8080Sstevel@tonic-gate flag |= apply_chg_list(DAD_MODE_ERR_RECOV, length,
8090Sstevel@tonic-gate (uchar_t *)page1, (uchar_t *)fixed,
8100Sstevel@tonic-gate cur_dtype->dtype_chglist);
8110Sstevel@tonic-gate /*
8120Sstevel@tonic-gate * If no changes required, do not issue a mode select
8130Sstevel@tonic-gate */
8140Sstevel@tonic-gate if (flag == 0) {
8150Sstevel@tonic-gate return (0);
8160Sstevel@tonic-gate }
8170Sstevel@tonic-gate /*
8180Sstevel@tonic-gate * We always want to set the Page Format bit for mode
8190Sstevel@tonic-gate * selects. Set the Save Page bit if the drive indicates
8200Sstevel@tonic-gate * that it can save this page via the mode sense.
8210Sstevel@tonic-gate */
8220Sstevel@tonic-gate sp_flags = MODE_SELECT_PF;
8230Sstevel@tonic-gate if (page1->mode_page.ps) {
8240Sstevel@tonic-gate sp_flags |= MODE_SELECT_SP;
8250Sstevel@tonic-gate }
8260Sstevel@tonic-gate page1->mode_page.ps = 0;
8270Sstevel@tonic-gate header.mode_header.length = 0;
8280Sstevel@tonic-gate header.mode_header.device_specific = 0;
8290Sstevel@tonic-gate status = uscsi_mode_select(cur_file, DAD_MODE_ERR_RECOV,
8300Sstevel@tonic-gate sp_flags, (caddr_t)page1, length, &header);
8310Sstevel@tonic-gate if (status && (sp_flags & MODE_SELECT_SP)) {
8320Sstevel@tonic-gate /* If failed, try not saving mode select params. */
8330Sstevel@tonic-gate sp_flags &= ~MODE_SELECT_SP;
8340Sstevel@tonic-gate status = uscsi_mode_select(cur_file, DAD_MODE_ERR_RECOV,
8350Sstevel@tonic-gate sp_flags, (caddr_t)page1, length, &header);
8360Sstevel@tonic-gate }
8370Sstevel@tonic-gate if (status && option_msg) {
8380Sstevel@tonic-gate err_print("\
8390Sstevel@tonic-gate Warning: Using default error recovery parameters.\n\n");
8400Sstevel@tonic-gate }
8410Sstevel@tonic-gate
8420Sstevel@tonic-gate /*
8430Sstevel@tonic-gate * If debugging, issue mode senses on the current and
8440Sstevel@tonic-gate * saved values, so we can see the result of the mode
8450Sstevel@tonic-gate * selects.
8460Sstevel@tonic-gate */
8470Sstevel@tonic-gate if (option_msg && diag_msg) {
8480Sstevel@tonic-gate (void) uscsi_mode_sense(cur_file, DAD_MODE_ERR_RECOV,
8490Sstevel@tonic-gate MODE_SENSE_PC_CURRENT, (caddr_t)page1,
8500Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header);
8510Sstevel@tonic-gate (void) uscsi_mode_sense(cur_file, DAD_MODE_ERR_RECOV,
8520Sstevel@tonic-gate MODE_SENSE_PC_SAVED, (caddr_t)page1,
8530Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header);
8540Sstevel@tonic-gate }
8550Sstevel@tonic-gate
8560Sstevel@tonic-gate return (0);
8570Sstevel@tonic-gate }
8580Sstevel@tonic-gate
8590Sstevel@tonic-gate /*
8600Sstevel@tonic-gate * Check disk disconnect/reconnect parameters via mode sense.
8610Sstevel@tonic-gate * Issue a mode select if we need to change something.
8620Sstevel@tonic-gate */
8630Sstevel@tonic-gate /*ARGSUSED*/
8640Sstevel@tonic-gate static int
scsi_ms_page2(scsi2_flag)8650Sstevel@tonic-gate scsi_ms_page2(scsi2_flag)
8660Sstevel@tonic-gate int scsi2_flag;
8670Sstevel@tonic-gate {
8680Sstevel@tonic-gate struct mode_disco_reco *page2;
8690Sstevel@tonic-gate struct mode_disco_reco *fixed;
8700Sstevel@tonic-gate struct scsi_ms_header header;
8710Sstevel@tonic-gate struct scsi_ms_header fixed_hdr;
8720Sstevel@tonic-gate int status;
8730Sstevel@tonic-gate int flag;
8740Sstevel@tonic-gate int length;
8750Sstevel@tonic-gate int sp_flags;
8760Sstevel@tonic-gate union {
8770Sstevel@tonic-gate struct mode_disco_reco page2;
8780Sstevel@tonic-gate char rawbuf[MAX_MODE_SENSE_SIZE];
8790Sstevel@tonic-gate } u_page2, u_fixed;
8800Sstevel@tonic-gate
8810Sstevel@tonic-gate page2 = &u_page2.page2;
8820Sstevel@tonic-gate fixed = &u_fixed.page2;
8830Sstevel@tonic-gate
8840Sstevel@tonic-gate /*
8850Sstevel@tonic-gate * If debugging, issue mode senses on the default and
8860Sstevel@tonic-gate * current values.
8870Sstevel@tonic-gate */
8880Sstevel@tonic-gate if (option_msg && diag_msg) {
8890Sstevel@tonic-gate (void) uscsi_mode_sense(cur_file, MODEPAGE_DISCO_RECO,
8900Sstevel@tonic-gate MODE_SENSE_PC_DEFAULT, (caddr_t)page2,
8910Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header);
8920Sstevel@tonic-gate (void) uscsi_mode_sense(cur_file, MODEPAGE_DISCO_RECO,
8930Sstevel@tonic-gate MODE_SENSE_PC_CURRENT, (caddr_t)page2,
8940Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header);
8950Sstevel@tonic-gate }
8960Sstevel@tonic-gate
8970Sstevel@tonic-gate /*
8980Sstevel@tonic-gate * Issue a mode sense to determine the saved parameters
8990Sstevel@tonic-gate * If the saved values fail, use the current instead.
9000Sstevel@tonic-gate */
9010Sstevel@tonic-gate status = uscsi_mode_sense(cur_file, MODEPAGE_DISCO_RECO,
9020Sstevel@tonic-gate MODE_SENSE_PC_SAVED, (caddr_t)page2,
9030Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header);
9040Sstevel@tonic-gate if (status) {
9050Sstevel@tonic-gate status = uscsi_mode_sense(cur_file, MODEPAGE_DISCO_RECO,
9060Sstevel@tonic-gate MODE_SENSE_PC_CURRENT, (caddr_t)page2,
9070Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header);
9080Sstevel@tonic-gate if (status) {
9090Sstevel@tonic-gate return (0);
9100Sstevel@tonic-gate }
9110Sstevel@tonic-gate }
9120Sstevel@tonic-gate
9130Sstevel@tonic-gate /*
9140Sstevel@tonic-gate * We only need the common subset between the CCS
9150Sstevel@tonic-gate * and SCSI-2 structures, so we can treat both
9160Sstevel@tonic-gate * cases identically. Whatever the drive gives
9170Sstevel@tonic-gate * us, we return to the drive in the mode select,
9180Sstevel@tonic-gate * delta'ed by whatever we want to change.
9190Sstevel@tonic-gate */
9200Sstevel@tonic-gate length = MODESENSE_PAGE_LEN(page2);
9210Sstevel@tonic-gate if (length < MIN_PAGE2_LEN) {
9220Sstevel@tonic-gate return (0);
9230Sstevel@tonic-gate }
9240Sstevel@tonic-gate
9250Sstevel@tonic-gate /*
9260Sstevel@tonic-gate * Ask for changeable parameters.
9270Sstevel@tonic-gate */
9280Sstevel@tonic-gate status = uscsi_mode_sense(cur_file, MODEPAGE_DISCO_RECO,
9290Sstevel@tonic-gate MODE_SENSE_PC_CHANGEABLE, (caddr_t)fixed,
9300Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &fixed_hdr);
9310Sstevel@tonic-gate if (status || MODESENSE_PAGE_LEN(fixed) < MIN_PAGE2_LEN) {
9320Sstevel@tonic-gate return (0);
9330Sstevel@tonic-gate }
9340Sstevel@tonic-gate
9350Sstevel@tonic-gate /*
9360Sstevel@tonic-gate * We need to issue a mode select only if one or more
9370Sstevel@tonic-gate * parameters need to be changed, and those parameters
9380Sstevel@tonic-gate * are flagged by the drive as changeable.
9390Sstevel@tonic-gate */
9400Sstevel@tonic-gate flag = 0;
9410Sstevel@tonic-gate /*
9420Sstevel@tonic-gate * Apply any changes requested via the change list method
9430Sstevel@tonic-gate */
9440Sstevel@tonic-gate flag |= apply_chg_list(MODEPAGE_DISCO_RECO, length,
9450Sstevel@tonic-gate (uchar_t *)page2, (uchar_t *)fixed,
9460Sstevel@tonic-gate cur_dtype->dtype_chglist);
9470Sstevel@tonic-gate /*
9480Sstevel@tonic-gate * If no changes required, do not issue a mode select
9490Sstevel@tonic-gate */
9500Sstevel@tonic-gate if (flag == 0) {
9510Sstevel@tonic-gate return (0);
9520Sstevel@tonic-gate }
9530Sstevel@tonic-gate /*
9540Sstevel@tonic-gate * We always want to set the Page Format bit for mode
9550Sstevel@tonic-gate * selects. Set the Save Page bit if the drive indicates
9560Sstevel@tonic-gate * that it can save this page via the mode sense.
9570Sstevel@tonic-gate */
9580Sstevel@tonic-gate sp_flags = MODE_SELECT_PF;
9590Sstevel@tonic-gate if (page2->mode_page.ps) {
9600Sstevel@tonic-gate sp_flags |= MODE_SELECT_SP;
9610Sstevel@tonic-gate }
9620Sstevel@tonic-gate page2->mode_page.ps = 0;
9630Sstevel@tonic-gate header.mode_header.length = 0;
9640Sstevel@tonic-gate header.mode_header.device_specific = 0;
9650Sstevel@tonic-gate status = uscsi_mode_select(cur_file, MODEPAGE_DISCO_RECO,
9660Sstevel@tonic-gate MODE_SELECT_SP, (caddr_t)page2, length, &header);
9670Sstevel@tonic-gate if (status && (sp_flags & MODE_SELECT_SP)) {
9680Sstevel@tonic-gate /* If failed, try not saving mode select params. */
9690Sstevel@tonic-gate sp_flags &= ~MODE_SELECT_SP;
9700Sstevel@tonic-gate status = uscsi_mode_select(cur_file, MODEPAGE_DISCO_RECO,
9710Sstevel@tonic-gate sp_flags, (caddr_t)page2, length, &header);
9720Sstevel@tonic-gate }
9730Sstevel@tonic-gate if (status && option_msg) {
9740Sstevel@tonic-gate err_print("Warning: Using default .\n\n");
9750Sstevel@tonic-gate }
9760Sstevel@tonic-gate
9770Sstevel@tonic-gate /*
9780Sstevel@tonic-gate * If debugging, issue mode senses on the current and
9790Sstevel@tonic-gate * saved values, so we can see the result of the mode
9800Sstevel@tonic-gate * selects.
9810Sstevel@tonic-gate */
9820Sstevel@tonic-gate if (option_msg && diag_msg) {
9830Sstevel@tonic-gate (void) uscsi_mode_sense(cur_file, MODEPAGE_DISCO_RECO,
9840Sstevel@tonic-gate MODE_SENSE_PC_CURRENT, (caddr_t)page2,
9850Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header);
9860Sstevel@tonic-gate (void) uscsi_mode_sense(cur_file, MODEPAGE_DISCO_RECO,
9870Sstevel@tonic-gate MODE_SENSE_PC_SAVED, (caddr_t)page2,
9880Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header);
9890Sstevel@tonic-gate }
9900Sstevel@tonic-gate
9910Sstevel@tonic-gate return (0);
9920Sstevel@tonic-gate }
9930Sstevel@tonic-gate
9940Sstevel@tonic-gate /*
9950Sstevel@tonic-gate * Check disk format parameters via mode sense.
9960Sstevel@tonic-gate * Issue a mode select if we need to change something.
9970Sstevel@tonic-gate */
9980Sstevel@tonic-gate /*ARGSUSED*/
9990Sstevel@tonic-gate static int
scsi_ms_page3(scsi2_flag)10000Sstevel@tonic-gate scsi_ms_page3(scsi2_flag)
10010Sstevel@tonic-gate int scsi2_flag;
10020Sstevel@tonic-gate {
10030Sstevel@tonic-gate struct mode_format *page3;
10040Sstevel@tonic-gate struct mode_format *fixed;
10050Sstevel@tonic-gate struct scsi_ms_header header;
10060Sstevel@tonic-gate struct scsi_ms_header fixed_hdr;
10070Sstevel@tonic-gate int status;
10080Sstevel@tonic-gate int tmp1, tmp2, tmp3;
10090Sstevel@tonic-gate int tmp4, tmp5, tmp6;
10100Sstevel@tonic-gate int flag;
10110Sstevel@tonic-gate int length;
10120Sstevel@tonic-gate int sp_flags;
10130Sstevel@tonic-gate union {
10140Sstevel@tonic-gate struct mode_format page3;
10150Sstevel@tonic-gate char rawbuf[MAX_MODE_SENSE_SIZE];
10160Sstevel@tonic-gate } u_page3, u_fixed;
10170Sstevel@tonic-gate
10180Sstevel@tonic-gate
10190Sstevel@tonic-gate page3 = &u_page3.page3;
10200Sstevel@tonic-gate fixed = &u_fixed.page3;
10210Sstevel@tonic-gate
10220Sstevel@tonic-gate /*
10230Sstevel@tonic-gate * If debugging, issue mode senses on the default and
10240Sstevel@tonic-gate * current values.
10250Sstevel@tonic-gate */
10260Sstevel@tonic-gate if (option_msg && diag_msg) {
10270Sstevel@tonic-gate (void) uscsi_mode_sense(cur_file, DAD_MODE_FORMAT,
10280Sstevel@tonic-gate MODE_SENSE_PC_DEFAULT, (caddr_t)page3,
10290Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header);
10300Sstevel@tonic-gate (void) uscsi_mode_sense(cur_file, DAD_MODE_FORMAT,
10310Sstevel@tonic-gate MODE_SENSE_PC_CURRENT, (caddr_t)page3,
10320Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header);
10330Sstevel@tonic-gate }
10340Sstevel@tonic-gate
10350Sstevel@tonic-gate /*
10360Sstevel@tonic-gate * Issue a mode sense to determine the saved parameters
10370Sstevel@tonic-gate * If the saved values fail, use the current instead.
10380Sstevel@tonic-gate */
10390Sstevel@tonic-gate status = uscsi_mode_sense(cur_file, DAD_MODE_FORMAT,
10400Sstevel@tonic-gate MODE_SENSE_PC_SAVED, (caddr_t)page3,
10410Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header);
10420Sstevel@tonic-gate if (status) {
10430Sstevel@tonic-gate status = uscsi_mode_sense(cur_file, DAD_MODE_FORMAT,
10440Sstevel@tonic-gate MODE_SENSE_PC_CURRENT, (caddr_t)page3,
10450Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header);
10460Sstevel@tonic-gate if (status) {
10470Sstevel@tonic-gate return (0);
10480Sstevel@tonic-gate }
10490Sstevel@tonic-gate }
10500Sstevel@tonic-gate
10510Sstevel@tonic-gate /*
10520Sstevel@tonic-gate * We only need the common subset between the CCS
10530Sstevel@tonic-gate * and SCSI-2 structures, so we can treat both
10540Sstevel@tonic-gate * cases identically. Whatever the drive gives
10550Sstevel@tonic-gate * us, we return to the drive in the mode select,
10560Sstevel@tonic-gate * delta'ed by whatever we want to change.
10570Sstevel@tonic-gate */
10580Sstevel@tonic-gate length = MODESENSE_PAGE_LEN(page3);
10590Sstevel@tonic-gate if (length < MIN_PAGE3_LEN) {
10600Sstevel@tonic-gate return (0);
10610Sstevel@tonic-gate }
10620Sstevel@tonic-gate
10630Sstevel@tonic-gate /*
10640Sstevel@tonic-gate * Ask for changeable parameters.
10650Sstevel@tonic-gate */
10660Sstevel@tonic-gate status = uscsi_mode_sense(cur_file, DAD_MODE_FORMAT,
10670Sstevel@tonic-gate MODE_SENSE_PC_CHANGEABLE, (caddr_t)fixed,
10680Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &fixed_hdr);
10690Sstevel@tonic-gate if (status || MODESENSE_PAGE_LEN(fixed) < MIN_PAGE3_LEN) {
10700Sstevel@tonic-gate return (0);
10710Sstevel@tonic-gate }
10720Sstevel@tonic-gate
10730Sstevel@tonic-gate /*
10740Sstevel@tonic-gate * We need to issue a mode select only if one or more
10750Sstevel@tonic-gate * parameters need to be changed, and those parameters
10760Sstevel@tonic-gate * are flagged by the drive as changeable.
10770Sstevel@tonic-gate */
10780Sstevel@tonic-gate tmp1 = page3->track_skew;
10790Sstevel@tonic-gate tmp2 = page3->cylinder_skew;
10800Sstevel@tonic-gate tmp3 = page3->sect_track;
10810Sstevel@tonic-gate tmp4 = page3->tracks_per_zone;
10820Sstevel@tonic-gate tmp5 = page3->alt_tracks_vol;
10830Sstevel@tonic-gate tmp6 = page3->alt_sect_zone;
10840Sstevel@tonic-gate
10859889SLarry.Liu@Sun.COM flag = (page3->data_bytes_sect != cur_blksz);
10869889SLarry.Liu@Sun.COM page3->data_bytes_sect = cur_blksz;
10870Sstevel@tonic-gate
10880Sstevel@tonic-gate flag |= (page3->interleave != 1);
10890Sstevel@tonic-gate page3->interleave = 1;
10900Sstevel@tonic-gate
10910Sstevel@tonic-gate if (cur_dtype->dtype_options & SUP_CYLSKEW &&
10920Sstevel@tonic-gate fixed->cylinder_skew != 0) {
10930Sstevel@tonic-gate flag |= (page3->cylinder_skew != cur_dtype->dtype_cyl_skew);
10940Sstevel@tonic-gate page3->cylinder_skew = cur_dtype->dtype_cyl_skew;
10950Sstevel@tonic-gate }
10960Sstevel@tonic-gate if (cur_dtype->dtype_options & SUP_TRKSKEW &&
10970Sstevel@tonic-gate fixed->track_skew != 0) {
10980Sstevel@tonic-gate flag |= (page3->track_skew != cur_dtype->dtype_trk_skew);
10990Sstevel@tonic-gate page3->track_skew = cur_dtype->dtype_trk_skew;
11000Sstevel@tonic-gate }
11010Sstevel@tonic-gate if (cur_dtype->dtype_options & SUP_PSECT &&
11020Sstevel@tonic-gate fixed->sect_track != 0) {
11030Sstevel@tonic-gate flag |= (page3->sect_track != psect);
11040Sstevel@tonic-gate page3->sect_track = (ushort_t)psect;
11050Sstevel@tonic-gate }
11060Sstevel@tonic-gate if (cur_dtype->dtype_options & SUP_TRKS_ZONE &&
11070Sstevel@tonic-gate fixed->tracks_per_zone != 0) {
11080Sstevel@tonic-gate flag |= (page3->tracks_per_zone != cur_dtype->dtype_trks_zone);
11090Sstevel@tonic-gate page3->tracks_per_zone = cur_dtype->dtype_trks_zone;
11100Sstevel@tonic-gate }
11110Sstevel@tonic-gate if (cur_dtype->dtype_options & SUP_ASECT &&
11120Sstevel@tonic-gate fixed->alt_sect_zone != 0) {
11130Sstevel@tonic-gate flag |= (page3->alt_sect_zone != cur_dtype->dtype_asect);
11140Sstevel@tonic-gate page3->alt_sect_zone = cur_dtype->dtype_asect;
11150Sstevel@tonic-gate }
11160Sstevel@tonic-gate if (cur_dtype->dtype_options & SUP_ATRKS &&
11170Sstevel@tonic-gate fixed->alt_tracks_vol != 0) {
11180Sstevel@tonic-gate flag |= (page3->alt_tracks_vol != cur_dtype->dtype_atrks);
11190Sstevel@tonic-gate page3->alt_tracks_vol = cur_dtype->dtype_atrks;
11200Sstevel@tonic-gate }
11210Sstevel@tonic-gate /*
11220Sstevel@tonic-gate * Notify user of any changes so far
11230Sstevel@tonic-gate */
11240Sstevel@tonic-gate if (flag && option_msg) {
11250Sstevel@tonic-gate fmt_print("PAGE 3: trk skew= %d (%d) cyl skew= %d (%d) ",
11260Sstevel@tonic-gate page3->track_skew, tmp1, page3->cylinder_skew, tmp2);
11270Sstevel@tonic-gate fmt_print("sects/trk= %d (%d)\n", page3->sect_track, tmp3);
11280Sstevel@tonic-gate fmt_print(" trks/zone= %d (%d) alt trks= %d (%d) ",
11290Sstevel@tonic-gate page3->tracks_per_zone, tmp4,
11300Sstevel@tonic-gate page3->alt_tracks_vol, tmp5);
11310Sstevel@tonic-gate fmt_print("alt sects/zone= %d (%d)\n",
11320Sstevel@tonic-gate page3->alt_sect_zone, tmp6);
11330Sstevel@tonic-gate }
11340Sstevel@tonic-gate /*
11350Sstevel@tonic-gate * Apply any changes requested via the change list method
11360Sstevel@tonic-gate */
11370Sstevel@tonic-gate flag |= apply_chg_list(DAD_MODE_FORMAT, length,
11380Sstevel@tonic-gate (uchar_t *)page3, (uchar_t *)fixed,
11390Sstevel@tonic-gate cur_dtype->dtype_chglist);
11400Sstevel@tonic-gate /*
11410Sstevel@tonic-gate * If no changes required, do not issue a mode select
11420Sstevel@tonic-gate */
11430Sstevel@tonic-gate if (flag == 0) {
11440Sstevel@tonic-gate return (0);
11450Sstevel@tonic-gate }
11460Sstevel@tonic-gate /*
11470Sstevel@tonic-gate * Issue a mode select
11480Sstevel@tonic-gate */
11490Sstevel@tonic-gate /*
11500Sstevel@tonic-gate * We always want to set the Page Format bit for mode
11510Sstevel@tonic-gate * selects. Set the Save Page bit if the drive indicates
11520Sstevel@tonic-gate * that it can save this page via the mode sense.
11530Sstevel@tonic-gate */
11540Sstevel@tonic-gate sp_flags = MODE_SELECT_PF;
11550Sstevel@tonic-gate if (page3->mode_page.ps) {
11560Sstevel@tonic-gate sp_flags |= MODE_SELECT_SP;
11570Sstevel@tonic-gate }
11580Sstevel@tonic-gate page3->mode_page.ps = 0;
11590Sstevel@tonic-gate header.mode_header.length = 0;
11600Sstevel@tonic-gate header.mode_header.device_specific = 0;
11610Sstevel@tonic-gate status = uscsi_mode_select(cur_file, DAD_MODE_FORMAT,
11620Sstevel@tonic-gate MODE_SELECT_SP, (caddr_t)page3, length, &header);
11630Sstevel@tonic-gate if (status && (sp_flags & MODE_SELECT_SP)) {
11640Sstevel@tonic-gate /* If failed, try not saving mode select params. */
11650Sstevel@tonic-gate sp_flags &= ~MODE_SELECT_SP;
11660Sstevel@tonic-gate status = uscsi_mode_select(cur_file, DAD_MODE_FORMAT,
11670Sstevel@tonic-gate sp_flags, (caddr_t)page3, length, &header);
11680Sstevel@tonic-gate }
11690Sstevel@tonic-gate if (status && option_msg) {
11700Sstevel@tonic-gate err_print("Warning: Using default drive format parameters.\n");
11710Sstevel@tonic-gate err_print("Warning: Drive format may not be correct.\n\n");
11720Sstevel@tonic-gate }
11730Sstevel@tonic-gate
11740Sstevel@tonic-gate /*
11750Sstevel@tonic-gate * If debugging, issue mode senses on the current and
11760Sstevel@tonic-gate * saved values, so we can see the result of the mode
11770Sstevel@tonic-gate * selects.
11780Sstevel@tonic-gate */
11790Sstevel@tonic-gate if (option_msg && diag_msg) {
11800Sstevel@tonic-gate (void) uscsi_mode_sense(cur_file, DAD_MODE_FORMAT,
11810Sstevel@tonic-gate MODE_SENSE_PC_CURRENT, (caddr_t)page3,
11820Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header);
11830Sstevel@tonic-gate (void) uscsi_mode_sense(cur_file, DAD_MODE_FORMAT,
11840Sstevel@tonic-gate MODE_SENSE_PC_SAVED, (caddr_t)page3,
11850Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header);
11860Sstevel@tonic-gate }
11870Sstevel@tonic-gate
11880Sstevel@tonic-gate return (0);
11890Sstevel@tonic-gate }
11900Sstevel@tonic-gate
11910Sstevel@tonic-gate /*
11920Sstevel@tonic-gate * Check disk geometry parameters via mode sense.
11930Sstevel@tonic-gate * Issue a mode select if we need to change something.
11940Sstevel@tonic-gate */
11950Sstevel@tonic-gate /*ARGSUSED*/
11960Sstevel@tonic-gate static int
scsi_ms_page4(scsi2_flag)11970Sstevel@tonic-gate scsi_ms_page4(scsi2_flag)
11980Sstevel@tonic-gate int scsi2_flag;
11990Sstevel@tonic-gate {
12000Sstevel@tonic-gate struct mode_geometry *page4;
12010Sstevel@tonic-gate struct mode_geometry *fixed;
12020Sstevel@tonic-gate struct scsi_ms_header header;
12030Sstevel@tonic-gate struct scsi_ms_header fixed_hdr;
12040Sstevel@tonic-gate int status;
12050Sstevel@tonic-gate int tmp1, tmp2;
12060Sstevel@tonic-gate int flag;
12070Sstevel@tonic-gate int length;
12080Sstevel@tonic-gate int sp_flags;
12090Sstevel@tonic-gate union {
12100Sstevel@tonic-gate struct mode_geometry page4;
12110Sstevel@tonic-gate char rawbuf[MAX_MODE_SENSE_SIZE];
12120Sstevel@tonic-gate } u_page4, u_fixed;
12130Sstevel@tonic-gate
12140Sstevel@tonic-gate page4 = &u_page4.page4;
12150Sstevel@tonic-gate fixed = &u_fixed.page4;
12160Sstevel@tonic-gate
12170Sstevel@tonic-gate /*
12180Sstevel@tonic-gate * If debugging, issue mode senses on the default and
12190Sstevel@tonic-gate * current values.
12200Sstevel@tonic-gate */
12210Sstevel@tonic-gate if (option_msg && diag_msg) {
12220Sstevel@tonic-gate (void) uscsi_mode_sense(cur_file, DAD_MODE_GEOMETRY,
12230Sstevel@tonic-gate MODE_SENSE_PC_DEFAULT, (caddr_t)page4,
12240Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header);
12250Sstevel@tonic-gate (void) uscsi_mode_sense(cur_file, DAD_MODE_GEOMETRY,
12260Sstevel@tonic-gate MODE_SENSE_PC_CURRENT, (caddr_t)page4,
12270Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header);
12280Sstevel@tonic-gate }
12290Sstevel@tonic-gate
12300Sstevel@tonic-gate /*
12310Sstevel@tonic-gate * Issue a mode sense to determine the saved parameters
12320Sstevel@tonic-gate * If the saved values fail, use the current instead.
12330Sstevel@tonic-gate */
12340Sstevel@tonic-gate status = uscsi_mode_sense(cur_file, DAD_MODE_GEOMETRY,
12350Sstevel@tonic-gate MODE_SENSE_PC_SAVED, (caddr_t)page4,
12360Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header);
12370Sstevel@tonic-gate if (status) {
12380Sstevel@tonic-gate status = uscsi_mode_sense(cur_file, DAD_MODE_GEOMETRY,
12390Sstevel@tonic-gate MODE_SENSE_PC_CURRENT, (caddr_t)page4,
12400Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header);
12410Sstevel@tonic-gate if (status) {
12420Sstevel@tonic-gate return (0);
12430Sstevel@tonic-gate }
12440Sstevel@tonic-gate }
12450Sstevel@tonic-gate
12460Sstevel@tonic-gate /*
12470Sstevel@tonic-gate * We only need the common subset between the CCS
12480Sstevel@tonic-gate * and SCSI-2 structures, so we can treat both
12490Sstevel@tonic-gate * cases identically. Whatever the drive gives
12500Sstevel@tonic-gate * us, we return to the drive in the mode select,
12510Sstevel@tonic-gate * delta'ed by whatever we want to change.
12520Sstevel@tonic-gate */
12530Sstevel@tonic-gate length = MODESENSE_PAGE_LEN(page4);
12540Sstevel@tonic-gate if (length < MIN_PAGE4_LEN) {
12550Sstevel@tonic-gate return (0);
12560Sstevel@tonic-gate }
12570Sstevel@tonic-gate
12580Sstevel@tonic-gate /*
12590Sstevel@tonic-gate * Ask for changeable parameters.
12600Sstevel@tonic-gate */
12610Sstevel@tonic-gate status = uscsi_mode_sense(cur_file, DAD_MODE_GEOMETRY,
12620Sstevel@tonic-gate MODE_SENSE_PC_CHANGEABLE, (caddr_t)fixed,
12630Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &fixed_hdr);
12640Sstevel@tonic-gate if (status || MODESENSE_PAGE_LEN(fixed) < MIN_PAGE4_LEN) {
12650Sstevel@tonic-gate return (0);
12660Sstevel@tonic-gate }
12670Sstevel@tonic-gate
12680Sstevel@tonic-gate /*
12690Sstevel@tonic-gate * We need to issue a mode select only if one or more
12700Sstevel@tonic-gate * parameters need to be changed, and those parameters
12710Sstevel@tonic-gate * are flagged by the drive as changeable.
12720Sstevel@tonic-gate */
12730Sstevel@tonic-gate tmp1 = (page4->cyl_ub << 16) + (page4->cyl_mb << 8) + page4->cyl_lb;
12740Sstevel@tonic-gate tmp2 = page4->heads;
12750Sstevel@tonic-gate
12760Sstevel@tonic-gate flag = 0;
12770Sstevel@tonic-gate if ((cur_dtype->dtype_options & SUP_PHEAD) && fixed->heads != 0) {
12780Sstevel@tonic-gate flag |= (page4->heads != phead);
12790Sstevel@tonic-gate page4->heads = phead;
12800Sstevel@tonic-gate }
12810Sstevel@tonic-gate /*
12820Sstevel@tonic-gate * Notify user of changes so far
12830Sstevel@tonic-gate */
12840Sstevel@tonic-gate if (flag && option_msg) {
12850Sstevel@tonic-gate fmt_print("PAGE 4: cylinders= %d heads= %d (%d)\n",
12860Sstevel@tonic-gate tmp1, page4->heads, tmp2);
12870Sstevel@tonic-gate }
12880Sstevel@tonic-gate /*
12890Sstevel@tonic-gate * Apply any changes requested via the change list method
12900Sstevel@tonic-gate */
12910Sstevel@tonic-gate flag |= apply_chg_list(DAD_MODE_GEOMETRY, length,
12920Sstevel@tonic-gate (uchar_t *)page4, (uchar_t *)fixed,
12930Sstevel@tonic-gate cur_dtype->dtype_chglist);
12940Sstevel@tonic-gate /*
12950Sstevel@tonic-gate * If no changes required, do not issue a mode select
12960Sstevel@tonic-gate */
12970Sstevel@tonic-gate if (flag == 0) {
12980Sstevel@tonic-gate return (0);
12990Sstevel@tonic-gate }
13000Sstevel@tonic-gate /*
13010Sstevel@tonic-gate * Issue a mode select
13020Sstevel@tonic-gate */
13030Sstevel@tonic-gate /*
13040Sstevel@tonic-gate * We always want to set the Page Format bit for mode
13050Sstevel@tonic-gate * selects. Set the Save Page bit if the drive indicates
13060Sstevel@tonic-gate * that it can save this page via the mode sense.
13070Sstevel@tonic-gate */
13080Sstevel@tonic-gate sp_flags = MODE_SELECT_PF;
13090Sstevel@tonic-gate if (page4->mode_page.ps) {
13100Sstevel@tonic-gate sp_flags |= MODE_SELECT_SP;
13110Sstevel@tonic-gate }
13120Sstevel@tonic-gate page4->mode_page.ps = 0;
13130Sstevel@tonic-gate header.mode_header.length = 0;
13140Sstevel@tonic-gate header.mode_header.device_specific = 0;
13150Sstevel@tonic-gate status = uscsi_mode_select(cur_file, DAD_MODE_GEOMETRY,
13160Sstevel@tonic-gate MODE_SELECT_SP, (caddr_t)page4, length, &header);
13170Sstevel@tonic-gate if (status && (sp_flags & MODE_SELECT_SP)) {
13180Sstevel@tonic-gate /* If failed, try not saving mode select params. */
13190Sstevel@tonic-gate sp_flags &= ~MODE_SELECT_SP;
13200Sstevel@tonic-gate status = uscsi_mode_select(cur_file, DAD_MODE_GEOMETRY,
13210Sstevel@tonic-gate sp_flags, (caddr_t)page4, length, &header);
13220Sstevel@tonic-gate }
13230Sstevel@tonic-gate if (status && option_msg) {
13240Sstevel@tonic-gate err_print("Warning: Using default drive geometry.\n\n");
13250Sstevel@tonic-gate }
13260Sstevel@tonic-gate
13270Sstevel@tonic-gate /*
13280Sstevel@tonic-gate * If debugging, issue mode senses on the current and
13290Sstevel@tonic-gate * saved values, so we can see the result of the mode
13300Sstevel@tonic-gate * selects.
13310Sstevel@tonic-gate */
13320Sstevel@tonic-gate if (option_msg && diag_msg) {
13330Sstevel@tonic-gate (void) uscsi_mode_sense(cur_file, DAD_MODE_GEOMETRY,
13340Sstevel@tonic-gate MODE_SENSE_PC_CURRENT, (caddr_t)page4,
13350Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header);
13360Sstevel@tonic-gate (void) uscsi_mode_sense(cur_file, DAD_MODE_GEOMETRY,
13370Sstevel@tonic-gate MODE_SENSE_PC_SAVED, (caddr_t)page4,
13380Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header);
13390Sstevel@tonic-gate }
13400Sstevel@tonic-gate
13410Sstevel@tonic-gate return (0);
13420Sstevel@tonic-gate }
13430Sstevel@tonic-gate
13440Sstevel@tonic-gate /*
13450Sstevel@tonic-gate * Check SCSI-2 disk cache parameters via mode sense.
13460Sstevel@tonic-gate * Issue a mode select if we need to change something.
13470Sstevel@tonic-gate */
13480Sstevel@tonic-gate /*ARGSUSED*/
13490Sstevel@tonic-gate static int
scsi_ms_page8(scsi2_flag)13500Sstevel@tonic-gate scsi_ms_page8(scsi2_flag)
13510Sstevel@tonic-gate int scsi2_flag;
13520Sstevel@tonic-gate {
13530Sstevel@tonic-gate struct mode_cache *page8;
13540Sstevel@tonic-gate struct mode_cache *fixed;
13550Sstevel@tonic-gate struct scsi_ms_header header;
13560Sstevel@tonic-gate struct scsi_ms_header fixed_hdr;
13570Sstevel@tonic-gate int status;
13580Sstevel@tonic-gate int flag;
13590Sstevel@tonic-gate int length;
13600Sstevel@tonic-gate int sp_flags;
13610Sstevel@tonic-gate union {
13620Sstevel@tonic-gate struct mode_cache page8;
13630Sstevel@tonic-gate char rawbuf[MAX_MODE_SENSE_SIZE];
13640Sstevel@tonic-gate } u_page8, u_fixed;
13650Sstevel@tonic-gate
13660Sstevel@tonic-gate page8 = &u_page8.page8;
13670Sstevel@tonic-gate fixed = &u_fixed.page8;
13680Sstevel@tonic-gate
13690Sstevel@tonic-gate /*
13700Sstevel@tonic-gate * Only SCSI-2 devices support this page
13710Sstevel@tonic-gate */
13720Sstevel@tonic-gate if (!scsi2_flag) {
13730Sstevel@tonic-gate return (0);
13740Sstevel@tonic-gate }
13750Sstevel@tonic-gate
13760Sstevel@tonic-gate /*
13770Sstevel@tonic-gate * If debugging, issue mode senses on the default and
13780Sstevel@tonic-gate * current values.
13790Sstevel@tonic-gate */
13800Sstevel@tonic-gate if (option_msg && diag_msg) {
13810Sstevel@tonic-gate (void) uscsi_mode_sense(cur_file, DAD_MODE_CACHE,
13820Sstevel@tonic-gate MODE_SENSE_PC_DEFAULT, (caddr_t)page8,
13830Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header);
13840Sstevel@tonic-gate (void) uscsi_mode_sense(cur_file, DAD_MODE_CACHE,
13850Sstevel@tonic-gate MODE_SENSE_PC_CURRENT, (caddr_t)page8,
13860Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header);
13870Sstevel@tonic-gate }
13880Sstevel@tonic-gate
13890Sstevel@tonic-gate /*
13900Sstevel@tonic-gate * Issue a mode sense to determine the saved parameters
13910Sstevel@tonic-gate * If the saved values fail, use the current instead.
13920Sstevel@tonic-gate */
13930Sstevel@tonic-gate status = uscsi_mode_sense(cur_file, DAD_MODE_CACHE,
13940Sstevel@tonic-gate MODE_SENSE_PC_SAVED, (caddr_t)page8,
13950Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header);
13960Sstevel@tonic-gate if (status) {
13970Sstevel@tonic-gate status = uscsi_mode_sense(cur_file, DAD_MODE_CACHE,
13980Sstevel@tonic-gate MODE_SENSE_PC_CURRENT, (caddr_t)page8,
13990Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header);
14000Sstevel@tonic-gate if (status) {
14010Sstevel@tonic-gate return (0);
14020Sstevel@tonic-gate }
14030Sstevel@tonic-gate }
14040Sstevel@tonic-gate
14050Sstevel@tonic-gate /*
14060Sstevel@tonic-gate * We only need the common subset between the CCS
14070Sstevel@tonic-gate * and SCSI-2 structures, so we can treat both
14080Sstevel@tonic-gate * cases identically. Whatever the drive gives
14090Sstevel@tonic-gate * us, we return to the drive in the mode select,
14100Sstevel@tonic-gate * delta'ed by whatever we want to change.
14110Sstevel@tonic-gate */
14120Sstevel@tonic-gate length = MODESENSE_PAGE_LEN(page8);
14130Sstevel@tonic-gate if (length < MIN_PAGE8_LEN) {
14140Sstevel@tonic-gate return (0);
14150Sstevel@tonic-gate }
14160Sstevel@tonic-gate
14170Sstevel@tonic-gate /*
14180Sstevel@tonic-gate * Ask for changeable parameters.
14190Sstevel@tonic-gate */
14200Sstevel@tonic-gate status = uscsi_mode_sense(cur_file, DAD_MODE_CACHE,
14210Sstevel@tonic-gate MODE_SENSE_PC_CHANGEABLE, (caddr_t)fixed,
14220Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &fixed_hdr);
14230Sstevel@tonic-gate if (status || MODESENSE_PAGE_LEN(fixed) < MIN_PAGE8_LEN) {
14240Sstevel@tonic-gate return (0);
14250Sstevel@tonic-gate }
14260Sstevel@tonic-gate
14270Sstevel@tonic-gate /*
14280Sstevel@tonic-gate * We need to issue a mode select only if one or more
14290Sstevel@tonic-gate * parameters need to be changed, and those parameters
14300Sstevel@tonic-gate * are flagged by the drive as changeable.
14310Sstevel@tonic-gate */
14320Sstevel@tonic-gate flag = 0;
14330Sstevel@tonic-gate /*
14340Sstevel@tonic-gate * Apply any changes requested via the change list method
14350Sstevel@tonic-gate */
14360Sstevel@tonic-gate flag |= apply_chg_list(DAD_MODE_CACHE, length,
14370Sstevel@tonic-gate (uchar_t *)page8, (uchar_t *)fixed,
14380Sstevel@tonic-gate cur_dtype->dtype_chglist);
14390Sstevel@tonic-gate /*
14400Sstevel@tonic-gate * If no changes required, do not issue a mode select
14410Sstevel@tonic-gate */
14420Sstevel@tonic-gate if (flag == 0) {
14430Sstevel@tonic-gate return (0);
14440Sstevel@tonic-gate }
14450Sstevel@tonic-gate /*
14460Sstevel@tonic-gate * Issue a mode select
14470Sstevel@tonic-gate */
14480Sstevel@tonic-gate /*
14490Sstevel@tonic-gate * We always want to set the Page Format bit for mode
14500Sstevel@tonic-gate * selects. Set the Save Page bit if the drive indicates
14510Sstevel@tonic-gate * that it can save this page via the mode sense.
14520Sstevel@tonic-gate */
14530Sstevel@tonic-gate sp_flags = MODE_SELECT_PF;
14540Sstevel@tonic-gate if (page8->mode_page.ps) {
14550Sstevel@tonic-gate sp_flags |= MODE_SELECT_SP;
14560Sstevel@tonic-gate }
14570Sstevel@tonic-gate page8->mode_page.ps = 0;
14580Sstevel@tonic-gate header.mode_header.length = 0;
14590Sstevel@tonic-gate header.mode_header.device_specific = 0;
14600Sstevel@tonic-gate status = uscsi_mode_select(cur_file, DAD_MODE_CACHE,
14610Sstevel@tonic-gate sp_flags, (caddr_t)page8, length, &header);
14620Sstevel@tonic-gate if (status && (sp_flags & MODE_SELECT_SP)) {
14630Sstevel@tonic-gate /* If failed, try not saving mode select params. */
14640Sstevel@tonic-gate sp_flags &= ~MODE_SELECT_SP;
14650Sstevel@tonic-gate status = uscsi_mode_select(cur_file, DAD_MODE_CACHE,
14660Sstevel@tonic-gate sp_flags, (caddr_t)page8, length, &header);
14670Sstevel@tonic-gate }
14680Sstevel@tonic-gate if (status && option_msg) {
14690Sstevel@tonic-gate err_print("\
14700Sstevel@tonic-gate Warning: Using default SCSI-2 cache parameters.\n\n");
14710Sstevel@tonic-gate }
14720Sstevel@tonic-gate
14730Sstevel@tonic-gate /*
14740Sstevel@tonic-gate * If debugging, issue mode senses on the current and
14750Sstevel@tonic-gate * saved values, so we can see the result of the mode
14760Sstevel@tonic-gate * selects.
14770Sstevel@tonic-gate */
14780Sstevel@tonic-gate if (option_msg && diag_msg) {
14790Sstevel@tonic-gate (void) uscsi_mode_sense(cur_file, DAD_MODE_CACHE,
14800Sstevel@tonic-gate MODE_SENSE_PC_CURRENT, (caddr_t)page8,
14810Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header);
14820Sstevel@tonic-gate (void) uscsi_mode_sense(cur_file, DAD_MODE_CACHE,
14830Sstevel@tonic-gate MODE_SENSE_PC_SAVED, (caddr_t)page8,
14840Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header);
14850Sstevel@tonic-gate }
14860Sstevel@tonic-gate
14870Sstevel@tonic-gate return (0);
14880Sstevel@tonic-gate }
14890Sstevel@tonic-gate
14900Sstevel@tonic-gate /*
14910Sstevel@tonic-gate * Check CCS disk cache parameters via mode sense.
14920Sstevel@tonic-gate * Issue a mode select if we need to change something.
14930Sstevel@tonic-gate */
14940Sstevel@tonic-gate /*ARGSUSED*/
14950Sstevel@tonic-gate static int
scsi_ms_page38(scsi2_flag)14960Sstevel@tonic-gate scsi_ms_page38(scsi2_flag)
14970Sstevel@tonic-gate int scsi2_flag;
14980Sstevel@tonic-gate {
14990Sstevel@tonic-gate struct mode_cache_ccs *page38;
15000Sstevel@tonic-gate struct mode_cache_ccs *fixed;
15010Sstevel@tonic-gate struct scsi_ms_header header;
15020Sstevel@tonic-gate struct scsi_ms_header fixed_hdr;
15030Sstevel@tonic-gate int status;
15040Sstevel@tonic-gate int tmp1, tmp2, tmp3, tmp4;
15050Sstevel@tonic-gate int flag;
15060Sstevel@tonic-gate int length;
15070Sstevel@tonic-gate int sp_flags;
15080Sstevel@tonic-gate union {
15090Sstevel@tonic-gate struct mode_cache_ccs page38;
15100Sstevel@tonic-gate char rawbuf[MAX_MODE_SENSE_SIZE];
15110Sstevel@tonic-gate } u_page38, u_fixed;
15120Sstevel@tonic-gate
15130Sstevel@tonic-gate /*
15140Sstevel@tonic-gate * First, determine if we need to look at page 38 at all.
15150Sstevel@tonic-gate * Not all devices support it.
15160Sstevel@tonic-gate */
15170Sstevel@tonic-gate if (((cur_dtype->dtype_options & (SUP_CACHE | SUP_PREFETCH |
15180Sstevel@tonic-gate SUP_CACHE_MIN | SUP_CACHE_MAX)) == 0) &&
15190Sstevel@tonic-gate (!chg_list_affects_page(cur_dtype->dtype_chglist,
15200Sstevel@tonic-gate 0x38))) {
15210Sstevel@tonic-gate return (0);
15220Sstevel@tonic-gate }
15230Sstevel@tonic-gate
15240Sstevel@tonic-gate page38 = &u_page38.page38;
15250Sstevel@tonic-gate fixed = &u_fixed.page38;
15260Sstevel@tonic-gate
15270Sstevel@tonic-gate /*
15280Sstevel@tonic-gate * If debugging, issue mode senses on the default and
15290Sstevel@tonic-gate * current values.
15300Sstevel@tonic-gate */
15310Sstevel@tonic-gate if (option_msg && diag_msg) {
15320Sstevel@tonic-gate (void) uscsi_mode_sense(cur_file, DAD_MODE_CACHE_CCS,
15330Sstevel@tonic-gate MODE_SENSE_PC_DEFAULT, (caddr_t)page38,
15340Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header);
15350Sstevel@tonic-gate (void) uscsi_mode_sense(cur_file, DAD_MODE_CACHE_CCS,
15360Sstevel@tonic-gate MODE_SENSE_PC_CURRENT, (caddr_t)page38,
15370Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header);
15380Sstevel@tonic-gate }
15390Sstevel@tonic-gate
15400Sstevel@tonic-gate /*
15410Sstevel@tonic-gate * Issue a mode sense to determine the saved parameters
15420Sstevel@tonic-gate * If the saved values fail, use the current instead.
15430Sstevel@tonic-gate */
15440Sstevel@tonic-gate status = uscsi_mode_sense(cur_file, DAD_MODE_CACHE_CCS,
15450Sstevel@tonic-gate MODE_SENSE_PC_SAVED, (caddr_t)page38,
15460Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header);
15470Sstevel@tonic-gate if (status) {
15480Sstevel@tonic-gate status = uscsi_mode_sense(cur_file, DAD_MODE_CACHE_CCS,
15490Sstevel@tonic-gate MODE_SENSE_PC_CURRENT, (caddr_t)page38,
15500Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header);
15510Sstevel@tonic-gate if (status) {
15520Sstevel@tonic-gate return (0);
15530Sstevel@tonic-gate }
15540Sstevel@tonic-gate }
15550Sstevel@tonic-gate
15560Sstevel@tonic-gate /*
15570Sstevel@tonic-gate * We only need the common subset between the CCS
15580Sstevel@tonic-gate * and SCSI-2 structures, so we can treat both
15590Sstevel@tonic-gate * cases identically. Whatever the drive gives
15600Sstevel@tonic-gate * us, we return to the drive in the mode select,
15610Sstevel@tonic-gate * delta'ed by whatever we want to change.
15620Sstevel@tonic-gate */
15630Sstevel@tonic-gate length = MODESENSE_PAGE_LEN(page38);
15640Sstevel@tonic-gate if (length < MIN_PAGE38_LEN) {
15650Sstevel@tonic-gate return (0);
15660Sstevel@tonic-gate }
15670Sstevel@tonic-gate
15680Sstevel@tonic-gate /*
15690Sstevel@tonic-gate * Ask for changeable parameters.
15700Sstevel@tonic-gate */
15710Sstevel@tonic-gate status = uscsi_mode_sense(cur_file, DAD_MODE_CACHE_CCS,
15720Sstevel@tonic-gate MODE_SENSE_PC_CHANGEABLE, (caddr_t)fixed,
15730Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &fixed_hdr);
15740Sstevel@tonic-gate if (status || MODESENSE_PAGE_LEN(fixed) < MIN_PAGE38_LEN) {
15750Sstevel@tonic-gate return (0);
15760Sstevel@tonic-gate }
15770Sstevel@tonic-gate
15780Sstevel@tonic-gate /*
15790Sstevel@tonic-gate * We need to issue a mode select only if one or more
15800Sstevel@tonic-gate * parameters need to be changed, and those parameters
15810Sstevel@tonic-gate * are flagged by the drive as changeable.
15820Sstevel@tonic-gate */
15830Sstevel@tonic-gate tmp1 = page38->mode;
15840Sstevel@tonic-gate tmp2 = page38->threshold;
15850Sstevel@tonic-gate tmp3 = page38->min_prefetch;
15860Sstevel@tonic-gate tmp4 = page38->max_prefetch;
15870Sstevel@tonic-gate
15880Sstevel@tonic-gate flag = 0;
15890Sstevel@tonic-gate if ((cur_dtype->dtype_options & SUP_CACHE) &&
15900Sstevel@tonic-gate (fixed->mode & cur_dtype->dtype_cache) ==
15910Sstevel@tonic-gate cur_dtype->dtype_cache) {
15920Sstevel@tonic-gate flag |= (page38->mode != cur_dtype->dtype_cache);
15930Sstevel@tonic-gate page38->mode = cur_dtype->dtype_cache;
15940Sstevel@tonic-gate }
15950Sstevel@tonic-gate if ((cur_dtype->dtype_options & SUP_PREFETCH) &&
15960Sstevel@tonic-gate (fixed->threshold & cur_dtype->dtype_threshold) ==
15970Sstevel@tonic-gate cur_dtype->dtype_threshold) {
15980Sstevel@tonic-gate flag |= (page38->threshold != cur_dtype->dtype_threshold);
15990Sstevel@tonic-gate page38->threshold = cur_dtype->dtype_threshold;
16000Sstevel@tonic-gate }
16010Sstevel@tonic-gate if ((cur_dtype->dtype_options & SUP_CACHE_MIN) &&
16020Sstevel@tonic-gate (fixed->min_prefetch & cur_dtype->dtype_prefetch_min) ==
16030Sstevel@tonic-gate cur_dtype->dtype_prefetch_min) {
16040Sstevel@tonic-gate flag |= (page38->min_prefetch != cur_dtype->dtype_prefetch_min);
16050Sstevel@tonic-gate page38->min_prefetch = cur_dtype->dtype_prefetch_min;
16060Sstevel@tonic-gate }
16070Sstevel@tonic-gate if ((cur_dtype->dtype_options & SUP_CACHE_MAX) &&
16080Sstevel@tonic-gate (fixed->max_prefetch & cur_dtype->dtype_prefetch_max) ==
16090Sstevel@tonic-gate cur_dtype->dtype_prefetch_max) {
16100Sstevel@tonic-gate flag |= (page38->max_prefetch != cur_dtype->dtype_prefetch_max);
16110Sstevel@tonic-gate page38->max_prefetch = cur_dtype->dtype_prefetch_max;
16120Sstevel@tonic-gate }
16130Sstevel@tonic-gate /*
16140Sstevel@tonic-gate * Notify the user of changes up to this point
16150Sstevel@tonic-gate */
16160Sstevel@tonic-gate if (flag && option_msg) {
16170Sstevel@tonic-gate fmt_print("PAGE 38: cache mode= 0x%x (0x%x)\n",
16180Sstevel@tonic-gate page38->mode, tmp1);
16190Sstevel@tonic-gate fmt_print(" min. prefetch multiplier= %d ",
16200Sstevel@tonic-gate page38->min_multiplier);
16210Sstevel@tonic-gate fmt_print("max. prefetch multiplier= %d\n",
16220Sstevel@tonic-gate page38->max_multiplier);
16230Sstevel@tonic-gate fmt_print(" threshold= %d (%d) ",
16240Sstevel@tonic-gate page38->threshold, tmp2);
16250Sstevel@tonic-gate fmt_print("min. prefetch= %d (%d) ",
16260Sstevel@tonic-gate page38->min_prefetch, tmp3);
16270Sstevel@tonic-gate fmt_print("max. prefetch= %d (%d)\n",
16280Sstevel@tonic-gate page38->max_prefetch, tmp4);
16290Sstevel@tonic-gate }
16300Sstevel@tonic-gate /*
16310Sstevel@tonic-gate * Apply any changes requested via the change list method
16320Sstevel@tonic-gate */
16330Sstevel@tonic-gate flag |= apply_chg_list(DAD_MODE_CACHE_CCS, length,
16340Sstevel@tonic-gate (uchar_t *)page38, (uchar_t *)fixed,
16350Sstevel@tonic-gate cur_dtype->dtype_chglist);
16360Sstevel@tonic-gate /*
16370Sstevel@tonic-gate * If no changes required, do not issue a mode select
16380Sstevel@tonic-gate */
16390Sstevel@tonic-gate if (flag == 0) {
16400Sstevel@tonic-gate return (0);
16410Sstevel@tonic-gate }
16420Sstevel@tonic-gate /*
16430Sstevel@tonic-gate * Issue a mode select
16440Sstevel@tonic-gate *
16450Sstevel@tonic-gate * We always want to set the Page Format bit for mode
16460Sstevel@tonic-gate * selects. Set the Save Page bit if the drive indicates
16470Sstevel@tonic-gate * that it can save this page via the mode sense.
16480Sstevel@tonic-gate */
16490Sstevel@tonic-gate sp_flags = MODE_SELECT_PF;
16500Sstevel@tonic-gate if (page38->mode_page.ps) {
16510Sstevel@tonic-gate sp_flags |= MODE_SELECT_SP;
16520Sstevel@tonic-gate }
16530Sstevel@tonic-gate page38->mode_page.ps = 0;
16540Sstevel@tonic-gate header.mode_header.length = 0;
16550Sstevel@tonic-gate header.mode_header.device_specific = 0;
16560Sstevel@tonic-gate status = uscsi_mode_select(cur_file, DAD_MODE_CACHE_CCS,
16570Sstevel@tonic-gate sp_flags, (caddr_t)page38, length, &header);
16580Sstevel@tonic-gate if (status && (sp_flags & MODE_SELECT_SP)) {
16590Sstevel@tonic-gate /* If failed, try not saving mode select params. */
16600Sstevel@tonic-gate sp_flags &= ~MODE_SELECT_SP;
16610Sstevel@tonic-gate status = uscsi_mode_select(cur_file, DAD_MODE_CACHE_CCS,
16620Sstevel@tonic-gate sp_flags, (caddr_t)page38, length, &header);
16630Sstevel@tonic-gate }
16640Sstevel@tonic-gate if (status && option_msg) {
16650Sstevel@tonic-gate err_print("Warning: Using default CCS cache parameters.\n\n");
16660Sstevel@tonic-gate }
16670Sstevel@tonic-gate
16680Sstevel@tonic-gate /*
16690Sstevel@tonic-gate * If debugging, issue mode senses on the current and
16700Sstevel@tonic-gate * saved values, so we can see the result of the mode
16710Sstevel@tonic-gate * selects.
16720Sstevel@tonic-gate */
16730Sstevel@tonic-gate if (option_msg && diag_msg) {
16740Sstevel@tonic-gate (void) uscsi_mode_sense(cur_file, DAD_MODE_CACHE_CCS,
16750Sstevel@tonic-gate MODE_SENSE_PC_CURRENT, (caddr_t)page38,
16760Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header);
16770Sstevel@tonic-gate (void) uscsi_mode_sense(cur_file, DAD_MODE_CACHE_CCS,
16780Sstevel@tonic-gate MODE_SENSE_PC_SAVED, (caddr_t)page38,
16790Sstevel@tonic-gate MAX_MODE_SENSE_SIZE, &header);
16800Sstevel@tonic-gate }
16810Sstevel@tonic-gate
16820Sstevel@tonic-gate return (0);
16830Sstevel@tonic-gate }
16840Sstevel@tonic-gate
16850Sstevel@tonic-gate
16860Sstevel@tonic-gate /*
16870Sstevel@tonic-gate * Extract the manufacturer's defect list.
16880Sstevel@tonic-gate */
16890Sstevel@tonic-gate int
scsi_ex_man(list)16900Sstevel@tonic-gate scsi_ex_man(list)
16910Sstevel@tonic-gate struct defect_list *list;
16920Sstevel@tonic-gate {
16930Sstevel@tonic-gate int i;
16940Sstevel@tonic-gate
16950Sstevel@tonic-gate i = scsi_read_defect_data(list, DLD_MAN_DEF_LIST);
16960Sstevel@tonic-gate if (i != 0)
16970Sstevel@tonic-gate return (i);
16980Sstevel@tonic-gate list->flags &= ~LIST_PGLIST;
16990Sstevel@tonic-gate return (0);
17000Sstevel@tonic-gate }
17010Sstevel@tonic-gate
17020Sstevel@tonic-gate /*
17030Sstevel@tonic-gate * Extract the current defect list.
17040Sstevel@tonic-gate * For embedded scsi drives, this means both the manufacturer's (P)
17050Sstevel@tonic-gate * and the grown (G) lists.
17060Sstevel@tonic-gate */
17070Sstevel@tonic-gate int
scsi_ex_cur(list)17080Sstevel@tonic-gate scsi_ex_cur(list)
17090Sstevel@tonic-gate struct defect_list *list;
17100Sstevel@tonic-gate {
17110Sstevel@tonic-gate int i;
17120Sstevel@tonic-gate
17130Sstevel@tonic-gate i = scsi_read_defect_data(list, DLD_GROWN_DEF_LIST|DLD_MAN_DEF_LIST);
17140Sstevel@tonic-gate if (i != 0)
17150Sstevel@tonic-gate return (i);
17160Sstevel@tonic-gate list->flags |= LIST_PGLIST;
17170Sstevel@tonic-gate return (0);
17180Sstevel@tonic-gate }
17190Sstevel@tonic-gate
17200Sstevel@tonic-gate
17210Sstevel@tonic-gate /*
17220Sstevel@tonic-gate * Extract the grown list only
17230Sstevel@tonic-gate */
17240Sstevel@tonic-gate int
scsi_ex_grown(list)17250Sstevel@tonic-gate scsi_ex_grown(list)
17260Sstevel@tonic-gate struct defect_list *list;
17270Sstevel@tonic-gate {
17280Sstevel@tonic-gate int i;
17290Sstevel@tonic-gate
17300Sstevel@tonic-gate i = scsi_read_defect_data(list, DLD_GROWN_DEF_LIST);
17310Sstevel@tonic-gate if (i != 0)
17320Sstevel@tonic-gate return (i);
17330Sstevel@tonic-gate list->flags |= LIST_PGLIST;
17340Sstevel@tonic-gate return (0);
17350Sstevel@tonic-gate }
17360Sstevel@tonic-gate
17370Sstevel@tonic-gate
17380Sstevel@tonic-gate static int
scsi_read_defect_data(list,pglist_flags)17390Sstevel@tonic-gate scsi_read_defect_data(list, pglist_flags)
17400Sstevel@tonic-gate struct defect_list *list;
17410Sstevel@tonic-gate int pglist_flags;
17420Sstevel@tonic-gate {
17430Sstevel@tonic-gate struct uscsi_cmd ucmd;
17440Sstevel@tonic-gate char rqbuf[255];
17450Sstevel@tonic-gate union scsi_cdb cdb;
17460Sstevel@tonic-gate struct scsi_defect_list *defects;
17470Sstevel@tonic-gate struct scsi_defect_list def_list;
17480Sstevel@tonic-gate struct scsi_defect_hdr *hdr;
17490Sstevel@tonic-gate int status;
17500Sstevel@tonic-gate int nbytes;
17510Sstevel@tonic-gate int len; /* returned defect list length */
17520Sstevel@tonic-gate struct scsi_extended_sense *rq;
17530Sstevel@tonic-gate
17540Sstevel@tonic-gate hdr = (struct scsi_defect_hdr *)&def_list;
17550Sstevel@tonic-gate
17560Sstevel@tonic-gate /*
17570Sstevel@tonic-gate * First get length of list by asking for the header only.
17580Sstevel@tonic-gate */
17590Sstevel@tonic-gate (void) memset((char *)&def_list, 0, sizeof (def_list));
17600Sstevel@tonic-gate
17610Sstevel@tonic-gate /*
17620Sstevel@tonic-gate * Build and execute the uscsi ioctl
17630Sstevel@tonic-gate */
17640Sstevel@tonic-gate (void) memset((char *)&ucmd, 0, sizeof (ucmd));
17650Sstevel@tonic-gate (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb));
17660Sstevel@tonic-gate (void) memset((char *)rqbuf, 0, 255);
17670Sstevel@tonic-gate cdb.scc_cmd = SCMD_READ_DEFECT_LIST;
17680Sstevel@tonic-gate FORMG1COUNT(&cdb, sizeof (struct scsi_defect_hdr));
17690Sstevel@tonic-gate cdb.cdb_opaque[2] = pglist_flags | DLD_BFI_FORMAT;
17700Sstevel@tonic-gate ucmd.uscsi_cdb = (caddr_t)&cdb;
17710Sstevel@tonic-gate ucmd.uscsi_cdblen = CDB_GROUP1;
17720Sstevel@tonic-gate ucmd.uscsi_bufaddr = (caddr_t)hdr;
17730Sstevel@tonic-gate ucmd.uscsi_buflen = sizeof (struct scsi_defect_hdr);
17740Sstevel@tonic-gate ucmd.uscsi_rqbuf = rqbuf;
17750Sstevel@tonic-gate ucmd.uscsi_rqlen = sizeof (rqbuf);
17760Sstevel@tonic-gate ucmd.uscsi_rqresid = sizeof (rqbuf);
17770Sstevel@tonic-gate rq = (struct scsi_extended_sense *)ucmd.uscsi_rqbuf;
17780Sstevel@tonic-gate
17790Sstevel@tonic-gate status = uscsi_cmd(cur_file, &ucmd,
17800Sstevel@tonic-gate (option_msg && diag_msg) ? F_NORMAL : F_SILENT);
17810Sstevel@tonic-gate
17820Sstevel@tonic-gate if (status != 0) {
17830Sstevel@tonic-gate /*
17840Sstevel@tonic-gate * check if read_defect_list_is_supported.
17850Sstevel@tonic-gate */
17860Sstevel@tonic-gate if (ucmd.uscsi_rqstatus == STATUS_GOOD &&
17870Sstevel@tonic-gate rq->es_key == KEY_ILLEGAL_REQUEST &&
17880Sstevel@tonic-gate rq->es_add_code == INVALID_OPCODE) {
17890Sstevel@tonic-gate err_print("\nWARNING: Current Disk does not support"
17900Sstevel@tonic-gate " defect lists. \n");
17910Sstevel@tonic-gate } else
17920Sstevel@tonic-gate if (option_msg) {
17930Sstevel@tonic-gate err_print("No %s defect list.\n",
17940Sstevel@tonic-gate pglist_flags & DLD_GROWN_DEF_LIST ?
17950Sstevel@tonic-gate "grown" : "manufacturer's");
17960Sstevel@tonic-gate }
17970Sstevel@tonic-gate return (-1);
17980Sstevel@tonic-gate }
17990Sstevel@tonic-gate
18000Sstevel@tonic-gate /*
18010Sstevel@tonic-gate * Read the full list the second time
18020Sstevel@tonic-gate */
18030Sstevel@tonic-gate hdr->length = BE_16(hdr->length);
18040Sstevel@tonic-gate len = hdr->length;
18050Sstevel@tonic-gate nbytes = len + sizeof (struct scsi_defect_hdr);
18060Sstevel@tonic-gate
18070Sstevel@tonic-gate defects = zalloc(nbytes);
18080Sstevel@tonic-gate *(struct scsi_defect_hdr *)defects = *(struct scsi_defect_hdr *)hdr;
18090Sstevel@tonic-gate
18100Sstevel@tonic-gate (void) memset((char *)&ucmd, 0, sizeof (ucmd));
18110Sstevel@tonic-gate (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb));
18120Sstevel@tonic-gate cdb.scc_cmd = SCMD_READ_DEFECT_LIST;
18130Sstevel@tonic-gate FORMG1COUNT(&cdb, nbytes);
18140Sstevel@tonic-gate cdb.cdb_opaque[2] = pglist_flags | DLD_BFI_FORMAT;
18150Sstevel@tonic-gate ucmd.uscsi_cdb = (caddr_t)&cdb;
18160Sstevel@tonic-gate ucmd.uscsi_cdblen = CDB_GROUP1;
18170Sstevel@tonic-gate ucmd.uscsi_bufaddr = (caddr_t)defects;
18180Sstevel@tonic-gate ucmd.uscsi_buflen = nbytes;
18190Sstevel@tonic-gate status = uscsi_cmd(cur_file, &ucmd,
18200Sstevel@tonic-gate (option_msg && diag_msg) ? F_NORMAL : F_SILENT);
18210Sstevel@tonic-gate
18220Sstevel@tonic-gate if (status) {
18230Sstevel@tonic-gate err_print("can't read defect list 2nd time");
18240Sstevel@tonic-gate destroy_data((char *)defects);
18250Sstevel@tonic-gate return (-1);
18260Sstevel@tonic-gate }
18270Sstevel@tonic-gate
18280Sstevel@tonic-gate defects->length = BE_16(defects->length);
18290Sstevel@tonic-gate
18300Sstevel@tonic-gate if (len != hdr->length) {
18310Sstevel@tonic-gate err_print("not enough defects");
18320Sstevel@tonic-gate destroy_data((char *)defects);
18330Sstevel@tonic-gate return (-1);
18340Sstevel@tonic-gate }
18350Sstevel@tonic-gate scsi_convert_list_to_new(list, (struct scsi_defect_list *)defects,
18360Sstevel@tonic-gate DLD_BFI_FORMAT);
18370Sstevel@tonic-gate destroy_data((char *)defects);
18380Sstevel@tonic-gate return (0);
18390Sstevel@tonic-gate }
18400Sstevel@tonic-gate
18410Sstevel@tonic-gate
18420Sstevel@tonic-gate /*
18430Sstevel@tonic-gate * Map a block.
18440Sstevel@tonic-gate */
18450Sstevel@tonic-gate /*ARGSUSED*/
18460Sstevel@tonic-gate static int
scsi_repair(bn,flag)18470Sstevel@tonic-gate scsi_repair(bn, flag)
18480Sstevel@tonic-gate uint64_t bn;
18490Sstevel@tonic-gate int flag;
18500Sstevel@tonic-gate {
18510Sstevel@tonic-gate struct uscsi_cmd ucmd;
18520Sstevel@tonic-gate union scsi_cdb cdb;
18530Sstevel@tonic-gate struct scsi_reassign_blk defect_list;
18540Sstevel@tonic-gate
18550Sstevel@tonic-gate /*
18560Sstevel@tonic-gate * Build and execute the uscsi ioctl
18570Sstevel@tonic-gate */
18580Sstevel@tonic-gate (void) memset((char *)&ucmd, 0, sizeof (ucmd));
18590Sstevel@tonic-gate (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb));
18600Sstevel@tonic-gate (void) memset((char *)&defect_list, 0,
18610Sstevel@tonic-gate sizeof (struct scsi_reassign_blk));
18620Sstevel@tonic-gate cdb.scc_cmd = SCMD_REASSIGN_BLOCK;
18630Sstevel@tonic-gate ucmd.uscsi_cdb = (caddr_t)&cdb;
18640Sstevel@tonic-gate ucmd.uscsi_cdblen = CDB_GROUP0;
18650Sstevel@tonic-gate ucmd.uscsi_bufaddr = (caddr_t)&defect_list;
18660Sstevel@tonic-gate ucmd.uscsi_buflen = sizeof (struct scsi_reassign_blk);
18670Sstevel@tonic-gate defect_list.length = sizeof (defect_list.defect);
18680Sstevel@tonic-gate defect_list.length = BE_16(defect_list.length);
18690Sstevel@tonic-gate defect_list.defect = bn;
18700Sstevel@tonic-gate defect_list.defect = BE_32(defect_list.defect);
18710Sstevel@tonic-gate return (uscsi_cmd(cur_file, &ucmd,
18720Sstevel@tonic-gate (option_msg && diag_msg) ? F_NORMAL : F_SILENT));
18730Sstevel@tonic-gate }
18740Sstevel@tonic-gate
18750Sstevel@tonic-gate /*
18760Sstevel@tonic-gate * Convert a SCSI-style defect list to our generic format.
18770Sstevel@tonic-gate * We can handle different format lists.
18780Sstevel@tonic-gate */
18790Sstevel@tonic-gate static void
scsi_convert_list_to_new(list,def_list,list_format)18800Sstevel@tonic-gate scsi_convert_list_to_new(list, def_list, list_format)
18810Sstevel@tonic-gate struct defect_list *list;
18820Sstevel@tonic-gate struct scsi_defect_list *def_list;
18830Sstevel@tonic-gate int list_format;
18840Sstevel@tonic-gate {
18850Sstevel@tonic-gate register struct scsi_bfi_defect *old_defect, *old_defect1;
18860Sstevel@tonic-gate register struct defect_entry *new_defect;
18870Sstevel@tonic-gate register int len, new_len, obfi, nbfi;
18880Sstevel@tonic-gate register int i;
18890Sstevel@tonic-gate int old_cyl, new_cyl;
18900Sstevel@tonic-gate unsigned char *cp;
18910Sstevel@tonic-gate
18920Sstevel@tonic-gate
18930Sstevel@tonic-gate switch (list_format) {
18940Sstevel@tonic-gate
18950Sstevel@tonic-gate case DLD_BFI_FORMAT:
18960Sstevel@tonic-gate /*
18970Sstevel@tonic-gate * Allocate space for the rest of the list.
18980Sstevel@tonic-gate */
18990Sstevel@tonic-gate len = def_list->length / sizeof (struct scsi_bfi_defect);
19000Sstevel@tonic-gate old_defect = def_list->list;
19010Sstevel@tonic-gate new_defect = (struct defect_entry *)
19029889SLarry.Liu@Sun.COM zalloc(deflist_size(cur_blksz, len) *
19039889SLarry.Liu@Sun.COM cur_blksz);
19040Sstevel@tonic-gate
19050Sstevel@tonic-gate list->header.magicno = (uint_t)DEFECT_MAGIC;
19060Sstevel@tonic-gate list->list = new_defect;
19070Sstevel@tonic-gate
19080Sstevel@tonic-gate for (i = 0, new_len = 0; i < len; new_defect++, new_len++) {
19090Sstevel@tonic-gate cp = (unsigned char *)old_defect;
19100Sstevel@tonic-gate new_defect->cyl = (cp[0] << 16 | cp[1] << 8) | cp[2];
19110Sstevel@tonic-gate new_defect->head = old_defect->head;
19120Sstevel@tonic-gate new_defect->bfi = (int)old_defect->bytes_from_index;
19130Sstevel@tonic-gate new_defect->bfi = BE_32(new_defect->bfi);
19140Sstevel@tonic-gate new_defect->nbits = 0; /* size of defect */
19150Sstevel@tonic-gate old_defect1 = old_defect++;
19160Sstevel@tonic-gate i++;
19170Sstevel@tonic-gate /*
19180Sstevel@tonic-gate * Since we reached the end of the list, old_defect
19190Sstevel@tonic-gate * now points to an invalid reference, since it got
19200Sstevel@tonic-gate * incremented in the above operation. So we don't
19210Sstevel@tonic-gate * need to proceed further. new_len needs to be
19220Sstevel@tonic-gate * incremented to account for the last element.
19230Sstevel@tonic-gate */
19240Sstevel@tonic-gate if (i == len) {
19250Sstevel@tonic-gate new_len++;
19260Sstevel@tonic-gate break;
19270Sstevel@tonic-gate }
19280Sstevel@tonic-gate obfi = new_defect->bfi;
19290Sstevel@tonic-gate nbfi = (int)old_defect->bytes_from_index;
19300Sstevel@tonic-gate nbfi = BE_32(nbfi);
19310Sstevel@tonic-gate
19320Sstevel@tonic-gate old_cyl = new_defect->cyl;
19330Sstevel@tonic-gate cp = (unsigned char *)old_defect;
19340Sstevel@tonic-gate new_cyl = (cp[0] << 16 | cp[1] << 8) | cp[2];
19350Sstevel@tonic-gate
19360Sstevel@tonic-gate
19370Sstevel@tonic-gate /*
19380Sstevel@tonic-gate * Merge adjacent contiguous defect entries into one
19390Sstevel@tonic-gate * and update the length of the defect
19400Sstevel@tonic-gate */
19410Sstevel@tonic-gate while ((i < len) &&
19420Sstevel@tonic-gate (old_cyl == new_cyl) &&
19430Sstevel@tonic-gate (old_defect->head == old_defect1->head) &&
19440Sstevel@tonic-gate (nbfi == (obfi + BITSPERBYTE))) {
19450Sstevel@tonic-gate old_defect1 = old_defect++;
19460Sstevel@tonic-gate cp = (unsigned char *)old_defect;
19470Sstevel@tonic-gate new_cyl = (cp[0] << 16 | cp[1] << 8) | cp[2];
19480Sstevel@tonic-gate obfi = (int)old_defect1->bytes_from_index;
19490Sstevel@tonic-gate obfi = BE_32(obfi);
19500Sstevel@tonic-gate nbfi = (int)old_defect->bytes_from_index;
19510Sstevel@tonic-gate nbfi = BE_32(nbfi);
19520Sstevel@tonic-gate new_defect->nbits += (8*BITSPERBYTE);
19530Sstevel@tonic-gate i++;
19540Sstevel@tonic-gate }
19550Sstevel@tonic-gate }
19560Sstevel@tonic-gate
19570Sstevel@tonic-gate list->header.count = new_len;
19580Sstevel@tonic-gate break;
19590Sstevel@tonic-gate
19600Sstevel@tonic-gate default:
19610Sstevel@tonic-gate err_print("scsi_convert_list_to_new: can't deal with it\n");
19620Sstevel@tonic-gate exit(0);
19630Sstevel@tonic-gate /*NOTREACHED*/
19640Sstevel@tonic-gate }
19650Sstevel@tonic-gate
19660Sstevel@tonic-gate (void) checkdefsum(list, CK_MAKESUM);
19670Sstevel@tonic-gate }
19680Sstevel@tonic-gate
19690Sstevel@tonic-gate
19700Sstevel@tonic-gate
19710Sstevel@tonic-gate /*
19720Sstevel@tonic-gate * Execute a command and determine the result.
19730Sstevel@tonic-gate * Uses the "uscsi" ioctl interface, which is
19740Sstevel@tonic-gate * fully supported.
19750Sstevel@tonic-gate *
19760Sstevel@tonic-gate * If the user wants request sense data to be returned
19770Sstevel@tonic-gate * in case of error then , the "uscsi_cmd" structure
19780Sstevel@tonic-gate * should have the request sense buffer allocated in
19790Sstevel@tonic-gate * uscsi_rqbuf.
19800Sstevel@tonic-gate *
19810Sstevel@tonic-gate */
19820Sstevel@tonic-gate int
uscsi_cmd(fd,ucmd,flags)19830Sstevel@tonic-gate uscsi_cmd(fd, ucmd, flags)
19840Sstevel@tonic-gate int fd;
19850Sstevel@tonic-gate struct uscsi_cmd *ucmd;
19860Sstevel@tonic-gate int flags;
19870Sstevel@tonic-gate {
19880Sstevel@tonic-gate struct scsi_extended_sense *rq;
19890Sstevel@tonic-gate char rqbuf[255];
19900Sstevel@tonic-gate int status;
19910Sstevel@tonic-gate int rqlen;
19920Sstevel@tonic-gate int timeout = 0;
19930Sstevel@tonic-gate
19940Sstevel@tonic-gate /*
19950Sstevel@tonic-gate * Set function flags for driver.
19960Sstevel@tonic-gate */
19970Sstevel@tonic-gate ucmd->uscsi_flags = USCSI_ISOLATE;
19980Sstevel@tonic-gate if (flags & F_SILENT) {
19990Sstevel@tonic-gate ucmd->uscsi_flags |= USCSI_SILENT;
20000Sstevel@tonic-gate }
20010Sstevel@tonic-gate if (flags & F_RQENABLE) {
20020Sstevel@tonic-gate ucmd->uscsi_flags |= USCSI_RQENABLE;
20030Sstevel@tonic-gate }
20040Sstevel@tonic-gate
20050Sstevel@tonic-gate /*
20060Sstevel@tonic-gate * If this command will perform a read, set the USCSI_READ flag
20070Sstevel@tonic-gate */
20080Sstevel@tonic-gate if (ucmd->uscsi_buflen > 0) {
20090Sstevel@tonic-gate /*
20100Sstevel@tonic-gate * uscsi_cdb is declared as a caddr_t, so any CDB
20110Sstevel@tonic-gate * command byte with the MSB set will result in a
20120Sstevel@tonic-gate * compiler error unless we cast to an unsigned value.
20130Sstevel@tonic-gate */
20140Sstevel@tonic-gate switch ((uint8_t)ucmd->uscsi_cdb[0]) {
20150Sstevel@tonic-gate case SCMD_READ:
20160Sstevel@tonic-gate case SCMD_READ|SCMD_GROUP1:
20170Sstevel@tonic-gate case SCMD_READ|SCMD_GROUP4:
20180Sstevel@tonic-gate case SCMD_MODE_SENSE:
20190Sstevel@tonic-gate case SCMD_INQUIRY:
20200Sstevel@tonic-gate case SCMD_READ_DEFECT_LIST:
20210Sstevel@tonic-gate case SCMD_READ_CAPACITY:
20220Sstevel@tonic-gate case SCMD_SVC_ACTION_IN_G4:
20230Sstevel@tonic-gate ucmd->uscsi_flags |= USCSI_READ;
20240Sstevel@tonic-gate break;
20250Sstevel@tonic-gate }
20260Sstevel@tonic-gate }
20270Sstevel@tonic-gate
20280Sstevel@tonic-gate /*
20290Sstevel@tonic-gate * Set timeout: 30 seconds for all commands except format
20300Sstevel@tonic-gate */
20310Sstevel@tonic-gate switch (ucmd->uscsi_cdb[0]) {
20320Sstevel@tonic-gate case SCMD_FORMAT:
20330Sstevel@tonic-gate if (ucmd->uscsi_timeout == 0) {
20340Sstevel@tonic-gate ucmd->uscsi_timeout = scsi_format_timeout;
20350Sstevel@tonic-gate /*
20360Sstevel@tonic-gate * Get the timeout value computed using page4 geometry.
20370Sstevel@tonic-gate * add 50% margin to cover defect management overhead.
20380Sstevel@tonic-gate * add another 50% margin to have a safe timeout.
20390Sstevel@tonic-gate * If it exceeds 2 hours then use this value.
20400Sstevel@tonic-gate */
20410Sstevel@tonic-gate if ((timeout = scsi_format_time()) > 0) {
20420Sstevel@tonic-gate timeout *= 60; /* convert to seconds */
20430Sstevel@tonic-gate timeout += timeout;
20440Sstevel@tonic-gate /*
20450Sstevel@tonic-gate * formatting drives with huge capacity
20460Sstevel@tonic-gate * will cause these heuristics to come
20470Sstevel@tonic-gate * up with times that overflow ~9 hours
20480Sstevel@tonic-gate */
20490Sstevel@tonic-gate if (timeout > SHRT_MAX)
20500Sstevel@tonic-gate timeout = SHRT_MAX;
20510Sstevel@tonic-gate if (timeout > scsi_format_timeout)
20520Sstevel@tonic-gate ucmd->uscsi_timeout = timeout;
20530Sstevel@tonic-gate }
20540Sstevel@tonic-gate }
20550Sstevel@tonic-gate if (option_msg && diag_msg) {
20560Sstevel@tonic-gate err_print("format_timeout set to %d seconds, %d"
20570Sstevel@tonic-gate " required\n", ucmd->uscsi_timeout, timeout);
20580Sstevel@tonic-gate }
20590Sstevel@tonic-gate break;
20600Sstevel@tonic-gate
20610Sstevel@tonic-gate default:
20620Sstevel@tonic-gate ucmd->uscsi_timeout = 30; /* 30 seconds */
20630Sstevel@tonic-gate break;
20640Sstevel@tonic-gate }
20650Sstevel@tonic-gate
20660Sstevel@tonic-gate /*
20670Sstevel@tonic-gate * Set up Request Sense buffer
20680Sstevel@tonic-gate */
20690Sstevel@tonic-gate ucmd->uscsi_flags |= USCSI_RQENABLE;
20700Sstevel@tonic-gate
20710Sstevel@tonic-gate if (ucmd->uscsi_rqbuf == NULL) {
20720Sstevel@tonic-gate ucmd->uscsi_rqbuf = rqbuf;
20730Sstevel@tonic-gate ucmd->uscsi_rqlen = sizeof (rqbuf);
20740Sstevel@tonic-gate ucmd->uscsi_rqresid = sizeof (rqbuf);
20750Sstevel@tonic-gate }
20760Sstevel@tonic-gate ucmd->uscsi_rqstatus = IMPOSSIBLE_SCSI_STATUS;
20770Sstevel@tonic-gate
20780Sstevel@tonic-gate /*
20790Sstevel@tonic-gate * Clear global error state
20800Sstevel@tonic-gate */
20810Sstevel@tonic-gate media_error = 0;
20820Sstevel@tonic-gate
20830Sstevel@tonic-gate /*
20840Sstevel@tonic-gate * Execute the ioctl
20850Sstevel@tonic-gate */
20860Sstevel@tonic-gate status = ioctl(fd, USCSICMD, ucmd);
20870Sstevel@tonic-gate if (status == 0 && ucmd->uscsi_status == 0) {
20880Sstevel@tonic-gate return (status);
20890Sstevel@tonic-gate }
20900Sstevel@tonic-gate
20910Sstevel@tonic-gate /*
20920Sstevel@tonic-gate * Check the status and return appropriate errors if the disk is
20930Sstevel@tonic-gate * unavailable (could be formatting) or reserved (by other host).
20940Sstevel@tonic-gate * In either case we can not talk to the disk now.
20950Sstevel@tonic-gate */
20960Sstevel@tonic-gate if (status == -1 && errno == EAGAIN) {
20970Sstevel@tonic-gate disk_error = DISK_STAT_UNAVAILABLE;
20980Sstevel@tonic-gate return (DSK_UNAVAILABLE);
20990Sstevel@tonic-gate }
21000Sstevel@tonic-gate if ((ucmd->uscsi_status & STATUS_MASK) == STATUS_RESERVATION_CONFLICT) {
21010Sstevel@tonic-gate disk_error = DISK_STAT_RESERVED;
21020Sstevel@tonic-gate return (DSK_RESERVED);
21030Sstevel@tonic-gate }
21040Sstevel@tonic-gate /*
21050Sstevel@tonic-gate * Check for physically removed or completely unresponsive drive
21060Sstevel@tonic-gate */
21070Sstevel@tonic-gate if (status == -1 && !ucmd->uscsi_status && errno == EIO) {
21080Sstevel@tonic-gate disk_error = DISK_STAT_UNAVAILABLE;
21090Sstevel@tonic-gate return (DSK_UNAVAILABLE);
21100Sstevel@tonic-gate }
21110Sstevel@tonic-gate
21120Sstevel@tonic-gate /*
21130Sstevel@tonic-gate * If an automatic Request Sense gave us valid
21140Sstevel@tonic-gate * info about the error, we may be able to use
21150Sstevel@tonic-gate * that to print a reasonable error msg.
21160Sstevel@tonic-gate */
21170Sstevel@tonic-gate if (ucmd->uscsi_rqstatus == IMPOSSIBLE_SCSI_STATUS) {
21180Sstevel@tonic-gate if (option_msg && diag_msg) {
21190Sstevel@tonic-gate err_print("No request sense for command %s\n",
21200Sstevel@tonic-gate scsi_find_command_name(ucmd->uscsi_cdb[0]));
21210Sstevel@tonic-gate }
21220Sstevel@tonic-gate return (-1);
21230Sstevel@tonic-gate }
21240Sstevel@tonic-gate if (ucmd->uscsi_rqstatus != STATUS_GOOD) {
21250Sstevel@tonic-gate if (option_msg && diag_msg) {
21260Sstevel@tonic-gate err_print("Request sense status for command %s: 0x%x\n",
21270Sstevel@tonic-gate scsi_find_command_name(ucmd->uscsi_cdb[0]),
21280Sstevel@tonic-gate ucmd->uscsi_rqstatus);
21290Sstevel@tonic-gate }
21300Sstevel@tonic-gate return (-1);
21310Sstevel@tonic-gate }
21320Sstevel@tonic-gate rq = (struct scsi_extended_sense *)ucmd->uscsi_rqbuf;
21330Sstevel@tonic-gate rqlen = ucmd->uscsi_rqlen - ucmd->uscsi_rqresid;
21340Sstevel@tonic-gate if ((((int)rq->es_add_len) + 8) < MIN_REQUEST_SENSE_LEN ||
21350Sstevel@tonic-gate rq->es_class != CLASS_EXTENDED_SENSE ||
21360Sstevel@tonic-gate rqlen < MIN_REQUEST_SENSE_LEN) {
21370Sstevel@tonic-gate if (option_msg) {
21380Sstevel@tonic-gate err_print("Request sense for command %s failed\n",
21390Sstevel@tonic-gate scsi_find_command_name(ucmd->uscsi_cdb[0]));
21400Sstevel@tonic-gate }
21410Sstevel@tonic-gate if (option_msg && diag_msg) {
21420Sstevel@tonic-gate err_print("Sense data:\n");
21430Sstevel@tonic-gate dump("", (caddr_t)rqbuf, rqlen, HEX_ONLY);
21440Sstevel@tonic-gate }
21456765Sbz211116 if (errno == EIO) {
21466765Sbz211116 disk_error = DISK_STAT_UNAVAILABLE;
21476765Sbz211116 return (DSK_UNAVAILABLE);
21486765Sbz211116 } else {
21496765Sbz211116 return (-1);
21506765Sbz211116 }
21510Sstevel@tonic-gate }
21520Sstevel@tonic-gate
21530Sstevel@tonic-gate /*
21540Sstevel@tonic-gate * If the failed command is a Mode Select, and the
21550Sstevel@tonic-gate * target is indicating that it has rounded one of
21560Sstevel@tonic-gate * the mode select parameters, as defined in the SCSI-2
21570Sstevel@tonic-gate * specification, then we should accept the command
21580Sstevel@tonic-gate * as successful.
21590Sstevel@tonic-gate */
21600Sstevel@tonic-gate if (ucmd->uscsi_cdb[0] == SCMD_MODE_SELECT) {
21610Sstevel@tonic-gate if (rq->es_key == KEY_RECOVERABLE_ERROR &&
21620Sstevel@tonic-gate rq->es_add_code == ROUNDED_PARAMETER &&
21630Sstevel@tonic-gate rq->es_qual_code == 0) {
21640Sstevel@tonic-gate return (0);
21650Sstevel@tonic-gate }
21660Sstevel@tonic-gate }
21670Sstevel@tonic-gate
21680Sstevel@tonic-gate switch (rq->es_key) {
21690Sstevel@tonic-gate case KEY_NOT_READY:
21700Sstevel@tonic-gate disk_error = DISK_STAT_NOTREADY;
21710Sstevel@tonic-gate break;
21720Sstevel@tonic-gate case KEY_DATA_PROTECT:
21730Sstevel@tonic-gate disk_error = DISK_STAT_DATA_PROTECT;
21740Sstevel@tonic-gate break;
21750Sstevel@tonic-gate }
21760Sstevel@tonic-gate
21770Sstevel@tonic-gate if (flags & F_ALLERRS) {
21780Sstevel@tonic-gate media_error = (rq->es_key == KEY_MEDIUM_ERROR);
21790Sstevel@tonic-gate }
21800Sstevel@tonic-gate if (!(flags & F_SILENT) || option_msg) {
21810Sstevel@tonic-gate scsi_printerr(ucmd, rq, rqlen);
21820Sstevel@tonic-gate }
21830Sstevel@tonic-gate if ((rq->es_key != KEY_RECOVERABLE_ERROR) || (flags & F_ALLERRS)) {
21840Sstevel@tonic-gate return (-1);
21850Sstevel@tonic-gate }
21866765Sbz211116
21876765Sbz211116 if (status == -1 && errno == EIO) {
21886765Sbz211116 disk_error = DISK_STAT_UNAVAILABLE;
21896765Sbz211116 return (DSK_UNAVAILABLE);
21906765Sbz211116 }
21916765Sbz211116
21920Sstevel@tonic-gate return (0);
21930Sstevel@tonic-gate }
21940Sstevel@tonic-gate
21950Sstevel@tonic-gate
21960Sstevel@tonic-gate /*
21970Sstevel@tonic-gate * Execute a uscsi mode sense command.
21980Sstevel@tonic-gate * This can only be used to return one page at a time.
21990Sstevel@tonic-gate * Return the mode header/block descriptor and the actual
22000Sstevel@tonic-gate * page data separately - this allows us to support
22010Sstevel@tonic-gate * devices which return either 0 or 1 block descriptors.
22020Sstevel@tonic-gate * Whatever a device gives us in the mode header/block descriptor
22030Sstevel@tonic-gate * will be returned to it upon subsequent mode selects.
22040Sstevel@tonic-gate */
22050Sstevel@tonic-gate int
uscsi_mode_sense(fd,page_code,page_control,page_data,page_size,header)22060Sstevel@tonic-gate uscsi_mode_sense(fd, page_code, page_control, page_data, page_size, header)
22070Sstevel@tonic-gate int fd; /* file descriptor */
22080Sstevel@tonic-gate int page_code; /* requested page number */
22090Sstevel@tonic-gate int page_control; /* current, changeable, etc. */
22100Sstevel@tonic-gate caddr_t page_data; /* place received data here */
22110Sstevel@tonic-gate int page_size; /* size of page_data */
22120Sstevel@tonic-gate struct scsi_ms_header *header; /* mode header/block descriptor */
22130Sstevel@tonic-gate {
22140Sstevel@tonic-gate caddr_t mode_sense_buf;
22150Sstevel@tonic-gate struct mode_header *hdr;
22160Sstevel@tonic-gate struct mode_page *pg;
22170Sstevel@tonic-gate int nbytes;
22180Sstevel@tonic-gate struct uscsi_cmd ucmd;
22190Sstevel@tonic-gate union scsi_cdb cdb;
22200Sstevel@tonic-gate int status;
22210Sstevel@tonic-gate int maximum;
22220Sstevel@tonic-gate
22230Sstevel@tonic-gate assert(page_size >= 0 && page_size < 256);
22240Sstevel@tonic-gate assert(page_control == MODE_SENSE_PC_CURRENT ||
22250Sstevel@tonic-gate page_control == MODE_SENSE_PC_CHANGEABLE ||
22260Sstevel@tonic-gate page_control == MODE_SENSE_PC_DEFAULT ||
22270Sstevel@tonic-gate page_control == MODE_SENSE_PC_SAVED);
22280Sstevel@tonic-gate /*
22290Sstevel@tonic-gate * Allocate a buffer for the mode sense headers
22300Sstevel@tonic-gate * and mode sense data itself.
22310Sstevel@tonic-gate */
22320Sstevel@tonic-gate nbytes = sizeof (struct block_descriptor) +
22330Sstevel@tonic-gate sizeof (struct mode_header) + page_size;
22340Sstevel@tonic-gate nbytes = page_size;
22350Sstevel@tonic-gate if ((mode_sense_buf = malloc((uint_t)nbytes)) == NULL) {
22360Sstevel@tonic-gate err_print("cannot malloc %d bytes\n", nbytes);
22370Sstevel@tonic-gate return (-1);
22380Sstevel@tonic-gate }
22390Sstevel@tonic-gate
22400Sstevel@tonic-gate /*
22410Sstevel@tonic-gate * Build and execute the uscsi ioctl
22420Sstevel@tonic-gate */
22430Sstevel@tonic-gate (void) memset(mode_sense_buf, 0, nbytes);
22440Sstevel@tonic-gate (void) memset((char *)&ucmd, 0, sizeof (ucmd));
22450Sstevel@tonic-gate (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb));
22460Sstevel@tonic-gate cdb.scc_cmd = SCMD_MODE_SENSE;
22470Sstevel@tonic-gate FORMG0COUNT(&cdb, (uchar_t)nbytes);
22480Sstevel@tonic-gate cdb.cdb_opaque[2] = page_control | page_code;
22490Sstevel@tonic-gate ucmd.uscsi_cdb = (caddr_t)&cdb;
22500Sstevel@tonic-gate ucmd.uscsi_cdblen = CDB_GROUP0;
22510Sstevel@tonic-gate ucmd.uscsi_bufaddr = mode_sense_buf;
22520Sstevel@tonic-gate ucmd.uscsi_buflen = nbytes;
22530Sstevel@tonic-gate status = uscsi_cmd(fd, &ucmd,
22540Sstevel@tonic-gate (option_msg && diag_msg) ? F_NORMAL : F_SILENT);
22550Sstevel@tonic-gate if (status) {
22560Sstevel@tonic-gate if (option_msg) {
22570Sstevel@tonic-gate err_print("Mode sense page 0x%x failed\n",
22580Sstevel@tonic-gate page_code);
22590Sstevel@tonic-gate }
22600Sstevel@tonic-gate free(mode_sense_buf);
22610Sstevel@tonic-gate return (-1);
22620Sstevel@tonic-gate }
22630Sstevel@tonic-gate
22640Sstevel@tonic-gate /*
22650Sstevel@tonic-gate * Verify that the returned data looks reasonabled,
22660Sstevel@tonic-gate * find the actual page data, and copy it into the
22670Sstevel@tonic-gate * user's buffer. Copy the mode_header and block_descriptor
22680Sstevel@tonic-gate * into the header structure, which can then be used to
22690Sstevel@tonic-gate * return the same data to the drive when issuing a mode select.
22700Sstevel@tonic-gate */
22710Sstevel@tonic-gate hdr = (struct mode_header *)mode_sense_buf;
22720Sstevel@tonic-gate (void) memset((caddr_t)header, 0, sizeof (struct scsi_ms_header));
22730Sstevel@tonic-gate if (hdr->bdesc_length != sizeof (struct block_descriptor) &&
22740Sstevel@tonic-gate hdr->bdesc_length != 0) {
22750Sstevel@tonic-gate if (option_msg) {
22760Sstevel@tonic-gate err_print("\
22770Sstevel@tonic-gate \nMode sense page 0x%x: block descriptor length %d incorrect\n",
22780Sstevel@tonic-gate page_code, hdr->bdesc_length);
22790Sstevel@tonic-gate if (diag_msg)
22800Sstevel@tonic-gate dump("Mode sense: ", mode_sense_buf,
22810Sstevel@tonic-gate nbytes, HEX_ONLY);
22820Sstevel@tonic-gate }
22830Sstevel@tonic-gate free(mode_sense_buf);
22840Sstevel@tonic-gate return (-1);
22850Sstevel@tonic-gate }
22860Sstevel@tonic-gate (void) memcpy((caddr_t)header, mode_sense_buf,
22870Sstevel@tonic-gate (int) (sizeof (struct mode_header) + hdr->bdesc_length));
22880Sstevel@tonic-gate pg = (struct mode_page *)((ulong_t)mode_sense_buf +
22890Sstevel@tonic-gate sizeof (struct mode_header) + hdr->bdesc_length);
22900Sstevel@tonic-gate if (pg->code != page_code) {
22910Sstevel@tonic-gate if (option_msg) {
22920Sstevel@tonic-gate err_print("\
22930Sstevel@tonic-gate \nMode sense page 0x%x: incorrect page code 0x%x\n",
22940Sstevel@tonic-gate page_code, pg->code);
22950Sstevel@tonic-gate if (diag_msg)
22960Sstevel@tonic-gate dump("Mode sense: ", mode_sense_buf,
22970Sstevel@tonic-gate nbytes, HEX_ONLY);
22980Sstevel@tonic-gate }
22990Sstevel@tonic-gate free(mode_sense_buf);
23000Sstevel@tonic-gate return (-1);
23010Sstevel@tonic-gate }
23020Sstevel@tonic-gate /*
23030Sstevel@tonic-gate * Accept up to "page_size" bytes of mode sense data.
23040Sstevel@tonic-gate * This allows us to accept both CCS and SCSI-2
23050Sstevel@tonic-gate * structures, as long as we request the greater
23060Sstevel@tonic-gate * of the two.
23070Sstevel@tonic-gate */
23080Sstevel@tonic-gate maximum = page_size - sizeof (struct mode_page) - hdr->bdesc_length;
23090Sstevel@tonic-gate if (((int)pg->length) > maximum) {
23100Sstevel@tonic-gate if (option_msg) {
23110Sstevel@tonic-gate err_print("\
23120Sstevel@tonic-gate Mode sense page 0x%x: incorrect page length %d - expected max %d\n",
23130Sstevel@tonic-gate page_code, pg->length, maximum);
23140Sstevel@tonic-gate if (diag_msg)
23150Sstevel@tonic-gate dump("Mode sense: ", mode_sense_buf,
23160Sstevel@tonic-gate nbytes, HEX_ONLY);
23170Sstevel@tonic-gate }
23180Sstevel@tonic-gate free(mode_sense_buf);
23190Sstevel@tonic-gate return (-1);
23200Sstevel@tonic-gate }
23210Sstevel@tonic-gate
23220Sstevel@tonic-gate (void) memcpy(page_data, (caddr_t)pg, MODESENSE_PAGE_LEN(pg));
23230Sstevel@tonic-gate
23240Sstevel@tonic-gate if (option_msg && diag_msg) {
23250Sstevel@tonic-gate char *pc = find_string(page_control_strings, page_control);
23260Sstevel@tonic-gate err_print("\nMode sense page 0x%x (%s):\n", page_code,
23270Sstevel@tonic-gate pc != NULL ? pc : "");
23280Sstevel@tonic-gate dump("header: ", (caddr_t)header,
23290Sstevel@tonic-gate sizeof (struct scsi_ms_header), HEX_ONLY);
23300Sstevel@tonic-gate dump("data: ", page_data,
23310Sstevel@tonic-gate MODESENSE_PAGE_LEN(pg), HEX_ONLY);
23320Sstevel@tonic-gate }
23330Sstevel@tonic-gate
23340Sstevel@tonic-gate free(mode_sense_buf);
23350Sstevel@tonic-gate return (0);
23360Sstevel@tonic-gate }
23370Sstevel@tonic-gate
23380Sstevel@tonic-gate
23390Sstevel@tonic-gate /*
23400Sstevel@tonic-gate * Execute a uscsi mode select command.
23410Sstevel@tonic-gate */
23420Sstevel@tonic-gate int
uscsi_mode_select(fd,page_code,options,page_data,page_size,header)23430Sstevel@tonic-gate uscsi_mode_select(fd, page_code, options, page_data, page_size, header)
23440Sstevel@tonic-gate int fd; /* file descriptor */
23450Sstevel@tonic-gate int page_code; /* mode select page */
23460Sstevel@tonic-gate int options; /* save page/page format */
23470Sstevel@tonic-gate caddr_t page_data; /* place received data here */
23480Sstevel@tonic-gate int page_size; /* size of page_data */
23490Sstevel@tonic-gate struct scsi_ms_header *header; /* mode header/block descriptor */
23500Sstevel@tonic-gate {
23510Sstevel@tonic-gate caddr_t mode_select_buf;
23520Sstevel@tonic-gate int nbytes;
23530Sstevel@tonic-gate struct uscsi_cmd ucmd;
23540Sstevel@tonic-gate union scsi_cdb cdb;
23550Sstevel@tonic-gate int status;
23560Sstevel@tonic-gate
23570Sstevel@tonic-gate assert(((struct mode_page *)page_data)->ps == 0);
23580Sstevel@tonic-gate assert(header->mode_header.length == 0);
23590Sstevel@tonic-gate assert(header->mode_header.device_specific == 0);
23600Sstevel@tonic-gate assert((options & ~(MODE_SELECT_SP|MODE_SELECT_PF)) == 0);
23610Sstevel@tonic-gate
23620Sstevel@tonic-gate /*
23630Sstevel@tonic-gate * Allocate a buffer for the mode select header and data
23640Sstevel@tonic-gate */
23650Sstevel@tonic-gate nbytes = sizeof (struct block_descriptor) +
23660Sstevel@tonic-gate sizeof (struct mode_header) + page_size;
23670Sstevel@tonic-gate if ((mode_select_buf = malloc((uint_t)nbytes)) == NULL) {
23680Sstevel@tonic-gate err_print("cannot malloc %d bytes\n", nbytes);
23690Sstevel@tonic-gate return (-1);
23700Sstevel@tonic-gate }
23710Sstevel@tonic-gate
23720Sstevel@tonic-gate /*
23730Sstevel@tonic-gate * Build the mode select data out of the header and page data
23740Sstevel@tonic-gate * This allows us to support devices which return either
23750Sstevel@tonic-gate * 0 or 1 block descriptors.
23760Sstevel@tonic-gate */
23770Sstevel@tonic-gate (void) memset(mode_select_buf, 0, nbytes);
23780Sstevel@tonic-gate nbytes = sizeof (struct mode_header);
23790Sstevel@tonic-gate if (header->mode_header.bdesc_length ==
23800Sstevel@tonic-gate sizeof (struct block_descriptor)) {
23810Sstevel@tonic-gate nbytes += sizeof (struct block_descriptor);
23820Sstevel@tonic-gate }
23830Sstevel@tonic-gate
23840Sstevel@tonic-gate /*
23850Sstevel@tonic-gate * Dump the structures if anyone's interested
23860Sstevel@tonic-gate */
23870Sstevel@tonic-gate if (option_msg && diag_msg) {
23880Sstevel@tonic-gate char *s;
23890Sstevel@tonic-gate s = find_string(mode_select_strings,
23900Sstevel@tonic-gate options & (MODE_SELECT_SP|MODE_SELECT_PF));
23910Sstevel@tonic-gate err_print("\nMode select page 0x%x%s:\n", page_code,
23920Sstevel@tonic-gate s != NULL ? s : "");
23930Sstevel@tonic-gate dump("header: ", (caddr_t)header,
23940Sstevel@tonic-gate nbytes, HEX_ONLY);
23950Sstevel@tonic-gate dump("data: ", (caddr_t)page_data,
23960Sstevel@tonic-gate page_size, HEX_ONLY);
23970Sstevel@tonic-gate }
23980Sstevel@tonic-gate
23990Sstevel@tonic-gate /*
24000Sstevel@tonic-gate * Fix the code for byte ordering
24010Sstevel@tonic-gate */
24020Sstevel@tonic-gate
24030Sstevel@tonic-gate switch (page_code) {
24040Sstevel@tonic-gate case DAD_MODE_ERR_RECOV:
24050Sstevel@tonic-gate {
24060Sstevel@tonic-gate struct mode_err_recov *pd;
24070Sstevel@tonic-gate pd = (struct mode_err_recov *)(void *)page_data;
24080Sstevel@tonic-gate pd->recovery_time_limit = BE_16(pd->recovery_time_limit);
24090Sstevel@tonic-gate break;
24100Sstevel@tonic-gate }
24110Sstevel@tonic-gate case MODEPAGE_DISCO_RECO:
24120Sstevel@tonic-gate {
24130Sstevel@tonic-gate struct mode_disco_reco *pd;
24140Sstevel@tonic-gate pd = (struct mode_disco_reco *)(void *)page_data;
24150Sstevel@tonic-gate pd->bus_inactivity_limit = BE_16(pd->bus_inactivity_limit);
24160Sstevel@tonic-gate pd->disconect_time_limit = BE_16(pd->disconect_time_limit);
24170Sstevel@tonic-gate pd->connect_time_limit = BE_16(pd->connect_time_limit);
24180Sstevel@tonic-gate pd->max_burst_size = BE_16(pd->max_burst_size);
24190Sstevel@tonic-gate break;
24200Sstevel@tonic-gate }
24210Sstevel@tonic-gate case DAD_MODE_FORMAT:
24220Sstevel@tonic-gate {
24230Sstevel@tonic-gate struct mode_format *pd;
24240Sstevel@tonic-gate pd = (struct mode_format *)(void *)page_data;
24250Sstevel@tonic-gate pd->tracks_per_zone = BE_16(pd->tracks_per_zone);
24260Sstevel@tonic-gate pd->alt_sect_zone = BE_16(pd->alt_sect_zone);
24270Sstevel@tonic-gate pd->alt_tracks_zone = BE_16(pd->alt_tracks_zone);
24280Sstevel@tonic-gate pd->alt_tracks_vol = BE_16(pd->alt_tracks_vol);
24290Sstevel@tonic-gate pd->sect_track = BE_16(pd->sect_track);
24300Sstevel@tonic-gate pd->data_bytes_sect = BE_16(pd->data_bytes_sect);
24310Sstevel@tonic-gate pd->interleave = BE_16(pd->interleave);
24320Sstevel@tonic-gate pd->track_skew = BE_16(pd->track_skew);
24330Sstevel@tonic-gate pd->cylinder_skew = BE_16(pd->cylinder_skew);
24340Sstevel@tonic-gate break;
24350Sstevel@tonic-gate }
24360Sstevel@tonic-gate case DAD_MODE_GEOMETRY:
24370Sstevel@tonic-gate {
24380Sstevel@tonic-gate struct mode_geometry *pd;
24390Sstevel@tonic-gate pd = (struct mode_geometry *)(void *)page_data;
24400Sstevel@tonic-gate pd->step_rate = BE_16(pd->step_rate);
24410Sstevel@tonic-gate pd->rpm = BE_16(pd->rpm);
24420Sstevel@tonic-gate break;
24430Sstevel@tonic-gate }
24440Sstevel@tonic-gate case DAD_MODE_CACHE:
24450Sstevel@tonic-gate {
24460Sstevel@tonic-gate struct mode_cache *pd;
24470Sstevel@tonic-gate pd = (struct mode_cache *)(void *)page_data;
24480Sstevel@tonic-gate pd->dis_prefetch_len = BE_16(pd->dis_prefetch_len);
24490Sstevel@tonic-gate pd->min_prefetch = BE_16(pd->min_prefetch);
24500Sstevel@tonic-gate pd->max_prefetch = BE_16(pd->max_prefetch);
24510Sstevel@tonic-gate pd->prefetch_ceiling = BE_16(pd->prefetch_ceiling);
24520Sstevel@tonic-gate break;
24530Sstevel@tonic-gate }
24540Sstevel@tonic-gate case MODEPAGE_PDEVICE:
24550Sstevel@tonic-gate {
24560Sstevel@tonic-gate struct mode_pdevice *pd;
24570Sstevel@tonic-gate pd = (struct mode_pdevice *)(void *)page_data;
24580Sstevel@tonic-gate pd->if_ident = BE_16(pd->if_ident);
24590Sstevel@tonic-gate break;
24600Sstevel@tonic-gate }
24610Sstevel@tonic-gate case MODEPAGE_CTRL_MODE:
24620Sstevel@tonic-gate {
24630Sstevel@tonic-gate struct mode_control *pd;
24640Sstevel@tonic-gate pd = (struct mode_control *)(void *)page_data;
24650Sstevel@tonic-gate pd->ready_aen_holdoff = BE_16(pd->ready_aen_holdoff);
24660Sstevel@tonic-gate break;
24670Sstevel@tonic-gate }
24680Sstevel@tonic-gate }
24690Sstevel@tonic-gate
24700Sstevel@tonic-gate /*
24710Sstevel@tonic-gate * Put the header and data together
24720Sstevel@tonic-gate */
24730Sstevel@tonic-gate (void) memcpy(mode_select_buf, (caddr_t)header, nbytes);
24740Sstevel@tonic-gate (void) memcpy(mode_select_buf + nbytes, page_data, page_size);
24750Sstevel@tonic-gate nbytes += page_size;
24760Sstevel@tonic-gate
24770Sstevel@tonic-gate /*
24780Sstevel@tonic-gate * Build and execute the uscsi ioctl
24790Sstevel@tonic-gate */
24800Sstevel@tonic-gate (void) memset((char *)&ucmd, 0, sizeof (ucmd));
24810Sstevel@tonic-gate (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb));
24820Sstevel@tonic-gate cdb.scc_cmd = SCMD_MODE_SELECT;
24830Sstevel@tonic-gate FORMG0COUNT(&cdb, (uchar_t)nbytes);
24840Sstevel@tonic-gate cdb.cdb_opaque[1] = (uchar_t)options;
24850Sstevel@tonic-gate ucmd.uscsi_cdb = (caddr_t)&cdb;
24860Sstevel@tonic-gate ucmd.uscsi_cdblen = CDB_GROUP0;
24870Sstevel@tonic-gate ucmd.uscsi_bufaddr = mode_select_buf;
24880Sstevel@tonic-gate ucmd.uscsi_buflen = nbytes;
24890Sstevel@tonic-gate status = uscsi_cmd(fd, &ucmd,
24900Sstevel@tonic-gate (option_msg && diag_msg) ? F_NORMAL : F_SILENT);
24910Sstevel@tonic-gate
24920Sstevel@tonic-gate if (status && option_msg) {
24930Sstevel@tonic-gate err_print("Mode select page 0x%x failed\n", page_code);
24940Sstevel@tonic-gate }
24950Sstevel@tonic-gate
24960Sstevel@tonic-gate free(mode_select_buf);
24970Sstevel@tonic-gate return (status);
24980Sstevel@tonic-gate }
24990Sstevel@tonic-gate
25000Sstevel@tonic-gate
25010Sstevel@tonic-gate /*
25020Sstevel@tonic-gate * Execute a uscsi inquiry command and return the
25030Sstevel@tonic-gate * resulting data.
25040Sstevel@tonic-gate */
25050Sstevel@tonic-gate int
uscsi_inquiry(fd,inqbuf,inqbufsiz)25060Sstevel@tonic-gate uscsi_inquiry(fd, inqbuf, inqbufsiz)
25070Sstevel@tonic-gate int fd;
25080Sstevel@tonic-gate caddr_t inqbuf;
25090Sstevel@tonic-gate int inqbufsiz;
25100Sstevel@tonic-gate {
25110Sstevel@tonic-gate struct uscsi_cmd ucmd;
25120Sstevel@tonic-gate union scsi_cdb cdb;
25130Sstevel@tonic-gate struct scsi_inquiry *inq;
25140Sstevel@tonic-gate int n;
25150Sstevel@tonic-gate int status;
25160Sstevel@tonic-gate
25170Sstevel@tonic-gate assert(inqbufsiz >= sizeof (struct scsi_inquiry) &&
25180Sstevel@tonic-gate inqbufsiz < 256);
25190Sstevel@tonic-gate
25200Sstevel@tonic-gate /*
25210Sstevel@tonic-gate * Build and execute the uscsi ioctl
25220Sstevel@tonic-gate */
25230Sstevel@tonic-gate (void) memset((char *)inqbuf, 0, inqbufsiz);
25240Sstevel@tonic-gate (void) memset((char *)&ucmd, 0, sizeof (ucmd));
25250Sstevel@tonic-gate (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb));
25260Sstevel@tonic-gate cdb.scc_cmd = SCMD_INQUIRY;
25270Sstevel@tonic-gate FORMG0COUNT(&cdb, (uchar_t)inqbufsiz);
25280Sstevel@tonic-gate ucmd.uscsi_cdb = (caddr_t)&cdb;
25290Sstevel@tonic-gate ucmd.uscsi_cdblen = CDB_GROUP0;
25300Sstevel@tonic-gate ucmd.uscsi_bufaddr = (caddr_t)inqbuf;
25310Sstevel@tonic-gate ucmd.uscsi_buflen = inqbufsiz;
25320Sstevel@tonic-gate status = uscsi_cmd(fd, &ucmd,
25330Sstevel@tonic-gate (option_msg && diag_msg) ? F_NORMAL : F_SILENT);
25340Sstevel@tonic-gate if (status) {
25350Sstevel@tonic-gate if (option_msg) {
25360Sstevel@tonic-gate err_print("Inquiry failed\n");
25370Sstevel@tonic-gate }
25380Sstevel@tonic-gate } else if (option_msg && diag_msg) {
25390Sstevel@tonic-gate /*
25400Sstevel@tonic-gate * Dump the inquiry data if anyone's interested
25410Sstevel@tonic-gate */
25420Sstevel@tonic-gate inq = (struct scsi_inquiry *)inqbuf;
25430Sstevel@tonic-gate n = (int)inq->inq_len + 4;
25440Sstevel@tonic-gate n = min(n, inqbufsiz);
25450Sstevel@tonic-gate err_print("Inquiry:\n");
25460Sstevel@tonic-gate dump("", (caddr_t)inqbuf, n, HEX_ASCII);
25470Sstevel@tonic-gate }
25480Sstevel@tonic-gate return (status);
25490Sstevel@tonic-gate }
25500Sstevel@tonic-gate
255112594SShengliang.Zhang@Sun.COM /*
255212594SShengliang.Zhang@Sun.COM * Execute a uscsi inquiry command with page code 86h
255312594SShengliang.Zhang@Sun.COM */
255412594SShengliang.Zhang@Sun.COM int
uscsi_inquiry_page_86h(fd,inqbuf,inqbufsiz)255512594SShengliang.Zhang@Sun.COM uscsi_inquiry_page_86h(fd, inqbuf, inqbufsiz)
255612594SShengliang.Zhang@Sun.COM int fd;
255712594SShengliang.Zhang@Sun.COM caddr_t inqbuf;
255812594SShengliang.Zhang@Sun.COM int inqbufsiz;
255912594SShengliang.Zhang@Sun.COM {
256012594SShengliang.Zhang@Sun.COM struct uscsi_cmd ucmd;
256112594SShengliang.Zhang@Sun.COM union scsi_cdb cdb;
256212594SShengliang.Zhang@Sun.COM int status;
256312594SShengliang.Zhang@Sun.COM
256412594SShengliang.Zhang@Sun.COM assert(inqbuf);
256512594SShengliang.Zhang@Sun.COM assert(inqbufsiz >= sizeof (struct scsi_inquiry) &&
256612594SShengliang.Zhang@Sun.COM inqbufsiz < 256);
256712594SShengliang.Zhang@Sun.COM /*
256812594SShengliang.Zhang@Sun.COM * Build and execute uscsi ioctl
256912594SShengliang.Zhang@Sun.COM */
257012594SShengliang.Zhang@Sun.COM (void) memset((char *)inqbuf, 0, inqbufsiz);
257112594SShengliang.Zhang@Sun.COM (void) memset((char *)&ucmd, 0, sizeof (ucmd));
257212594SShengliang.Zhang@Sun.COM (void) memset((char *)&cdb, 0, sizeof (cdb));
257312594SShengliang.Zhang@Sun.COM cdb.scc_cmd = SCMD_INQUIRY;
257412594SShengliang.Zhang@Sun.COM FORMG0COUNT(&cdb, (uchar_t)inqbufsiz);
257512594SShengliang.Zhang@Sun.COM cdb.cdb_opaque[1] |= 0x01;
257612594SShengliang.Zhang@Sun.COM cdb.cdb_opaque[2] = 0x86;
257712594SShengliang.Zhang@Sun.COM ucmd.uscsi_cdb = (caddr_t)&cdb;
257812594SShengliang.Zhang@Sun.COM ucmd.uscsi_cdblen = CDB_GROUP0;
257912594SShengliang.Zhang@Sun.COM ucmd.uscsi_bufaddr = (caddr_t)inqbuf;
258012594SShengliang.Zhang@Sun.COM ucmd.uscsi_buflen = inqbufsiz;
258112594SShengliang.Zhang@Sun.COM
258212594SShengliang.Zhang@Sun.COM status = uscsi_cmd(fd, &ucmd,
258312594SShengliang.Zhang@Sun.COM (option_msg && diag_msg) ? F_NORMAL : F_SILENT);
258412594SShengliang.Zhang@Sun.COM
258512594SShengliang.Zhang@Sun.COM if (status) {
258612594SShengliang.Zhang@Sun.COM if (option_msg) {
258712594SShengliang.Zhang@Sun.COM err_print("Inquriy with page_86h failed\n");
258812594SShengliang.Zhang@Sun.COM }
258912594SShengliang.Zhang@Sun.COM }
259012594SShengliang.Zhang@Sun.COM return (status);
259112594SShengliang.Zhang@Sun.COM }
25920Sstevel@tonic-gate
25930Sstevel@tonic-gate /*
25940Sstevel@tonic-gate * Return the Read Capacity information
25950Sstevel@tonic-gate */
25960Sstevel@tonic-gate int
uscsi_read_capacity_16(fd,capacity)259712594SShengliang.Zhang@Sun.COM uscsi_read_capacity_16(fd, capacity)
259812594SShengliang.Zhang@Sun.COM int fd;
259912594SShengliang.Zhang@Sun.COM struct scsi_capacity_16 *capacity;
260012594SShengliang.Zhang@Sun.COM {
260112594SShengliang.Zhang@Sun.COM struct uscsi_cmd ucmd;
260212594SShengliang.Zhang@Sun.COM union scsi_cdb cdb;
260312594SShengliang.Zhang@Sun.COM int status;
260412594SShengliang.Zhang@Sun.COM
260512594SShengliang.Zhang@Sun.COM (void) memset((char *)capacity, 0, sizeof (struct scsi_capacity_16));
260612594SShengliang.Zhang@Sun.COM (void) memset((char *)&ucmd, 0, sizeof (ucmd));
260712594SShengliang.Zhang@Sun.COM (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb));
260812594SShengliang.Zhang@Sun.COM
260912594SShengliang.Zhang@Sun.COM ucmd.uscsi_cdb = (caddr_t)&cdb;
261012594SShengliang.Zhang@Sun.COM ucmd.uscsi_cdblen = CDB_GROUP4;
261112594SShengliang.Zhang@Sun.COM ucmd.uscsi_bufaddr = (caddr_t)capacity;
261212594SShengliang.Zhang@Sun.COM ucmd.uscsi_buflen = sizeof (struct scsi_capacity_16);
261312594SShengliang.Zhang@Sun.COM
261412594SShengliang.Zhang@Sun.COM /*
261512594SShengliang.Zhang@Sun.COM * Read Capacity (16) is a Service Action In command. One
261612594SShengliang.Zhang@Sun.COM * command byte (0x9E) is overloaded for multiple operations,
261712594SShengliang.Zhang@Sun.COM * with the second CDB byte specifying the desired operation
261812594SShengliang.Zhang@Sun.COM */
261912594SShengliang.Zhang@Sun.COM cdb.scc_cmd = SCMD_SVC_ACTION_IN_G4;
262012594SShengliang.Zhang@Sun.COM cdb.cdb_opaque[1] = SSVC_ACTION_READ_CAPACITY_G4;
262112594SShengliang.Zhang@Sun.COM
262212594SShengliang.Zhang@Sun.COM /*
262312594SShengliang.Zhang@Sun.COM * Fill in allocation length field
262412594SShengliang.Zhang@Sun.COM */
262512594SShengliang.Zhang@Sun.COM cdb.cdb_opaque[10] =
262612594SShengliang.Zhang@Sun.COM (uchar_t)((ucmd.uscsi_buflen & 0xff000000) >> 24);
262712594SShengliang.Zhang@Sun.COM cdb.cdb_opaque[11] =
262812594SShengliang.Zhang@Sun.COM (uchar_t)((ucmd.uscsi_buflen & 0x00ff0000) >> 16);
262912594SShengliang.Zhang@Sun.COM cdb.cdb_opaque[12] =
263012594SShengliang.Zhang@Sun.COM (uchar_t)((ucmd.uscsi_buflen & 0x0000ff00) >> 8);
263112594SShengliang.Zhang@Sun.COM cdb.cdb_opaque[13] =
263212594SShengliang.Zhang@Sun.COM (uchar_t)(ucmd.uscsi_buflen & 0x000000ff);
263312594SShengliang.Zhang@Sun.COM
263412594SShengliang.Zhang@Sun.COM status = uscsi_cmd(fd, &ucmd,
263512594SShengliang.Zhang@Sun.COM (option_msg && diag_msg) ? F_NORMAL : F_SILENT);
263612594SShengliang.Zhang@Sun.COM
263712594SShengliang.Zhang@Sun.COM if (status) {
263812594SShengliang.Zhang@Sun.COM if (option_msg) {
263912594SShengliang.Zhang@Sun.COM err_print("Read capacity 16 failed\n");
264012594SShengliang.Zhang@Sun.COM }
264112594SShengliang.Zhang@Sun.COM } else if (option_msg && diag_msg) {
264212594SShengliang.Zhang@Sun.COM /*
264312594SShengliang.Zhang@Sun.COM * Dump the capacity data if anyone's interested
264412594SShengliang.Zhang@Sun.COM */
264512594SShengliang.Zhang@Sun.COM dump("Capacity: ", (caddr_t)capacity,
264612594SShengliang.Zhang@Sun.COM sizeof (struct scsi_capacity_16), HEX_ONLY);
264712594SShengliang.Zhang@Sun.COM }
264812594SShengliang.Zhang@Sun.COM
264912594SShengliang.Zhang@Sun.COM capacity->sc_capacity = BE_64(capacity->sc_capacity);
265012594SShengliang.Zhang@Sun.COM capacity->sc_lbasize = BE_32(capacity->sc_lbasize);
265112594SShengliang.Zhang@Sun.COM
265212594SShengliang.Zhang@Sun.COM return (status);
265312594SShengliang.Zhang@Sun.COM }
265412594SShengliang.Zhang@Sun.COM
265512594SShengliang.Zhang@Sun.COM int
uscsi_read_capacity(fd,capacity)26560Sstevel@tonic-gate uscsi_read_capacity(fd, capacity)
26570Sstevel@tonic-gate int fd;
26580Sstevel@tonic-gate struct scsi_capacity_16 *capacity;
26590Sstevel@tonic-gate {
26600Sstevel@tonic-gate struct uscsi_cmd ucmd;
26610Sstevel@tonic-gate union scsi_cdb cdb;
26620Sstevel@tonic-gate int status;
26630Sstevel@tonic-gate struct scsi_capacity cap_old;
26640Sstevel@tonic-gate
26650Sstevel@tonic-gate /*
26660Sstevel@tonic-gate * Build and execute the uscsi ioctl
26670Sstevel@tonic-gate */
26680Sstevel@tonic-gate (void) memset((char *)capacity, 0, sizeof (struct scsi_capacity_16));
26690Sstevel@tonic-gate (void) memset((char *)&cap_old, 0, sizeof (struct scsi_capacity));
26700Sstevel@tonic-gate (void) memset((char *)&ucmd, 0, sizeof (ucmd));
26710Sstevel@tonic-gate (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb));
26720Sstevel@tonic-gate cdb.scc_cmd = SCMD_READ_CAPACITY;
26730Sstevel@tonic-gate ucmd.uscsi_cdb = (caddr_t)&cdb;
26740Sstevel@tonic-gate ucmd.uscsi_cdblen = CDB_GROUP1;
26750Sstevel@tonic-gate ucmd.uscsi_bufaddr = (caddr_t)&cap_old;
26760Sstevel@tonic-gate ucmd.uscsi_buflen = sizeof (struct scsi_capacity);
26770Sstevel@tonic-gate status = uscsi_cmd(fd, &ucmd,
26780Sstevel@tonic-gate (option_msg && diag_msg) ? F_NORMAL : F_SILENT);
26790Sstevel@tonic-gate
26800Sstevel@tonic-gate if (cap_old.capacity == UINT_MAX32) {
26810Sstevel@tonic-gate /*
26820Sstevel@tonic-gate * A capacity of 0xffffffff in response to a
26830Sstevel@tonic-gate * READ CAPACITY 10 indicates that the lun
26840Sstevel@tonic-gate * is too large to report the size in a 32 bit
26850Sstevel@tonic-gate * value, and a READ CAPACITY 16 is required
26860Sstevel@tonic-gate * to get the correct size.
26870Sstevel@tonic-gate */
26880Sstevel@tonic-gate (void) memset((char *)&ucmd, 0, sizeof (ucmd));
26890Sstevel@tonic-gate (void) memset((char *)&cdb, 0,
26900Sstevel@tonic-gate sizeof (union scsi_cdb));
26910Sstevel@tonic-gate
26920Sstevel@tonic-gate ucmd.uscsi_cdb = (caddr_t)&cdb;
26930Sstevel@tonic-gate ucmd.uscsi_cdblen = CDB_GROUP4;
26940Sstevel@tonic-gate ucmd.uscsi_bufaddr = (caddr_t)capacity;
26950Sstevel@tonic-gate ucmd.uscsi_buflen = sizeof (struct scsi_capacity_16);
26960Sstevel@tonic-gate
26970Sstevel@tonic-gate /*
26980Sstevel@tonic-gate * Read Capacity (16) is a Service Action In command. One
26990Sstevel@tonic-gate * command byte (0x9E) is overloaded for multiple operations,
27000Sstevel@tonic-gate * with the second CDB byte specifying the desired operation
27010Sstevel@tonic-gate */
27020Sstevel@tonic-gate cdb.scc_cmd = SCMD_SVC_ACTION_IN_G4;
27030Sstevel@tonic-gate cdb.cdb_opaque[1] = SSVC_ACTION_READ_CAPACITY_G4;
27040Sstevel@tonic-gate
27050Sstevel@tonic-gate /*
27060Sstevel@tonic-gate * Fill in allocation length field
27070Sstevel@tonic-gate */
27080Sstevel@tonic-gate cdb.cdb_opaque[10] =
27090Sstevel@tonic-gate (uchar_t)((ucmd.uscsi_buflen & 0xff000000) >> 24);
27100Sstevel@tonic-gate cdb.cdb_opaque[11] =
27110Sstevel@tonic-gate (uchar_t)((ucmd.uscsi_buflen & 0x00ff0000) >> 16);
27120Sstevel@tonic-gate cdb.cdb_opaque[12] =
27130Sstevel@tonic-gate (uchar_t)((ucmd.uscsi_buflen & 0x0000ff00) >> 8);
27140Sstevel@tonic-gate cdb.cdb_opaque[13] =
27150Sstevel@tonic-gate (uchar_t)(ucmd.uscsi_buflen & 0x000000ff);
27160Sstevel@tonic-gate
27170Sstevel@tonic-gate status = uscsi_cmd(fd, &ucmd,
27180Sstevel@tonic-gate (option_msg && diag_msg) ? F_NORMAL : F_SILENT);
27190Sstevel@tonic-gate }
27200Sstevel@tonic-gate
27210Sstevel@tonic-gate if (status) {
27220Sstevel@tonic-gate if (option_msg) {
27230Sstevel@tonic-gate /*
27240Sstevel@tonic-gate * Indicate which of the commands failed
27250Sstevel@tonic-gate */
27260Sstevel@tonic-gate if (cdb.scc_cmd == SCMD_READ_CAPACITY) {
27270Sstevel@tonic-gate err_print("Read capacity failed\n");
27280Sstevel@tonic-gate } else {
27290Sstevel@tonic-gate err_print("Read capacity 16 failed\n");
27300Sstevel@tonic-gate }
27310Sstevel@tonic-gate }
27320Sstevel@tonic-gate } else if (option_msg && diag_msg) {
27330Sstevel@tonic-gate /*
27340Sstevel@tonic-gate * Dump the capacity data if anyone's interested
27350Sstevel@tonic-gate */
27361180Slh195018 if (cap_old.capacity == UINT_MAX32) {
27371180Slh195018 dump("Capacity: ", (caddr_t)capacity,
27381180Slh195018 sizeof (struct scsi_capacity_16), HEX_ONLY);
27391180Slh195018 } else {
27401180Slh195018 dump("Capacity: ", (caddr_t)&cap_old,
27411180Slh195018 sizeof (struct scsi_capacity), HEX_ONLY);
27421180Slh195018 }
27430Sstevel@tonic-gate }
27441180Slh195018
27451180Slh195018 if (cap_old.capacity == UINT_MAX32) {
27461180Slh195018 capacity->sc_capacity = BE_64(capacity->sc_capacity);
27471180Slh195018 capacity->sc_lbasize = BE_32(capacity->sc_lbasize);
27481180Slh195018 } else {
27491180Slh195018 capacity->sc_capacity = (uint64_t)BE_32(cap_old.capacity);
27501180Slh195018 capacity->sc_lbasize = BE_32(cap_old.lbasize);
27511180Slh195018 }
27521180Slh195018
27530Sstevel@tonic-gate return (status);
27540Sstevel@tonic-gate }
27550Sstevel@tonic-gate
27560Sstevel@tonic-gate
27570Sstevel@tonic-gate /*
27580Sstevel@tonic-gate * Reserve the current disk
27590Sstevel@tonic-gate */
27600Sstevel@tonic-gate static int
uscsi_reserve_release(int fd,int cmd)27610Sstevel@tonic-gate uscsi_reserve_release(int fd, int cmd)
27620Sstevel@tonic-gate {
27630Sstevel@tonic-gate int status = 0;
27640Sstevel@tonic-gate #ifdef sparc
27650Sstevel@tonic-gate struct uscsi_cmd ucmd;
27660Sstevel@tonic-gate union scsi_cdb cdb;
27670Sstevel@tonic-gate
27680Sstevel@tonic-gate /*
27690Sstevel@tonic-gate * Build and execute the uscsi ioctl
27700Sstevel@tonic-gate */
27710Sstevel@tonic-gate (void) memset((char *)&ucmd, 0, sizeof (ucmd));
27720Sstevel@tonic-gate (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb));
27730Sstevel@tonic-gate cdb.scc_cmd = (cmd == SCMD_RESERVE) ? SCMD_RESERVE : SCMD_RELEASE;
27740Sstevel@tonic-gate ucmd.uscsi_cdb = (caddr_t)&cdb;
27750Sstevel@tonic-gate ucmd.uscsi_cdblen = CDB_GROUP0;
27760Sstevel@tonic-gate status = uscsi_cmd(fd, &ucmd,
27779889SLarry.Liu@Sun.COM (option_msg && diag_msg) ? F_NORMAL : F_SILENT);
27780Sstevel@tonic-gate
27790Sstevel@tonic-gate if (status) {
27800Sstevel@tonic-gate /*
27810Sstevel@tonic-gate * Reserve/Release(6) failed.
27820Sstevel@tonic-gate * Try Reserve/Release(10) , if it succeeds then
27830Sstevel@tonic-gate * return success.
27840Sstevel@tonic-gate */
27850Sstevel@tonic-gate (void) memset((char *)&ucmd, 0, sizeof (ucmd));
27860Sstevel@tonic-gate (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb));
27870Sstevel@tonic-gate ucmd.uscsi_cdb = (caddr_t)&cdb;
27880Sstevel@tonic-gate cdb.scc_cmd = (cmd == SCMD_RESERVE) ?
27899889SLarry.Liu@Sun.COM SCMD_RESERVE_G1 : SCMD_RELEASE_G1;
27900Sstevel@tonic-gate ucmd.uscsi_cdblen = CDB_GROUP1;
27910Sstevel@tonic-gate status = uscsi_cmd(fd, &ucmd,
27929889SLarry.Liu@Sun.COM (option_msg && diag_msg) ? F_NORMAL : F_SILENT);
27930Sstevel@tonic-gate if (status) {
27940Sstevel@tonic-gate if (option_msg) {
27959889SLarry.Liu@Sun.COM err_print("%s failed\n", (cmd == SCMD_RESERVE) ?
27969889SLarry.Liu@Sun.COM "Reserve" : "Release");
27970Sstevel@tonic-gate }
27980Sstevel@tonic-gate }
27990Sstevel@tonic-gate }
28000Sstevel@tonic-gate #else /* not sparc */
28010Sstevel@tonic-gate
28020Sstevel@tonic-gate #ifdef lint
28030Sstevel@tonic-gate fd = fd;
28040Sstevel@tonic-gate cmd = cmd;
28050Sstevel@tonic-gate #endif /* lint */
28060Sstevel@tonic-gate
28070Sstevel@tonic-gate #endif /* not sparc */
28080Sstevel@tonic-gate
28090Sstevel@tonic-gate return (status);
28100Sstevel@tonic-gate }
28110Sstevel@tonic-gate
28120Sstevel@tonic-gate int
scsi_dump_mode_sense_pages(page_control)28130Sstevel@tonic-gate scsi_dump_mode_sense_pages(page_control)
28140Sstevel@tonic-gate int page_control;
28150Sstevel@tonic-gate {
28160Sstevel@tonic-gate struct uscsi_cmd ucmd;
28170Sstevel@tonic-gate union scsi_cdb cdb;
28180Sstevel@tonic-gate char *msbuf;
28190Sstevel@tonic-gate int nbytes;
28200Sstevel@tonic-gate char *pc_str;
28210Sstevel@tonic-gate int status;
28220Sstevel@tonic-gate struct mode_header *mh;
28230Sstevel@tonic-gate char *p;
28240Sstevel@tonic-gate struct mode_page *mp;
28250Sstevel@tonic-gate int n;
28260Sstevel@tonic-gate char s[16];
28270Sstevel@tonic-gate int result = 0;
28280Sstevel@tonic-gate
28290Sstevel@tonic-gate pc_str = find_string(page_control_strings, page_control);
28300Sstevel@tonic-gate
28310Sstevel@tonic-gate /*
28320Sstevel@tonic-gate * Allocate memory for the mode sense buffer.
28330Sstevel@tonic-gate */
28340Sstevel@tonic-gate nbytes = 255;
28350Sstevel@tonic-gate msbuf = (char *)zalloc(nbytes);
28360Sstevel@tonic-gate
28370Sstevel@tonic-gate /*
28380Sstevel@tonic-gate * Build and execute the uscsi ioctl
28390Sstevel@tonic-gate */
28400Sstevel@tonic-gate (void) memset(msbuf, 0, nbytes);
28410Sstevel@tonic-gate (void) memset((char *)&ucmd, 0, sizeof (ucmd));
28420Sstevel@tonic-gate (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb));
28430Sstevel@tonic-gate cdb.scc_cmd = SCMD_MODE_SENSE;
28440Sstevel@tonic-gate FORMG0COUNT(&cdb, (uchar_t)nbytes);
28450Sstevel@tonic-gate cdb.cdb_opaque[2] = page_control | 0x3f;
28460Sstevel@tonic-gate ucmd.uscsi_cdb = (caddr_t)&cdb;
28470Sstevel@tonic-gate ucmd.uscsi_cdblen = CDB_GROUP0;
28480Sstevel@tonic-gate ucmd.uscsi_bufaddr = msbuf;
28490Sstevel@tonic-gate ucmd.uscsi_buflen = nbytes;
28500Sstevel@tonic-gate status = uscsi_cmd(cur_file, &ucmd,
28510Sstevel@tonic-gate (option_msg && diag_msg) ? F_NORMAL : F_SILENT);
28520Sstevel@tonic-gate if (status) {
28530Sstevel@tonic-gate err_print("\nMode sense page 0x3f (%s) failed\n",
28540Sstevel@tonic-gate pc_str);
28550Sstevel@tonic-gate result = 1;
28560Sstevel@tonic-gate } else {
28570Sstevel@tonic-gate err_print("\nMode sense pages (%s):\n", pc_str);
28580Sstevel@tonic-gate mh = (struct mode_header *)msbuf;
28590Sstevel@tonic-gate nbytes = mh->length - sizeof (struct mode_header) -
28600Sstevel@tonic-gate mh->bdesc_length + 1;
28610Sstevel@tonic-gate p = msbuf + sizeof (struct mode_header) +
28620Sstevel@tonic-gate mh->bdesc_length;
28630Sstevel@tonic-gate dump(" ", msbuf, sizeof (struct mode_header) +
28640Sstevel@tonic-gate (int)mh->bdesc_length, HEX_ONLY);
28650Sstevel@tonic-gate while (nbytes > 0) {
28660Sstevel@tonic-gate mp = (struct mode_page *)p;
28670Sstevel@tonic-gate n = mp->length + sizeof (struct mode_page);
28680Sstevel@tonic-gate nbytes -= n;
28690Sstevel@tonic-gate if (nbytes < 0)
28700Sstevel@tonic-gate break;
28710Sstevel@tonic-gate (void) sprintf(s, " %3x: ", mp->code);
28720Sstevel@tonic-gate dump(s, p, n, HEX_ONLY);
28730Sstevel@tonic-gate p += n;
28740Sstevel@tonic-gate }
28750Sstevel@tonic-gate if (nbytes < 0) {
28760Sstevel@tonic-gate err_print(" Sense data formatted incorrectly:\n");
28770Sstevel@tonic-gate dump(" ", msbuf, (int)mh->length+1, HEX_ONLY);
28780Sstevel@tonic-gate result = 1;
28790Sstevel@tonic-gate }
28800Sstevel@tonic-gate err_print("\n");
28810Sstevel@tonic-gate }
28820Sstevel@tonic-gate
28830Sstevel@tonic-gate free(msbuf);
28840Sstevel@tonic-gate return (result);
28850Sstevel@tonic-gate }
28860Sstevel@tonic-gate
28870Sstevel@tonic-gate
28880Sstevel@tonic-gate static void
scsi_printerr(ucmd,rq,rqlen)28890Sstevel@tonic-gate scsi_printerr(ucmd, rq, rqlen)
28900Sstevel@tonic-gate struct uscsi_cmd *ucmd;
28910Sstevel@tonic-gate struct scsi_extended_sense *rq;
28920Sstevel@tonic-gate int rqlen;
28930Sstevel@tonic-gate {
28940Sstevel@tonic-gate diskaddr_t blkno;
28950Sstevel@tonic-gate struct scsi_descr_sense_hdr *sdsp =
28960Sstevel@tonic-gate (struct scsi_descr_sense_hdr *)rq;
28970Sstevel@tonic-gate
28980Sstevel@tonic-gate switch (rq->es_key) {
28990Sstevel@tonic-gate case KEY_NO_SENSE:
29000Sstevel@tonic-gate err_print("No sense error");
29010Sstevel@tonic-gate break;
29020Sstevel@tonic-gate case KEY_RECOVERABLE_ERROR:
29030Sstevel@tonic-gate err_print("Recoverable error");
29040Sstevel@tonic-gate break;
29050Sstevel@tonic-gate case KEY_NOT_READY:
29060Sstevel@tonic-gate err_print("Not ready error");
29070Sstevel@tonic-gate break;
29080Sstevel@tonic-gate case KEY_MEDIUM_ERROR:
29090Sstevel@tonic-gate err_print("Medium error");
29100Sstevel@tonic-gate break;
29110Sstevel@tonic-gate case KEY_HARDWARE_ERROR:
29120Sstevel@tonic-gate err_print("Hardware error");
29130Sstevel@tonic-gate break;
29140Sstevel@tonic-gate case KEY_ILLEGAL_REQUEST:
29150Sstevel@tonic-gate err_print("Illegal request");
29160Sstevel@tonic-gate break;
29170Sstevel@tonic-gate case KEY_UNIT_ATTENTION:
29180Sstevel@tonic-gate err_print("Unit attention error");
29190Sstevel@tonic-gate break;
29200Sstevel@tonic-gate case KEY_WRITE_PROTECT:
29210Sstevel@tonic-gate err_print("Write protect error");
29220Sstevel@tonic-gate break;
29230Sstevel@tonic-gate case KEY_BLANK_CHECK:
29240Sstevel@tonic-gate err_print("Blank check error");
29250Sstevel@tonic-gate break;
29260Sstevel@tonic-gate case KEY_VENDOR_UNIQUE:
29270Sstevel@tonic-gate err_print("Vendor unique error");
29280Sstevel@tonic-gate break;
29290Sstevel@tonic-gate case KEY_COPY_ABORTED:
29300Sstevel@tonic-gate err_print("Copy aborted error");
29310Sstevel@tonic-gate break;
29320Sstevel@tonic-gate case KEY_ABORTED_COMMAND:
29330Sstevel@tonic-gate err_print("Aborted command");
29340Sstevel@tonic-gate break;
29350Sstevel@tonic-gate case KEY_EQUAL:
29360Sstevel@tonic-gate err_print("Equal error");
29370Sstevel@tonic-gate break;
29380Sstevel@tonic-gate case KEY_VOLUME_OVERFLOW:
29390Sstevel@tonic-gate err_print("Volume overflow");
29400Sstevel@tonic-gate break;
29410Sstevel@tonic-gate case KEY_MISCOMPARE:
29420Sstevel@tonic-gate err_print("Miscompare error");
29430Sstevel@tonic-gate break;
29440Sstevel@tonic-gate case KEY_RESERVED:
29450Sstevel@tonic-gate err_print("Reserved error");
29460Sstevel@tonic-gate break;
29470Sstevel@tonic-gate default:
29480Sstevel@tonic-gate err_print("Unknown error");
29490Sstevel@tonic-gate break;
29500Sstevel@tonic-gate }
29510Sstevel@tonic-gate
29520Sstevel@tonic-gate err_print(" during %s", scsi_find_command_name(ucmd->uscsi_cdb[0]));
29530Sstevel@tonic-gate
29540Sstevel@tonic-gate /*
29550Sstevel@tonic-gate * Get asc, ascq and info field from sense data. There are two
29560Sstevel@tonic-gate * possible formats (fixed sense data and descriptor sense data)
29570Sstevel@tonic-gate * depending on the value of es_code.
29580Sstevel@tonic-gate */
29590Sstevel@tonic-gate switch (rq->es_code) {
29600Sstevel@tonic-gate case CODE_FMT_DESCR_CURRENT:
29610Sstevel@tonic-gate case CODE_FMT_DESCR_DEFERRED:
29620Sstevel@tonic-gate blkno =
29630Sstevel@tonic-gate (diskaddr_t)scsi_extract_sense_info_descr(sdsp, rqlen);
29640Sstevel@tonic-gate if (blkno != (diskaddr_t)-1) {
29650Sstevel@tonic-gate err_print(": block %lld (0x%llx) (", blkno, blkno);
29660Sstevel@tonic-gate pr_dblock(err_print, blkno);
29670Sstevel@tonic-gate err_print(")");
29680Sstevel@tonic-gate }
29690Sstevel@tonic-gate
29700Sstevel@tonic-gate err_print("\n");
29710Sstevel@tonic-gate
29720Sstevel@tonic-gate err_print("ASC: 0x%x ASCQ: 0x%x\n",
29730Sstevel@tonic-gate sdsp->ds_add_code, sdsp->ds_qual_code);
29740Sstevel@tonic-gate break;
29750Sstevel@tonic-gate case CODE_FMT_FIXED_CURRENT:
29760Sstevel@tonic-gate case CODE_FMT_FIXED_DEFERRED:
29770Sstevel@tonic-gate default:
29780Sstevel@tonic-gate if (rq->es_valid) {
29790Sstevel@tonic-gate blkno = (rq->es_info_1 << 24) |
29800Sstevel@tonic-gate (rq->es_info_2 << 16) |
29810Sstevel@tonic-gate (rq->es_info_3 << 8) | rq->es_info_4;
29820Sstevel@tonic-gate err_print(": block %lld (0x%llx) (", blkno, blkno);
29830Sstevel@tonic-gate pr_dblock(err_print, blkno);
29840Sstevel@tonic-gate err_print(")");
29850Sstevel@tonic-gate }
29860Sstevel@tonic-gate
29870Sstevel@tonic-gate err_print("\n");
29880Sstevel@tonic-gate
29890Sstevel@tonic-gate if (rq->es_add_len >= 6) {
29900Sstevel@tonic-gate err_print("ASC: 0x%x ASCQ: 0x%x\n",
29910Sstevel@tonic-gate rq->es_add_code, rq->es_qual_code);
29920Sstevel@tonic-gate }
29930Sstevel@tonic-gate break;
29940Sstevel@tonic-gate }
29950Sstevel@tonic-gate
29960Sstevel@tonic-gate if (option_msg && diag_msg) {
29970Sstevel@tonic-gate if (rq->es_key == KEY_ILLEGAL_REQUEST) {
29980Sstevel@tonic-gate dump("cmd: ", (caddr_t)ucmd,
29990Sstevel@tonic-gate sizeof (struct uscsi_cmd), HEX_ONLY);
30000Sstevel@tonic-gate dump("cdb: ", (caddr_t)ucmd->uscsi_cdb,
30010Sstevel@tonic-gate ucmd->uscsi_cdblen, HEX_ONLY);
30020Sstevel@tonic-gate }
30030Sstevel@tonic-gate dump("sense: ", (caddr_t)rq, rqlen, HEX_ONLY);
30040Sstevel@tonic-gate }
30050Sstevel@tonic-gate
30060Sstevel@tonic-gate if (option_msg) {
30070Sstevel@tonic-gate switch (rq->es_code) {
30080Sstevel@tonic-gate case CODE_FMT_DESCR_CURRENT:
30090Sstevel@tonic-gate case CODE_FMT_DESCR_DEFERRED:
30100Sstevel@tonic-gate scsi_print_descr_sense(sdsp, rqlen);
30110Sstevel@tonic-gate break;
30120Sstevel@tonic-gate case CODE_FMT_FIXED_CURRENT:
30130Sstevel@tonic-gate case CODE_FMT_FIXED_DEFERRED:
30140Sstevel@tonic-gate default:
30150Sstevel@tonic-gate scsi_print_extended_sense(rq, rqlen);
30160Sstevel@tonic-gate break;
30170Sstevel@tonic-gate }
30180Sstevel@tonic-gate }
30190Sstevel@tonic-gate }
30200Sstevel@tonic-gate
30210Sstevel@tonic-gate /*
30220Sstevel@tonic-gate * Retrieve "information" field from descriptor format
30230Sstevel@tonic-gate * sense data. Iterates through each sense descriptor
30240Sstevel@tonic-gate * looking for the information descriptor and returns
30250Sstevel@tonic-gate * the information field from that descriptor.
30260Sstevel@tonic-gate */
30270Sstevel@tonic-gate static diskaddr_t
scsi_extract_sense_info_descr(struct scsi_descr_sense_hdr * sdsp,int rqlen)30280Sstevel@tonic-gate scsi_extract_sense_info_descr(struct scsi_descr_sense_hdr *sdsp, int rqlen)
30290Sstevel@tonic-gate {
30300Sstevel@tonic-gate diskaddr_t result;
30310Sstevel@tonic-gate uint8_t *descr_offset;
30320Sstevel@tonic-gate int valid_sense_length;
30330Sstevel@tonic-gate struct scsi_information_sense_descr *isd;
30340Sstevel@tonic-gate
30350Sstevel@tonic-gate /*
30360Sstevel@tonic-gate * Initialize result to -1 indicating there is no information
30370Sstevel@tonic-gate * descriptor
30380Sstevel@tonic-gate */
30390Sstevel@tonic-gate result = (diskaddr_t)-1;
30400Sstevel@tonic-gate
30410Sstevel@tonic-gate /*
30420Sstevel@tonic-gate * The first descriptor will immediately follow the header
30430Sstevel@tonic-gate */
30440Sstevel@tonic-gate descr_offset = (uint8_t *)(sdsp+1); /* Pointer arithmetic */
30450Sstevel@tonic-gate
30460Sstevel@tonic-gate /*
30470Sstevel@tonic-gate * Calculate the amount of valid sense data
30480Sstevel@tonic-gate */
30490Sstevel@tonic-gate valid_sense_length =
30500Sstevel@tonic-gate min((sizeof (struct scsi_descr_sense_hdr) +
30510Sstevel@tonic-gate sdsp->ds_addl_sense_length),
30520Sstevel@tonic-gate rqlen);
30530Sstevel@tonic-gate
30540Sstevel@tonic-gate /*
30550Sstevel@tonic-gate * Iterate through the list of descriptors, stopping when we
30560Sstevel@tonic-gate * run out of sense data
30570Sstevel@tonic-gate */
30580Sstevel@tonic-gate while ((descr_offset + sizeof (struct scsi_information_sense_descr)) <=
30590Sstevel@tonic-gate (uint8_t *)sdsp + valid_sense_length) {
30600Sstevel@tonic-gate /*
30610Sstevel@tonic-gate * Check if this is an information descriptor. We can
30620Sstevel@tonic-gate * use the scsi_information_sense_descr structure as a
30630Sstevel@tonic-gate * template sense the first two fields are always the
30640Sstevel@tonic-gate * same
30650Sstevel@tonic-gate */
30660Sstevel@tonic-gate isd = (struct scsi_information_sense_descr *)descr_offset;
30670Sstevel@tonic-gate if (isd->isd_descr_type == DESCR_INFORMATION) {
30680Sstevel@tonic-gate /*
30690Sstevel@tonic-gate * Found an information descriptor. Copy the
30700Sstevel@tonic-gate * information field. There will only be one
30710Sstevel@tonic-gate * information descriptor so we can stop looking.
30720Sstevel@tonic-gate */
30730Sstevel@tonic-gate result =
30740Sstevel@tonic-gate (((diskaddr_t)isd->isd_information[0] << 56) |
30759889SLarry.Liu@Sun.COM ((diskaddr_t)isd->isd_information[1] << 48) |
30769889SLarry.Liu@Sun.COM ((diskaddr_t)isd->isd_information[2] << 40) |
30779889SLarry.Liu@Sun.COM ((diskaddr_t)isd->isd_information[3] << 32) |
30789889SLarry.Liu@Sun.COM ((diskaddr_t)isd->isd_information[4] << 24) |
30799889SLarry.Liu@Sun.COM ((diskaddr_t)isd->isd_information[5] << 16) |
30809889SLarry.Liu@Sun.COM ((diskaddr_t)isd->isd_information[6] << 8) |
30819889SLarry.Liu@Sun.COM ((diskaddr_t)isd->isd_information[7]));
30820Sstevel@tonic-gate break;
30830Sstevel@tonic-gate }
30840Sstevel@tonic-gate
30850Sstevel@tonic-gate /*
30860Sstevel@tonic-gate * Get pointer to the next descriptor. The "additional
30870Sstevel@tonic-gate * length" field holds the length of the descriptor except
30880Sstevel@tonic-gate * for the "type" and "additional length" fields, so
30890Sstevel@tonic-gate * we need to add 2 to get the total length.
30900Sstevel@tonic-gate */
30910Sstevel@tonic-gate descr_offset += (isd->isd_addl_length + 2);
30920Sstevel@tonic-gate }
30930Sstevel@tonic-gate
30940Sstevel@tonic-gate return (result);
30950Sstevel@tonic-gate }
30960Sstevel@tonic-gate
30970Sstevel@tonic-gate /*
30980Sstevel@tonic-gate * Return a pointer to a string telling us the name of the command.
30990Sstevel@tonic-gate */
31000Sstevel@tonic-gate static char *
scsi_find_command_name(uint_t cmd)31010Sstevel@tonic-gate scsi_find_command_name(uint_t cmd)
31020Sstevel@tonic-gate {
31030Sstevel@tonic-gate struct scsi_command_name *c;
31040Sstevel@tonic-gate
31050Sstevel@tonic-gate for (c = scsi_command_names; c->command != SCMD_UNKNOWN; c++)
31060Sstevel@tonic-gate if (c->command == cmd)
31070Sstevel@tonic-gate break;
31080Sstevel@tonic-gate return (c->name);
31090Sstevel@tonic-gate }
31100Sstevel@tonic-gate
31110Sstevel@tonic-gate
31120Sstevel@tonic-gate /*
31130Sstevel@tonic-gate * Return true if we support a particular mode page
31140Sstevel@tonic-gate */
31150Sstevel@tonic-gate int
scsi_supported_page(int page)31160Sstevel@tonic-gate scsi_supported_page(int page) {
31170Sstevel@tonic-gate return (page == 1 || page == 2 || page == 3 || page == 4 ||
31180Sstevel@tonic-gate page == 8 || page == 0x38);
31190Sstevel@tonic-gate }
31200Sstevel@tonic-gate
31210Sstevel@tonic-gate
31220Sstevel@tonic-gate int
apply_chg_list(int pageno,int pagsiz,uchar_t * curbits,uchar_t * chgbits,struct chg_list * chglist)31230Sstevel@tonic-gate apply_chg_list(int pageno, int pagsiz, uchar_t *curbits,
31240Sstevel@tonic-gate uchar_t *chgbits, struct chg_list *chglist)
31250Sstevel@tonic-gate {
31260Sstevel@tonic-gate uchar_t c;
31270Sstevel@tonic-gate int i;
31280Sstevel@tonic-gate int m;
31290Sstevel@tonic-gate int delta;
31300Sstevel@tonic-gate int changed = 0;
31310Sstevel@tonic-gate
31320Sstevel@tonic-gate while (chglist != NULL) {
31330Sstevel@tonic-gate if (chglist->pageno == pageno &&
31349889SLarry.Liu@Sun.COM chglist->byteno < pagsiz) {
31350Sstevel@tonic-gate i = chglist->byteno;
31360Sstevel@tonic-gate c = curbits[i];
31370Sstevel@tonic-gate switch (chglist->mode) {
31380Sstevel@tonic-gate case CHG_MODE_SET:
31390Sstevel@tonic-gate c |= (uchar_t)chglist->value;
31400Sstevel@tonic-gate break;
31410Sstevel@tonic-gate case CHG_MODE_CLR:
31420Sstevel@tonic-gate c &= (uchar_t)chglist->value;
31430Sstevel@tonic-gate break;
31440Sstevel@tonic-gate case CHG_MODE_ABS:
31450Sstevel@tonic-gate c = (uchar_t)chglist->value;
31460Sstevel@tonic-gate break;
31470Sstevel@tonic-gate }
31480Sstevel@tonic-gate /*
31490Sstevel@tonic-gate * Figure out which bits changed, and
31500Sstevel@tonic-gate * are marked as changeable. If this
31510Sstevel@tonic-gate * result actually differs from the
31520Sstevel@tonic-gate * current value, update the current
31530Sstevel@tonic-gate * value, and note that a mode select
31540Sstevel@tonic-gate * should be done.
31550Sstevel@tonic-gate */
31560Sstevel@tonic-gate delta = c ^ curbits[i];
31570Sstevel@tonic-gate for (m = 0x01; m < 0x100; m <<= 1) {
31580Sstevel@tonic-gate if ((delta & m) && (chgbits[i] & m)) {
31590Sstevel@tonic-gate curbits[i] ^= m;
31600Sstevel@tonic-gate changed = 1;
31610Sstevel@tonic-gate }
31620Sstevel@tonic-gate }
31630Sstevel@tonic-gate }
31640Sstevel@tonic-gate chglist = chglist->next;
31650Sstevel@tonic-gate }
31660Sstevel@tonic-gate
31670Sstevel@tonic-gate return (changed);
31680Sstevel@tonic-gate }
31690Sstevel@tonic-gate
31700Sstevel@tonic-gate
31710Sstevel@tonic-gate /*
31720Sstevel@tonic-gate * Return whether a given page is affected by an item on
31730Sstevel@tonic-gate * the change list.
31740Sstevel@tonic-gate */
31750Sstevel@tonic-gate static int
chg_list_affects_page(chglist,pageno)31760Sstevel@tonic-gate chg_list_affects_page(chglist, pageno)
31770Sstevel@tonic-gate struct chg_list *chglist;
31780Sstevel@tonic-gate int pageno;
31790Sstevel@tonic-gate {
31800Sstevel@tonic-gate while (chglist != NULL) {
31810Sstevel@tonic-gate if (chglist->pageno == pageno) {
31820Sstevel@tonic-gate return (1);
31830Sstevel@tonic-gate }
31840Sstevel@tonic-gate chglist = chglist->next;
31850Sstevel@tonic-gate }
31860Sstevel@tonic-gate
31870Sstevel@tonic-gate return (0);
31880Sstevel@tonic-gate }
31890Sstevel@tonic-gate
31900Sstevel@tonic-gate
31910Sstevel@tonic-gate /*
31920Sstevel@tonic-gate * Labels for the various fields of the scsi_extended_sense structure
31930Sstevel@tonic-gate */
31940Sstevel@tonic-gate static char *scsi_extended_sense_labels[] = {
31950Sstevel@tonic-gate "Request sense valid: ",
31960Sstevel@tonic-gate "Error class and code: ",
31970Sstevel@tonic-gate "Segment number: ",
31980Sstevel@tonic-gate "Filemark: ",
31990Sstevel@tonic-gate "End-of-medium: ",
32000Sstevel@tonic-gate "Incorrect length indicator: ",
32010Sstevel@tonic-gate "Sense key: ",
32020Sstevel@tonic-gate "Information field: ",
32030Sstevel@tonic-gate "Additional sense length: ",
32040Sstevel@tonic-gate "Command-specific information: ",
32050Sstevel@tonic-gate "Additional sense code: ",
32060Sstevel@tonic-gate "Additional sense code qualifier: ",
32070Sstevel@tonic-gate "Field replaceable unit code: ",
32080Sstevel@tonic-gate "Sense-key specific: ",
32090Sstevel@tonic-gate "Additional sense bytes: "
32100Sstevel@tonic-gate };
32110Sstevel@tonic-gate
32120Sstevel@tonic-gate
32130Sstevel@tonic-gate /*
32140Sstevel@tonic-gate * Display the full scsi_extended_sense as returned by the device
32150Sstevel@tonic-gate */
32160Sstevel@tonic-gate static void
scsi_print_extended_sense(rq,rqlen)32170Sstevel@tonic-gate scsi_print_extended_sense(rq, rqlen)
32180Sstevel@tonic-gate struct scsi_extended_sense *rq;
32190Sstevel@tonic-gate int rqlen;
32200Sstevel@tonic-gate {
32210Sstevel@tonic-gate char **p;
32220Sstevel@tonic-gate
32230Sstevel@tonic-gate p = scsi_extended_sense_labels;
32240Sstevel@tonic-gate if (rqlen < (sizeof (*rq) - 2) || !rq->es_valid) {
32250Sstevel@tonic-gate /*
32260Sstevel@tonic-gate * target should be capable of returning at least 18
32270Sstevel@tonic-gate * bytes of data, i.e upto rq->es_skey_specific field.
32280Sstevel@tonic-gate * The additional sense bytes (2 or more ...) are optional.
32290Sstevel@tonic-gate */
32300Sstevel@tonic-gate return;
32310Sstevel@tonic-gate }
32320Sstevel@tonic-gate
32330Sstevel@tonic-gate fmt_print("\n%s%s\n", *p++, rq->es_valid ? "yes" : "no");
32340Sstevel@tonic-gate fmt_print("%s0x%02x\n", *p++, (rq->es_class << 4) + rq->es_code);
32350Sstevel@tonic-gate fmt_print("%s%d\n", *p++, rq->es_segnum);
32360Sstevel@tonic-gate fmt_print("%s%s\n", *p++, rq->es_filmk ? "yes" : "no");
32370Sstevel@tonic-gate fmt_print("%s%s\n", *p++, rq->es_eom ? "yes" : "no");
32380Sstevel@tonic-gate fmt_print("%s%s\n", *p++, rq->es_ili ? "yes" : "no");
32390Sstevel@tonic-gate fmt_print("%s%d\n", *p++, rq->es_key);
32400Sstevel@tonic-gate
32410Sstevel@tonic-gate fmt_print("%s0x%02x 0x%02x 0x%02x 0x%02x\n", *p++, rq->es_info_1,
32420Sstevel@tonic-gate rq->es_info_2, rq->es_info_3, rq->es_info_4);
32430Sstevel@tonic-gate fmt_print("%s%d\n", *p++, rq->es_add_len);
32440Sstevel@tonic-gate fmt_print("%s0x%02x 0x%02x 0x%02x 0x%02x\n", *p++, rq->es_cmd_info[0],
32450Sstevel@tonic-gate rq->es_cmd_info[1], rq->es_cmd_info[2], rq->es_cmd_info[3]);
32460Sstevel@tonic-gate fmt_print("%s0x%02x = %d\n", *p++, rq->es_add_code, rq->es_add_code);
32470Sstevel@tonic-gate fmt_print("%s0x%02x = %d\n", *p++, rq->es_qual_code, rq->es_qual_code);
32480Sstevel@tonic-gate fmt_print("%s%d\n", *p++, rq->es_fru_code);
32490Sstevel@tonic-gate fmt_print("%s0x%02x 0x%02x 0x%02x\n", *p++, rq->es_skey_specific[0],
32500Sstevel@tonic-gate rq->es_skey_specific[1], rq->es_skey_specific[2]);
32510Sstevel@tonic-gate if (rqlen >= sizeof (*rq)) {
32520Sstevel@tonic-gate fmt_print("%s0x%02x 0x%02x%s\n", *p, rq->es_add_info[0],
32530Sstevel@tonic-gate rq->es_add_info[1], (rqlen > sizeof (*rq)) ? " ..." : "");
32540Sstevel@tonic-gate }
32550Sstevel@tonic-gate
32560Sstevel@tonic-gate fmt_print("\n");
32570Sstevel@tonic-gate }
32580Sstevel@tonic-gate
32590Sstevel@tonic-gate /*
32600Sstevel@tonic-gate * Labels for the various fields of the scsi_descr_sense_hdr structure
32610Sstevel@tonic-gate */
32620Sstevel@tonic-gate static char *scsi_descr_sense_labels[] = {
32630Sstevel@tonic-gate "Error class and code: ",
32640Sstevel@tonic-gate "Sense key: ",
32650Sstevel@tonic-gate "Additional sense length: ",
32660Sstevel@tonic-gate "Additional sense code: ",
32670Sstevel@tonic-gate "Additional sense code qualifier: ",
32680Sstevel@tonic-gate "Additional sense bytes: "
32690Sstevel@tonic-gate };
32700Sstevel@tonic-gate
32710Sstevel@tonic-gate
32720Sstevel@tonic-gate /*
32730Sstevel@tonic-gate * Display the full descriptor sense data as returned by the device
32740Sstevel@tonic-gate */
32750Sstevel@tonic-gate
32760Sstevel@tonic-gate static void
scsi_print_descr_sense(rq,rqlen)32770Sstevel@tonic-gate scsi_print_descr_sense(rq, rqlen)
32780Sstevel@tonic-gate struct scsi_descr_sense_hdr *rq;
32790Sstevel@tonic-gate int rqlen;
32800Sstevel@tonic-gate {
32810Sstevel@tonic-gate char **p;
32820Sstevel@tonic-gate uint8_t *descr_offset;
32830Sstevel@tonic-gate int valid_sense_length;
32840Sstevel@tonic-gate struct scsi_information_sense_descr *isd;
32850Sstevel@tonic-gate
32860Sstevel@tonic-gate p = scsi_descr_sense_labels;
32870Sstevel@tonic-gate if (rqlen < sizeof (struct scsi_descr_sense_hdr)) {
32880Sstevel@tonic-gate /*
32890Sstevel@tonic-gate * target must return at least 8 bytes of data
32900Sstevel@tonic-gate */
32910Sstevel@tonic-gate return;
32920Sstevel@tonic-gate }
32930Sstevel@tonic-gate
32940Sstevel@tonic-gate /* Print descriptor sense header */
32950Sstevel@tonic-gate fmt_print("%s0x%02x\n", *p++, (rq->ds_class << 4) + rq->ds_code);
32960Sstevel@tonic-gate fmt_print("%s%d\n", *p++, rq->ds_key);
32970Sstevel@tonic-gate
32980Sstevel@tonic-gate fmt_print("%s%d\n", *p++, rq->ds_addl_sense_length);
32990Sstevel@tonic-gate fmt_print("%s0x%02x = %d\n", *p++, rq->ds_add_code, rq->ds_add_code);
33000Sstevel@tonic-gate fmt_print("%s0x%02x = %d\n", *p++, rq->ds_qual_code, rq->ds_qual_code);
33010Sstevel@tonic-gate fmt_print("\n");
33020Sstevel@tonic-gate
33030Sstevel@tonic-gate /*
33040Sstevel@tonic-gate * Now print any sense descriptors. The first descriptor will
33050Sstevel@tonic-gate * immediately follow the header
33060Sstevel@tonic-gate */
33070Sstevel@tonic-gate descr_offset = (uint8_t *)(rq+1); /* Pointer arithmetic */
33080Sstevel@tonic-gate
33090Sstevel@tonic-gate /*
33100Sstevel@tonic-gate * Calculate the amount of valid sense data
33110Sstevel@tonic-gate */
33120Sstevel@tonic-gate valid_sense_length =
33130Sstevel@tonic-gate min((sizeof (struct scsi_descr_sense_hdr) +
33140Sstevel@tonic-gate rq->ds_addl_sense_length), rqlen);
33150Sstevel@tonic-gate
33160Sstevel@tonic-gate /*
33170Sstevel@tonic-gate * Iterate through the list of descriptors, stopping when we
33180Sstevel@tonic-gate * run out of sense data. Descriptor format is:
33190Sstevel@tonic-gate *
33200Sstevel@tonic-gate * <Descriptor type> <Descriptor length> <Descriptor data> ...
33210Sstevel@tonic-gate */
33220Sstevel@tonic-gate while ((descr_offset + *(descr_offset + 1)) <=
33230Sstevel@tonic-gate (uint8_t *)rq + valid_sense_length) {
33240Sstevel@tonic-gate /*
33250Sstevel@tonic-gate * Determine descriptor type. We can use the
33260Sstevel@tonic-gate * scsi_information_sense_descr structure as a
33270Sstevel@tonic-gate * template since the first two fields are always the
33280Sstevel@tonic-gate * same.
33290Sstevel@tonic-gate */
33300Sstevel@tonic-gate isd = (struct scsi_information_sense_descr *)descr_offset;
33310Sstevel@tonic-gate switch (isd->isd_descr_type) {
33320Sstevel@tonic-gate case DESCR_INFORMATION: {
33330Sstevel@tonic-gate uint64_t information;
33340Sstevel@tonic-gate
33350Sstevel@tonic-gate information =
33360Sstevel@tonic-gate (((uint64_t)isd->isd_information[0] << 56) |
33370Sstevel@tonic-gate ((uint64_t)isd->isd_information[1] << 48) |
33380Sstevel@tonic-gate ((uint64_t)isd->isd_information[2] << 40) |
33390Sstevel@tonic-gate ((uint64_t)isd->isd_information[3] << 32) |
33400Sstevel@tonic-gate ((uint64_t)isd->isd_information[4] << 24) |
33410Sstevel@tonic-gate ((uint64_t)isd->isd_information[5] << 16) |
33420Sstevel@tonic-gate ((uint64_t)isd->isd_information[6] << 8) |
33430Sstevel@tonic-gate ((uint64_t)isd->isd_information[7]));
33440Sstevel@tonic-gate fmt_print("Information field: "
33450Sstevel@tonic-gate "%0llx\n", information);
33460Sstevel@tonic-gate break;
33470Sstevel@tonic-gate }
33480Sstevel@tonic-gate case DESCR_COMMAND_SPECIFIC: {
33490Sstevel@tonic-gate struct scsi_cmd_specific_sense_descr *c =
33500Sstevel@tonic-gate (struct scsi_cmd_specific_sense_descr *)isd;
33510Sstevel@tonic-gate uint64_t cmd_specific;
33520Sstevel@tonic-gate
33530Sstevel@tonic-gate cmd_specific =
33540Sstevel@tonic-gate (((uint64_t)c->css_cmd_specific_info[0] << 56) |
33550Sstevel@tonic-gate ((uint64_t)c->css_cmd_specific_info[1] << 48) |
33560Sstevel@tonic-gate ((uint64_t)c->css_cmd_specific_info[2] << 40) |
33570Sstevel@tonic-gate ((uint64_t)c->css_cmd_specific_info[3] << 32) |
33580Sstevel@tonic-gate ((uint64_t)c->css_cmd_specific_info[4] << 24) |
33590Sstevel@tonic-gate ((uint64_t)c->css_cmd_specific_info[5] << 16) |
33600Sstevel@tonic-gate ((uint64_t)c->css_cmd_specific_info[6] << 8) |
33610Sstevel@tonic-gate ((uint64_t)c->css_cmd_specific_info[7]));
33620Sstevel@tonic-gate fmt_print("Command-specific information: "
33630Sstevel@tonic-gate "%0llx\n", cmd_specific);
33640Sstevel@tonic-gate break;
33650Sstevel@tonic-gate }
33660Sstevel@tonic-gate case DESCR_SENSE_KEY_SPECIFIC: {
33670Sstevel@tonic-gate struct scsi_sk_specific_sense_descr *ssd =
33680Sstevel@tonic-gate (struct scsi_sk_specific_sense_descr *)isd;
33690Sstevel@tonic-gate uint8_t *sk_spec_ptr = (uint8_t *)&ssd->sss_data;
33700Sstevel@tonic-gate fmt_print("Sense-key specific: "
33710Sstevel@tonic-gate "0x%02x 0x%02x 0x%02x\n", sk_spec_ptr[0],
33720Sstevel@tonic-gate sk_spec_ptr[1], sk_spec_ptr[2]);
33730Sstevel@tonic-gate break;
33740Sstevel@tonic-gate }
33750Sstevel@tonic-gate case DESCR_FRU: {
33760Sstevel@tonic-gate struct scsi_fru_sense_descr *fsd =
33770Sstevel@tonic-gate (struct scsi_fru_sense_descr *)isd;
33780Sstevel@tonic-gate fmt_print("Field replaceable unit code: "
33790Sstevel@tonic-gate "%d\n", fsd->fs_fru_code);
33800Sstevel@tonic-gate break;
33810Sstevel@tonic-gate }
33820Sstevel@tonic-gate case DESCR_BLOCK_COMMANDS: {
33830Sstevel@tonic-gate struct scsi_block_cmd_sense_descr *bsd =
33840Sstevel@tonic-gate (struct scsi_block_cmd_sense_descr *)isd;
33850Sstevel@tonic-gate fmt_print("Incorrect length indicator: "
33860Sstevel@tonic-gate "%s\n", bsd->bcs_ili ? "yes" : "no");
33870Sstevel@tonic-gate break;
33880Sstevel@tonic-gate }
33890Sstevel@tonic-gate default:
33900Sstevel@tonic-gate /* Ignore */
33910Sstevel@tonic-gate break;
33920Sstevel@tonic-gate }
33930Sstevel@tonic-gate
33940Sstevel@tonic-gate /*
33950Sstevel@tonic-gate * Get pointer to the next descriptor. The "additional
33960Sstevel@tonic-gate * length" field holds the length of the descriptor except
33970Sstevel@tonic-gate * for the "type" and "additional length" fields, so
33980Sstevel@tonic-gate * we need to add 2 to get the total length.
33990Sstevel@tonic-gate */
34000Sstevel@tonic-gate descr_offset += (isd->isd_addl_length + 2);
34010Sstevel@tonic-gate }
34020Sstevel@tonic-gate
34030Sstevel@tonic-gate fmt_print("\n");
34040Sstevel@tonic-gate }
34050Sstevel@tonic-gate
34060Sstevel@tonic-gate /*
34070Sstevel@tonic-gate * Function checks if READ DEFECT DATA command is supported
34080Sstevel@tonic-gate * on the current disk.
34090Sstevel@tonic-gate */
34100Sstevel@tonic-gate static int
check_support_for_defects()34110Sstevel@tonic-gate check_support_for_defects()
34120Sstevel@tonic-gate {
34130Sstevel@tonic-gate struct uscsi_cmd ucmd;
34140Sstevel@tonic-gate union scsi_cdb cdb;
34150Sstevel@tonic-gate struct scsi_defect_list def_list;
34160Sstevel@tonic-gate struct scsi_defect_hdr *hdr;
34170Sstevel@tonic-gate int status;
34180Sstevel@tonic-gate char rqbuf[255];
34190Sstevel@tonic-gate struct scsi_extended_sense *rq;
34200Sstevel@tonic-gate
34210Sstevel@tonic-gate hdr = (struct scsi_defect_hdr *)&def_list;
34220Sstevel@tonic-gate
34230Sstevel@tonic-gate /*
34240Sstevel@tonic-gate * First get length of list by asking for the header only.
34250Sstevel@tonic-gate */
34260Sstevel@tonic-gate (void) memset((char *)&def_list, 0, sizeof (def_list));
34270Sstevel@tonic-gate
34280Sstevel@tonic-gate /*
34290Sstevel@tonic-gate * Build and execute the uscsi ioctl
34300Sstevel@tonic-gate */
34310Sstevel@tonic-gate (void) memset((char *)&ucmd, 0, sizeof (ucmd));
34320Sstevel@tonic-gate (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb));
34330Sstevel@tonic-gate (void) memset((char *)rqbuf, 0, 255);
34340Sstevel@tonic-gate cdb.scc_cmd = SCMD_READ_DEFECT_LIST;
34350Sstevel@tonic-gate FORMG1COUNT(&cdb, sizeof (struct scsi_defect_hdr));
34360Sstevel@tonic-gate cdb.cdb_opaque[2] = DLD_MAN_DEF_LIST | DLD_BFI_FORMAT;
34370Sstevel@tonic-gate ucmd.uscsi_cdb = (caddr_t)&cdb;
34380Sstevel@tonic-gate ucmd.uscsi_cdblen = CDB_GROUP1;
34390Sstevel@tonic-gate ucmd.uscsi_bufaddr = (caddr_t)hdr;
34400Sstevel@tonic-gate ucmd.uscsi_buflen = sizeof (struct scsi_defect_hdr);
34410Sstevel@tonic-gate ucmd.uscsi_rqbuf = rqbuf;
34420Sstevel@tonic-gate ucmd.uscsi_rqlen = sizeof (rqbuf);
34430Sstevel@tonic-gate ucmd.uscsi_rqresid = sizeof (rqbuf);
34440Sstevel@tonic-gate rq = (struct scsi_extended_sense *)ucmd.uscsi_rqbuf;
34450Sstevel@tonic-gate
34460Sstevel@tonic-gate status = uscsi_cmd(cur_file, &ucmd,
34479889SLarry.Liu@Sun.COM (option_msg && diag_msg) ? F_NORMAL : F_SILENT);
34480Sstevel@tonic-gate
34490Sstevel@tonic-gate if (status != 0) {
34500Sstevel@tonic-gate /*
34510Sstevel@tonic-gate * check if read_defect_list_is_supported.
34520Sstevel@tonic-gate */
34530Sstevel@tonic-gate if (ucmd.uscsi_rqstatus == STATUS_GOOD &&
34549889SLarry.Liu@Sun.COM rq->es_key == KEY_ILLEGAL_REQUEST &&
34559889SLarry.Liu@Sun.COM rq->es_add_code == INVALID_OPCODE)
34569889SLarry.Liu@Sun.COM return (0);
34570Sstevel@tonic-gate }
34580Sstevel@tonic-gate return (1);
34590Sstevel@tonic-gate }
34600Sstevel@tonic-gate
34610Sstevel@tonic-gate /*
34620Sstevel@tonic-gate * Format the disk, the whole disk, and nothing but the disk.
34630Sstevel@tonic-gate * Function will be called only for disks
34640Sstevel@tonic-gate * which do not support read defect list command.
34650Sstevel@tonic-gate */
34660Sstevel@tonic-gate static int
scsi_format_without_defects()34670Sstevel@tonic-gate scsi_format_without_defects()
34680Sstevel@tonic-gate {
34690Sstevel@tonic-gate struct uscsi_cmd ucmd;
34700Sstevel@tonic-gate union scsi_cdb cdb;
34710Sstevel@tonic-gate struct scsi_defect_hdr defect_hdr;
34720Sstevel@tonic-gate int status;
34730Sstevel@tonic-gate
34740Sstevel@tonic-gate /*
34750Sstevel@tonic-gate * Construct the uscsi format ioctl.
34760Sstevel@tonic-gate * Use fmtdata = 0 , indicating the no source of
34770Sstevel@tonic-gate * defects information is provided .
34780Sstevel@tonic-gate * Function will be called only for disks
34790Sstevel@tonic-gate * which do not support read defect list command.
34800Sstevel@tonic-gate */
34810Sstevel@tonic-gate (void) memset((char *)&ucmd, 0, sizeof (ucmd));
34820Sstevel@tonic-gate (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb));
34830Sstevel@tonic-gate (void) memset((char *)&defect_hdr, 0, sizeof (defect_hdr));
34840Sstevel@tonic-gate cdb.scc_cmd = SCMD_FORMAT;
34850Sstevel@tonic-gate ucmd.uscsi_cdb = (caddr_t)&cdb;
34860Sstevel@tonic-gate ucmd.uscsi_cdblen = CDB_GROUP0;
34870Sstevel@tonic-gate ucmd.uscsi_bufaddr = (caddr_t)&defect_hdr;
34880Sstevel@tonic-gate ucmd.uscsi_buflen = sizeof (defect_hdr);
34890Sstevel@tonic-gate cdb.cdb_opaque[1] = 0;
34900Sstevel@tonic-gate /*
34910Sstevel@tonic-gate * Issue the format ioctl
34920Sstevel@tonic-gate */
34930Sstevel@tonic-gate status = uscsi_cmd(cur_file, &ucmd,
34949889SLarry.Liu@Sun.COM (option_msg && diag_msg) ? F_NORMAL : F_SILENT);
34950Sstevel@tonic-gate return (status);
34960Sstevel@tonic-gate }
34970Sstevel@tonic-gate
34980Sstevel@tonic-gate /*
34990Sstevel@tonic-gate * Name: test_until_ready
35000Sstevel@tonic-gate *
35010Sstevel@tonic-gate * Description: This function is used by scsi_format and
35020Sstevel@tonic-gate * scsi_format_raw to poll the device while the FORMAT
35030Sstevel@tonic-gate * UNIT cdb in in progress.
35040Sstevel@tonic-gate *
35050Sstevel@tonic-gate * Parameters:
35060Sstevel@tonic-gate * file descriptor to poll
35070Sstevel@tonic-gate *
35080Sstevel@tonic-gate * Returns:
35090Sstevel@tonic-gate * 0 - good status
35100Sstevel@tonic-gate * !0 - bad status
35110Sstevel@tonic-gate */
test_until_ready(int fd)35120Sstevel@tonic-gate static int test_until_ready(int fd) {
35130Sstevel@tonic-gate int status = 1;
35140Sstevel@tonic-gate struct uscsi_cmd ucmd;
35150Sstevel@tonic-gate union scsi_cdb cdb;
35160Sstevel@tonic-gate struct scsi_extended_sense sense;
35170Sstevel@tonic-gate time_t start, check, time_left;
35180Sstevel@tonic-gate uint16_t progress;
35190Sstevel@tonic-gate int hour, min, sec;
35200Sstevel@tonic-gate
35210Sstevel@tonic-gate (void) memset((char *)&ucmd, 0, sizeof (ucmd));
35220Sstevel@tonic-gate (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb));
35230Sstevel@tonic-gate
35240Sstevel@tonic-gate ucmd.uscsi_cdb = (caddr_t)&cdb;
35250Sstevel@tonic-gate ucmd.uscsi_cdblen = CDB_GROUP0;
35260Sstevel@tonic-gate ucmd.uscsi_rqbuf = (caddr_t)&sense;
35270Sstevel@tonic-gate ucmd.uscsi_rqlen = SENSE_LEN;
35280Sstevel@tonic-gate
35290Sstevel@tonic-gate start = check = time((time_t *)0);
35300Sstevel@tonic-gate
35310Sstevel@tonic-gate /* Loop sending TEST UNIT READY until format is complete */
35320Sstevel@tonic-gate while (status) {
35330Sstevel@tonic-gate /* clear last request sense data */
35340Sstevel@tonic-gate ucmd.uscsi_rqstatus = 0;
35350Sstevel@tonic-gate ucmd.uscsi_rqresid = 0;
35360Sstevel@tonic-gate (void) memset((char *)&sense, 0, SENSE_LEN);
35370Sstevel@tonic-gate
35380Sstevel@tonic-gate /* issue test unit ready */
35390Sstevel@tonic-gate status = uscsi_cmd(fd, &ucmd, F_SILENT
35400Sstevel@tonic-gate | F_RQENABLE);
35410Sstevel@tonic-gate
35420Sstevel@tonic-gate check = time((time_t *)0);
35430Sstevel@tonic-gate
35440Sstevel@tonic-gate /* If device returns not ready we get EIO */
35450Sstevel@tonic-gate if (status != 0 && errno == EIO) {
35460Sstevel@tonic-gate /* Check SKSV if progress indication is avail */
35470Sstevel@tonic-gate if (sense.es_skey_specific[0] == 0x80) {
35480Sstevel@tonic-gate /* Store progress indication */
35490Sstevel@tonic-gate progress = ((uint16_t)sense.
35500Sstevel@tonic-gate es_skey_specific[1]) << 8;
35510Sstevel@tonic-gate progress |= (uint16_t)sense.
35520Sstevel@tonic-gate es_skey_specific[2];
35530Sstevel@tonic-gate progress = (uint16_t)(((float)progress /
35540Sstevel@tonic-gate (float)PROGRESS_INDICATION_BASE)*100);
35550Sstevel@tonic-gate
35560Sstevel@tonic-gate fmt_print("\015");
35570Sstevel@tonic-gate
35580Sstevel@tonic-gate /*
35590Sstevel@tonic-gate * check to see if we can estimate
35600Sstevel@tonic-gate * time remaining - wait until the format
35610Sstevel@tonic-gate * is at least 5 percent complete to avoid
35620Sstevel@tonic-gate * wildly-fluctuating time estimates
35630Sstevel@tonic-gate */
35640Sstevel@tonic-gate if ((check - start) <= 0 || progress <= 5) {
35650Sstevel@tonic-gate /* unable to estimate */
35660Sstevel@tonic-gate fmt_print(" %02d%% complete ",
35670Sstevel@tonic-gate progress);
35680Sstevel@tonic-gate } else {
35690Sstevel@tonic-gate /* display with estimated time */
35700Sstevel@tonic-gate time_left = (time_t)(((float)(check
35710Sstevel@tonic-gate - start) / (float)progress) *
35720Sstevel@tonic-gate (float)(100 - progress));
35730Sstevel@tonic-gate sec = time_left % 60;
35740Sstevel@tonic-gate min = (time_left / 60) % 60;
35750Sstevel@tonic-gate hour = time_left / 3600;
35760Sstevel@tonic-gate
35770Sstevel@tonic-gate fmt_print(" %02d%% complete "
35780Sstevel@tonic-gate "(%02d:%02d:%02d remaining) ",
35790Sstevel@tonic-gate progress, hour, min, sec);
35800Sstevel@tonic-gate }
35810Sstevel@tonic-gate /* flush or the screen will not update */
35820Sstevel@tonic-gate (void) fflush(stdout);
35830Sstevel@tonic-gate }
35840Sstevel@tonic-gate } else {
35850Sstevel@tonic-gate /* format not in progress */
35860Sstevel@tonic-gate if (option_msg) {
35870Sstevel@tonic-gate fmt_print("\nRequest Sense ASC=0x%x ASCQ=0x%x",
35880Sstevel@tonic-gate sense.es_add_code, sense.es_qual_code);
35890Sstevel@tonic-gate }
35900Sstevel@tonic-gate break;
35910Sstevel@tonic-gate }
35920Sstevel@tonic-gate
35930Sstevel@tonic-gate /* delay so we don't waste cpu time */
35940Sstevel@tonic-gate (void) sleep(RETRY_DELAY);
35950Sstevel@tonic-gate }
35960Sstevel@tonic-gate return (status);
35970Sstevel@tonic-gate }
359812594SShengliang.Zhang@Sun.COM
359912594SShengliang.Zhang@Sun.COM /*
360012594SShengliang.Zhang@Sun.COM * Get the current protection type from the PROT_EN and P_TYPE
360112594SShengliang.Zhang@Sun.COM */
360212594SShengliang.Zhang@Sun.COM uint8_t
get_cur_protection_type(struct scsi_capacity_16 * capacity)360312594SShengliang.Zhang@Sun.COM get_cur_protection_type(struct scsi_capacity_16 *capacity)
360412594SShengliang.Zhang@Sun.COM {
360512594SShengliang.Zhang@Sun.COM uint8_t cp13;
360612594SShengliang.Zhang@Sun.COM uint8_t prot_en;
360712594SShengliang.Zhang@Sun.COM uint8_t p_type;
360812594SShengliang.Zhang@Sun.COM
360912594SShengliang.Zhang@Sun.COM cp13 = ((capacity->sc_rsvd0 & 0x3f) << 2)
361012594SShengliang.Zhang@Sun.COM | ((capacity->sc_prot_en & 0x01) << 1)
361112594SShengliang.Zhang@Sun.COM | (capacity->sc_rto_en & 0x01);
361212594SShengliang.Zhang@Sun.COM prot_en = cp13 & 0x01;
361312594SShengliang.Zhang@Sun.COM if (prot_en == 0) {
361412594SShengliang.Zhang@Sun.COM p_type = 0;
361512594SShengliang.Zhang@Sun.COM } else {
361612594SShengliang.Zhang@Sun.COM p_type = (cp13 << 4) >> 5;
361712594SShengliang.Zhang@Sun.COM p_type += 1;
361812594SShengliang.Zhang@Sun.COM }
361912594SShengliang.Zhang@Sun.COM return (p_type);
362012594SShengliang.Zhang@Sun.COM }
3621