xref: /illumos-gate/usr/src/uts/common/io/scsi/targets/st.c (revision 0dcef4d4)
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
54ab75253Smrj  * Common Development and Distribution License (the "License").
64ab75253Smrj  * 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  */
214ab75253Smrj 
227c478bd9Sstevel@tonic-gate /*
2318d65520SDavid Major  *  Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
2489b43686SBayard Bell  *  Copyright (c) 2011 Bayard G. Bell. All rights reserved.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate /*
287c478bd9Sstevel@tonic-gate  * SCSI	 SCSA-compliant and not-so-DDI-compliant Tape Driver
297c478bd9Sstevel@tonic-gate  */
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate #if defined(lint) && !defined(DEBUG)
327c478bd9Sstevel@tonic-gate #define	DEBUG	1
337c478bd9Sstevel@tonic-gate #endif
347c478bd9Sstevel@tonic-gate 
357c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
367c478bd9Sstevel@tonic-gate #include <sys/scsi/scsi.h>
377c478bd9Sstevel@tonic-gate #include <sys/mtio.h>
387c478bd9Sstevel@tonic-gate #include <sys/scsi/targets/stdef.h>
397c478bd9Sstevel@tonic-gate #include <sys/file.h>
407c478bd9Sstevel@tonic-gate #include <sys/kstat.h>
41f3531714Scz #include <sys/ddidmareq.h>
42f3531714Scz #include <sys/ddi.h>
43f3531714Scz #include <sys/sunddi.h>
449f931db8Syl #include <sys/byteorder.h>
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate #define	IOSP	KSTAT_IO_PTR(un->un_stats)
477c478bd9Sstevel@tonic-gate /*
487c478bd9Sstevel@tonic-gate  * stats maintained only for reads/writes as commands
497c478bd9Sstevel@tonic-gate  * like rewind etc skew the wait/busy times
507c478bd9Sstevel@tonic-gate  */
511ef1b398SToomas Soome #define	IS_RW(bp)	((bp)->b_bcount > 0)
527c478bd9Sstevel@tonic-gate #define	ST_DO_KSTATS(bp, kstat_function) \
537c478bd9Sstevel@tonic-gate 	if ((bp != un->un_sbufp) && un->un_stats && IS_RW(bp)) { \
547c478bd9Sstevel@tonic-gate 		kstat_function(IOSP); \
557c478bd9Sstevel@tonic-gate 	}
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate #define	ST_DO_ERRSTATS(un, x)  \
587c478bd9Sstevel@tonic-gate 	if (un->un_errstats) { \
597c478bd9Sstevel@tonic-gate 		struct st_errstats *stp; \
607c478bd9Sstevel@tonic-gate 		stp = (struct st_errstats *)un->un_errstats->ks_data; \
617c478bd9Sstevel@tonic-gate 		stp->x.value.ul++; \
627c478bd9Sstevel@tonic-gate 	}
637c478bd9Sstevel@tonic-gate 
641ef1b398SToomas Soome #define	FILL_SCSI1_LUN(devp, pkt)					\
65f3f5a4ddSjongkis 	if ((devp)->sd_inq->inq_ansi == 0x1) {				\
66f3f5a4ddSjongkis 		int _lun;						\
67f3f5a4ddSjongkis 		_lun = ddi_prop_get_int(DDI_DEV_T_ANY, (devp)->sd_dev,	\
68f3f5a4ddSjongkis 		    DDI_PROP_DONTPASS, SCSI_ADDR_PROP_LUN, 0);		\
69f3f5a4ddSjongkis 		if (_lun > 0) {						\
70f3f5a4ddSjongkis 			((union scsi_cdb *)(pkt)->pkt_cdbp)->scc_lun =	\
71f3f5a4ddSjongkis 			    _lun;					\
72f3f5a4ddSjongkis 		}							\
737c478bd9Sstevel@tonic-gate 	}
747c478bd9Sstevel@tonic-gate 
75a7333962Scz /*
76a7333962Scz  * get an available contig mem header, cp.
77a7333962Scz  * when big_enough is true, we will return NULL, if no big enough
78a7333962Scz  * contig mem is found.
79a7333962Scz  * when big_enough is false, we will try to find cp containing big
80a7333962Scz  * enough contig mem. if not found, we will ruturn the last cp available.
81a7333962Scz  *
82a7333962Scz  * used by st_get_contig_mem()
83a7333962Scz  */
84a7333962Scz #define	ST_GET_CONTIG_MEM_HEAD(un, cp, len, big_enough) {		\
85a7333962Scz 	struct contig_mem *tmp_cp = NULL;				\
86a7333962Scz 	for ((cp) = (un)->un_contig_mem;				\
87a7333962Scz 	    (cp) != NULL;						\
881ef1b398SToomas Soome 	    tmp_cp = (cp), (cp) = (cp)->cm_next) {			\
891ef1b398SToomas Soome 		if (((cp)->cm_len >= (len)) ||				\
901ef1b398SToomas Soome 		    (!(big_enough) && ((cp)->cm_next == NULL))) {	\
911ef1b398SToomas Soome 			if (tmp_cp == NULL) {				\
921ef1b398SToomas Soome 				(un)->un_contig_mem = (cp)->cm_next;	\
931ef1b398SToomas Soome 			} else {					\
941ef1b398SToomas Soome 				tmp_cp->cm_next = (cp)->cm_next;	\
951ef1b398SToomas Soome 			}						\
961ef1b398SToomas Soome 			(cp)->cm_next = NULL;				\
971ef1b398SToomas Soome 			(un)->un_contig_mem_available_num--;		\
981ef1b398SToomas Soome 			break;						\
991ef1b398SToomas Soome 		}							\
1001ef1b398SToomas Soome 	}								\
101a7333962Scz }
102a7333962Scz 
1037c478bd9Sstevel@tonic-gate #define	ST_NUM_MEMBERS(array)	(sizeof (array) / sizeof (array[0]))
104c6914c10Srralphs #define	COPY_POS(dest, source) bcopy(source, dest, sizeof (tapepos_t))
105f218e94bSrralphs #define	ISALNUM(byte) \
106f218e94bSrralphs 	(((byte) >= 'a' && (byte) <= 'z') || \
107f218e94bSrralphs 	((byte) >= 'A' && (byte) <= 'Z') || \
108f218e94bSrralphs 	((byte) >= '0' && (byte) <= '9'))
109c6914c10Srralphs 
110c6914c10Srralphs #define	ONE_K	1024
1117c478bd9Sstevel@tonic-gate 
1120205780bSrralphs #define	MAX_SPACE_CNT(cnt) if (cnt >= 0) { \
1130205780bSrralphs 		if (cnt > MIN(SP_CNT_MASK, INT32_MAX)) \
1140205780bSrralphs 			return (EINVAL); \
1150205780bSrralphs 	} else { \
1160205780bSrralphs 		if (-(cnt) > MIN(SP_CNT_MASK, INT32_MAX)) \
1170205780bSrralphs 			return (EINVAL); \
1180205780bSrralphs 	} \
1190205780bSrralphs 
1207c478bd9Sstevel@tonic-gate /*
1217c478bd9Sstevel@tonic-gate  * Global External Data Definitions
1227c478bd9Sstevel@tonic-gate  */
1237c478bd9Sstevel@tonic-gate extern struct scsi_key_strings scsi_cmds[];
124c6914c10Srralphs extern uchar_t	scsi_cdb_size[];
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate /*
1277c478bd9Sstevel@tonic-gate  * Local Static Data
1287c478bd9Sstevel@tonic-gate  */
1297c478bd9Sstevel@tonic-gate static void *st_state;
130c6914c10Srralphs static char *const st_label = "st";
131f218e94bSrralphs static volatile int st_recov_sz = sizeof (recov_info);
1320205780bSrralphs static const char mp_misconf[] = {
1330205780bSrralphs 	"St Tape is misconfigured, MPxIO enabled and "
1340205780bSrralphs 	"tape-command-recovery-disable set in st.conf\n"
1350205780bSrralphs };
1367c478bd9Sstevel@tonic-gate 
13736945f79Smrj #ifdef	__x86
138f3531714Scz /*
139f3531714Scz  * We need to use below DMA attr to alloc physically contiguous
140f3531714Scz  * memory to do I/O in big block size
141f3531714Scz  */
142f3531714Scz static ddi_dma_attr_t st_contig_mem_dma_attr = {
143f3531714Scz 	DMA_ATTR_V0,    /* version number */
144f3531714Scz 	0x0,		/* lowest usable address */
145f3531714Scz 	0xFFFFFFFFull,  /* high DMA address range */
146f3531714Scz 	0xFFFFFFFFull,  /* DMA counter register */
147f3531714Scz 	1,		/* DMA address alignment */
148f3531714Scz 	1,		/* DMA burstsizes */
149f3531714Scz 	1,		/* min effective DMA size */
150f3531714Scz 	0xFFFFFFFFull,  /* max DMA xfer size */
151f3531714Scz 	0xFFFFFFFFull,  /* segment boundary */
152f3531714Scz 	1,		/* s/g list length */
153f3531714Scz 	1,		/* granularity of device */
154f3531714Scz 	0		/* DMA transfer flags */
155f3531714Scz };
156f3531714Scz 
157f3531714Scz static ddi_device_acc_attr_t st_acc_attr = {
158f3531714Scz 	DDI_DEVICE_ATTR_V0,
159f3531714Scz 	DDI_NEVERSWAP_ACC,
160f3531714Scz 	DDI_STRICTORDER_ACC
161f3531714Scz };
162f3531714Scz 
163f3531714Scz /* set limitation for the number of contig_mem */
164f3531714Scz static int st_max_contig_mem_num = ST_MAX_CONTIG_MEM_NUM;
165f3531714Scz #endif
166f3531714Scz 
1677c478bd9Sstevel@tonic-gate /*
1687c478bd9Sstevel@tonic-gate  * Tunable parameters
1697c478bd9Sstevel@tonic-gate  *
1707c478bd9Sstevel@tonic-gate  * DISCLAIMER
1717c478bd9Sstevel@tonic-gate  * ----------
1727c478bd9Sstevel@tonic-gate  * These parameters are intended for use only in system testing; if you use
1737c478bd9Sstevel@tonic-gate  * them in production systems, you do so at your own risk. Altering any
1747c478bd9Sstevel@tonic-gate  * variable not listed below may cause unpredictable system behavior.
1757c478bd9Sstevel@tonic-gate  *
1767c478bd9Sstevel@tonic-gate  * st_check_media_time
1777c478bd9Sstevel@tonic-gate  *
1787c478bd9Sstevel@tonic-gate  *   Three second state check
1797c478bd9Sstevel@tonic-gate  *
1807c478bd9Sstevel@tonic-gate  * st_allow_large_xfer
1817c478bd9Sstevel@tonic-gate  *
1827c478bd9Sstevel@tonic-gate  *   Gated with ST_NO_RECSIZE_LIMIT
1837c478bd9Sstevel@tonic-gate  *
1847c478bd9Sstevel@tonic-gate  *   0 - Transfers larger than 64KB will not be allowed
1857c478bd9Sstevel@tonic-gate  *       regardless of the setting of ST_NO_RECSIZE_LIMIT
1867c478bd9Sstevel@tonic-gate  *   1 - Transfers larger than 64KB will be allowed
1877c478bd9Sstevel@tonic-gate  *       if ST_NO_RECSIZE_LIMIT is TRUE for the drive
1887c478bd9Sstevel@tonic-gate  *
1897c478bd9Sstevel@tonic-gate  * st_report_soft_errors_on_close
1907c478bd9Sstevel@tonic-gate  *
1917c478bd9Sstevel@tonic-gate  *  Gated with ST_SOFT_ERROR_REPORTING
1927c478bd9Sstevel@tonic-gate  *
1937c478bd9Sstevel@tonic-gate  *  0 - Errors will not be reported on close regardless
1947c478bd9Sstevel@tonic-gate  *      of the setting of ST_SOFT_ERROR_REPORTING
1957c478bd9Sstevel@tonic-gate  *
1967c478bd9Sstevel@tonic-gate  *  1 - Errors will be reported on close if
1977c478bd9Sstevel@tonic-gate  *      ST_SOFT_ERROR_REPORTING is TRUE for the drive
1987c478bd9Sstevel@tonic-gate  */
1997c478bd9Sstevel@tonic-gate static int st_selection_retry_count = ST_SEL_RETRY_COUNT;
2007c478bd9Sstevel@tonic-gate static int st_retry_count	= ST_RETRY_COUNT;
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate static int st_io_time		= ST_IO_TIME;
2037c478bd9Sstevel@tonic-gate static int st_long_timeout_x	= ST_LONG_TIMEOUT_X;
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate static int st_space_time	= ST_SPACE_TIME;
2067c478bd9Sstevel@tonic-gate static int st_long_space_time_x	= ST_LONG_SPACE_TIME_X;
2077c478bd9Sstevel@tonic-gate 
2087c478bd9Sstevel@tonic-gate static int st_error_level	= SCSI_ERR_RETRYABLE;
2097c478bd9Sstevel@tonic-gate static int st_check_media_time	= 3000000;	/* 3 Second State Check */
2107c478bd9Sstevel@tonic-gate 
2117c478bd9Sstevel@tonic-gate static int st_max_throttle	= ST_MAX_THROTTLE;
2127c478bd9Sstevel@tonic-gate 
2137c478bd9Sstevel@tonic-gate static clock_t st_wait_cmds_complete = ST_WAIT_CMDS_COMPLETE;
2147c478bd9Sstevel@tonic-gate 
2157c478bd9Sstevel@tonic-gate static int st_allow_large_xfer = 1;
2167c478bd9Sstevel@tonic-gate static int st_report_soft_errors_on_close = 1;
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate /*
2197c478bd9Sstevel@tonic-gate  * End of tunable parameters list
2207c478bd9Sstevel@tonic-gate  */
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate 
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate /*
2257c478bd9Sstevel@tonic-gate  * Asynchronous I/O and persistent errors, refer to PSARC/1995/228
2267c478bd9Sstevel@tonic-gate  *
2277c478bd9Sstevel@tonic-gate  * Asynchronous I/O's main offering is that it is a non-blocking way to do
2287c478bd9Sstevel@tonic-gate  * reads and writes.  The driver will queue up all the requests it gets and
2297c478bd9Sstevel@tonic-gate  * have them ready to transport to the HBA.  Unfortunately, we cannot always
2307c478bd9Sstevel@tonic-gate  * just ship the I/O requests to the HBA, as there errors and exceptions
2317c478bd9Sstevel@tonic-gate  * that may happen when we don't want the HBA to continue.  Therein comes
2327c478bd9Sstevel@tonic-gate  * the flush-on-errors capability.  If the HBA supports it, then st will
2337c478bd9Sstevel@tonic-gate  * send in st_max_throttle I/O requests at the same time.
2347c478bd9Sstevel@tonic-gate  *
2357c478bd9Sstevel@tonic-gate  * Persistent errors : This was also reasonably simple.  In the interrupt
2367c478bd9Sstevel@tonic-gate  * routines, if there was an error or exception (FM, LEOT, media error,
2377c478bd9Sstevel@tonic-gate  * transport error), the persistent error bits are set and shuts everything
2387c478bd9Sstevel@tonic-gate  * down, but setting the throttle to zero.  If we hit and exception in the
2397c478bd9Sstevel@tonic-gate  * HBA, and flush-on-errors were set, we wait for all outstanding I/O's to
2407c478bd9Sstevel@tonic-gate  * come back (with CMD_ABORTED), then flush all bp's in the wait queue with
2417c478bd9Sstevel@tonic-gate  * the appropriate error, and this will preserve order. Of course, depending
2427c478bd9Sstevel@tonic-gate  * on the exception we have to show a zero read or write before we show
2437c478bd9Sstevel@tonic-gate  * errors back to the application.
2447c478bd9Sstevel@tonic-gate  */
2457c478bd9Sstevel@tonic-gate 
2467c478bd9Sstevel@tonic-gate extern const int st_ndrivetypes;	/* defined in st_conf.c */
2477c478bd9Sstevel@tonic-gate extern const struct st_drivetype st_drivetypes[];
248c6914c10Srralphs extern const char st_conf_version[];
2497c478bd9Sstevel@tonic-gate 
2507c478bd9Sstevel@tonic-gate #ifdef STDEBUG
2517c478bd9Sstevel@tonic-gate static int st_soft_error_report_debug = 0;
2525988135dSrralphs volatile int st_debug = 0;
2530205780bSrralphs static volatile dev_info_t *st_lastdev;
2540205780bSrralphs static kmutex_t st_debug_mutex;
2557c478bd9Sstevel@tonic-gate #endif
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate #define	ST_MT02_NAME	"Emulex  MT02 QIC-11/24  "
2587c478bd9Sstevel@tonic-gate 
2599f931db8Syl static const struct vid_drivetype {
2609f931db8Syl 	char	*vid;
2619f931db8Syl 	char	type;
2629f931db8Syl } st_vid_dt[] = {
2639f931db8Syl 	{"LTO-CVE ",	MT_LTO},
2649f931db8Syl 	{"QUANTUM ",    MT_ISDLT},
2659f931db8Syl 	{"SONY    ",    MT_ISAIT},
2669f931db8Syl 	{"STK     ",	MT_ISSTK9840}
2679f931db8Syl };
2689f931db8Syl 
2697c478bd9Sstevel@tonic-gate static const struct driver_minor_data {
2707c478bd9Sstevel@tonic-gate 	char	*name;
2717c478bd9Sstevel@tonic-gate 	int	minor;
2727c478bd9Sstevel@tonic-gate } st_minor_data[] = {
2737c478bd9Sstevel@tonic-gate 	/*
2747c478bd9Sstevel@tonic-gate 	 * The top 4 entries are for the default densities,
2757c478bd9Sstevel@tonic-gate 	 * don't alter their position.
2767c478bd9Sstevel@tonic-gate 	 */
2777c478bd9Sstevel@tonic-gate 	{"",	0},
2787c478bd9Sstevel@tonic-gate 	{"n",	MT_NOREWIND},
2797c478bd9Sstevel@tonic-gate 	{"b",	MT_BSD},
2807c478bd9Sstevel@tonic-gate 	{"bn",	MT_NOREWIND | MT_BSD},
2817c478bd9Sstevel@tonic-gate 	{"l",	MT_DENSITY1},
2827c478bd9Sstevel@tonic-gate 	{"m",	MT_DENSITY2},
2837c478bd9Sstevel@tonic-gate 	{"h",	MT_DENSITY3},
2847c478bd9Sstevel@tonic-gate 	{"c",	MT_DENSITY4},
2857c478bd9Sstevel@tonic-gate 	{"u",	MT_DENSITY4},
2867c478bd9Sstevel@tonic-gate 	{"ln",	MT_DENSITY1 | MT_NOREWIND},
2877c478bd9Sstevel@tonic-gate 	{"mn",	MT_DENSITY2 | MT_NOREWIND},
2887c478bd9Sstevel@tonic-gate 	{"hn",	MT_DENSITY3 | MT_NOREWIND},
2897c478bd9Sstevel@tonic-gate 	{"cn",	MT_DENSITY4 | MT_NOREWIND},
2907c478bd9Sstevel@tonic-gate 	{"un",	MT_DENSITY4 | MT_NOREWIND},
2917c478bd9Sstevel@tonic-gate 	{"lb",	MT_DENSITY1 | MT_BSD},
2927c478bd9Sstevel@tonic-gate 	{"mb",	MT_DENSITY2 | MT_BSD},
2937c478bd9Sstevel@tonic-gate 	{"hb",	MT_DENSITY3 | MT_BSD},
2947c478bd9Sstevel@tonic-gate 	{"cb",	MT_DENSITY4 | MT_BSD},
2957c478bd9Sstevel@tonic-gate 	{"ub",	MT_DENSITY4 | MT_BSD},
2967c478bd9Sstevel@tonic-gate 	{"lbn",	MT_DENSITY1 | MT_NOREWIND | MT_BSD},
2977c478bd9Sstevel@tonic-gate 	{"mbn",	MT_DENSITY2 | MT_NOREWIND | MT_BSD},
2987c478bd9Sstevel@tonic-gate 	{"hbn",	MT_DENSITY3 | MT_NOREWIND | MT_BSD},
2997c478bd9Sstevel@tonic-gate 	{"cbn",	MT_DENSITY4 | MT_NOREWIND | MT_BSD},
3007c478bd9Sstevel@tonic-gate 	{"ubn",	MT_DENSITY4 | MT_NOREWIND | MT_BSD}
3017c478bd9Sstevel@tonic-gate };
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate /* strings used in many debug and warning messages */
3047c478bd9Sstevel@tonic-gate static const char wr_str[]  = "write";
3057c478bd9Sstevel@tonic-gate static const char rd_str[]  = "read";
3067c478bd9Sstevel@tonic-gate static const char wrg_str[] = "writing";
3077c478bd9Sstevel@tonic-gate static const char rdg_str[] = "reading";
308c6914c10Srralphs static const char *space_strs[] = {
309c6914c10Srralphs 	"records",
310c6914c10Srralphs 	"filemarks",
311c6914c10Srralphs 	"sequential filemarks",
312c6914c10Srralphs 	"eod",
313c6914c10Srralphs 	"setmarks",
314c6914c10Srralphs 	"sequential setmarks",
315c6914c10Srralphs 	"Reserved",
316c6914c10Srralphs 	"Reserved"
317c6914c10Srralphs };
318f218e94bSrralphs static const char *load_strs[] = {
319f218e94bSrralphs 	"unload",		/* LD_UNLOAD		0 */
320f218e94bSrralphs 	"load",			/* LD_LOAD		1 */
321f218e94bSrralphs 	"retension",		/* LD_RETEN		2 */
322f218e94bSrralphs 	"load reten",		/* LD_LOAD | LD_RETEN	3 */
323f218e94bSrralphs 	"eod",			/* LD_EOT		4 */
324f218e94bSrralphs 	"load EOD",		/* LD_LOAD | LD_EOT	5 */
325f218e94bSrralphs 	"reten EOD",		/* LD_RETEN | LD_EOT	6 */
326f218e94bSrralphs 	"load reten EOD"	/* LD_LOAD|LD_RETEN|LD_EOT 7 */
327f218e94bSrralphs 	"hold",			/* LD_HOLD		8 */
328f218e94bSrralphs 	"load and hold"		/* LD_LOAD | LD_HOLD	9 */
329f218e94bSrralphs };
330f218e94bSrralphs 
3310205780bSrralphs static const char *errstatenames[] = {
3320205780bSrralphs 	"COMMAND_DONE",
3330205780bSrralphs 	"COMMAND_DONE_ERROR",
3340205780bSrralphs 	"COMMAND_DONE_ERROR_RECOVERED",
3350205780bSrralphs 	"QUE_COMMAND",
3360205780bSrralphs 	"QUE_BUSY_COMMAND",
3370205780bSrralphs 	"QUE_SENSE",
3380205780bSrralphs 	"JUST_RETURN",
3390205780bSrralphs 	"COMMAND_DONE_EACCES",
3400205780bSrralphs 	"QUE_LAST_COMMAND",
3410205780bSrralphs 	"COMMAND_TIMEOUT",
3420205780bSrralphs 	"PATH_FAILED",
3430205780bSrralphs 	"DEVICE_RESET",
3440205780bSrralphs 	"DEVICE_TAMPER",
3450205780bSrralphs 	"ATTEMPT_RETRY"
3460205780bSrralphs };
3470205780bSrralphs 
348f218e94bSrralphs const char *bogusID = "Unknown Media ID";
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate /* default density offsets in the table above */
3517c478bd9Sstevel@tonic-gate #define	DEF_BLANK	0
3527c478bd9Sstevel@tonic-gate #define	DEF_NOREWIND	1
3537c478bd9Sstevel@tonic-gate #define	DEF_BSD		2
3547c478bd9Sstevel@tonic-gate #define	DEF_BSD_NR	3
3557c478bd9Sstevel@tonic-gate 
3567c478bd9Sstevel@tonic-gate /* Sense Key, ASC/ASCQ for which tape ejection is needed */
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate static struct tape_failure_code {
3597c478bd9Sstevel@tonic-gate 	uchar_t key;
3607c478bd9Sstevel@tonic-gate 	uchar_t add_code;
3617c478bd9Sstevel@tonic-gate 	uchar_t qual_code;
3627c478bd9Sstevel@tonic-gate } st_tape_failure_code[] = {
3637c478bd9Sstevel@tonic-gate 	{ KEY_HARDWARE_ERROR, 0x15, 0x01},
3647c478bd9Sstevel@tonic-gate 	{ KEY_HARDWARE_ERROR, 0x44, 0x00},
3657c478bd9Sstevel@tonic-gate 	{ KEY_HARDWARE_ERROR, 0x53, 0x00},
3667c478bd9Sstevel@tonic-gate 	{ KEY_HARDWARE_ERROR, 0x53, 0x01},
3677c478bd9Sstevel@tonic-gate 	{ KEY_NOT_READY, 0x53, 0x00},
3687c478bd9Sstevel@tonic-gate 	{ 0xff}
3697c478bd9Sstevel@tonic-gate };
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate /*  clean bit position and mask */
3727c478bd9Sstevel@tonic-gate 
3737c478bd9Sstevel@tonic-gate static struct cln_bit_position {
3747c478bd9Sstevel@tonic-gate 	ushort_t cln_bit_byte;
3757c478bd9Sstevel@tonic-gate 	uchar_t cln_bit_mask;
3767c478bd9Sstevel@tonic-gate } st_cln_bit_position[] = {
3777c478bd9Sstevel@tonic-gate 	{ 21, 0x08},
3787c478bd9Sstevel@tonic-gate 	{ 70, 0xc0},
3797c478bd9Sstevel@tonic-gate 	{ 18, 0x81}  /* 80 bit indicates in bit mode, 1 bit clean light is on */
3807c478bd9Sstevel@tonic-gate };
3817c478bd9Sstevel@tonic-gate 
3824ab75253Smrj /*
3834ab75253Smrj  * architecture dependent allocation restrictions. For x86, we'll set
3844ab75253Smrj  * dma_attr_addr_hi to st_max_phys_addr and dma_attr_sgllen to
3854ab75253Smrj  * st_sgl_size during _init().
3864ab75253Smrj  */
3874ab75253Smrj #if defined(__sparc)
3884ab75253Smrj static ddi_dma_attr_t st_alloc_attr = {
3894ab75253Smrj 	DMA_ATTR_V0,	/* version number */
3904ab75253Smrj 	0x0,		/* lowest usable address */
3914ab75253Smrj 	0xFFFFFFFFull,	/* high DMA address range */
3924ab75253Smrj 	0xFFFFFFFFull,	/* DMA counter register */
3934ab75253Smrj 	1,		/* DMA address alignment */
3944ab75253Smrj 	1,		/* DMA burstsizes */
3954ab75253Smrj 	1,		/* min effective DMA size */
3964ab75253Smrj 	0xFFFFFFFFull,	/* max DMA xfer size */
3974ab75253Smrj 	0xFFFFFFFFull,	/* segment boundary */
3984ab75253Smrj 	1,		/* s/g list length */
3994ab75253Smrj 	512,		/* granularity of device */
4004ab75253Smrj 	0		/* DMA transfer flags */
4014ab75253Smrj };
4024ab75253Smrj #elif defined(__x86)
4034ab75253Smrj static ddi_dma_attr_t st_alloc_attr = {
4044ab75253Smrj 	DMA_ATTR_V0,	/* version number */
4054ab75253Smrj 	0x0,		/* lowest usable address */
4064ab75253Smrj 	0x0,		/* high DMA address range [set in _init()] */
4074ab75253Smrj 	0xFFFFull,	/* DMA counter register */
4084ab75253Smrj 	512,		/* DMA address alignment */
4094ab75253Smrj 	1,		/* DMA burstsizes */
4104ab75253Smrj 	1,		/* min effective DMA size */
4114ab75253Smrj 	0xFFFFFFFFull,	/* max DMA xfer size */
4124ab75253Smrj 	0xFFFFFFFFull,  /* segment boundary */
4134ab75253Smrj 	0,		/* s/g list length */
4144ab75253Smrj 	512,		/* granularity of device [set in _init()] */
4154ab75253Smrj 	0		/* DMA transfer flags */
4164ab75253Smrj };
4174ab75253Smrj uint64_t st_max_phys_addr = 0xFFFFFFFFull;
4184ab75253Smrj int st_sgl_size = 0xF;
4194ab75253Smrj 
4204ab75253Smrj #endif
4214ab75253Smrj 
4227c478bd9Sstevel@tonic-gate /*
4237c478bd9Sstevel@tonic-gate  * Configuration Data:
4247c478bd9Sstevel@tonic-gate  *
4257c478bd9Sstevel@tonic-gate  * Device driver ops vector
4267c478bd9Sstevel@tonic-gate  */
4277c478bd9Sstevel@tonic-gate static int st_aread(dev_t dev, struct aio_req *aio, cred_t *cred_p);
4287c478bd9Sstevel@tonic-gate static int st_awrite(dev_t dev, struct aio_req *aio, cred_t *cred_p);
4297c478bd9Sstevel@tonic-gate static int st_read(dev_t  dev,  struct   uio   *uio_p,   cred_t *cred_p);
4307c478bd9Sstevel@tonic-gate static int st_write(dev_t  dev,  struct  uio   *uio_p,   cred_t *cred_p);
4317c478bd9Sstevel@tonic-gate static int st_open(dev_t  *devp,  int  flag,  int  otyp,  cred_t *cred_p);
4327c478bd9Sstevel@tonic-gate static int st_close(dev_t  dev,  int  flag,  int  otyp,  cred_t *cred_p);
4337c478bd9Sstevel@tonic-gate static int st_strategy(struct buf *bp);
434f218e94bSrralphs static int st_queued_strategy(buf_t *bp);
4357c478bd9Sstevel@tonic-gate static int st_ioctl(dev_t dev, int cmd, intptr_t arg, int  flag,
4367c478bd9Sstevel@tonic-gate 	cred_t *cred_p, int *rval_p);
4377c478bd9Sstevel@tonic-gate extern int nulldev(), nodev();
4387c478bd9Sstevel@tonic-gate 
4397c478bd9Sstevel@tonic-gate static struct cb_ops st_cb_ops = {
440c6914c10Srralphs 	st_open,		/* open */
4417c478bd9Sstevel@tonic-gate 	st_close,		/* close */
442f218e94bSrralphs 	st_queued_strategy,	/* strategy Not Block device but async checks */
4437c478bd9Sstevel@tonic-gate 	nodev,			/* print */
4447c478bd9Sstevel@tonic-gate 	nodev,			/* dump */
4457c478bd9Sstevel@tonic-gate 	st_read,		/* read */
4467c478bd9Sstevel@tonic-gate 	st_write,		/* write */
4477c478bd9Sstevel@tonic-gate 	st_ioctl,		/* ioctl */
4487c478bd9Sstevel@tonic-gate 	nodev,			/* devmap */
4497c478bd9Sstevel@tonic-gate 	nodev,			/* mmap */
4507c478bd9Sstevel@tonic-gate 	nodev,			/* segmap */
4517c478bd9Sstevel@tonic-gate 	nochpoll,		/* poll */
4527c478bd9Sstevel@tonic-gate 	ddi_prop_op,		/* cb_prop_op */
4537c478bd9Sstevel@tonic-gate 	0,			/* streamtab  */
454e099bf07Scth 	D_64BIT | D_MP | D_NEW | D_HOTPLUG |
455e099bf07Scth 	D_OPEN_RETURNS_EINTR,	/* cb_flag */
4567c478bd9Sstevel@tonic-gate 	CB_REV,			/* cb_rev */
4571ef1b398SToomas Soome 	st_aread,		/* async I/O read entry point */
4587c478bd9Sstevel@tonic-gate 	st_awrite		/* async I/O write entry point */
4597c478bd9Sstevel@tonic-gate 
4607c478bd9Sstevel@tonic-gate };
4617c478bd9Sstevel@tonic-gate 
462f218e94bSrralphs static int st_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
4637c478bd9Sstevel@tonic-gate 		void **result);
4647c478bd9Sstevel@tonic-gate static int st_probe(dev_info_t *dev);
4657c478bd9Sstevel@tonic-gate static int st_attach(dev_info_t *dev, ddi_attach_cmd_t cmd);
4667c478bd9Sstevel@tonic-gate static int st_detach(dev_info_t *dev, ddi_detach_cmd_t cmd);
4677c478bd9Sstevel@tonic-gate 
4687c478bd9Sstevel@tonic-gate static struct dev_ops st_ops = {
4697c478bd9Sstevel@tonic-gate 	DEVO_REV,		/* devo_rev, */
4707c478bd9Sstevel@tonic-gate 	0,			/* refcnt  */
471f218e94bSrralphs 	st_info,		/* info */
4727c478bd9Sstevel@tonic-gate 	nulldev,		/* identify */
4737c478bd9Sstevel@tonic-gate 	st_probe,		/* probe */
4747c478bd9Sstevel@tonic-gate 	st_attach,		/* attach */
4757c478bd9Sstevel@tonic-gate 	st_detach,		/* detach */
4767c478bd9Sstevel@tonic-gate 	nodev,			/* reset */
4777c478bd9Sstevel@tonic-gate 	&st_cb_ops,		/* driver operations */
4787c478bd9Sstevel@tonic-gate 	(struct bus_ops *)0,	/* bus operations */
47919397407SSherry Moore 	nulldev,		/* power */
4808bef02c3Sbo zhou - Sun Microsystems - Beijing China 	ddi_quiesce_not_needed,	/* devo_quiesce */
4817c478bd9Sstevel@tonic-gate };
4827c478bd9Sstevel@tonic-gate 
4837c478bd9Sstevel@tonic-gate /*
4847c478bd9Sstevel@tonic-gate  * Local Function Declarations
4857c478bd9Sstevel@tonic-gate  */
486c6914c10Srralphs static char *st_print_scsi_cmd(char cmd);
487c6914c10Srralphs static void st_print_cdb(dev_info_t *dip, char *label, uint_t level,
488c6914c10Srralphs     char *title, char *cdb);
4897c478bd9Sstevel@tonic-gate static void st_clean_print(dev_info_t *dev, char *label, uint_t level,
490f218e94bSrralphs     char *title, char *data, int len);
4917c478bd9Sstevel@tonic-gate static int st_doattach(struct scsi_device *devp, int (*canwait)());
4927c478bd9Sstevel@tonic-gate static void st_known_tape_type(struct scsi_tape *un);
4937c478bd9Sstevel@tonic-gate static int st_get_conf_from_st_dot_conf(struct scsi_tape *, char *,
4947c478bd9Sstevel@tonic-gate     struct st_drivetype *);
4957c478bd9Sstevel@tonic-gate static int st_get_conf_from_st_conf_dot_c(struct scsi_tape *, char *,
4967c478bd9Sstevel@tonic-gate     struct st_drivetype *);
4979f931db8Syl static int st_get_conf_from_tape_drive(struct scsi_tape *, char *,
4989f931db8Syl     struct st_drivetype *);
4999f931db8Syl static int st_get_densities_from_tape_drive(struct scsi_tape *,
5009f931db8Syl     struct st_drivetype *);
5019f931db8Syl static int st_get_timeout_values_from_tape_drive(struct scsi_tape *,
5029f931db8Syl     struct st_drivetype *);
5039f931db8Syl static int st_get_timeouts_value(struct scsi_tape *, uchar_t, ushort_t *,
5049f931db8Syl     ushort_t);
5057c478bd9Sstevel@tonic-gate static int st_get_default_conf(struct scsi_tape *, char *,
5067c478bd9Sstevel@tonic-gate     struct st_drivetype *);
5077c478bd9Sstevel@tonic-gate static int st_rw(dev_t dev, struct uio *uio, int flag);
5087c478bd9Sstevel@tonic-gate static int st_arw(dev_t dev, struct aio_req *aio, int flag);
509f218e94bSrralphs static int st_find_eod(struct scsi_tape *un);
5107c478bd9Sstevel@tonic-gate static int st_check_density_or_wfm(dev_t dev, int wfm, int mode, int stepflag);
511f218e94bSrralphs static int st_uscsi_cmd(struct scsi_tape *un, struct uscsi_cmd *, int flag);
5127c478bd9Sstevel@tonic-gate static int st_mtioctop(struct scsi_tape *un, intptr_t arg, int flag);
513c6914c10Srralphs static int st_mtiocltop(struct scsi_tape *un, intptr_t arg, int flag);
514c6914c10Srralphs static int st_do_mtioctop(struct scsi_tape *un, struct mtlop *mtop);
5156550f384Srralphs static void st_start(struct scsi_tape *un);
5167c478bd9Sstevel@tonic-gate static int st_handle_start_busy(struct scsi_tape *un, struct buf *bp,
517f218e94bSrralphs     clock_t timeout_interval, int queued);
5187c478bd9Sstevel@tonic-gate static int st_handle_intr_busy(struct scsi_tape *un, struct buf *bp,
5197c478bd9Sstevel@tonic-gate     clock_t timeout_interval);
5207c478bd9Sstevel@tonic-gate static int st_handle_intr_retry_lcmd(struct scsi_tape *un, struct buf *bp);
5217c478bd9Sstevel@tonic-gate static void st_done_and_mutex_exit(struct scsi_tape *un, struct buf *bp);
5227c478bd9Sstevel@tonic-gate static void st_init(struct scsi_tape *un);
5237c478bd9Sstevel@tonic-gate static void st_make_cmd(struct scsi_tape *un, struct buf *bp,
5246550f384Srralphs     int (*func)(caddr_t));
5257c478bd9Sstevel@tonic-gate static void st_make_uscsi_cmd(struct scsi_tape *, struct uscsi_cmd *,
5266550f384Srralphs     struct buf *bp, int (*func)(caddr_t));
5277c478bd9Sstevel@tonic-gate static void st_intr(struct scsi_pkt *pkt);
528f218e94bSrralphs static void st_set_state(struct scsi_tape *un, buf_t *bp);
5297c478bd9Sstevel@tonic-gate static void st_test_append(struct buf *bp);
5306550f384Srralphs static int st_runout(caddr_t);
531f218e94bSrralphs static int st_cmd(struct scsi_tape *un, int com, int64_t count, int wait);
532f218e94bSrralphs static int st_setup_cmd(struct scsi_tape *un, buf_t *bp, int com,
533f218e94bSrralphs     int64_t count);
5347c478bd9Sstevel@tonic-gate static int st_set_compression(struct scsi_tape *un);
5357c478bd9Sstevel@tonic-gate static int st_write_fm(dev_t dev, int wfm);
536f218e94bSrralphs static int st_determine_generic(struct scsi_tape *un);
537f218e94bSrralphs static int st_determine_density(struct scsi_tape *un, int rw);
538f218e94bSrralphs static int st_get_density(struct scsi_tape *un);
539f218e94bSrralphs static int st_set_density(struct scsi_tape *un);
540f218e94bSrralphs static int st_loadtape(struct scsi_tape *un);
5417c478bd9Sstevel@tonic-gate static int st_modesense(struct scsi_tape *un);
5427c478bd9Sstevel@tonic-gate static int st_modeselect(struct scsi_tape *un);
543f218e94bSrralphs static errstate st_handle_incomplete(struct scsi_tape *un, struct buf *bp);
5447c478bd9Sstevel@tonic-gate static int st_wrongtapetype(struct scsi_tape *un);
545f218e94bSrralphs static errstate st_check_error(struct scsi_tape *un, struct scsi_pkt *pkt);
546f218e94bSrralphs static errstate st_handle_sense(struct scsi_tape *un, struct buf *bp,
547f218e94bSrralphs     tapepos_t *);
548f218e94bSrralphs static errstate st_handle_autosense(struct scsi_tape *un, struct buf *bp,
549f218e94bSrralphs     tapepos_t *);
550fa4c0ec8Sbz static int st_get_error_entry(struct scsi_tape *un, intptr_t arg, int flag);
551fa4c0ec8Sbz static void st_update_error_stack(struct scsi_tape *un, struct scsi_pkt *pkt,
552fa4c0ec8Sbz     struct scsi_arq_status *cmd);
553fa4c0ec8Sbz static void st_empty_error_stack(struct scsi_tape *un);
554f218e94bSrralphs static errstate st_decode_sense(struct scsi_tape *un, struct buf *bp, int amt,
5550205780bSrralphs     struct scsi_arq_status *, tapepos_t *);
5567c478bd9Sstevel@tonic-gate static int st_report_soft_errors(dev_t dev, int flag);
5577c478bd9Sstevel@tonic-gate static void st_delayed_cv_broadcast(void *arg);
5587c478bd9Sstevel@tonic-gate static int st_check_media(dev_t dev, enum mtio_state state);
5597c478bd9Sstevel@tonic-gate static int st_media_watch_cb(caddr_t arg, struct scsi_watch_result *resultp);
5607c478bd9Sstevel@tonic-gate static void st_intr_restart(void *arg);
5617c478bd9Sstevel@tonic-gate static void st_start_restart(void *arg);
562f218e94bSrralphs static int st_gen_mode_sense(struct scsi_tape *un, ubufunc_t ubf, int page,
563f218e94bSrralphs     struct seq_mode *page_data, int page_size);
564f218e94bSrralphs static int st_change_block_size(struct scsi_tape *un, uint32_t nblksz);
565f218e94bSrralphs static int st_gen_mode_select(struct scsi_tape *un, ubufunc_t ubf,
5667c478bd9Sstevel@tonic-gate     struct seq_mode *page_data, int page_size);
5679f931db8Syl static int st_read_block_limits(struct scsi_tape *un,
5689f931db8Syl     struct read_blklim *read_blk);
5699f931db8Syl static int st_report_density_support(struct scsi_tape *un,
5709f931db8Syl     uchar_t *density_data, size_t buflen);
5719f931db8Syl static int st_report_supported_operation(struct scsi_tape *un,
5729f931db8Syl     uchar_t *oper_data, uchar_t option_code, ushort_t service_action);
573f218e94bSrralphs static int st_tape_init(struct scsi_tape *un);
5747c478bd9Sstevel@tonic-gate static void st_flush(struct scsi_tape *un);
5757c478bd9Sstevel@tonic-gate static void st_set_pe_errno(struct scsi_tape *un);
5767c478bd9Sstevel@tonic-gate static void st_hba_unflush(struct scsi_tape *un);
5777c478bd9Sstevel@tonic-gate static void st_turn_pe_on(struct scsi_tape *un);
5787c478bd9Sstevel@tonic-gate static void st_turn_pe_off(struct scsi_tape *un);
5797c478bd9Sstevel@tonic-gate static void st_set_pe_flag(struct scsi_tape *un);
5807c478bd9Sstevel@tonic-gate static void st_clear_pe(struct scsi_tape *un);
5817c478bd9Sstevel@tonic-gate static void st_wait_for_io(struct scsi_tape *un);
5827c478bd9Sstevel@tonic-gate static int st_set_devconfig_page(struct scsi_tape *un, int compression_on);
5837c478bd9Sstevel@tonic-gate static int st_set_datacomp_page(struct scsi_tape *un, int compression_on);
584f218e94bSrralphs static int st_reserve_release(struct scsi_tape *un, int command, ubufunc_t ubf);
585f218e94bSrralphs static int st_check_cdb_for_need_to_reserve(struct scsi_tape *un, uchar_t *cdb);
586e213afc3Srralphs static int st_check_cmd_for_need_to_reserve(struct scsi_tape *un, uchar_t cmd,
587e213afc3Srralphs     int count);
5880205780bSrralphs static int st_take_ownership(struct scsi_tape *un, ubufunc_t ubf);
5897c478bd9Sstevel@tonic-gate static int st_check_asc_ascq(struct scsi_tape *un);
590f218e94bSrralphs static int st_check_clean_bit(struct scsi_tape *un);
591f218e94bSrralphs static int st_check_alert_flags(struct scsi_tape *un);
592f218e94bSrralphs static int st_check_sequential_clean_bit(struct scsi_tape *un);
593f218e94bSrralphs static int st_check_sense_clean_bit(struct scsi_tape *un);
5947c478bd9Sstevel@tonic-gate static int st_clear_unit_attentions(dev_t dev_instance, int max_trys);
5957c478bd9Sstevel@tonic-gate static void st_calculate_timeouts(struct scsi_tape *un);
5965988135dSrralphs static writablity st_is_drive_worm(struct scsi_tape *un);
5975988135dSrralphs static int st_read_attributes(struct scsi_tape *un, uint16_t attribute,
598f218e94bSrralphs     void *buf, size_t size, ubufunc_t bufunc);
5995988135dSrralphs static int st_get_special_inquiry(struct scsi_tape *un, uchar_t size,
6005988135dSrralphs     caddr_t dest, uchar_t page);
601f218e94bSrralphs static int st_update_block_pos(struct scsi_tape *un, bufunc_t bf,
602f218e94bSrralphs     int post_space);
603f218e94bSrralphs static int st_interpret_read_pos(struct scsi_tape const *un, tapepos_t *dest,
604f218e94bSrralphs     read_p_types type, size_t data_sz, const caddr_t responce, int post_space);
605c6914c10Srralphs static int st_get_read_pos(struct scsi_tape *un, buf_t *bp);
606f218e94bSrralphs static int st_logical_block_locate(struct scsi_tape *un, ubufunc_t ubf,
607f218e94bSrralphs     tapepos_t *pos, uint64_t lblk, uchar_t partition);
6080205780bSrralphs static int st_mtfsf_ioctl(struct scsi_tape *un, int64_t files);
6090205780bSrralphs static int st_mtfsr_ioctl(struct scsi_tape *un, int64_t count);
6100205780bSrralphs static int st_mtbsf_ioctl(struct scsi_tape *un, int64_t files);
6110205780bSrralphs static int st_mtnbsf_ioctl(struct scsi_tape *un, int64_t count);
6120205780bSrralphs static int st_mtbsr_ioctl(struct scsi_tape *un, int64_t num);
6130205780bSrralphs static int st_mtfsfm_ioctl(struct scsi_tape *un, int64_t cnt);
6140205780bSrralphs static int st_mtbsfm_ioctl(struct scsi_tape *un, int64_t cnt);
6150205780bSrralphs static int st_backward_space_files(struct scsi_tape *un, int64_t count,
616c6914c10Srralphs     int infront);
6170205780bSrralphs static int st_forward_space_files(struct scsi_tape *un, int64_t files);
618c6914c10Srralphs static int st_scenic_route_to_begining_of_file(struct scsi_tape *un,
619c6914c10Srralphs     int32_t fileno);
620c6914c10Srralphs static int st_space_to_begining_of_file(struct scsi_tape *un);
6210205780bSrralphs static int st_space_records(struct scsi_tape *un, int64_t records);
622f218e94bSrralphs static int st_get_media_identification(struct scsi_tape *un, ubufunc_t bufunc);
623f218e94bSrralphs static errstate st_command_recovery(struct scsi_tape *un, struct scsi_pkt *pkt,
624f218e94bSrralphs     errstate onentry);
625f218e94bSrralphs static void st_recover(void *arg);
626f218e94bSrralphs static void st_recov_cb(struct scsi_pkt *pkt);
627f218e94bSrralphs static int st_rcmd(struct scsi_tape *un, int com, int64_t count, int wait);
628f218e94bSrralphs static int st_uscsi_rcmd(struct scsi_tape *un, struct uscsi_cmd *ucmd,
629f218e94bSrralphs     int flag);
630f218e94bSrralphs static void st_add_recovery_info_to_pkt(struct scsi_tape *un, buf_t *bp,
631f218e94bSrralphs     struct scsi_pkt *cmd);
632f218e94bSrralphs static int st_check_mode_for_change(struct scsi_tape *un, ubufunc_t ubf);
633f218e94bSrralphs static int st_test_path_to_device(struct scsi_tape *un);
634f218e94bSrralphs static int st_recovery_read_pos(struct scsi_tape *un, read_p_types type,
635f218e94bSrralphs     read_pos_data_t *raw);
636f218e94bSrralphs static int st_recovery_get_position(struct scsi_tape *un, tapepos_t *read,
637f218e94bSrralphs     read_pos_data_t *raw);
638f218e94bSrralphs static int st_compare_expected_position(struct scsi_tape *un, st_err_info *ei,
639f218e94bSrralphs     cmd_attribute const * cmd_att, tapepos_t *read);
640f218e94bSrralphs static errstate st_recover_reissue_pkt(struct scsi_tape *us,
641f218e94bSrralphs     struct scsi_pkt *pkt);
642f218e94bSrralphs static int st_transport(struct scsi_tape *un, struct scsi_pkt *pkt);
643f218e94bSrralphs static buf_t *st_remove_from_queue(buf_t **head, buf_t **tail, buf_t *bp);
644f218e94bSrralphs static void st_add_to_queue(buf_t **head, buf_t **tail, buf_t *end, buf_t *bp);
645f218e94bSrralphs static int st_reset(struct scsi_tape *un, int reset_type);
646f218e94bSrralphs static void st_reset_notification(caddr_t arg);
647f218e94bSrralphs static const cmd_attribute *st_lookup_cmd_attribute(unsigned char cmd);
6487c478bd9Sstevel@tonic-gate 
649af483cc8Sjianfei wang - Sun Microsystems - Beijing China static int st_set_target_TLR_mode(struct scsi_tape *un, ubufunc_t ubf);
650af483cc8Sjianfei wang - Sun Microsystems - Beijing China static int st_make_sure_mode_data_is_correct(struct scsi_tape *un,
651af483cc8Sjianfei wang - Sun Microsystems - Beijing China     ubufunc_t ubf);
652af483cc8Sjianfei wang - Sun Microsystems - Beijing China 
65336945f79Smrj #ifdef	__x86
654f3531714Scz /*
655f3531714Scz  * routines for I/O in big block size
656f3531714Scz  */
657f3531714Scz static void st_release_contig_mem(struct scsi_tape *un, struct contig_mem *cp);
658f3531714Scz static struct contig_mem *st_get_contig_mem(struct scsi_tape *un, size_t len,
659f3531714Scz     int alloc_flags);
660f3531714Scz static int st_bigblk_xfer_done(struct buf *bp);
661f3531714Scz static struct buf *st_get_bigblk_bp(struct buf *bp);
662f3531714Scz #endif
663f218e94bSrralphs static void st_print_position(dev_info_t *dev, char *label, uint_t level,
664f218e94bSrralphs     const char *comment, tapepos_t *pos);
665f3531714Scz 
6667c478bd9Sstevel@tonic-gate /*
6677c478bd9Sstevel@tonic-gate  * error statistics create/update functions
6687c478bd9Sstevel@tonic-gate  */
6697c478bd9Sstevel@tonic-gate static int st_create_errstats(struct scsi_tape *, int);
670f218e94bSrralphs static int st_validate_tapemarks(struct scsi_tape *un, ubufunc_t ubf,
671f218e94bSrralphs     tapepos_t *pos);
6727c478bd9Sstevel@tonic-gate 
6737c478bd9Sstevel@tonic-gate #ifdef STDEBUG
6747c478bd9Sstevel@tonic-gate static void st_debug_cmds(struct scsi_tape *un, int com, int count, int wait);
6757c478bd9Sstevel@tonic-gate #endif /* STDEBUG */
6760205780bSrralphs static char *st_dev_name(dev_t dev);
6777c478bd9Sstevel@tonic-gate 
6787c478bd9Sstevel@tonic-gate #if !defined(lint)
6796567eb0aSlh _NOTE(SCHEME_PROTECTS_DATA("unique per pkt",
6806567eb0aSlh     scsi_pkt buf uio scsi_cdb uscsi_cmd))
6817c478bd9Sstevel@tonic-gate _NOTE(SCHEME_PROTECTS_DATA("unique per pkt", scsi_extended_sense scsi_status))
6820205780bSrralphs _NOTE(SCHEME_PROTECTS_DATA("unique per pkt", recov_info))
6837c478bd9Sstevel@tonic-gate _NOTE(SCHEME_PROTECTS_DATA("stable data", scsi_device))
6847c478bd9Sstevel@tonic-gate _NOTE(DATA_READABLE_WITHOUT_LOCK(st_drivetype scsi_address))
6857c478bd9Sstevel@tonic-gate #endif
6867c478bd9Sstevel@tonic-gate 
6877c478bd9Sstevel@tonic-gate /*
6887c478bd9Sstevel@tonic-gate  * autoconfiguration routines.
6897c478bd9Sstevel@tonic-gate  */
6907c478bd9Sstevel@tonic-gate 
6917c478bd9Sstevel@tonic-gate static struct modldrv modldrv = {
6927c478bd9Sstevel@tonic-gate 	&mod_driverops,		/* Type of module. This one is a driver */
6931ef1b398SToomas Soome 	"SCSI tape Driver",	/* Name of the module. */
6947c478bd9Sstevel@tonic-gate 	&st_ops			/* driver ops */
6957c478bd9Sstevel@tonic-gate };
6967c478bd9Sstevel@tonic-gate 
6977c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
6987c478bd9Sstevel@tonic-gate 	MODREV_1, &modldrv, NULL
6997c478bd9Sstevel@tonic-gate };
7007c478bd9Sstevel@tonic-gate 
7017c478bd9Sstevel@tonic-gate /*
7027c478bd9Sstevel@tonic-gate  * Notes on Post Reset Behavior in the tape driver:
7037c478bd9Sstevel@tonic-gate  *
7047c478bd9Sstevel@tonic-gate  * When the tape drive is opened, the driver  attempts  to make sure that
7057c478bd9Sstevel@tonic-gate  * the tape head is positioned exactly where it was left when it was last
7067c478bd9Sstevel@tonic-gate  * closed  provided  the  medium  is not  changed.  If the tape  drive is
7077c478bd9Sstevel@tonic-gate  * opened in O_NDELAY mode, the repositioning  (if necessary for any loss
7087c478bd9Sstevel@tonic-gate  * of position due to reset) will happen when the first tape operation or
7097c478bd9Sstevel@tonic-gate  * I/O occurs.  The repositioning (if required) may not be possible under
7107c478bd9Sstevel@tonic-gate  * certain situations such as when the device firmware not able to report
7117c478bd9Sstevel@tonic-gate  * the medium  change in the REQUEST  SENSE data  because of a reset or a
7127c478bd9Sstevel@tonic-gate  * misbehaving  bus  not  allowing  the  reposition  to  happen.  In such
7137c478bd9Sstevel@tonic-gate  * extraordinary  situations, where the driver fails to position the head
7147c478bd9Sstevel@tonic-gate  * at its  original  position,  it will fail the open the first  time, to
7157c478bd9Sstevel@tonic-gate  * save the applications from overwriting the data.  All further attempts
7167c478bd9Sstevel@tonic-gate  * to open the tape device will result in the driver  attempting  to load
7177c478bd9Sstevel@tonic-gate  * the  tape at BOT  (beginning  of  tape).  Also a  warning  message  to
7187c478bd9Sstevel@tonic-gate  * indicate  that further  attempts to open the tape device may result in
7197c478bd9Sstevel@tonic-gate  * the tape being  loaded at BOT will be printed on the  console.  If the
7207c478bd9Sstevel@tonic-gate  * tape  device is opened  in  O_NDELAY  mode,  failure  to  restore  the
7217c478bd9Sstevel@tonic-gate  * original tape head  position,  will result in the failure of the first
7227c478bd9Sstevel@tonic-gate  * tape  operation  or I/O,  Further,  the  driver  will  invalidate  its
7237c478bd9Sstevel@tonic-gate  * internal tape position  which will  necessitate  the  applications  to
7247c478bd9Sstevel@tonic-gate  * validate the position by using either a tape  positioning  ioctl (such
7257c478bd9Sstevel@tonic-gate  * as MTREW) or closing and reopening the tape device.
7267c478bd9Sstevel@tonic-gate  *
7277c478bd9Sstevel@tonic-gate  */
7287c478bd9Sstevel@tonic-gate 
7297c478bd9Sstevel@tonic-gate int
_init(void)7307c478bd9Sstevel@tonic-gate _init(void)
7317c478bd9Sstevel@tonic-gate {
732f218e94bSrralphs 	int e;
7337c478bd9Sstevel@tonic-gate 
7347c478bd9Sstevel@tonic-gate 	if (((e = ddi_soft_state_init(&st_state,
7357c478bd9Sstevel@tonic-gate 	    sizeof (struct scsi_tape), ST_MAXUNIT)) != 0)) {
7367c478bd9Sstevel@tonic-gate 		return (e);
7377c478bd9Sstevel@tonic-gate 	}
7387c478bd9Sstevel@tonic-gate 
7397c478bd9Sstevel@tonic-gate 	if ((e = mod_install(&modlinkage)) != 0) {
7407c478bd9Sstevel@tonic-gate 		ddi_soft_state_fini(&st_state);
7410205780bSrralphs 	} else {
7420205780bSrralphs #ifdef STDEBUG
7430205780bSrralphs 		mutex_init(&st_debug_mutex, NULL, MUTEX_DRIVER, NULL);
7440205780bSrralphs #endif
7457c478bd9Sstevel@tonic-gate 
7464ab75253Smrj #if defined(__x86)
7470205780bSrralphs 		/* set the max physical address for iob allocs on x86 */
7480205780bSrralphs 		st_alloc_attr.dma_attr_addr_hi = st_max_phys_addr;
7494ab75253Smrj 
7500205780bSrralphs 		/*
7510205780bSrralphs 		 * set the sgllen for iob allocs on x86. If this is set less
7520205780bSrralphs 		 * than the number of pages the buffer will take
7530205780bSrralphs 		 * (taking into account alignment), it would force the
7540205780bSrralphs 		 * allocator to try and allocate contiguous pages.
7550205780bSrralphs 		 */
7560205780bSrralphs 		st_alloc_attr.dma_attr_sgllen = st_sgl_size;
7574ab75253Smrj #endif
7580205780bSrralphs 	}
7594ab75253Smrj 
7607c478bd9Sstevel@tonic-gate 	return (e);
7617c478bd9Sstevel@tonic-gate }
7627c478bd9Sstevel@tonic-gate 
7637c478bd9Sstevel@tonic-gate int
_fini(void)7647c478bd9Sstevel@tonic-gate _fini(void)
7657c478bd9Sstevel@tonic-gate {
7667c478bd9Sstevel@tonic-gate 	int e;
7677c478bd9Sstevel@tonic-gate 
7687c478bd9Sstevel@tonic-gate 	if ((e = mod_remove(&modlinkage)) != 0) {
7697c478bd9Sstevel@tonic-gate 		return (e);
7707c478bd9Sstevel@tonic-gate 	}
7717c478bd9Sstevel@tonic-gate 
7720205780bSrralphs #ifdef STDEBUG
7730205780bSrralphs 	mutex_destroy(&st_debug_mutex);
7740205780bSrralphs #endif
7750205780bSrralphs 
7767c478bd9Sstevel@tonic-gate 	ddi_soft_state_fini(&st_state);
7777c478bd9Sstevel@tonic-gate 
7787c478bd9Sstevel@tonic-gate 	return (e);
7797c478bd9Sstevel@tonic-gate }
7807c478bd9Sstevel@tonic-gate 
7817c478bd9Sstevel@tonic-gate int
_info(struct modinfo * modinfop)7827c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
7837c478bd9Sstevel@tonic-gate {
7847c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
7857c478bd9Sstevel@tonic-gate }
7867c478bd9Sstevel@tonic-gate 
7877c478bd9Sstevel@tonic-gate 
7887c478bd9Sstevel@tonic-gate static int
st_probe(dev_info_t * devi)7897c478bd9Sstevel@tonic-gate st_probe(dev_info_t *devi)
7907c478bd9Sstevel@tonic-gate {
7917c478bd9Sstevel@tonic-gate 	int instance;
7927c478bd9Sstevel@tonic-gate 	struct scsi_device *devp;
7937c478bd9Sstevel@tonic-gate 	int rval;
7947c478bd9Sstevel@tonic-gate 
7957c478bd9Sstevel@tonic-gate #if !defined(__sparc)
7967c478bd9Sstevel@tonic-gate 	char    *tape_prop;
7977c478bd9Sstevel@tonic-gate 	int	tape_prop_len;
7987c478bd9Sstevel@tonic-gate #endif
7997c478bd9Sstevel@tonic-gate 
800c6914c10Srralphs 	ST_ENTR(devi, st_probe);
801c6914c10Srralphs 
8027c478bd9Sstevel@tonic-gate 	/* If self identifying device */
8037c478bd9Sstevel@tonic-gate 	if (ddi_dev_is_sid(devi) == DDI_SUCCESS) {
8047c478bd9Sstevel@tonic-gate 		return (DDI_PROBE_DONTCARE);
8057c478bd9Sstevel@tonic-gate 	}
8067c478bd9Sstevel@tonic-gate 
8077c478bd9Sstevel@tonic-gate #if !defined(__sparc)
8087c478bd9Sstevel@tonic-gate 	/*
8097c478bd9Sstevel@tonic-gate 	 * Since some x86 HBAs have devnodes that look like SCSI as
8107c478bd9Sstevel@tonic-gate 	 * far as we can tell but aren't really SCSI (DADK, like mlx)
8117c478bd9Sstevel@tonic-gate 	 * we check for the presence of the "tape" property.
8127c478bd9Sstevel@tonic-gate 	 */
8137c478bd9Sstevel@tonic-gate 	if (ddi_prop_op(DDI_DEV_T_NONE, devi, PROP_LEN_AND_VAL_ALLOC,
8147c478bd9Sstevel@tonic-gate 	    DDI_PROP_CANSLEEP, "tape",
8157c478bd9Sstevel@tonic-gate 	    (caddr_t)&tape_prop, &tape_prop_len) != DDI_PROP_SUCCESS) {
8167c478bd9Sstevel@tonic-gate 		return (DDI_PROBE_FAILURE);
8177c478bd9Sstevel@tonic-gate 	}
8187c478bd9Sstevel@tonic-gate 	if (strncmp(tape_prop, "sctp", tape_prop_len) != 0) {
8197c478bd9Sstevel@tonic-gate 		kmem_free(tape_prop, tape_prop_len);
8207c478bd9Sstevel@tonic-gate 		return (DDI_PROBE_FAILURE);
8217c478bd9Sstevel@tonic-gate 	}
8227c478bd9Sstevel@tonic-gate 	kmem_free(tape_prop, tape_prop_len);
8237c478bd9Sstevel@tonic-gate #endif
8247c478bd9Sstevel@tonic-gate 
8257c478bd9Sstevel@tonic-gate 	devp = ddi_get_driver_private(devi);
8267c478bd9Sstevel@tonic-gate 	instance = ddi_get_instance(devi);
8277c478bd9Sstevel@tonic-gate 
8287c478bd9Sstevel@tonic-gate 	if (ddi_get_soft_state(st_state, instance) != NULL) {
8297c478bd9Sstevel@tonic-gate 		return (DDI_PROBE_PARTIAL);
8307c478bd9Sstevel@tonic-gate 	}
8317c478bd9Sstevel@tonic-gate 
8327c478bd9Sstevel@tonic-gate 
8337c478bd9Sstevel@tonic-gate 	/*
8347c478bd9Sstevel@tonic-gate 	 * Turn around and call probe routine to see whether
8357c478bd9Sstevel@tonic-gate 	 * we actually have a tape at this SCSI nexus.
8367c478bd9Sstevel@tonic-gate 	 */
8377c478bd9Sstevel@tonic-gate 	if (scsi_probe(devp, NULL_FUNC) == SCSIPROBE_EXISTS) {
8387c478bd9Sstevel@tonic-gate 
8397c478bd9Sstevel@tonic-gate 		/*
8407c478bd9Sstevel@tonic-gate 		 * In checking the whole inq_dtype byte we are looking at both
8417c478bd9Sstevel@tonic-gate 		 * the Peripheral Qualifier and the Peripheral Device Type.
8427c478bd9Sstevel@tonic-gate 		 * For this driver we are only interested in sequential devices
8437c478bd9Sstevel@tonic-gate 		 * that are connected or capable if connecting to this logical
8447c478bd9Sstevel@tonic-gate 		 * unit.
8457c478bd9Sstevel@tonic-gate 		 */
8467c478bd9Sstevel@tonic-gate 		if (devp->sd_inq->inq_dtype ==
8477c478bd9Sstevel@tonic-gate 		    (DTYPE_SEQUENTIAL | DPQ_POSSIBLE)) {
8487c478bd9Sstevel@tonic-gate 			ST_DEBUG6(devi, st_label, SCSI_DEBUG,
8497c478bd9Sstevel@tonic-gate 			    "probe exists\n");
8507c478bd9Sstevel@tonic-gate 			rval = DDI_PROBE_SUCCESS;
8517c478bd9Sstevel@tonic-gate 		} else {
8527c478bd9Sstevel@tonic-gate 			rval = DDI_PROBE_FAILURE;
8537c478bd9Sstevel@tonic-gate 		}
8547c478bd9Sstevel@tonic-gate 	} else {
8557c478bd9Sstevel@tonic-gate 		ST_DEBUG6(devi, st_label, SCSI_DEBUG,
8567c478bd9Sstevel@tonic-gate 		    "probe failure: nothing there\n");
8577c478bd9Sstevel@tonic-gate 		rval = DDI_PROBE_FAILURE;
8587c478bd9Sstevel@tonic-gate 	}
8597c478bd9Sstevel@tonic-gate 	scsi_unprobe(devp);
8607c478bd9Sstevel@tonic-gate 	return (rval);
8617c478bd9Sstevel@tonic-gate }
8627c478bd9Sstevel@tonic-gate 
8637c478bd9Sstevel@tonic-gate static int
st_attach(dev_info_t * devi,ddi_attach_cmd_t cmd)8647c478bd9Sstevel@tonic-gate st_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
8657c478bd9Sstevel@tonic-gate {
8661ef1b398SToomas Soome 	int	instance;
8677c478bd9Sstevel@tonic-gate 	int	wide;
8681ef1b398SToomas Soome 	int	dev_instance;
8697c478bd9Sstevel@tonic-gate 	int	ret_status;
8707c478bd9Sstevel@tonic-gate 	struct	scsi_device *devp;
8717c478bd9Sstevel@tonic-gate 	int	node_ix;
8727c478bd9Sstevel@tonic-gate 	struct	scsi_tape *un;
8737c478bd9Sstevel@tonic-gate 
874c6914c10Srralphs 	ST_ENTR(devi, st_attach);
875c6914c10Srralphs 
8767c478bd9Sstevel@tonic-gate 	devp = ddi_get_driver_private(devi);
8777c478bd9Sstevel@tonic-gate 	instance = ddi_get_instance(devi);
8787c478bd9Sstevel@tonic-gate 
8797c478bd9Sstevel@tonic-gate 	switch (cmd) {
8807c478bd9Sstevel@tonic-gate 		case DDI_ATTACH:
881f218e94bSrralphs 			if (ddi_getprop(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS,
882f218e94bSrralphs 			    "tape-command-recovery-disable", 0) != 0) {
883f218e94bSrralphs 				st_recov_sz = sizeof (pkt_info);
884f218e94bSrralphs 			}
8857c478bd9Sstevel@tonic-gate 			if (st_doattach(devp, SLEEP_FUNC) == DDI_FAILURE) {
8867c478bd9Sstevel@tonic-gate 				return (DDI_FAILURE);
8877c478bd9Sstevel@tonic-gate 			}
8887c478bd9Sstevel@tonic-gate 			break;
8897c478bd9Sstevel@tonic-gate 		case DDI_RESUME:
8907c478bd9Sstevel@tonic-gate 			/*
8917c478bd9Sstevel@tonic-gate 			 * Suspend/Resume
8927c478bd9Sstevel@tonic-gate 			 *
8937c478bd9Sstevel@tonic-gate 			 * When the driver suspended, there might be
8947c478bd9Sstevel@tonic-gate 			 * outstanding cmds and therefore we need to
8957c478bd9Sstevel@tonic-gate 			 * reset the suspended flag and resume the scsi
8967c478bd9Sstevel@tonic-gate 			 * watch thread and restart commands and timeouts
8977c478bd9Sstevel@tonic-gate 			 */
8987c478bd9Sstevel@tonic-gate 
8997c478bd9Sstevel@tonic-gate 			if (!(un = ddi_get_soft_state(st_state, instance))) {
9007c478bd9Sstevel@tonic-gate 				return (DDI_FAILURE);
9017c478bd9Sstevel@tonic-gate 			}
9027c478bd9Sstevel@tonic-gate 			dev_instance = ((un->un_dev == 0) ? MTMINOR(instance) :
9037c478bd9Sstevel@tonic-gate 			    un->un_dev);
9047c478bd9Sstevel@tonic-gate 
9057c478bd9Sstevel@tonic-gate 			mutex_enter(ST_MUTEX);
9067c478bd9Sstevel@tonic-gate 
9077c478bd9Sstevel@tonic-gate 			un->un_throttle = un->un_max_throttle;
9087c478bd9Sstevel@tonic-gate 			un->un_tids_at_suspend = 0;
9097c478bd9Sstevel@tonic-gate 			un->un_pwr_mgmt = ST_PWR_NORMAL;
910