17c478bdstevel@tonic-gate/*
27c478bdstevel@tonic-gate * CDDL HEADER START
37c478bdstevel@tonic-gate *
47c478bdstevel@tonic-gate * The contents of this file are subject to the terms of the
54ab7525mrj * Common Development and Distribution License (the "License").
64ab7525mrj * You may not use this file except in compliance with the License.
77c478bdstevel@tonic-gate *
87c478bdstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bdstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bdstevel@tonic-gate * See the License for the specific language governing permissions
117c478bdstevel@tonic-gate * and limitations under the License.
127c478bdstevel@tonic-gate *
137c478bdstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bdstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bdstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bdstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bdstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bdstevel@tonic-gate *
197c478bdstevel@tonic-gate * CDDL HEADER END
207c478bdstevel@tonic-gate */
214ab7525mrj
227c478bdstevel@tonic-gate/*
2318d6552David Major *  Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
2489b4368Bayard Bell *  Copyright (c) 2011 Bayard G. Bell. All rights reserved.
257c478bdstevel@tonic-gate */
267c478bdstevel@tonic-gate
277c478bdstevel@tonic-gate/*
287c478bdstevel@tonic-gate * SCSI	 SCSA-compliant and not-so-DDI-compliant Tape Driver
297c478bdstevel@tonic-gate */
307c478bdstevel@tonic-gate
317c478bdstevel@tonic-gate#if defined(lint) && !defined(DEBUG)
327c478bdstevel@tonic-gate#define	DEBUG	1
337c478bdstevel@tonic-gate#endif
347c478bdstevel@tonic-gate
357c478bdstevel@tonic-gate#include <sys/modctl.h>
367c478bdstevel@tonic-gate#include <sys/scsi/scsi.h>
377c478bdstevel@tonic-gate#include <sys/mtio.h>
387c478bdstevel@tonic-gate#include <sys/scsi/targets/stdef.h>
397c478bdstevel@tonic-gate#include <sys/file.h>
407c478bdstevel@tonic-gate#include <sys/kstat.h>
41f353171cz#include <sys/ddidmareq.h>
42f353171cz#include <sys/ddi.h>
43f353171cz#include <sys/sunddi.h>
449f931dbyl#include <sys/byteorder.h>
457c478bdstevel@tonic-gate
467c478bdstevel@tonic-gate#define	IOSP	KSTAT_IO_PTR(un->un_stats)
477c478bdstevel@tonic-gate/*
487c478bdstevel@tonic-gate * stats maintained only for reads/writes as commands
497c478bdstevel@tonic-gate * like rewind etc skew the wait/busy times
507c478bdstevel@tonic-gate */
511ef1b39Toomas Soome#define	IS_RW(bp)	((bp)->b_bcount > 0)
527c478bdstevel@tonic-gate#define	ST_DO_KSTATS(bp, kstat_function) \
537c478bdstevel@tonic-gate	if ((bp != un->un_sbufp) && un->un_stats && IS_RW(bp)) { \
547c478bdstevel@tonic-gate		kstat_function(IOSP); \
557c478bdstevel@tonic-gate	}
567c478bdstevel@tonic-gate
577c478bdstevel@tonic-gate#define	ST_DO_ERRSTATS(un, x)  \
587c478bdstevel@tonic-gate	if (un->un_errstats) { \
597c478bdstevel@tonic-gate		struct st_errstats *stp; \
607c478bdstevel@tonic-gate		stp = (struct st_errstats *)un->un_errstats->ks_data; \
617c478bdstevel@tonic-gate		stp->x.value.ul++; \
627c478bdstevel@tonic-gate	}
637c478bdstevel@tonic-gate
641ef1b39Toomas Soome#define	FILL_SCSI1_LUN(devp, pkt)					\
65f3f5a4djongkis	if ((devp)->sd_inq->inq_ansi == 0x1) {				\
66f3f5a4djongkis		int _lun;						\
67f3f5a4djongkis		_lun = ddi_prop_get_int(DDI_DEV_T_ANY, (devp)->sd_dev,	\
68f3f5a4djongkis		    DDI_PROP_DONTPASS, SCSI_ADDR_PROP_LUN, 0);		\
69f3f5a4djongkis		if (_lun > 0) {						\
70f3f5a4djongkis			((union scsi_cdb *)(pkt)->pkt_cdbp)->scc_lun =	\
71f3f5a4djongkis			    _lun;					\
72f3f5a4djongkis		}							\
737c478bdstevel@tonic-gate	}
747c478bdstevel@tonic-gate
75a733396cz/*
76a733396cz * get an available contig mem header, cp.
77a733396cz * when big_enough is true, we will return NULL, if no big enough
78a733396cz * contig mem is found.
79a733396cz * when big_enough is false, we will try to find cp containing big
80a733396cz * enough contig mem. if not found, we will ruturn the last cp available.
81a733396cz *
82a733396cz * used by st_get_contig_mem()
83a733396cz */
84a733396cz#define	ST_GET_CONTIG_MEM_HEAD(un, cp, len, big_enough) {		\
85a733396cz	struct contig_mem *tmp_cp = NULL;				\
86a733396cz	for ((cp) = (un)->un_contig_mem;				\
87a733396cz	    (cp) != NULL;						\
881ef1b39Toomas Soome	    tmp_cp = (cp), (cp) = (cp)->cm_next) {			\
891ef1b39Toomas Soome		if (((cp)->cm_len >= (len)) ||				\
901ef1b39Toomas Soome		    (!(big_enough) && ((cp)->cm_next == NULL))) {	\
911ef1b39Toomas Soome			if (tmp_cp == NULL) {				\
921ef1b39Toomas Soome				(un)->un_contig_mem = (cp)->cm_next;	\
931ef1b39Toomas Soome			} else {					\
941ef1b39Toomas Soome				tmp_cp->cm_next = (cp)->cm_next;	\
951ef1b39Toomas Soome			}						\
961ef1b39Toomas Soome			(cp)->cm_next = NULL;				\
971ef1b39Toomas Soome			(un)->un_contig_mem_available_num--;		\
981ef1b39Toomas Soome			break;						\
991ef1b39Toomas Soome		}							\
1001ef1b39Toomas Soome	}								\
101a733396cz}
102a733396cz
1037c478bdstevel@tonic-gate#define	ST_NUM_MEMBERS(array)	(sizeof (array) / sizeof (array[0]))
104c6914c1rralphs#define	COPY_POS(dest, source) bcopy(source, dest, sizeof (tapepos_t))
105f218e94rralphs#define	ISALNUM(byte) \
106f218e94rralphs	(((byte) >= 'a' && (byte) <= 'z') || \
107f218e94rralphs	((byte) >= 'A' && (byte) <= 'Z') || \
108f218e94rralphs	((byte) >= '0' && (byte) <= '9'))
109c6914c1rralphs
110c6914c1rralphs#define	ONE_K	1024
1117c478bdstevel@tonic-gate
1120205780rralphs#define	MAX_SPACE_CNT(cnt) if (cnt >= 0) { \
1130205780rralphs		if (cnt > MIN(SP_CNT_MASK, INT32_MAX)) \
1140205780rralphs			return (EINVAL); \
1150205780rralphs	} else { \
1160205780rralphs		if (-(cnt) > MIN(SP_CNT_MASK, INT32_MAX)) \
1170205780rralphs			return (EINVAL); \
1180205780rralphs	} \
1190205780rralphs
1207c478bdstevel@tonic-gate/*
1217c478bdstevel@tonic-gate * Global External Data Definitions
1227c478bdstevel@tonic-gate */
1237c478bdstevel@tonic-gateextern struct scsi_key_strings scsi_cmds[];
124c6914c1rralphsextern uchar_t	scsi_cdb_size[];
1257c478bdstevel@tonic-gate
1267c478bdstevel@tonic-gate/*
1277c478bdstevel@tonic-gate * Local Static Data
1287c478bdstevel@tonic-gate */
1297c478bdstevel@tonic-gatestatic void *st_state;
130c6914c1rralphsstatic char *const st_label = "st";
131f218e94rralphsstatic volatile int st_recov_sz = sizeof (recov_info);
1320205780rralphsstatic const char mp_misconf[] = {
1330205780rralphs	"St Tape is misconfigured, MPxIO enabled and "
1340205780rralphs	"tape-command-recovery-disable set in st.conf\n"
1350205780rralphs};
1367c478bdstevel@tonic-gate
13736945f7mrj#ifdef	__x86
138f353171cz/*
139f353171cz * We need to use below DMA attr to alloc physically contiguous
140f353171cz * memory to do I/O in big block size
141f353171cz */
142f353171czstatic ddi_dma_attr_t st_contig_mem_dma_attr = {
143f353171cz	DMA_ATTR_V0,    /* version number */
144f353171cz	0x0,		/* lowest usable address */
145f353171cz	0xFFFFFFFFull,  /* high DMA address range */
146f353171cz	0xFFFFFFFFull,  /* DMA counter register */
147f353171cz	1,		/* DMA address alignment */
148f353171cz	1,		/* DMA burstsizes */
149f353171cz	1,		/* min effective DMA size */
150f353171cz	0xFFFFFFFFull,  /* max DMA xfer size */
151f353171cz	0xFFFFFFFFull,  /* segment boundary */
152f353171cz	1,		/* s/g list length */
153f353171cz	1,		/* granularity of device */
154f353171cz	0		/* DMA transfer flags */
155f353171cz};
156f353171cz
157f353171czstatic ddi_device_acc_attr_t st_acc_attr = {
158f353171cz	DDI_DEVICE_ATTR_V0,
159f353171cz	DDI_NEVERSWAP_ACC,
160f353171cz	DDI_STRICTORDER_ACC
161f353171cz};
162f353171cz
163f353171cz/* set limitation for the number of contig_mem */
164f353171czstatic int st_max_contig_mem_num = ST_MAX_CONTIG_MEM_NUM;
165f353171cz#endif
166f353171cz
1677c478bdstevel@tonic-gate/*
1687c478bdstevel@tonic-gate * Tunable parameters
1697c478bdstevel@tonic-gate *
1707c478bdstevel@tonic-gate * DISCLAIMER
1717c478bdstevel@tonic-gate * ----------
1727c478bdstevel@tonic-gate * These parameters are intended for use only in system testing; if you use
1737c478bdstevel@tonic-gate * them in production systems, you do so at your own risk. Altering any
1747c478bdstevel@tonic-gate * variable not listed below may cause unpredictable system behavior.
1757c478bdstevel@tonic-gate *
1767c478bdstevel@tonic-gate * st_check_media_time
1777c478bdstevel@tonic-gate *
1787c478bdstevel@tonic-gate *   Three second state check
1797c478bdstevel@tonic-gate *
1807c478bdstevel@tonic-gate * st_allow_large_xfer
1817c478bdstevel@tonic-gate *
1827c478bdstevel@tonic-gate *   Gated with ST_NO_RECSIZE_LIMIT
1837c478bdstevel@tonic-gate *
1847c478bdstevel@tonic-gate *   0 - Transfers larger than 64KB will not be allowed
1857c478bdstevel@tonic-gate *       regardless of the setting of ST_NO_RECSIZE_LIMIT
1867c478bdstevel@tonic-gate *   1 - Transfers larger than 64KB will be allowed
1877c478bdstevel@tonic-gate *       if ST_NO_RECSIZE_LIMIT is TRUE for the drive
1887c478bdstevel@tonic-gate *
1897c478bdstevel@tonic-gate * st_report_soft_errors_on_close
1907c478bdstevel@tonic-gate *
1917c478bdstevel@tonic-gate *  Gated with ST_SOFT_ERROR_REPORTING
1927c478bdstevel@tonic-gate *
1937c478bdstevel@tonic-gate *  0 - Errors will not be reported on close regardless
1947c478bdstevel@tonic-gate *      of the setting of ST_SOFT_ERROR_REPORTING
1957c478bdstevel@tonic-gate *
1967c478bdstevel@tonic-gate *  1 - Errors will be reported on close if
1977c478bdstevel@tonic-gate *      ST_SOFT_ERROR_REPORTING is TRUE for the drive
1987c478bdstevel@tonic-gate */
1997c478bdstevel@tonic-gatestatic int st_selection_retry_count = ST_SEL_RETRY_COUNT;
2007c478bdstevel@tonic-gatestatic int st_retry_count	= ST_RETRY_COUNT;
2017c478bdstevel@tonic-gate
2027c478bdstevel@tonic-gatestatic int st_io_time		= ST_IO_TIME;
2037c478bdstevel@tonic-gatestatic int st_long_timeout_x	= ST_LONG_TIMEOUT_X;
2047c478bdstevel@tonic-gate
2057c478bdstevel@tonic-gatestatic int st_space_time	= ST_SPACE_TIME;
2067c478bdstevel@tonic-gatestatic int st_long_space_time_x	= ST_LONG_SPACE_TIME_X;
2077c478bdstevel@tonic-gate
2087c478bdstevel@tonic-gatestatic int st_error_level	= SCSI_ERR_RETRYABLE;
2097c478bdstevel@tonic-gatestatic int st_check_media_time	= 3000000;	/* 3 Second State Check */
2107c478bdstevel@tonic-gate
2117c478bdstevel@tonic-gatestatic int st_max_throttle	= ST_MAX_THROTTLE;
2127c478bdstevel@tonic-gate
2137c478bdstevel@tonic-gatestatic clock_t st_wait_cmds_complete = ST_WAIT_CMDS_COMPLETE;
2147c478bdstevel@tonic-gate
2157c478bdstevel@tonic-gatestatic int st_allow_large_xfer = 1;
2167c478bdstevel@tonic-gatestatic int st_report_soft_errors_on_close = 1;
2177c478bdstevel@tonic-gate
2187c478bdstevel@tonic-gate/*
2197c478bdstevel@tonic-gate * End of tunable parameters list
2207c478bdstevel@tonic-gate */
2217c478bdstevel@tonic-gate
2227c478bdstevel@tonic-gate
2237c478bdstevel@tonic-gate
2247c478bdstevel@tonic-gate/*
2257c478bdstevel@tonic-gate * Asynchronous I/O and persistent errors, refer to PSARC/1995/228
2267c478bdstevel@tonic-gate *
2277c478bdstevel@tonic-gate * Asynchronous I/O's main offering is that it is a non-blocking way to do
2287c478bdstevel@tonic-gate * reads and writes.  The driver will queue up all the requests it gets and
2297c478bdstevel@tonic-gate * have them ready to transport to the HBA.  Unfortunately, we cannot always
2307c478bdstevel@tonic-gate * just ship the I/O requests to the HBA, as there errors and exceptions
2317c478bdstevel@tonic-gate * that may happen when we don't want the HBA to continue.  Therein comes
2327c478bdstevel@tonic-gate * the flush-on-errors capability.  If the HBA supports it, then st will
2337c478bdstevel@tonic-gate * send in st_max_throttle I/O requests at the same time.
2347c478bdstevel@tonic-gate *
2357c478bdstevel@tonic-gate * Persistent errors : This was also reasonably simple.  In the interrupt
2367c478bdstevel@tonic-gate * routines, if there was an error or exception (FM, LEOT, media error,
2377c478bdstevel@tonic-gate * transport error), the persistent error bits are set and shuts everything
2387c478bdstevel@tonic-gate * down, but setting the throttle to zero.  If we hit and exception in the
2397c478bdstevel@tonic-gate * HBA, and flush-on-errors were set, we wait for all outstanding I/O's to
2407c478bdstevel@tonic-gate * come back (with CMD_ABORTED), then flush all bp's in the wait queue with
2417c478bdstevel@tonic-gate * the appropriate error, and this will preserve order. Of course, depending
2427c478bdstevel@tonic-gate * on the exception we have to show a zero read or write before we show
2437c478bdstevel@tonic-gate * errors back to the application.
2447c478bdstevel@tonic-gate */
2457c478bdstevel@tonic-gate
2467c478bdstevel@tonic-gateextern const int st_ndrivetypes;	/* defined in st_conf.c */
2477c478bdstevel@tonic-gateextern const struct st_drivetype st_drivetypes[];
248c6914c1rralphsextern const char st_conf_version[];
2497c478bdstevel@tonic-gate
2507c478bdstevel@tonic-gate#ifdef STDEBUG
2517c478bdstevel@tonic-gatestatic int st_soft_error_report_debug = 0;
2525988135rralphsvolatile int st_debug = 0;
2530205780rralphsstatic volatile dev_info_t *st_lastdev;
2540205780rralphsstatic kmutex_t st_debug_mutex;
2557c478bdstevel@tonic-gate#endif
2567c478bdstevel@tonic-gate
2577c478bdstevel@tonic-gate#define	ST_MT02_NAME	"Emulex  MT02 QIC-11/24  "
2587c478bdstevel@tonic-gate
2599f931dbylstatic const struct vid_drivetype {
2609f931dbyl	char	*vid;
2619f931dbyl	char	type;
2629f931dbyl} st_vid_dt[] = {
2639f931dbyl	{"LTO-CVE ",	MT_LTO},
2649f931dbyl	{"QUANTUM ",    MT_ISDLT},
2659f931dbyl	{"SONY    ",    MT_ISAIT},
2669f931dbyl	{"STK     ",	MT_ISSTK9840}
2679f931dbyl};
2689f931dbyl
2697c478bdstevel@tonic-gatestatic const struct driver_minor_data {
2707c478bdstevel@tonic-gate	char	*name;
2717c478bdstevel@tonic-gate	int	minor;
2727c478bdstevel@tonic-gate} st_minor_data[] = {
2737c478bdstevel@tonic-gate	/*
2747c478bdstevel@tonic-gate	 * The top 4 entries are for the default densities,
2757c478bdstevel@tonic-gate	 * don't alter their position.
2767c478bdstevel@tonic-gate	 */
2777c478bdstevel@tonic-gate	{"",	0},
2787c478bdstevel@tonic-gate	{"n",	MT_NOREWIND},
2797c478bdstevel@tonic-gate	{"b",	MT_BSD},
2807c478bdstevel@tonic-gate	{"bn",	MT_NOREWIND | MT_BSD},
2817c478bdstevel@tonic-gate	{"l",	MT_DENSITY1},
2827c478bdstevel@tonic-gate	{"m",	MT_DENSITY2},
2837c478bdstevel@tonic-gate	{"h",	MT_DENSITY3},
2847c478bdstevel@tonic-gate	{"c",	MT_DENSITY4},
2857c478bdstevel@tonic-gate	{"u",	MT_DENSITY4},
2867c478bdstevel@tonic-gate	{"ln",	MT_DENSITY1 | MT_NOREWIND},
2877c478bdstevel@tonic-gate	{"mn",	MT_DENSITY2 | MT_NOREWIND},
2887c478bdstevel@tonic-gate	{"hn",	MT_DENSITY3 | MT_NOREWIND},
2897c478bdstevel@tonic-gate	{"cn",	MT_DENSITY4 | MT_NOREWIND},
2907c478bdstevel@tonic-gate	{"un",	MT_DENSITY4 | MT_NOREWIND},
2917c478bdstevel@tonic-gate	{"lb",	MT_DENSITY1 | MT_BSD},
2927c478bdstevel@tonic-gate	{"mb",	MT_DENSITY2 | MT_BSD},
2937c478bdstevel@tonic-gate	{"hb",	MT_DENSITY3 | MT_BSD},
2947c478bdstevel@tonic-gate	{"cb",	MT_DENSITY4 | MT_BSD},
2957c478bdstevel@tonic-gate	{"ub",	MT_DENSITY4 | MT_BSD},
2967c478bdstevel@tonic-gate	{"lbn",	MT_DENSITY1 | MT_NOREWIND | MT_BSD},
2977c478bdstevel@tonic-gate	{"mbn",	MT_DENSITY2 | MT_NOREWIND | MT_BSD},
2987c478bdstevel@tonic-gate	{"hbn",	MT_DENSITY3 | MT_NOREWIND | MT_BSD},
2997c478bdstevel@tonic-gate	{"cbn",	MT_DENSITY4 | MT_NOREWIND | MT_BSD},
3007c478bdstevel@tonic-gate	{"ubn",	MT_DENSITY4 | MT_NOREWIND | MT_BSD}
3017c478bdstevel@tonic-gate};
3027c478bdstevel@tonic-gate
3037c478bdstevel@tonic-gate/* strings used in many debug and warning messages */
3047c478bdstevel@tonic-gatestatic const char wr_str[]  = "write";
3057c478bdstevel@tonic-gatestatic const char rd_str[]  = "read";
3067c478bdstevel@tonic-gatestatic const char wrg_str[] = "writing";
3077c478bdstevel@tonic-gatestatic const char rdg_str[] = "reading";
308c6914c1rralphsstatic const char *space_strs[] = {
309c6914c1rralphs	"records",
310c6914c1rralphs	"filemarks",
311c6914c1rralphs	"sequential filemarks",
312c6914c1rralphs	"eod",
313c6914c1rralphs	"setmarks",
314c6914c1rralphs	"sequential setmarks",
315c6914c1rralphs	"Reserved",
316c6914c1rralphs	"Reserved"
317c6914c1rralphs};
318f218e94rralphsstatic const char *load_strs[] = {
319f218e94rralphs	"unload",		/* LD_UNLOAD		0 */
320f218e94rralphs	"load",			/* LD_LOAD		1 */
321f218e94rralphs	"retension",		/* LD_RETEN		2 */
322f218e94rralphs	"load reten",		/* LD_LOAD | LD_RETEN	3 */
323f218e94rralphs	"eod",			/* LD_EOT		4 */
324f218e94rralphs	"load EOD",		/* LD_LOAD | LD_EOT	5 */
325f218e94rralphs	"reten EOD",		/* LD_RETEN | LD_EOT	6 */
326f218e94rralphs	"load reten EOD"	/* LD_LOAD|LD_RETEN|LD_EOT 7 */
327f218e94rralphs	"hold",			/* LD_HOLD		8 */
328f218e94rralphs	"load and hold"		/* LD_LOAD | LD_HOLD	9 */
329f218e94rralphs};
330f218e94rralphs
3310205780rralphsstatic const char *errstatenames[] = {
3320205780rralphs	"COMMAND_DONE",
3330205780rralphs	"COMMAND_DONE_ERROR",
3340205780rralphs	"COMMAND_DONE_ERROR_RECOVERED",
3350205780rralphs	"QUE_COMMAND",
3360205780rralphs	"QUE_BUSY_COMMAND",
3370205780rralphs	"QUE_SENSE",
3380205780rralphs	"JUST_RETURN",
3390205780rralphs	"COMMAND_DONE_EACCES",
3400205780rralphs	"QUE_LAST_COMMAND",
3410205780rralphs	"COMMAND_TIMEOUT",
3420205780rralphs	"PATH_FAILED",
3430205780rralphs	"DEVICE_RESET",
3440205780rralphs	"DEVICE_TAMPER",
3450205780rralphs	"ATTEMPT_RETRY"
3460205780rralphs};
3470205780rralphs
348f218e94rralphsconst char *bogusID = "Unknown Media ID";
3497c478bdstevel@tonic-gate
3507c478bdstevel@tonic-gate/* default density offsets in the table above */
3517c478bdstevel@tonic-gate#define	DEF_BLANK	0
3527c478bdstevel@tonic-gate#define	DEF_NOREWIND	1
3537c478bdstevel@tonic-gate#define	DEF_BSD		2
3547c478bdstevel@tonic-gate#define	DEF_BSD_NR	3
3557c478bdstevel@tonic-gate
3567c478bdstevel@tonic-gate/* Sense Key, ASC/ASCQ for which tape ejection is needed */
3577c478bdstevel@tonic-gate
3587c478bdstevel@tonic-gatestatic struct tape_failure_code {
3597c478bdstevel@tonic-gate	uchar_t key;
3607c478bdstevel@tonic-gate	uchar_t add_code;
3617c478bdstevel@tonic-gate	uchar_t qual_code;
3627c478bdstevel@tonic-gate} st_tape_failure_code[] = {
3637c478bdstevel@tonic-gate	{ KEY_HARDWARE_ERROR, 0x15, 0x01},
3647c478bdstevel@tonic-gate	{ KEY_HARDWARE_ERROR, 0x44, 0x00},
3657c478bdstevel@tonic-gate	{ KEY_HARDWARE_ERROR, 0x53, 0x00},
3667c478bdstevel@tonic-gate	{ KEY_HARDWARE_ERROR, 0x53, 0x01},
3677c478bdstevel@tonic-gate	{ KEY_NOT_READY, 0x53, 0x00},
3687c478bdstevel@tonic-gate	{ 0xff}
3697c478bdstevel@tonic-gate};
3707c478bdstevel@tonic-gate
3717c478bdstevel@tonic-gate/*  clean bit position and mask */
3727c478bdstevel@tonic-gate
3737c478bdstevel@tonic-gatestatic struct cln_bit_position {
3747c478bdstevel@tonic-gate	ushort_t cln_bit_byte;
3757c478bdstevel@tonic-gate	uchar_t cln_bit_mask;
3767c478bdstevel@tonic-gate} st_cln_bit_position[] = {
3777c478bdstevel@tonic-gate	{ 21, 0x08},
3787c478bdstevel@tonic-gate	{ 70, 0xc0},
3797c478bdstevel@tonic-gate	{ 18, 0x81}  /* 80 bit indicates in bit mode, 1 bit clean light is on */
3807c478bdstevel@tonic-gate};
3817c478bdstevel@tonic-gate
3827c478bdstevel@tonic-gate/*
3834ab7525mrj * architecture dependent allocation restrictions. For x86, we'll set
3844ab7525mrj * dma_attr_addr_hi to st_max_phys_addr and dma_attr_sgllen to
3854ab7525mrj * st_sgl_size during _init().
3864ab7525mrj */
3874ab7525mrj#if defined(__sparc)
3884ab7525mrjstatic ddi_dma_attr_t st_alloc_attr = {
3894ab7525mrj	DMA_ATTR_V0,	/* version number */
3904ab7525mrj	0x0,		/* lowest usable address */
3914ab7525mrj	0xFFFFFFFFull,	/* high DMA address range */
3924ab7525mrj	0xFFFFFFFFull,	/* DMA counter register */
3934ab7525mrj	1,		/* DMA address alignment */
3944ab7525mrj	1,		/* DMA burstsizes */
3954ab7525mrj	1,		/* min effective DMA size */
3964ab7525mrj	0xFFFFFFFFull,	/* max DMA xfer size */
3974ab7525mrj	0xFFFFFFFFull,	/* segment boundary */
3984ab7525mrj	1,		/* s/g list length */
3994ab7525mrj	512,		/* granularity of device */
4004ab7525mrj	0		/* DMA transfer flags */
4014ab7525mrj};
4024ab7525mrj#elif defined(__x86)
4034ab7525mrjstatic ddi_dma_attr_t st_alloc_attr = {
4044ab7525mrj	DMA_ATTR_V0,	/* version number */
4054ab7525mrj	0x0,		/* lowest usable address */
4064ab7525mrj	0x0,		/* high DMA address range [set in _init()] */
4074ab7525mrj	0xFFFFull,	/* DMA counter register */
4084ab7525mrj	512,		/* DMA address alignment */
4094ab7525mrj	1,		/* DMA burstsizes */
4104ab7525mrj	1,		/* min effective DMA size */
4114ab7525mrj	0xFFFFFFFFull,	/* max DMA xfer size */
4124ab7525mrj	0xFFFFFFFFull,  /* segment boundary */
4134ab7525mrj	0,		/* s/g list length */
4144ab7525mrj	512,		/* granularity of device [set in _init()] */
4154ab7525mrj	0		/* DMA transfer flags */
4164ab7525mrj};
4174ab7525mrjuint64_t st_max_phys_addr = 0xFFFFFFFFull;
4184ab7525mrjint st_sgl_size = 0xF;
4194ab7525mrj
4204ab7525mrj#endif
4214ab7525mrj
4224ab7525mrj/*
4237c478bdstevel@tonic-gate * Configuration Data:
4247c478bdstevel@tonic-gate *
4257c478bdstevel@tonic-gate * Device driver ops vector
4267c478bdstevel@tonic-gate */
4277c478bdstevel@tonic-gatestatic int st_aread(dev_t dev, struct aio_req *aio, cred_t *cred_p);
4287c478bdstevel@tonic-gatestatic int st_awrite(dev_t dev, struct aio_req *aio, cred_t *cred_p);
4297c478bdstevel@tonic-gatestatic int st_read(dev_t  dev,  struct   uio   *uio_p,   cred_t *cred_p);
4307c478bdstevel@tonic-gatestatic int st_write(dev_t  dev,  struct  uio   *uio_p,   cred_t *cred_p);
4317c478bdstevel@tonic-gatestatic int st_open(dev_t  *devp,  int  flag,  int  otyp,  cred_t *cred_p);
4327c478bdstevel@tonic-gatestatic int st_close(dev_t  dev,  int  flag,  int  otyp,  cred_t *cred_p);
4337c478bdstevel@tonic-gatestatic int st_strategy(struct buf *bp);
434f218e94rralphsstatic int st_queued_strategy(buf_t *bp);
4357c478bdstevel@tonic-gatestatic int st_ioctl(dev_t dev, int cmd, intptr_t arg, int  flag,
4367c478bdstevel@tonic-gate	cred_t *cred_p, int *rval_p);
4377c478bdstevel@tonic-gateextern int nulldev(), nodev();
4387c478bdstevel@tonic-gate
4397c478bdstevel@tonic-gatestatic struct cb_ops st_cb_ops = {
440c6914c1rralphs	st_open,		/* open */
4417c478bdstevel@tonic-gate	st_close,		/* close */
442f218e94rralphs	st_queued_strategy,	/* strategy Not Block device but async checks */
4437c478bdstevel@tonic-gate	nodev,			/* print */
4447c478bdstevel@tonic-gate	nodev,			/* dump */
4457c478bdstevel@tonic-gate	st_read,		/* read */
4467c478bdstevel@tonic-gate	st_write,		/* write */
4477c478bdstevel@tonic-gate	st_ioctl,		/* ioctl */
4487c478bdstevel@tonic-gate	nodev,			/* devmap */
4497c478bdstevel@tonic-gate	nodev,			/* mmap */
4507c478bdstevel@tonic-gate	nodev,			/* segmap */
4517c478bdstevel@tonic-gate	nochpoll,		/* poll */
4527c478bdstevel@tonic-gate	ddi_prop_op,		/* cb_prop_op */
4537c478bdstevel@tonic-gate	0,			/* streamtab  */
454e099bf0cth	D_64BIT | D_MP | D_NEW | D_HOTPLUG |
455e099bf0cth	D_OPEN_RETURNS_EINTR,	/* cb_flag */
4567c478bdstevel@tonic-gate	CB_REV,			/* cb_rev */
4571ef1b39Toomas Soome	st_aread,		/* async I/O read entry point */
4587c478bdstevel@tonic-gate	st_awrite		/* async I/O write entry point */
4597c478bdstevel@tonic-gate
4607c478bdstevel@tonic-gate};
4617c478bdstevel@tonic-gate
462f218e94rralphsstatic int st_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
4637c478bdstevel@tonic-gate		void **result);
4647c478bdstevel@tonic-gatestatic int st_probe(dev_info_t *dev);
4657c478bdstevel@tonic-gatestatic int st_attach(dev_info_t *dev, ddi_attach_cmd_t cmd);
4667c478bdstevel@tonic-gatestatic int st_detach(dev_info_t *dev, ddi_detach_cmd_t cmd);
4677c478bdstevel@tonic-gate
4687c478bdstevel@tonic-gatestatic struct dev_ops st_ops = {
4697c478bdstevel@tonic-gate	DEVO_REV,		/* devo_rev, */
4707c478bdstevel@tonic-gate	0,			/* refcnt  */
471f218e94rralphs	st_info,		/* info */
4727c478bdstevel@tonic-gate	nulldev,		/* identify */
4737c478bdstevel@tonic-gate	st_probe,		/* probe */
4747c478bdstevel@tonic-gate	st_attach,		/* attach */
4757c478bdstevel@tonic-gate	st_detach,		/* detach */
4767c478bdstevel@tonic-gate	nodev,			/* reset */
4777c478bdstevel@tonic-gate	&st_cb_ops,		/* driver operations */
4787c478bdstevel@tonic-gate	(struct bus_ops *)0,	/* bus operations */
4791939740Sherry Moore	nulldev,		/* power */
4808bef02cbo zhou - Sun Microsystems - Beijing China	ddi_quiesce_not_needed,	/* devo_quiesce */
4817c478bdstevel@tonic-gate};
4827c478bdstevel@tonic-gate
4837c478bdstevel@tonic-gate/*
4847c478bdstevel@tonic-gate * Local Function Declarations
4857c478bdstevel@tonic-gate */
486c6914c1rralphsstatic char *st_print_scsi_cmd(char cmd);
487c6914c1rralphsstatic void st_print_cdb(dev_info_t *dip, char *label, uint_t level,
488c6914c1rralphs    char *title, char *cdb);
4897c478bdstevel@tonic-gatestatic void st_clean_print(dev_info_t *dev, char *label, uint_t level,
490f218e94rralphs    char *title, char *data, int len);
4917c478bdstevel@tonic-gatestatic int st_doattach(struct scsi_device *devp, int (*canwait)());
4927c478bdstevel@tonic-gatestatic void st_known_tape_type(struct scsi_tape *un);
4937c478bdstevel@tonic-gatestatic int st_get_conf_from_st_dot_conf(struct scsi_tape *, char *,
4947c478bdstevel@tonic-gate    struct st_drivetype *);
4957c478bdstevel@tonic-gatestatic int st_get_conf_from_st_conf_dot_c(struct scsi_tape *, char *,
4967c478bdstevel@tonic-gate    struct st_drivetype *);
4979f931dbylstatic int st_get_conf_from_tape_drive(struct scsi_tape *, char *,
4989f931dbyl    struct st_drivetype *);
4999f931dbylstatic int st_get_densities_from_tape_drive(struct scsi_tape *,
5009f931dbyl    struct st_drivetype *);
5019f931dbylstatic int st_get_timeout_values_from_tape_drive(struct scsi_tape *,
5029f931dbyl    struct st_drivetype *);
5039f931dbylstatic int st_get_timeouts_value(struct scsi_tape *, uchar_t, ushort_t *,
5049f931dbyl    ushort_t);
5057c478bdstevel@tonic-gatestatic int st_get_default_conf(struct scsi_tape *, char *,
5067c478bdstevel@tonic-gate    struct st_drivetype *);
5077c478bdstevel@tonic-gatestatic int st_rw(dev_t dev, struct uio *uio, int flag);
5087c478bdstevel@tonic-gatestatic int st_arw(dev_t dev, struct aio_req *aio, int flag);
509f218e94rralphsstatic int st_find_eod(struct scsi_tape *un);
5107c478bdstevel@tonic-gatestatic int st_check_density_or_wfm(dev_t dev, int wfm, int mode, int stepflag);
511f218e94rralphsstatic int st_uscsi_cmd(struct scsi_tape *un, struct uscsi_cmd *, int flag);
5127c478bdstevel@tonic-gatestatic int st_mtioctop(struct scsi_tape *un, intptr_t arg, int flag);
513c6914c1rralphsstatic int st_mtiocltop(struct scsi_tape *un, intptr_t arg, int flag);
514c6914c1rralphsstatic int st_do_mtioctop(struct scsi_tape *un, struct mtlop *mtop);
5156550f38rralphsstatic void st_start(struct scsi_tape *un);
5167c478bdstevel@tonic-gatestatic int st_handle_start_busy(struct scsi_tape *un, struct buf *bp,
517f218e94rralphs    clock_t timeout_interval, int queued);
5187c478bdstevel@tonic-gatestatic int st_handle_intr_busy(struct scsi_tape *un, struct buf *bp,
5197c478bdstevel@tonic-gate    clock_t timeout_interval);
5207c478bdstevel@tonic-gatestatic int st_handle_intr_retry_lcmd(struct scsi_tape *un, struct buf *bp);
5217c478bdstevel@tonic-gatestatic void st_done_and_mutex_exit(struct scsi_tape *un, struct buf *bp);
5227c478bdstevel@tonic-gatestatic void st_init(struct scsi_tape *un);
5237c478bdstevel@tonic-gatestatic void st_make_cmd(struct scsi_tape *un, struct buf *bp,
5246550f38rralphs    int (*func)(caddr_t));
5257c478bdstevel@tonic-gatestatic void st_make_uscsi_cmd(struct scsi_tape *, struct uscsi_cmd *,
5266550f38rralphs    struct buf *bp, int (*func)(caddr_t));
5277c478bdstevel@tonic-gatestatic void st_intr(struct scsi_pkt *pkt);
528f218e94rralphsstatic void st_set_state(struct scsi_tape *un, buf_t *bp);
5297c478bdstevel@tonic-gatestatic void st_test_append(struct buf *bp);
5306550f38rralphsstatic int st_runout(caddr_t);
531f218e94rralphsstatic int st_cmd(struct scsi_tape *un, int com, int64_t count, int wait);
532f218e94rralphsstatic int st_setup_cmd(struct scsi_tape *un, buf_t *bp, int com,
533f218e94rralphs    int64_t count);
5347c478bdstevel@tonic-gatestatic int st_set_compression(struct scsi_tape *un);
5357c478bdstevel@tonic-gatestatic int st_write_fm(dev_t dev, int wfm);
536f218e94rralphsstatic int st_determine_generic(struct scsi_tape *un);
537f218e94rralphsstatic int st_determine_density(struct scsi_tape *un, int rw);
538f218e94rralphsstatic int st_get_density(struct scsi_tape *un);
539f218e94rralphsstatic int st_set_density(struct scsi_tape *un);
540f218e94rralphsstatic int st_loadtape(struct scsi_tape *un);
5417c478bdstevel@tonic-gatestatic int st_modesense(struct scsi_tape *un);
5427c478bdstevel@tonic-gatestatic int st_modeselect(struct scsi_tape *un);
543f218e94rralphsstatic errstate st_handle_incomplete(struct scsi_tape *un, struct buf *bp);
5447c478bdstevel@tonic-gatestatic int st_wrongtapetype(struct scsi_tape *un);
545f218e94rralphsstatic errstate st_check_error(struct scsi_tape *un, struct scsi_pkt *pkt);
546f218e94rralphsstatic errstate st_handle_sense(struct scsi_tape *un, struct buf *bp,
547f218e94rralphs    tapepos_t *);
548f218e94rralphsstatic errstate st_handle_autosense(struct scsi_tape *un, struct buf *bp,
549f218e94rralphs    tapepos_t *);
550fa4c0ecbzstatic int st_get_error_entry(struct scsi_tape *un, intptr_t arg, int flag);
551fa4c0ecbzstatic void st_update_error_stack(struct scsi_tape *un, struct scsi_pkt *pkt,
552fa4c0ecbz    struct scsi_arq_status *cmd);
553fa4c0ecbzstatic void st_empty_error_stack(struct scsi_tape *un);
554f218e94rralphsstatic errstate st_decode_sense(struct scsi_tape *un, struct buf *bp, int amt,
5550205780rralphs    struct scsi_arq_status *, tapepos_t *);
5567c478bdstevel@tonic-gatestatic int st_report_soft_errors(dev_t dev, int flag);
5577c478bdstevel@tonic-gatestatic void st_delayed_cv_broadcast(void *arg);
5587c478bdstevel@tonic-gatestatic int st_check_media(dev_t dev, enum mtio_state state);
5597c478bdstevel@tonic-gatestatic int st_media_watch_cb(caddr_t arg, struct scsi_watch_result *resultp);
5607c478bdstevel@tonic-gatestatic void st_intr_restart(void *arg);
5617c478bdstevel@tonic-gatestatic void st_start_restart(void *arg);
562f218e94rralphsstatic int st_gen_mode_sense(struct scsi_tape *un, ubufunc_t ubf, int page,
563f218e94rralphs    struct seq_mode *page_data, int page_size);
564f218e94rralphsstatic int st_change_block_size(struct scsi_tape *un, uint32_t nblksz);
565f218e94rralphsstatic int st_gen_mode_select(struct scsi_tape *un, ubufunc_t ubf,
5667c478bdstevel@tonic-gate    struct seq_mode *page_data, int page_size);
5679f931dbylstatic int st_read_block_limits(struct scsi_tape *un,
5689f931dbyl    struct read_blklim *read_blk);
5699f931dbylstatic int st_report_density_support(struct scsi_tape *un,
5709f931dbyl    uchar_t *density_data, size_t buflen);
5719f931dbylstatic int st_report_supported_operation(struct scsi_tape *un,
5729f931dbyl    uchar_t *oper_data, uchar_t option_code, ushort_t service_action);
573f218e94rralphsstatic int st_tape_init(struct scsi_tape *un);
5747c478bdstevel@tonic-gatestatic void st_flush(struct scsi_tape *un);
5757c478bdstevel@tonic-gatestatic void st_set_pe_errno(struct scsi_tape *un);
5767c478bdstevel@tonic-gatestatic void st_hba_unflush(struct scsi_tape *un);
5777c478bdstevel@tonic-gatestatic void st_turn_pe_on(struct scsi_tape *un);
5787c478bdstevel@tonic-gatestatic void st_turn_pe_off(struct scsi_tape *un);
5797c478bdstevel@tonic-gatestatic void st_set_pe_flag(struct scsi_tape *un);
5807c478bdstevel@tonic-gatestatic void st_clear_pe(struct scsi_tape *un);
5817c478bdstevel@tonic-gatestatic void st_wait_for_io(struct scsi_tape *un);
5827c478bdstevel@tonic-gatestatic int st_set_devconfig_page(struct scsi_tape *un, int compression_on);
5837c478bdstevel@tonic-gatestatic int st_set_datacomp_page(struct scsi_tape *un, int compression_on);
584f218e94rralphsstatic int st_reserve_release(struct scsi_tape *un, int command, ubufunc_t ubf);
585f218e94rralphsstatic int st_check_cdb_for_need_to_reserve(struct scsi_tape *un, uchar_t *cdb);
586e213afcrralphsstatic int st_check_cmd_for_need_to_reserve(struct scsi_tape *un, uchar_t cmd,
587e213afcrralphs    int count);
5880205780rralphsstatic int st_take_ownership(struct scsi_tape *un, ubufunc_t ubf);
5897c478bdstevel@tonic-gatestatic int st_check_asc_ascq(struct scsi_tape *un);
590f218e94rralphsstatic int st_check_clean_bit(struct scsi_tape *un);
591f218e94rralphsstatic int st_check_alert_flags(struct scsi_tape *un);
592f218e94rralphsstatic int st_check_sequential_clean_bit(struct scsi_tape *un);
593f218e94rralphsstatic int st_check_sense_clean_bit(struct scsi_tape *un);
5947c478bdstevel@tonic-gatestatic int st_clear_unit_attentions(dev_t dev_instance, int max_trys);
5957c478bdstevel@tonic-gatestatic void st_calculate_timeouts(struct scsi_tape *un);
5965988135rralphsstatic writablity st_is_drive_worm(struct scsi_tape *un);
5975988135rralphsstatic int st_read_attributes(struct scsi_tape *un, uint16_t attribute,
598f218e94rralphs    void *buf, size_t size, ubufunc_t bufunc);
5995988135rralphsstatic int st_get_special_inquiry(struct scsi_tape *un, uchar_t size,
6005988135rralphs    caddr_t dest, uchar_t page);
601f218e94rralphsstatic int st_update_block_pos(struct scsi_tape *un, bufunc_t bf,
602f218e94rralphs    int post_space);
603f218e94rralphsstatic int st_interpret_read_pos(struct scsi_tape const *un, tapepos_t *dest,
604f218e94rralphs    read_p_types type, size_t data_sz, const caddr_t responce, int post_space);
605c6914c1rralphsstatic int st_get_read_pos(struct scsi_tape *un, buf_t *bp);
606f218e94rralphsstatic int st_logical_block_locate(struct scsi_tape *un, ubufunc_t ubf,
607f218e94rralphs    tapepos_t *pos, uint64_t lblk, uchar_t partition);
6080205780rralphsstatic int st_mtfsf_ioctl(struct scsi_tape *un, int64_t files);
6090205780rralphsstatic int st_mtfsr_ioctl(struct scsi_tape *un, int64_t count);
6100205780rralphsstatic int st_mtbsf_ioctl(struct scsi_tape *un, int64_t files);
6110205780rralphsstatic int st_mtnbsf_ioctl(struct scsi_tape *un, int64_t count);
6120205780rralphsstatic int st_mtbsr_ioctl(struct scsi_tape *un, int64_t num);
6130205780rralphsstatic int st_mtfsfm_ioctl(struct scsi_tape *un, int64_t cnt);
6140205780rralphsstatic int st_mtbsfm_ioctl(struct scsi_tape *un, int64_t cnt);
6150205780rralphsstatic int st_backward_space_files(struct scsi_tape *un, int64_t count,
616c6914c1rralphs    int infront);
6170205780rralphsstatic int st_forward_space_files(struct scsi_tape *un, int64_t files);
618c6914c1rralphsstatic int st_scenic_route_to_begining_of_file(struct scsi_tape *un,
619c6914c1rralphs    int32_t fileno);
620c6914c1rralphsstatic int st_space_to_begining_of_file(struct scsi_tape *un);
6210205780rralphsstatic int st_space_records(struct scsi_tape *un, int64_t records);
622f218e94rralphsstatic int st_get_media_identification(struct scsi_tape *un, ubufunc_t bufunc);
623f218e94rralphsstatic errstate st_command_recovery(struct scsi_tape *un, struct scsi_pkt *pkt,
624f218e94rralphs    errstate onentry);
625f218e94rralphsstatic void st_recover(void *arg);
626f218e94rralphsstatic void st_recov_cb(struct scsi_pkt *pkt);
627f218e94rralphsstatic int st_rcmd(struct scsi_tape *un, int com, int64_t count, int wait);
628f218e94rralphsstatic int st_uscsi_rcmd(struct scsi_tape *un, struct uscsi_cmd *ucmd,
629f218e94rralphs    int flag);
630f218e94rralphsstatic void st_add_recovery_info_to_pkt(struct scsi_tape *un, buf_t *bp,
631f218e94rralphs    struct scsi_pkt *cmd);
632f218e94rralphsstatic int st_check_mode_for_change(struct scsi_tape *un, ubufunc_t ubf);
633f218e94rralphsstatic int st_test_path_to_device(struct scsi_tape *un);
634f218e94rralphsstatic int st_recovery_read_pos(struct scsi_tape *un, read_p_types type,
635f218e94rralphs    read_pos_data_t *raw);
636f218e94rralphsstatic int st_recovery_get_position(struct scsi_tape *un, tapepos_t *read,
637f218e94rralphs    read_pos_data_t *raw);
638f218e94rralphsstatic int st_compare_expected_position(struct scsi_tape *un, st_err_info *ei,
639f218e94rralphs    cmd_attribute const * cmd_att, tapepos_t *read);
640f218e94rralphsstatic errstate st_recover_reissue_pkt(struct scsi_tape *us,
641f218e94rralphs    struct scsi_pkt *pkt);
642f218e94rralphsstatic int st_transport(struct scsi_tape *un, struct scsi_pkt *pkt);
643f218e94rralphsstatic buf_t *st_remove_from_queue(buf_t **head, buf_t **tail, buf_t *bp);
644f218e94rralphsstatic void st_add_to_queue(buf_t **head, buf_t **tail, buf_t *end, buf_t *bp);
645f218e94rralphsstatic int st_reset(struct scsi_tape *un, int reset_type);
646f218e94rralphsstatic void st_reset_notification(caddr_t arg);
647f218e94rralphsstatic const cmd_attribute *st_lookup_cmd_attribute(unsigned char cmd);
6487c478bdstevel@tonic-gate
649af483ccjianfei wang - Sun Microsystems - Beijing Chinastatic int st_set_target_TLR_mode(struct scsi_tape *un, ubufunc_t ubf);
650af483ccjianfei wang - Sun Microsystems - Beijing Chinastatic int st_make_sure_mode_data_is_correct(struct scsi_tape *un,
651af483ccjianfei wang - Sun Microsystems - Beijing China    ubufunc_t ubf);
652af483ccjianfei wang - Sun Microsystems - Beijing China
65336945f7mrj#ifdef	__x86
654f353171cz/*
655f353171cz * routines for I/O in big block size
656f353171cz */
657f353171czstatic void st_release_contig_mem(struct scsi_tape *un, struct contig_mem *cp);
658f353171czstatic struct contig_mem *st_get_contig_mem(struct scsi_tape *un, size_t len,
659f353171cz    int alloc_flags);
660f353171czstatic int st_bigblk_xfer_done(struct buf *bp);
661f353171czstatic struct buf *st_get_bigblk_bp(struct buf *bp);
662f353171cz#endif
663f218e94rralphsstatic void st_print_position(dev_info_t *dev, char *label, uint_t level,
664f218e94rralphs    const char *comment, tapepos_t *pos);
665f353171cz
6667c478bdstevel@tonic-gate/*
6677c478bdstevel@tonic-gate * error statistics create/update functions
6687c478bdstevel@tonic-gate */
6697c478bdstevel@tonic-gatestatic int st_create_errstats(struct scsi_tape *, int);
670f218e94rralphsstatic int st_validate_tapemarks(struct scsi_tape *un, ubufunc_t ubf,
671f218e94rralphs    tapepos_t *pos);
6727c478bdstevel@tonic-gate
6737c478bdstevel@tonic-gate#ifdef STDEBUG
6747c478bdstevel@tonic-gatestatic void st_debug_cmds(struct scsi_tape *un, int com, int count, int wait);
6757c478bdstevel@tonic-gate#endif /* STDEBUG */
6760205780rralphsstatic char *st_dev_name(dev_t dev);
6777c478bdstevel@tonic-gate
6787c478bdstevel@tonic-gate#if !defined(lint)
6796567eb0lh_NOTE(SCHEME_PROTECTS_DATA("unique per pkt",
6806567eb0lh    scsi_pkt buf uio scsi_cdb uscsi_cmd))
6817c478bdstevel@tonic-gate_NOTE(SCHEME_PROTECTS_DATA("unique per pkt", scsi_extended_sense scsi_status))
6820205780rralphs_NOTE(SCHEME_PROTECTS_DATA("unique per pkt", recov_info))
6837c478bdstevel@tonic-gate_NOTE(SCHEME_PROTECTS_DATA("stable data", scsi_device))
6847c478bdstevel@tonic-gate_NOTE(DATA_READABLE_WITHOUT_LOCK(st_drivetype scsi_address))
6857c478bdstevel@tonic-gate#endif
6867c478bdstevel@tonic-gate
6877c478bdstevel@tonic-gate/*
6887c478bdstevel@tonic-gate * autoconfiguration routines.
6897c478bdstevel@tonic-gate */
6907c478bdstevel@tonic-gate
6917c478bdstevel@tonic-gatestatic struct modldrv modldrv = {
6927c478bdstevel@tonic-gate	&mod_driverops,		/* Type of module. This one is a driver */
6931ef1b39Toomas Soome	"SCSI tape Driver",	/* Name of the module. */
6947c478bdstevel@tonic-gate	&st_ops			/* driver ops */
6957c478bdstevel@tonic-gate};
6967c478bdstevel@tonic-gate
6977c478bdstevel@tonic-gatestatic struct modlinkage modlinkage = {
6987c478bdstevel@tonic-gate	MODREV_1, &modldrv, NULL
6997c478bdstevel@tonic-gate};
7007c478bdstevel@tonic-gate
7017c478bdstevel@tonic-gate/*
7027c478bdstevel@tonic-gate * Notes on Post Reset Behavior in the tape driver:
7037c478bdstevel@tonic-gate *
7047c478bdstevel@tonic-gate * When the tape drive is opened, the driver  attempts  to make sure that
7057c478bdstevel@tonic-gate * the tape head is positioned exactly where it was left when it was last
7067c478bdstevel@tonic-gate * closed  provided  the  medium  is not  changed.  If the tape  drive is
7077c478bdstevel@tonic-gate * opened in O_NDELAY mode, the repositioning  (if necessary for any loss
7087c478bdstevel@tonic-gate * of position due to reset) will happen when the first tape operation or
7097c478bdstevel@tonic-gate * I/O occurs.  The repositioning (if required) may not be possible under
7107c478bdstevel@tonic-gate * certain situations such as when the device firmware not able to report
7117c478bdstevel@tonic-gate * the medium  change in the REQUEST  SENSE data  because of a reset or a
7127c478bdstevel@tonic-gate * misbehaving  bus  not  allowing  the  reposition  to  happen.  In such
7137c478bdstevel@tonic-gate * extraordinary  situations, where the driver fails to position the head
7147c478bdstevel@tonic-gate * at its  original  position,  it will fail the open the first  time, to
7157c478bdstevel@tonic-gate * save the applications from overwriting the data.  All further attempts
7167c478bdstevel@tonic-gate * to open the tape device will result in the driver  attempting  to load
7177c478bdstevel@tonic-gate * the  tape at BOT  (beginning  of  tape).  Also a  warning  message  to
7187c478bdstevel@tonic-gate * indicate  that further  attempts to open the tape device may result in
7197c478bdstevel@tonic-gate * the tape being  loaded at BOT will be printed on the  console.  If the
7207c478bdstevel@tonic-gate * tape  device is opened  in  O_NDELAY  mode,  failure  to  restore  the
7217c478bdstevel@tonic-gate * original tape head  position,  will result in the failure of the first
7227c478bdstevel@tonic-gate * tape  operation  or I/O,  Further,  the  driver  will  invalidate  its
7237c478bdstevel@tonic-gate * internal tape position  which will  necessitate  the  applications  to
7247c478bdstevel@tonic-gate * validate the position by using either a tape  positioning  ioctl (such
7257c478bdstevel@tonic-gate * as MTREW) or closing and reopening the tape device.
7267c478bdstevel@tonic-gate *
7277c478bdstevel@tonic-gate */
7287c478bdstevel@tonic-gate
7297c478bdstevel@tonic-gateint
7307c478bdstevel@tonic-gate_init(void)
7317c478bdstevel@tonic-gate{
732f218e94rralphs	int e;
7337c478bdstevel@tonic-gate
7347c478bdstevel@tonic-gate	if (((e = ddi_soft_state_init(&st_state,
7357c478bdstevel@tonic-gate	    sizeof (struct scsi_tape), ST_MAXUNIT)) != 0)) {
7367c478bdstevel@tonic-gate		return (e);
7377c478bdstevel@tonic-gate	}
7387c478bdstevel@tonic-gate
7397c478bdstevel@tonic-gate	if ((e = mod_install(&modlinkage)) != 0) {
7407c478bdstevel@tonic-gate		ddi_soft_state_fini(&st_state);
7410205780rralphs	} else {
7420205780rralphs#ifdef STDEBUG
7430205780rralphs		mutex_init(&st_debug_mutex, NULL, MUTEX_DRIVER, NULL);
7440205780rralphs#endif
7457c478bdstevel@tonic-gate
7464ab7525mrj#if defined(__x86)
7470205780rralphs		/* set the max physical address for iob allocs on x86 */
7480205780rralphs		st_alloc_attr.dma_attr_addr_hi = st_max_phys_addr;
7494ab7525mrj
7500205780rralphs		/*
7510205780rralphs		 * set the sgllen for iob allocs on x86. If this is set less
7520205780rralphs		 * than the number of pages the buffer will take
7530205780rralphs		 * (taking into account alignment), it would force the
7540205780rralphs		 * allocator to try and allocate contiguous pages.
7550205780rralphs		 */
7560205780rralphs		st_alloc_attr.dma_attr_sgllen = st_sgl_size;
7574ab7525mrj#endif
7580205780rralphs	}
7594ab7525mrj
7607c478bdstevel@tonic-gate	return (e);
7617c478bdstevel@tonic-gate}
7627c478bdstevel@tonic-gate
7637c478bdstevel@tonic-gateint
7647c478bdstevel@tonic-gate_fini(void)
7657c478bdstevel@tonic-gate{
7667c478bdstevel@tonic-gate	int e;
7677c478bdstevel@tonic-gate
7687c478bdstevel@tonic-gate	if ((e = mod_remove(&modlinkage)) != 0) {
7697c478bdstevel@tonic-gate		return (e);
7707c478bdstevel@tonic-gate	}
7717c478bdstevel@tonic-gate
7720205780rralphs#ifdef STDEBUG
7730205780rralphs	mutex_destroy(&st_debug_mutex);
7740205780rralphs#endif
7750205780rralphs
7767c478bdstevel@tonic-gate	ddi_soft_state_fini(&st_state);
7777c478bdstevel@tonic-gate
7787c478bdstevel@tonic-gate	return (e);
7797c478bdstevel@tonic-gate}
7807c478bdstevel@tonic-gate
7817c478bdstevel@tonic-gateint
7827c478bdstevel@tonic-gate_info(struct modinfo *modinfop)
7837c478bdstevel@tonic-gate{
7847c478bdstevel@tonic-gate	return (mod_info(&modlinkage, modinfop));
7857c478bdstevel@tonic-gate}
7867c478bdstevel@tonic-gate
7877c478bdstevel@tonic-gate
7887c478bdstevel@tonic-gatestatic int
7897c478bdstevel@tonic-gatest_probe(dev_info_t *devi)
7907c478bdstevel@tonic-gate{
7917c478bdstevel@tonic-gate	int instance;
7927c478bdstevel@tonic-gate	struct scsi_device *devp;
7937c478bdstevel@tonic-gate	int rval;
7947c478bdstevel@tonic-gate
7957c478bdstevel@tonic-gate#if !defined(__sparc)
7967c478bdstevel@tonic-gate	char    *tape_prop;
7977c478bdstevel@tonic-gate	int	tape_prop_len;
7987c478bdstevel@tonic-gate#endif
7997c478bdstevel@tonic-gate
800c6914c1rralphs	ST_ENTR(devi, st_probe);
801c6914c1rralphs
8027c478bdstevel@tonic-gate	/* If self identifying device */
8037c478bdstevel@tonic-gate	if (ddi_dev_is_sid(devi) == DDI_SUCCESS) {
8047c478bdstevel@tonic-gate		return (DDI_PROBE_DONTCARE);
8057c478bdstevel@tonic-gate	}
8067c478bdstevel@tonic-gate
8077c478bdstevel@tonic-gate#if !defined(__sparc)
8087c478bdstevel@tonic-gate	/*
8097c478bdstevel@tonic-gate	 * Since some x86 HBAs have devnodes that look like SCSI as
8107c478bdstevel@tonic-gate	 * far as we can tell but aren't really SCSI (DADK, like mlx)
8117c478bdstevel@tonic-gate	 * we check for the presence of the "tape" property.
8127c478bdstevel@tonic-gate	 */
8137c478bdstevel@tonic-gate	if (ddi_prop_op(DDI_DEV_T_NONE, devi, PROP_LEN_AND_VAL_ALLOC,
8147c478bdstevel@tonic-gate	    DDI_PROP_CANSLEEP, "tape",
8157c478bdstevel@tonic-gate	    (caddr_t)&tape_prop, &tape_prop_len) != DDI_PROP_SUCCESS) {
8167c478bdstevel@tonic-gate		return (DDI_PROBE_FAILURE);
8177c478bdstevel@tonic-gate	}
8187c478bdstevel@tonic-gate	if (strncmp(tape_prop, "sctp", tape_prop_len) != 0) {
8197c478bdstevel@tonic-gate		kmem_free(tape_prop, tape_prop_len);
8207c478bdstevel@tonic-gate		return (DDI_PROBE_FAILURE);
8217c478bdstevel@tonic-gate	}
8227c478bdstevel@tonic-gate	kmem_free(tape_prop, tape_prop_len);
8237c478bdstevel@tonic-gate#endif
8247c478bdstevel@tonic-gate
8257c478bdstevel@tonic-gate	devp = ddi_get_driver_private(devi);
8267c478bdstevel@tonic-gate	instance = ddi_get_instance(devi);
8277c478bdstevel@tonic-gate
8287c478bdstevel@tonic-gate	if (ddi_get_soft_state(st_state, instance) != NULL) {
8297c478bdstevel@tonic-gate		return (DDI_PROBE_PARTIAL);
8307c478bdstevel@tonic-gate	}
8317c478bdstevel@tonic-gate
8327c478bdstevel@tonic-gate
8337c478bdstevel@tonic-gate	/*
8347c478bdstevel@tonic-gate	 * Turn around and call probe routine to see whether
8357c478bdstevel@tonic-gate	 * we actually have a tape at this SCSI nexus.
8367c478bdstevel@tonic-gate	 */
8377c478bdstevel@tonic-gate	if (scsi_probe(devp, NULL_FUNC) == SCSIPROBE_EXISTS) {
8387c478bdstevel@tonic-gate
8397c478bdstevel@tonic-gate		/*
8407c478bdstevel@tonic-gate		 * In checking the whole inq_dtype byte we are looking at both
8417c478bdstevel@tonic-gate		 * the Peripheral Qualifier and the Peripheral Device Type.
8427c478bdstevel@tonic-gate		 * For this driver we are only interested in sequential devices
8437c478bdstevel@tonic-gate		 * that are connected or capable if connecting to this logical
8447c478bdstevel@tonic-gate		 * unit.
8457c478bdstevel@tonic-gate		 */
8467c478bdstevel@tonic-gate		if (devp->sd_inq->inq_dtype ==
8477c478bdstevel@tonic-gate		    (DTYPE_SEQUENTIAL | DPQ_POSSIBLE)) {
8487c478bdstevel@tonic-gate			ST_DEBUG6(devi, st_label, SCSI_DEBUG,
8497c478bdstevel@tonic-gate			    "probe exists\n");
8507c478bdstevel@tonic-gate			rval = DDI_PROBE_SUCCESS;
8517c478bdstevel@tonic-gate		} else {
8527c478bdstevel@tonic-gate			rval = DDI_PROBE_FAILURE;
8537c478bdstevel@tonic-gate		}
8547c478bdstevel@tonic-gate	} else {
8557c478bdstevel@tonic-gate		ST_DEBUG6(devi, st_label, SCSI_DEBUG,
8567c478bdstevel@tonic-gate		    "probe failure: nothing there\n");
8577c478bdstevel@tonic-gate		rval = DDI_PROBE_FAILURE;
8587c478bdstevel@tonic-gate	}
8597c478bdstevel@tonic-gate	scsi_unprobe(devp);
8607c478bdstevel@tonic-gate	return (rval);
8617c478bdstevel@tonic-gate}
8627c478bdstevel@tonic-gate
8637c478bdstevel@tonic-gatestatic int
8647c478bdstevel@tonic-gatest_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
8657c478bdstevel@tonic-gate{
8661ef1b39Toomas Soome	int	instance;
8677c478bdstevel@tonic-gate	int	wide;
8681ef1b39Toomas Soome	int	dev_instance;
8697c478bdstevel@tonic-gate	int	ret_status;
8707c478bdstevel@tonic-gate	struct	scsi_device *devp;
8717c478bdstevel@tonic-gate	int	node_ix;
8727c478bdstevel@tonic-gate	struct	scsi_tape *un;
8737c478bdstevel@tonic-gate
874c6914c1rralphs	ST_ENTR(devi, st_attach);
875c6914c1rralphs
8767c478bdstevel@tonic-gate	devp = ddi_get_driver_private(devi);
8777c478bdstevel@tonic-gate	instance = ddi_get_instance(devi);
8787c478bdstevel@tonic-gate
8797c478bdstevel@tonic-gate	switch (cmd) {
8807c478bdstevel@tonic-gate		case DDI_ATTACH:
881f218e94rralphs			if (ddi_getprop(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS,
882f218e94rralphs			    "tape-command-recovery-disable", 0) != 0) {
883f218e94rralphs				st_recov_sz = sizeof (pkt_info);
884f218e94rralphs			}
8857c478bdstevel@tonic-gate			if (st_doattach(devp, SLEEP_FUNC) == DDI_FAILURE) {
8867c478bdstevel@tonic-gate				return (DDI_FAILURE);
8877c478bdstevel@tonic-gate			}
8887c478bdstevel@tonic-gate			break;
8897c478bdstevel@tonic-gate		case DDI_RESUME:
8907c478bdstevel@tonic-gate			/*
8917c478bdstevel@tonic-gate			 * Suspend/Resume
8927c478bdstevel@tonic-gate			 *
8937c478bdstevel@tonic-gate			 * When the driver suspended, there might be
8947c478bdstevel@tonic-gate			 * outstanding cmds and therefore we need to
8957c478bdstevel@tonic-gate			 * reset the suspended flag and resume the scsi
8967c478bdstevel@tonic-gate			 * watch thread and restart commands and timeouts
8977c478bdstevel@tonic-gate			 */
8987c478bdstevel@tonic-gate
8997c478bdstevel@tonic-gate			if (!(un = ddi_get_soft_state(st_state, instance))) {
9007c478bdstevel@tonic-gate				return (DDI_FAILURE);
9017c478bdstevel@tonic-gate			}
9027c478bdstevel@tonic-gate			dev_instance = ((un->un_dev == 0) ? MTMINOR(instance) :
9037c478bdstevel@tonic-gate			    un->un_dev);
9047c478bdstevel@tonic-gate
9057c478bdstevel@tonic-gate			mutex_enter(ST_MUTEX);
9067c478bdstevel@tonic-gate
9077c478bdstevel@tonic-gate			un->un_throttle = un->un_max_throttle;
9087c478bdstevel@tonic-gate			un->un_tids_at_suspend = 0;
9097c478bdstevel@tonic-gate			un->un_pwr_mgmt = ST_PWR_NORMAL;
9107c478bdstevel@tonic-gate
9117c478bdstevel@tonic-gate			if (un->un_swr_token) {
9127c478bdstevel@tonic-gate				scsi_watch_resume(un->un_swr_token);
9137c478bdstevel@tonic-gate			}
9147c478bdstevel@tonic-gate
9157c478bdstevel@tonic-gate			/*
9167c478bdstevel@tonic-gate			 * Restart timeouts
9177c478bdstevel@tonic-gate			 */
9187c478bdstevel@tonic-gate			if ((un->un_tids_at_suspend & ST_DELAY_TID) != 0) {
9197c478bdstevel@tonic-gate				mutex_exit(ST_MUTEX);
920c6914c1rralphs				un->un_delay_tid = timeout(
921c6914c1rralphs				    st_delayed_cv_broadcast, un,
922c6914c1rralphs				    drv_usectohz((clock_t)
923c6914c1rralphs				    MEDIA_ACCESS_DELAY));
9247c478bdstevel@tonic-gate				mutex_enter(ST_MUTEX);
9257c478bdstevel@tonic-gate			}
9267c478bdstevel@tonic-gate
9277c478bdstevel@tonic-gate			if (un->un_tids_at_suspend & ST_HIB_TID) {
9287c478bdstevel@tonic-gate				mutex_exit(ST_MUTEX);
9297c478bdstevel@tonic-gate				un->un_hib_tid = timeout(st_intr_restart, un,
9307c478bdstevel@tonic-gate				    ST_STATUS_BUSY_TIMEOUT);
9317c478bdstevel@tonic-gate				mutex_enter(ST_MUTEX);
9327c478bdstevel@tonic-gate			}
9337c478bdstevel@tonic-gate
9347c478bdstevel@tonic-gate			ret_status = st_clear_unit_attentions(dev_instance, 5);
9357c478bdstevel@tonic-gate
9367c478bdstevel@tonic-gate			/*
9377c478bdstevel@tonic-gate			 * now check if we need to restore the tape position
9387c478bdstevel@tonic-gate			 */
939c6914c1rralphs			if ((un->un_suspend_pos.pmode != invalid) &&
940c6914c1rralphs			    ((un->un_suspend_pos.fileno > 0) ||
941c6914c1rralphs			    (un->un_suspend_pos.blkno > 0)) ||
942c6914c1rralphs			    (un->un_suspend_pos.lgclblkno > 0)) {
9437c478bdstevel@tonic-gate				if (ret_status != 0) {
9447c478bdstevel@tonic-gate					/*
9457c478bdstevel@tonic-gate					 * tape didn't get good TUR
9467c478bdstevel@tonic-gate					 * just print out error messages
9477c478bdstevel@tonic-gate					 */
9487c478bdstevel@tonic-gate					scsi_log(ST_DEVINFO, st_label, CE_WARN,
9497c478bdstevel@tonic-gate					    "st_attach-RESUME: tape failure "
9507c478bdstevel@tonic-gate					    " tape position will be lost");
9517c478bdstevel@tonic-gate				} else {
9527c478bdstevel@tonic-gate					/* this prints errors */
9537c478bdstevel@tonic-gate					(void) st_validate_tapemarks(un,
954f218e94rralphs					    st_uscsi_cmd, &un->un_suspend_pos);
9557c478bdstevel@tonic-gate				}
9567c478bdstevel@tonic-gate				/*
9577c478bdstevel@tonic-gate				 * there are no retries, if there is an error
9587c478bdstevel@tonic-gate				 * we don't know if the tape has changed
9597c478bdstevel@tonic-gate				 */
960c6914c1rralphs				un->un_suspend_pos.pmode = invalid;
9617c478bdstevel@tonic-gate			}
9627c478bdstevel@tonic-gate
9637c478bdstevel@tonic-gate			/* now we are ready to start up any queued I/Os */
9647c478bdstevel@tonic-gate			if (un->un_ncmds || un->un_quef) {
9656550f38rralphs				st_start(un);
9667c478bdstevel@tonic-gate			}
9677c478bdstevel@tonic-gate
9687c478bdstevel@tonic-gate			cv_broadcast(&un->un_suspend_cv);
9697c478bdstevel@tonic-gate			mutex_exit(ST_MUTEX);
9707c478bdstevel@tonic-gate			return (DDI_SUCCESS);
9717c478bdstevel@tonic-gate
9727c478bdstevel@tonic-gate		default:
9737c478bdstevel@tonic-gate			return (DDI_FAILURE);
9747c478bdstevel@tonic-gate	}
9757c478bdstevel@tonic-gate
9767c478bdstevel@tonic-gate	un = ddi_get_soft_state(st_state, instance);
9777c478bdstevel@tonic-gate
9787c478bdstevel@tonic-gate	ST_DEBUG(devi, st_label, SCSI_DEBUG,
9797c478bdstevel@tonic-gate	    "st_attach: instance=%x\n", instance);
9807c478bdstevel@tonic-gate
9817c478bdstevel@tonic-gate	/*
9827c478bdstevel@tonic-gate	 * Add a zero-length attribute to tell the world we support
9837c478bdstevel@tonic-gate	 * kernel ioctls (for layered drivers)
9847c478bdstevel@tonic-gate	 */
9857c478bdstevel@tonic-gate	(void) ddi_prop_create(DDI_DEV_T_NONE, devi, DDI_PROP_CANSLEEP,
9867c478bdstevel@tonic-gate	    DDI_KERNEL_IOCTL, NULL, 0);
9877c478bdstevel@tonic-gate
9887c478bdstevel@tonic-gate	ddi_report_dev((dev_info_t *)devi);
9897c478bdstevel@tonic-gate
9907c478bdstevel@tonic-gate	/*
9917c478bdstevel@tonic-gate	 * If it's a SCSI-2 tape drive which supports wide,
9927c478bdstevel@tonic-gate	 * tell the host adapter to use wide.
9937c478bdstevel@tonic-gate	 */
9947c478bdstevel@tonic-gate	wide = ((devp->sd_inq->inq_rdf == RDF_SCSI2) &&
995c6914c1rralphs	    (devp->sd_inq->inq_wbus16 || devp->sd_inq->inq_wbus32)) ?  1 : 0;
9967c478bdstevel@tonic-gate
9977c478bdstevel@tonic-gate	if (scsi_ifsetcap(ROUTE, "wide-xfer", wide, 1) == 1) {
9987c478bdstevel@tonic-gate		ST_DEBUG(devi, st_label, SCSI_DEBUG,
9997c478bdstevel@tonic-gate		    "Wide Transfer %s\n", wide ? "enabled" : "disabled");
10007c478bdstevel@tonic-gate	}
10017c478bdstevel@tonic-gate
10027c478bdstevel@tonic-gate	/*
10037c478bdstevel@tonic-gate	 * enable autorequest sense; keep the rq packet around in case
10047c478bdstevel@tonic-gate	 * the autorequest sense fails because of a busy condition
10057c478bdstevel@tonic-gate	 * do a getcap first in case the capability is not variable
10067c478bdstevel@tonic-gate	 */
10077c478bdstevel@tonic-gate	if (scsi_ifgetcap(ROUTE, "auto-rqsense", 1) == 1) {
10087c478bdstevel@tonic-gate		un->un_arq_enabled = 1;
10097c478bdstevel@tonic-gate	} else {
10107c478bdstevel@tonic-gate		un->un_arq_enabled =
10117c478bdstevel@tonic-gate		    ((scsi_ifsetcap(ROUTE, "auto-rqsense", 1, 1) == 1) ? 1 : 0);
10127c478bdstevel@tonic-gate	}
10137c478bdstevel@tonic-gate
10147c478bdstevel@tonic-gate	ST_DEBUG(devi, st_label, SCSI_DEBUG, "auto request sense %s\n",
1015c6914c1rralphs	    (un->un_arq_enabled ? "enabled" : "disabled"));
10167c478bdstevel@tonic-gate
10177c478bdstevel@tonic-gate	un->un_untagged_qing =
10187c478bdstevel@tonic-gate	    (scsi_ifgetcap(ROUTE, "untagged-qing", 0) == 1);
10197c478bdstevel@tonic-gate
10207c478bdstevel@tonic-gate	/*
10217c478bdstevel@tonic-gate	 * XXX - This is just for 2.6.  to tell users that write buffering
10227c478bdstevel@tonic-gate	 *	has gone away.
10237c478bdstevel@tonic-gate	 */
10247c478bdstevel@tonic-gate	if (un->un_arq_enabled && un->un_untagged_qing) {
10257c478bdstevel@tonic-gate		if (ddi_getprop(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS,
10267c478bdstevel@tonic-gate		    "tape-driver-buffering", 0) != 0) {
10277c478bdstevel@tonic-gate			scsi_log(ST_DEVINFO, st_label, CE_NOTE,
10287c478bdstevel@tonic-gate			    "Write Data Buffering has been depricated. Your "
10297c478bdstevel@tonic-gate			    "applications should continue to work normally.\n"
10307c478bdstevel@tonic-gate			    " But, they should  ported to use Asynchronous "
10317c478bdstevel@tonic-gate			    " I/O\n"
10327c478bdstevel@tonic-gate			    " For more information, read about "
10337c478bdstevel@tonic-gate			    " tape-driver-buffering "
10347c478bdstevel@tonic-gate			    "property in the st(7d) man page\n");
10357c478bdstevel@tonic-gate		}
10367c478bdstevel@tonic-gate	}
10377c478bdstevel@tonic-gate
10387c478bdstevel@tonic-gate	un->un_max_throttle = un->un_throttle = un->un_last_throttle = 1;
10397c478bdstevel@tonic-gate	un->un_flush_on_errors = 0;
10407c478bdstevel@tonic-gate	un->un_mkr_pkt = (struct scsi_pkt *)NULL;
10417c478bdstevel@tonic-gate
10427c478bdstevel@tonic-gate	ST_DEBUG(devi, st_label, SCSI_DEBUG,
10437c478bdstevel@tonic-gate	    "throttle=%x, max_throttle = %x\n",
10447c478bdstevel@tonic-gate	    un->un_throttle, un->un_max_throttle);
10457c478bdstevel@tonic-gate
10467c478bdstevel@tonic-gate	/* initialize persistent errors to nil */
10477c478bdstevel@tonic-gate	un->un_persistence = 0;
10487c478bdstevel@tonic-gate	un->un_persist_errors = 0;
10497c478bdstevel@tonic-gate
10507c478bdstevel@tonic-gate	/*
10517c478bdstevel@tonic-gate	 * Get dma-max from HBA driver. If it is not defined, use 64k
10527c478bdstevel@tonic-gate	 */
10537c478bdstevel@tonic-gate	un->un_maxdma	= scsi_ifgetcap(&devp->sd_address, "dma-max", 1);
10547c478bdstevel@tonic-gate	if (un->un_maxdma == -1) {
10555988135rralphs		ST_DEBUG(devi, st_label, SCSI_DEBUG,
1056c6914c1rralphs		    "Received a value that looked like -1. Using 64k maxdma");
1057c6914c1rralphs		un->un_maxdma = (64 * ONE_K);
10587c478bdstevel@tonic-gate	}
10597c478bdstevel@tonic-gate
106036945f7mrj#ifdef	__x86
106136945f7mrj	/*
106236945f7mrj	 * for x86, the device may be able to DMA more than the system will
106336945f7mrj	 * allow under some circumstances. We need account for both the HBA's
106436945f7mrj	 * and system's contraints.
106536945f7mrj	 *
106636945f7mrj	 * Get the maximum DMA under worse case conditions. e.g. looking at the
106736945f7mrj	 * device constraints, the max copy buffer size, and the worse case
106836945f7mrj	 * fragmentation. NOTE: this may differ from dma-max since dma-max
106936945f7mrj	 * doesn't take the worse case framentation into account.
107036945f7mrj	 *
107136945f7mrj	 * e.g. a device may be able to DMA 16MBytes, but can only DMA 1MByte
107236945f7mrj	 * if none of the pages are contiguous. Keeping track of both of these
107336945f7mrj	 * values allows us to support larger tape block sizes on some devices.
107436945f7mrj	 */
107536945f7mrj	un->un_maxdma_arch = scsi_ifgetcap(&devp->sd_address, "dma-max-arch",
107636945f7mrj	    1);
107736945f7mrj
107836945f7mrj	/*
107936945f7mrj	 * If the dma-max-arch capability is not implemented, or the value
108036945f7mrj	 * comes back higher than what was reported in dma-max, use dma-max.
108136945f7mrj	 */
108236945f7mrj	if ((un->un_maxdma_arch == -1) ||
108336945f7mrj	    ((uint_t)un->un_maxdma < (uint_t)un->un_maxdma_arch)) {
108436945f7mrj		un->un_maxdma_arch = un->un_maxdma;
108536945f7mrj	}
108636945f7mrj#endif
108736945f7mrj
10885988135rralphs	/*
10895988135rralphs	 * Get the max allowable cdb size
10905988135rralphs	 */
10915988135rralphs	un->un_max_cdb_sz =
10925988135rralphs	    scsi_ifgetcap(&devp->sd_address, "max-cdb-length", 1);
10935988135rralphs	if (un->un_max_cdb_sz < CDB_GROUP0) {
10945988135rralphs		ST_DEBUG(devi, st_label, SCSI_DEBUG,
10955988135rralphs		    "HBA reported max-cdb-length as %d\n", un->un_max_cdb_sz);
10965988135rralphs		un->un_max_cdb_sz = CDB_GROUP4; /* optimistic default */
10975988135rralphs	}
10985988135rralphs
10990205780rralphs	if (strcmp(ddi_driver_name(ddi_get_parent(ST_DEVINFO)), "scsi_vhci")) {
11000205780rralphs		un->un_multipath = 0;
11010205780rralphs	} else {
11020205780rralphs		un->un_multipath = 1;
11030205780rralphs	}
11040205780rralphs
11057c478bdstevel@tonic-gate	un->un_maxbsize = MAXBSIZE_UNKNOWN;
11067c478bdstevel@tonic-gate
11077c478bdstevel@tonic-gate	un->un_mediastate = MTIO_NONE;
11087c478bdstevel@tonic-gate	un->un_HeadClean  = TAPE_ALERT_SUPPORT_UNKNOWN;
11097c478bdstevel@tonic-gate
11107c478bdstevel@tonic-gate	/*
11117c478bdstevel@tonic-gate	 * initialize kstats
11127c478bdstevel@tonic-gate	 */
11137c478bdstevel@tonic-gate	un->un_stats = kstat_create("st", instance, NULL, "tape",
1114c6914c1rralphs	    KSTAT_TYPE_IO, 1, KSTAT_FLAG_PERSISTENT);
11157c478bdstevel@tonic-gate	if (un->un_stats) {
11167c478bdstevel@tonic-gate		un->un_stats->ks_lock = ST_MUTEX;
11177c478bdstevel@tonic-gate		kstat_install(un->un_stats);
11187c478bdstevel@tonic-gate	}
11197c478bdstevel@tonic-gate	(void) st_create_errstats(un, instance);
11207c478bdstevel@tonic-gate
11219f931dbyl	/*
11229f931dbyl	 * find the drive type for this target
11239f931dbyl	 */
11249f931dbyl	mutex_enter(ST_MUTEX);
1125602b746yl	un->un_dev = MTMINOR(instance);
11269f931dbyl	st_known_tape_type(un);
11279f931dbyl	un->un_dev = 0;
11289f931dbyl	mutex_exit(ST_MUTEX);
11299f931dbyl
11309f931dbyl	for (node_ix = 0; node_ix < ST_NUM_MEMBERS(st_minor_data); node_ix++) {
11319f931dbyl		int minor;
11329f931dbyl		char *name;
11339f931dbyl
11349f931dbyl		name  = st_minor_data[node_ix].name;
11359f931dbyl		minor = st_minor_data[node_ix].minor;
11369f931dbyl
11379f931dbyl		/*
11389f931dbyl		 * For default devices set the density to the
11399f931dbyl		 * preferred default density for this device.
11409f931dbyl		 */
11419f931dbyl		if (node_ix <= DEF_BSD_NR) {
11429f931dbyl			minor |= un->un_dp->default_density;
11439f931dbyl		}
11449f931dbyl		minor |= MTMINOR(instance);
11459f931dbyl
11469f931dbyl		if (ddi_create_minor_node(devi, name, S_IFCHR, minor,
11471adf40fToomas Soome		    DDI_NT_TAPE, 0) == DDI_SUCCESS) {
11489f931dbyl			continue;
11499f931dbyl		}
11509f931dbyl
11519f931dbyl		ddi_remove_minor_node(devi, NULL);
11529f931dbyl
1153f218e94rralphs		(void) scsi_reset_notify(ROUTE, SCSI_RESET_CANCEL,
1154f218e94rralphs		    st_reset_notification, (caddr_t)un);
11559f931dbyl		cv_destroy(&un->un_clscv);
11569f931dbyl		cv_destroy(&un->un_sbuf_cv);
11579f931dbyl		cv_destroy(&un->un_queue_cv);
11589f931dbyl		cv_destroy(&un->un_state_cv);
1159f218e94rralphs#ifdef	__x86
1160f218e94rralphs		cv_destroy(&un->un_contig_mem_cv);
1161f218e94rralphs#endif
11629f931dbyl		cv_destroy(&un->un_suspend_cv);
11639f931dbyl		cv_destroy(&un->un_tape_busy_cv);
1164f218e94rralphs		cv_destroy(&un->un_recov_buf_cv);
1165f218e94rralphs		if (un->un_recov_taskq) {
1166f218e94rralphs			ddi_taskq_destroy(un->un_recov_taskq);
1167f218e94rralphs		}
11689f931dbyl		if (un->un_sbufp) {
11699f931dbyl			freerbuf(un->un_sbufp);
11709f931dbyl		}
1171f218e94rralphs		if (un->un_recov_buf) {
1172f218e94rralphs			freerbuf(un->un_recov_buf);
1173f218e94rralphs		}
11749f931dbyl		if (un->un_uscsi_rqs_buf) {
11759f931dbyl			kmem_free(un->un_uscsi_rqs_buf, SENSE_LENGTH);
11769f931dbyl		}
11779f931dbyl		if (un->un_mspl) {
11789f931dbyl			i_ddi_mem_free((caddr_t)un->un_mspl, NULL);
11799f931dbyl		}
11809f931dbyl		if (un->un_dp_size) {
11819f931dbyl			kmem_free(un->un_dp, un->un_dp_size);
11829f931dbyl		}
11839f931dbyl		if (un->un_state) {
11849f931dbyl			kstat_delete(un->un_stats);
11859f931dbyl		}
11869f931dbyl		if (un->un_errstats) {
11879f931dbyl			kstat_delete(un->un_errstats);
11889f931dbyl		}
11899f931dbyl
11909f931dbyl		scsi_destroy_pkt(un->un_rqs);
11919f931dbyl		scsi_free_consistent_buf(un->un_rqs_bp);
11929f931dbyl		ddi_soft_state_free(st_state, instance);
11939f931dbyl		devp->sd_private = NULL;
11949f931dbyl		devp->sd_sense = NULL;
11959f931dbyl
11969f931dbyl		ddi_prop_remove_all(devi);
11979f931dbyl		return (DDI_FAILURE);
11989f931dbyl	}
11999f931dbyl
12007c478bdstevel@tonic-gate	return (DDI_SUCCESS);
12017c478bdstevel@tonic-gate}
12027c478bdstevel@tonic-gate
12037c478bdstevel@tonic-gate/*
12047c478bdstevel@tonic-gate * st_detach:
12057c478bdstevel@tonic-gate *
12067c478bdstevel@tonic-gate * we allow a detach if and only if:
12077c478bdstevel@tonic-gate *	- no tape is currently inserted
12087c478bdstevel@tonic-gate *	- tape position is at BOT or unknown
12097c478bdstevel@tonic-gate *		(if it is not at BOT then a no rewind
12107c478bdstevel@tonic-gate *		device was opened and we have to preserve state)
12117c478bdstevel@tonic-gate *	- it must be in a closed state : no timeouts or scsi_watch requests
12127c478bdstevel@tonic-gate *		will exist if it is closed, so we don't need to check for
12137c478bdstevel@tonic-gate *		them here.
12147c478bdstevel@tonic-gate */
12157c478bdstevel@tonic-gate/*ARGSUSED*/
12167c478bdstevel@tonic-gatestatic int
12177c478bdstevel@tonic-gatest_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
12187c478bdstevel@tonic-gate{
12190205780rralphs	int instance;
12200205780rralphs	int result;
12217c478bdstevel@tonic-gate	struct scsi_device *devp;
12227c478bdstevel@tonic-gate	struct scsi_tape *un;
12237c478bdstevel@tonic-gate	clock_t wait_cmds_complete;
12247c478bdstevel@tonic-gate
1225c6914c1rralphs	ST_ENTR(devi, st_detach);
1226c6914c1rralphs
12277c478bdstevel@tonic-gate	instance = ddi_get_instance(devi);
12287c478bdstevel@tonic-gate
12297c478bdstevel@tonic-gate	if (!(un = ddi_get_soft_state(st_state, instance))) {
12307c478bdstevel@tonic-gate		return (DDI_FAILURE);
12317c478bdstevel@tonic-gate	}
12327c478bdstevel@tonic-gate
12339edfcb9bz	mutex_enter(ST_MUTEX);
12349edfcb9bz
12359edfcb9bz	/*
12369edfcb9bz	 * Clear error entry stack
12379edfcb9bz	 */
12389edfcb9bz	st_empty_error_stack(un);
12399edfcb9bz
12409edfcb9bz	mutex_exit(ST_MUTEX);
12419edfcb9bz
12427c478bdstevel@tonic-gate	switch (cmd) {
12437c478bdstevel@tonic-gate
12447c478bdstevel@tonic-gate	case DDI_DETACH:
12457c478bdstevel@tonic-gate		/*
12467c478bdstevel@tonic-gate		 * Undo what we did in st_attach & st_doattach,
12477c478bdstevel@tonic-gate		 * freeing resources and removing things we installed.
12487c478bdstevel@tonic-gate		 * The system framework guarantees we are not active
12497c478bdstevel@tonic-gate		 * with this devinfo node in any other entry points at
12507c478bdstevel@tonic-gate		 * this time.
12517c478bdstevel@tonic-gate		 */
12527c478bdstevel@tonic-gate
12537c478bdstevel@tonic-gate		ST_DEBUG(ST_DEVINFO, st_label, SCSI_DEBUG,
12547c478bdstevel@tonic-gate		    "st_detach: instance=%x, un=%p\n", instance,
12557c478bdstevel@tonic-gate		    (void *)un);
12567c478bdstevel@tonic-gate
12577c478bdstevel@tonic-gate		if (((un->un_dp->options & ST_UNLOADABLE) == 0) ||
12580205780rralphs		    ((un->un_rsvd_status & ST_APPLICATION_RESERVATIONS) != 0) ||
12597c478bdstevel@tonic-gate		    (un->un_ncmds != 0) || (un->un_quef != NULL) ||
12607c478bdstevel@tonic-gate		    (un->un_state != ST_STATE_CLOSED)) {
12617c478bdstevel@tonic-gate			/*
12627c478bdstevel@tonic-gate			 * we cannot unload some targets because the
12637c478bdstevel@tonic-gate			 * inquiry returns junk unless immediately
12647c478bdstevel@tonic-gate			 * after a reset
12657c478bdstevel@tonic-gate			 */
12667c478bdstevel@tonic-gate			ST_DEBUG2(ST_DEVINFO, st_label, SCSI_DEBUG,
12677c478bdstevel@tonic-gate			    "cannot unload instance %x\n", instance);
12680205780rralphs			un->un_unit_attention_flags |= 4;
12697c478bdstevel@tonic-gate			return (DDI_FAILURE);
12707c478bdstevel@tonic-gate		}
12717c478bdstevel@tonic-gate
12727c478bdstevel@tonic-gate		/*
12737c478bdstevel@tonic-gate		 * if the tape has been removed then we may unload;
12747c478bdstevel@tonic-gate		 * do a test unit ready and if it returns NOT READY
12757c478bdstevel@tonic-gate		 * then we assume that it is safe to unload.
1276c6914c1rralphs		 * as a side effect, pmode may be set to invalid if the
12777c478bdstevel@tonic-gate		 * the test unit ready fails;
12787c478bdstevel@tonic-gate		 * also un_state may be set to non-closed, so reset it
12797c478bdstevel@tonic-gate		 */
12806550f38rralphs		if ((un->un_dev) &&		/* Been opened since attach */
1281c6914c1rralphs		    ((un->un_pos.pmode == legacy) &&
1282c6914c1rralphs		    (un->un_pos.fileno > 0) ||	/* Known position not rewound */
1283c6914c1rralphs		    (un->un_pos.blkno != 0)) ||	/* Or within first file */
1284c6914c1rralphs		    ((un->un_pos.pmode == logical) &&
1285c6914c1rralphs		    (un->un_pos.lgclblkno > 0))) {
12866550f38rralphs			mutex_enter(ST_MUTEX);
12877c478bdstevel@tonic-gate			/*
12886550f38rralphs			 * Send Test Unit Ready in the hopes that if
12896550f38rralphs			 * the drive is not in the state we think it is.
12906550f38rralphs			 * And the state will be changed so it can be detached.
12916550f38rralphs			 * If the command fails to reach the device and
12926550f38rralphs			 * the drive was not rewound or unloaded we want
12936550f38rralphs			 * to fail the detach till a user command fails
12946550f38rralphs			 * where after the detach will succead.
12957c478bdstevel@tonic-gate			 */
12960205780rralphs			result = st_cmd(un, SCMD_TEST_UNIT_READY, 0, SYNC_CMD);
12977c478bdstevel@tonic-gate			/*
12986550f38rralphs			 * After TUR un_state may be set to non-closed,
12996550f38rralphs			 * so reset it back.
13007c478bdstevel@tonic-gate			 */
13016550f38rralphs			un->un_state = ST_STATE_CLOSED;
13026550f38rralphs			mutex_exit(ST_MUTEX);
13036550f38rralphs		}
13046550f38rralphs		ST_DEBUG(ST_DEVINFO, st_label, SCSI_DEBUG,
1305c6914c1rralphs		    "un_status=%x, fileno=%x, blkno=%x\n",
1306c6914c1rralphs		    un->un_status, un->un_pos.fileno, un->un_pos.blkno);
13076550f38rralphs
13086550f38rralphs		/*
13096550f38rralphs		 * check again:
13106550f38rralphs		 * if we are not at BOT then it is not safe to unload
13116550f38rralphs		 */
13126550f38rralphs		if ((un->un_dev) &&		/* Been opened since attach */
13130205780rralphs		    (result != EACCES) &&	/* drive is use by somebody */
13142833b5brn		    ((((un->un_pos.pmode == legacy) &&
1315c6914c1rralphs		    (un->un_pos.fileno > 0) ||	/* Known position not rewound */
1316c6914c1rralphs		    (un->un_pos.blkno != 0)) ||	/* Or within first file */
1317c6914c1rralphs		    ((un->un_pos.pmode == logical) &&
13182833b5brn		    (un->un_pos.lgclblkno > 0))) &&
1319e7f6b7arn		    ((un->un_state == ST_STATE_CLOSED) &&
1320e7f6b7arn		    (un->un_laststate == ST_STATE_CLOSING)))) {
1321c6914c1rralphs
13226550f38rralphs			ST_DEBUG(ST_DEVINFO, st_label, SCSI_DEBUG,
1323f218e94rralphs			    "cannot detach: pmode=%d fileno=0x%x, blkno=0x%x"
1324c6914c1rralphs			    " lgclblkno=0x%"PRIx64"\n", un->un_pos.pmode,
1325c6914c1rralphs			    un->un_pos.fileno, un->un_pos.blkno,
1326c6914c1rralphs			    un->un_pos.lgclblkno);
13270205780rralphs			un->un_unit_attention_flags |= 4;
13286550f38rralphs			return (DDI_FAILURE);
13296550f38rralphs		}
13306550f38rralphs
13316550f38rralphs		/*
13326550f38rralphs		 * Just To make sure that we have released the
13336550f38rralphs		 * tape unit .
13346550f38rralphs		 */
13356550f38rralphs		if (un->un_dev && (un->un_rsvd_status & ST_RESERVE) &&
13366550f38rralphs		    !DEVI_IS_DEVICE_REMOVED(devi)) {
13376550f38rralphs			mutex_enter(ST_MUTEX);
1338f218e94rralphs			(void) st_reserve_release(un, ST_RELEASE, st_uscsi_cmd);
13396550f38rralphs			mutex_exit(ST_MUTEX);
13407c478bdstevel@tonic-gate		}
13417c478bdstevel@tonic-gate
13427c478bdstevel@tonic-gate		/*
13437c478bdstevel@tonic-gate		 * now remove other data structures allocated in st_doattach()
13447c478bdstevel@tonic-gate		 */
13457c478bdstevel@tonic-gate		ST_DEBUG(ST_DEVINFO, st_label, SCSI_DEBUG,
13467c478bdstevel@tonic-gate		    "destroying/freeing\n");
1347f218e94rralphs
1348f218e94rralphs		(void) scsi_reset_notify(ROUTE, SCSI_RESET_CANCEL,
1349f218e94rralphs		    st_reset_notification, (caddr_t)un);
13507c478bdstevel@tonic-gate		cv_destroy(&un->un_clscv);
13517c478bdstevel@tonic-gate		cv_destroy(&un->un_sbuf_cv);
13527c478bdstevel@tonic-gate		cv_destroy(&un->un_queue_cv);
13537c478bdstevel@tonic-gate		cv_destroy(&un->un_suspend_cv);
13547c478bdstevel@tonic-gate		cv_destroy(&un->un_tape_busy_cv);
1355f218e94rralphs		cv_destroy(&un->un_recov_buf_cv);
1356f218e94rralphs
1357f218e94rralphs		if (un->un_recov_taskq) {
1358f218e94rralphs			ddi_taskq_destroy(un->un_recov_taskq);
1359f218e94rralphs		}
13607c478bdstevel@tonic-gate
13617c478bdstevel@tonic-gate		if (un->un_hib_tid) {
13627c478bdstevel@tonic-gate			(void) untimeout(un->un_hib_tid);
13637c478bdstevel@tonic-gate			un->un_hib_tid = 0;
13647c478bdstevel@tonic-gate		}
13657c478bdstevel@tonic-gate
13667c478bdstevel@tonic-gate		if (un->un_delay_tid) {
13677c478bdstevel@tonic-gate			(void) untimeout(un->un_delay_tid);
13687c478bdstevel@tonic-gate			un->un_delay_tid = 0;
13697c478bdstevel@tonic-gate		}
13707c478bdstevel@tonic-gate		cv_destroy(&un->un_state_cv);
13717c478bdstevel@tonic-gate
137236945f7mrj#ifdef	__x86
1373f218e94rralphs		cv_destroy(&un->un_contig_mem_cv);
1374f218e94rralphs
1375f353171cz		if (un->un_contig_mem_hdl != NULL) {
1376f353171cz			ddi_dma_free_handle(&un->un_contig_mem_hdl);
1377f353171cz		}
1378f353171cz#endif
13797c478bdstevel@tonic-gate		if (un->un_sbufp) {
13807c478bdstevel@tonic-gate			freerbuf(un->un_sbufp);
13817c478bdstevel@tonic-gate		}
1382f218e94rralphs		if (un->un_recov_buf) {
1383f218e94rralphs			freerbuf(un->un_recov_buf);
1384f218e94rralphs		}
13857c478bdstevel@tonic-gate		if (un->un_uscsi_rqs_buf) {
13867c478bdstevel@tonic-gate			kmem_free(un->un_uscsi_rqs_buf, SENSE_LENGTH);
13877c478bdstevel@tonic-gate		}
13887c478bdstevel@tonic-gate		if (un->un_mspl) {
13897b93957eota			i_ddi_mem_free((caddr_t)un->un_mspl, NULL);
13907c478bdstevel@tonic-gate		}
13917c478bdstevel@tonic-gate		if (un->un_rqs) {
13927c478bdstevel@tonic-gate			scsi_destroy_pkt(un->un_rqs);
13937c478bdstevel@tonic-gate			scsi_free_consistent_buf(un->un_rqs_bp);
13947c478bdstevel@tonic-gate		}
13957c478bdstevel@tonic-gate		if (un->un_mkr_pkt) {
13967c478bdstevel@tonic-gate			scsi_destroy_pkt(un->un_mkr_pkt);
13977c478bdstevel@tonic-gate		}
13987c478bdstevel@tonic-gate		if (un->un_arq_enabled) {
13997c478bdstevel@tonic-gate			(void) scsi_ifsetcap(ROUTE, "auto-rqsense", 0, 1);
14007c478bdstevel@tonic-gate		}
14017c478bdstevel@tonic-gate		if (un->un_dp_size) {
14027c478bdstevel@tonic-gate			kmem_free(un->un_dp, un->un_dp_size);
14037c478bdstevel@tonic-gate		}
14047c478bdstevel@tonic-gate		if (un->un_stats) {
14057c478bdstevel@tonic-gate			kstat_delete(un->un_stats);
14067c478bdstevel@tonic-gate			un->un_stats = (kstat_t *)0;
14077c478bdstevel@tonic-gate		}
14087c478bdstevel@tonic-gate		if (un->un_errstats) {
14097c478bdstevel@tonic-gate			kstat_delete(un->un_errstats);
14107c478bdstevel@tonic-gate			un->un_errstats = (kstat_t *)0;
14117c478bdstevel@tonic-gate		}
1412f218e94rralphs		if (un->un_media_id_len) {
1413f218e94rralphs			kmem_free(un->un_media_id, un->un_media_id_len);
1414f218e94rralphs		}
14157c478bdstevel@tonic-gate		devp = ST_SCSI_DEVP;
14167c478bdstevel@tonic-gate		ddi_soft_state_free(st_state, instance);
14177c478bdstevel@tonic-gate		devp->sd_private = NULL;
14187c478bdstevel@tonic-gate		devp->sd_sense = NULL;
14197c478bdstevel@tonic-gate		scsi_unprobe(devp);
14207c478bdstevel@tonic-gate		ddi_prop_remove_all(devi);
14217c478bdstevel@tonic-gate		ddi_remove_minor_node(devi, NULL);
14227c478bdstevel@tonic-gate		ST_DEBUG(0, st_label, SCSI_DEBUG, "st_detach done\n");
14237c478bdstevel@tonic-gate		return (DDI_SUCCESS);
14247c478bdstevel@tonic-gate
14257c478bdstevel@tonic-gate	case DDI_SUSPEND:
14267c478bdstevel@tonic-gate
14277c478bdstevel@tonic-gate		/*
14287c478bdstevel@tonic-gate		 * Suspend/Resume
14297c478bdstevel@tonic-gate		 *
14307c478bdstevel@tonic-gate		 * To process DDI_SUSPEND, we must do the following:
14317c478bdstevel@tonic-gate		 *
14327c478bdstevel@tonic-gate		 *  - check ddi_removing_power to see if power will be turned
14337c478bdstevel@tonic-gate		 *    off. if so, return DDI_FAILURE
14347c478bdstevel@tonic-gate		 *  - check if we are already suspended,
14357c478bdstevel@tonic-gate		 *    if so, return DDI_FAILURE
14367c478bdstevel@tonic-gate		 *  - check if device state is CLOSED,
14377c478bdstevel@tonic-gate		 *    if not, return DDI_FAILURE.
14387c478bdstevel@tonic-gate		 *  - wait until outstanding operations complete
14397c478bdstevel@tonic-gate		 *  - save tape state
14407c478bdstevel@tonic-gate		 *  - block new operations
14417c478bdstevel@tonic-gate		 *  - cancel pending timeouts
14427c478bdstevel@tonic-gate		 *
14437c478bdstevel@tonic-gate		 */
14447c478bdstevel@tonic-gate
1445c6914c1rralphs		if (ddi_removing_power(devi)) {
14467c478bdstevel@tonic-gate			return (DDI_FAILURE);
1447c6914c1rralphs		}
1448ca6d4efbo zhou - Sun Microsystems - Beijing China
1449ca6d4efbo zhou - Sun Microsystems - Beijing China		if (un->un_dev == 0)
1450ca6d4efbo zhou - Sun Microsystems - Beijing China			un->un_dev = MTMINOR(instance);
1451ca6d4efbo zhou - Sun Microsystems - Beijing China
14527c478bdstevel@tonic-gate		mutex_enter(ST_MUTEX);
14537c478bdstevel@tonic-gate
14547c478bdstevel@tonic-gate		/*
14557c478bdstevel@tonic-gate		 * Shouldn't already be suspended, if so return failure
14567c478bdstevel@tonic-gate		 */
14577c478bdstevel@tonic-gate		if (un->un_pwr_mgmt == ST_PWR_SUSPENDED) {
14587c478bdstevel@tonic-gate			mutex_exit(ST_MUTEX);
14597c478bdstevel@tonic-gate			return (DDI_FAILURE);
14607c478bdstevel@tonic-gate		}
14617c478bdstevel@tonic-gate		if (un->un_state != ST_STATE_CLOSED) {
14627c478bdstevel@tonic-gate			mutex_exit(ST_MUTEX);
14637c478bdstevel@tonic-gate			return (DDI_FAILURE);
14647c478bdstevel@tonic-gate		}
14657c478bdstevel@tonic-gate
14667c478bdstevel@tonic-gate		/*
14677c478bdstevel@tonic-gate		 * Wait for all outstanding I/O's to complete
14687c478bdstevel@tonic-gate		 *
14697c478bdstevel@tonic-gate		 * we wait on both ncmds and the wait queue for times
14707c478bdstevel@tonic-gate		 * when we are flushing after persistent errors are
14717c478bdstevel@tonic-gate		 * flagged, which is when ncmds can be 0, and the
14727c478bdstevel@tonic-gate		 * queue can still have I/O's.  This way we preserve
14737c478bdstevel@tonic-gate		 * order of biodone's.
14747c478bdstevel@tonic-gate		 */
14757c478bdstevel@tonic-gate		wait_cmds_complete = ddi_get_lbolt();
14767c478bdstevel@tonic-gate		wait_cmds_complete +=
14777c478bdstevel@tonic-gate		    st_wait_cmds_complete * drv_usectohz(1000000);
14787c478bdstevel@tonic-gate		while (un->un_ncmds || un->un_quef ||
14797c478bdstevel@tonic-gate		    (un->un_state == ST_STATE_RESOURCE_WAIT)) {
14807c478bdstevel@tonic-gate
14817c478bdstevel@tonic-gate			if (cv_timedwait(&un->un_tape_busy_cv, ST_MUTEX,
14827c478bdstevel@tonic-gate			    wait_cmds_complete) == -1) {
14837c478bdstevel@tonic-gate				/*
14847c478bdstevel@tonic-gate				 * Time expired then cancel the command
14857c478bdstevel@tonic-gate				 */
1486f218e94rralphs				if (st_reset(un, RESET_LUN) == 0) {
14877c478bdstevel@tonic-gate					if (un->un_last_throttle) {
14887c478bdstevel@tonic-gate						un->un_throttle =
14897c478bdstevel@tonic-gate						    un->un_last_throttle;
14907c478bdstevel@tonic-gate					}
14917c478bdstevel@tonic-gate					mutex_exit(ST_MUTEX);
14927c478bdstevel@tonic-gate					return (DDI_FAILURE);
14937c478bdstevel@tonic-gate				} else {
14947c478bdstevel@tonic-gate					break;
14957c478bdstevel@tonic-gate				}
14967c478bdstevel@tonic-gate			}
14977c478bdstevel@tonic-gate		}
14987c478bdstevel@tonic-gate
14997c478bdstevel@tonic-gate		/*
15007c478bdstevel@tonic-gate		 * DDI_SUSPEND says that the system "may" power down, we
15017c478bdstevel@tonic-gate		 * remember the file and block number before rewinding.
15027c478bdstevel@tonic-gate		 * we also need to save state before issuing
15037c478bdstevel@tonic-gate		 * any WRITE_FILE_MARK command.
15047c478bdstevel@tonic-gate		 */
1505f218e94rralphs		(void) st_update_block_pos(un, st_cmd, 0);
1506