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