xref: /openbmc/linux/drivers/scsi/st.c (revision 360823a09426347ea8f232b0b0b5156d0aed0302)
109c434b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds    SCSI Tape Driver for Linux version 1.1 and newer. See the accompanying
4bf65c846SMauro Carvalho Chehab    file Documentation/scsi/st.rst for more information.
51da177e4SLinus Torvalds 
61da177e4SLinus Torvalds    History:
71da177e4SLinus Torvalds    Rewritten from Dwayne Forsyth's SCSI tape driver by Kai Makisara.
81da177e4SLinus Torvalds    Contribution and ideas from several people including (in alphabetical
91da177e4SLinus Torvalds    order) Klaus Ehrenfried, Eugene Exarevsky, Eric Lee Green, Wolfgang Denk,
101da177e4SLinus Torvalds    Steve Hirsch, Andreas Koppenh"ofer, Michael Leodolter, Eyal Lebedinsky,
111da177e4SLinus Torvalds    Michael Schaefer, J"org Weule, and Eric Youngdale.
121da177e4SLinus Torvalds 
138038e645SKai Makisara    Copyright 1992 - 2016 Kai Makisara
141da177e4SLinus Torvalds    email Kai.Makisara@kolumbus.fi
151da177e4SLinus Torvalds 
161da177e4SLinus Torvalds    Some small formal changes - aeb, 950809
171da177e4SLinus Torvalds 
181da177e4SLinus Torvalds    Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support
191da177e4SLinus Torvalds  */
201da177e4SLinus Torvalds 
218038e645SKai Makisara static const char *verstr = "20160209";
221da177e4SLinus Torvalds 
231da177e4SLinus Torvalds #include <linux/module.h>
241da177e4SLinus Torvalds 
251207045dSArnd Bergmann #include <linux/compat.h>
261da177e4SLinus Torvalds #include <linux/fs.h>
271da177e4SLinus Torvalds #include <linux/kernel.h>
28174cd4b1SIngo Molnar #include <linux/sched/signal.h>
291da177e4SLinus Torvalds #include <linux/mm.h>
301da177e4SLinus Torvalds #include <linux/init.h>
311da177e4SLinus Torvalds #include <linux/string.h>
325a0e3ad6STejun Heo #include <linux/slab.h>
331da177e4SLinus Torvalds #include <linux/errno.h>
341da177e4SLinus Torvalds #include <linux/mtio.h>
35b81e0c23SChristoph Hellwig #include <linux/major.h>
3616c4b3e2SKai Makisara  #include <linux/cdrom.h>
371da177e4SLinus Torvalds #include <linux/ioctl.h>
381da177e4SLinus Torvalds #include <linux/fcntl.h>
391da177e4SLinus Torvalds #include <linux/spinlock.h>
401da177e4SLinus Torvalds #include <linux/blkdev.h>
411da177e4SLinus Torvalds #include <linux/moduleparam.h>
421da177e4SLinus Torvalds #include <linux/cdev.h>
436c648d95SJeff Mahoney #include <linux/idr.h>
441da177e4SLinus Torvalds #include <linux/delay.h>
450b950672SArjan van de Ven #include <linux/mutex.h>
461da177e4SLinus Torvalds 
477c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
481da177e4SLinus Torvalds #include <asm/dma.h>
4935b703dbSBart Van Assche #include <asm/unaligned.h>
501da177e4SLinus Torvalds 
511da177e4SLinus Torvalds #include <scsi/scsi.h>
521da177e4SLinus Torvalds #include <scsi/scsi_dbg.h>
531da177e4SLinus Torvalds #include <scsi/scsi_device.h>
541da177e4SLinus Torvalds #include <scsi/scsi_driver.h>
551da177e4SLinus Torvalds #include <scsi/scsi_eh.h>
561da177e4SLinus Torvalds #include <scsi/scsi_host.h>
571da177e4SLinus Torvalds #include <scsi/scsi_ioctl.h>
5816c4b3e2SKai Makisara  #include <scsi/sg.h>
591da177e4SLinus Torvalds 
601da177e4SLinus Torvalds 
611da177e4SLinus Torvalds /* The driver prints some debugging information on the console if DEBUG
621da177e4SLinus Torvalds    is defined and non-zero. */
632bec708aSLaurence Oberman #define DEBUG 1
642bec708aSLaurence Oberman #define NO_DEBUG 0
651da177e4SLinus Torvalds 
66b30d8bcaSHannes Reinecke #define ST_DEB_MSG  KERN_NOTICE
671da177e4SLinus Torvalds #if DEBUG
681da177e4SLinus Torvalds /* The message level for the debug messages is currently set to KERN_NOTICE
691da177e4SLinus Torvalds    so that people can easily see the messages. Later when the debugging messages
701da177e4SLinus Torvalds    in the drivers are more widely classified, this may be changed to KERN_DEBUG. */
711da177e4SLinus Torvalds #define DEB(a) a
721da177e4SLinus Torvalds #define DEBC(a) if (debugging) { a ; }
731da177e4SLinus Torvalds #else
741da177e4SLinus Torvalds #define DEB(a)
751da177e4SLinus Torvalds #define DEBC(a)
761da177e4SLinus Torvalds #endif
771da177e4SLinus Torvalds 
781da177e4SLinus Torvalds #define ST_KILOBYTE 1024
791da177e4SLinus Torvalds 
801da177e4SLinus Torvalds #include "st_options.h"
811da177e4SLinus Torvalds #include "st.h"
821da177e4SLinus Torvalds 
831da177e4SLinus Torvalds static int buffer_kbs;
841da177e4SLinus Torvalds static int max_sg_segs;
851da177e4SLinus Torvalds static int try_direct_io = TRY_DIRECT_IO;
861da177e4SLinus Torvalds static int try_rdio = 1;
871da177e4SLinus Torvalds static int try_wdio = 1;
882bec708aSLaurence Oberman static int debug_flag;
891da177e4SLinus Torvalds 
90af23782bSJeff Mahoney static struct class st_sysfs_class;
91c69c6be5SGreg Kroah-Hartman static const struct attribute_group *st_dev_groups[];
92442d7562SSeymour, Shane M static const struct attribute_group *st_drv_groups[];
931da177e4SLinus Torvalds 
941da177e4SLinus Torvalds MODULE_AUTHOR("Kai Makisara");
95f018fa55SRene Herman MODULE_DESCRIPTION("SCSI tape (st) driver");
961da177e4SLinus Torvalds MODULE_LICENSE("GPL");
97f018fa55SRene Herman MODULE_ALIAS_CHARDEV_MAJOR(SCSI_TAPE_MAJOR);
98d7b8bcb0SMichael Tokarev MODULE_ALIAS_SCSI_DEVICE(TYPE_TAPE);
991da177e4SLinus Torvalds 
1001da177e4SLinus Torvalds /* Set 'perm' (4th argument) to 0 to disable module_param's definition
1011da177e4SLinus Torvalds  * of sysfs parameters (which module_param doesn't yet support).
1021da177e4SLinus Torvalds  * Sysfs parameters defined explicitly later.
1031da177e4SLinus Torvalds  */
1041da177e4SLinus Torvalds module_param_named(buffer_kbs, buffer_kbs, int, 0);
1051da177e4SLinus Torvalds MODULE_PARM_DESC(buffer_kbs, "Default driver buffer size for fixed block mode (KB; 32)");
1061da177e4SLinus Torvalds module_param_named(max_sg_segs, max_sg_segs, int, 0);
1071da177e4SLinus Torvalds MODULE_PARM_DESC(max_sg_segs, "Maximum number of scatter/gather segments to use (256)");
1081da177e4SLinus Torvalds module_param_named(try_direct_io, try_direct_io, int, 0);
1091da177e4SLinus Torvalds MODULE_PARM_DESC(try_direct_io, "Try direct I/O between user buffer and tape drive (1)");
1102bec708aSLaurence Oberman module_param_named(debug_flag, debug_flag, int, 0);
1112bec708aSLaurence Oberman MODULE_PARM_DESC(debug_flag, "Enable DEBUG, same as setting debugging=1");
1122bec708aSLaurence Oberman 
1131da177e4SLinus Torvalds 
1141da177e4SLinus Torvalds /* Extra parameters for testing */
1151da177e4SLinus Torvalds module_param_named(try_rdio, try_rdio, int, 0);
1161da177e4SLinus Torvalds MODULE_PARM_DESC(try_rdio, "Try direct read i/o when possible");
1171da177e4SLinus Torvalds module_param_named(try_wdio, try_wdio, int, 0);
1181da177e4SLinus Torvalds MODULE_PARM_DESC(try_wdio, "Try direct write i/o when possible");
1191da177e4SLinus Torvalds 
1201da177e4SLinus Torvalds #ifndef MODULE
1211da177e4SLinus Torvalds static int write_threshold_kbs;  /* retained for compatibility */
1221da177e4SLinus Torvalds static struct st_dev_parm {
1231da177e4SLinus Torvalds 	char *name;
1241da177e4SLinus Torvalds 	int *val;
1251da177e4SLinus Torvalds } parms[] __initdata = {
1261da177e4SLinus Torvalds 	{
1271da177e4SLinus Torvalds 		"buffer_kbs", &buffer_kbs
1281da177e4SLinus Torvalds 	},
1291da177e4SLinus Torvalds 	{       /* Retained for compatibility with 2.4 */
1301da177e4SLinus Torvalds 		"write_threshold_kbs", &write_threshold_kbs
1311da177e4SLinus Torvalds 	},
1321da177e4SLinus Torvalds 	{
1331da177e4SLinus Torvalds 		"max_sg_segs", NULL
1341da177e4SLinus Torvalds 	},
1351da177e4SLinus Torvalds 	{
1361da177e4SLinus Torvalds 		"try_direct_io", &try_direct_io
1372bec708aSLaurence Oberman 	},
1382bec708aSLaurence Oberman 	{
1392bec708aSLaurence Oberman 		"debug_flag", &debug_flag
1401da177e4SLinus Torvalds 	}
1411da177e4SLinus Torvalds };
1421da177e4SLinus Torvalds #endif
1431da177e4SLinus Torvalds 
1441da177e4SLinus Torvalds /* Restrict the number of modes so that names for all are assigned */
1451da177e4SLinus Torvalds #if ST_NBR_MODES > 16
1461da177e4SLinus Torvalds #error "Maximum number of modes is 16"
1471da177e4SLinus Torvalds #endif
1481da177e4SLinus Torvalds /* Bit reversed order to get same names for same minors with all
1491da177e4SLinus Torvalds    mode counts */
1500ad78200SArjan van de Ven static const char *st_formats[] = {
1511da177e4SLinus Torvalds 	"",  "r", "k", "s", "l", "t", "o", "u",
1521da177e4SLinus Torvalds 	"m", "v", "p", "x", "a", "y", "q", "z"};
1531da177e4SLinus Torvalds 
1541da177e4SLinus Torvalds /* The default definitions have been moved to st_options.h */
1551da177e4SLinus Torvalds 
1561da177e4SLinus Torvalds #define ST_FIXED_BUFFER_SIZE (ST_FIXED_BUFFER_BLOCKS * ST_KILOBYTE)
1571da177e4SLinus Torvalds 
1581da177e4SLinus Torvalds /* The buffer size should fit into the 24 bits for length in the
1591da177e4SLinus Torvalds    6-byte SCSI read and write commands. */
1601da177e4SLinus Torvalds #if ST_FIXED_BUFFER_SIZE >= (2 << 24 - 1)
1611da177e4SLinus Torvalds #error "Buffer size should not exceed (2 << 24 - 1) bytes!"
1621da177e4SLinus Torvalds #endif
1631da177e4SLinus Torvalds 
1641da177e4SLinus Torvalds static int debugging = DEBUG;
1651da177e4SLinus Torvalds 
1661da177e4SLinus Torvalds #define MAX_RETRIES 0
1671da177e4SLinus Torvalds #define MAX_WRITE_RETRIES 0
1681da177e4SLinus Torvalds #define MAX_READY_RETRIES 0
1691da177e4SLinus Torvalds #define NO_TAPE  NOT_READY
1701da177e4SLinus Torvalds 
1711da177e4SLinus Torvalds #define ST_TIMEOUT (900 * HZ)
1721da177e4SLinus Torvalds #define ST_LONG_TIMEOUT (14000 * HZ)
1731da177e4SLinus Torvalds 
1741da177e4SLinus Torvalds /* Remove mode bits and auto-rewind bit (7) */
1751da177e4SLinus Torvalds #define TAPE_NR(x) ( ((iminor(x) & ~255) >> (ST_NBR_MODE_BITS + 1)) | \
1766f46f718SIustin Pop 	(iminor(x) & ((1 << ST_MODE_SHIFT)-1)))
1771da177e4SLinus Torvalds #define TAPE_MODE(x) ((iminor(x) & ST_MODE_MASK) >> ST_MODE_SHIFT)
1781da177e4SLinus Torvalds 
1791da177e4SLinus Torvalds /* Construct the minor number from the device (d), mode (m), and non-rewind (n) data */
1801da177e4SLinus Torvalds #define TAPE_MINOR(d, m, n) (((d & ~(255 >> (ST_NBR_MODE_BITS + 1))) << (ST_NBR_MODE_BITS + 1)) | \
1811da177e4SLinus Torvalds   (d & (255 >> (ST_NBR_MODE_BITS + 1))) | (m << ST_MODE_SHIFT) | ((n != 0) << 7) )
1821da177e4SLinus Torvalds 
1831da177e4SLinus Torvalds /* Internal ioctl to set both density (uppermost 8 bits) and blocksize (lower
1841da177e4SLinus Torvalds    24 bits) */
1851da177e4SLinus Torvalds #define SET_DENS_AND_BLK 0x10001
1861da177e4SLinus Torvalds 
1871da177e4SLinus Torvalds static int st_fixed_buffer_size = ST_FIXED_BUFFER_SIZE;
1881da177e4SLinus Torvalds static int st_max_sg_segs = ST_MAX_SG;
1891da177e4SLinus Torvalds 
1901da177e4SLinus Torvalds static int modes_defined;
1911da177e4SLinus Torvalds 
192aaff5ebaSChristoph Hellwig static int enlarge_buffer(struct st_buffer *, int);
19340f6b36cSKai Makisara static void clear_buffer(struct st_buffer *);
1941da177e4SLinus Torvalds static void normalize_buffer(struct st_buffer *);
1951da177e4SLinus Torvalds static int append_to_buffer(const char __user *, struct st_buffer *, int);
1961da177e4SLinus Torvalds static int from_buffer(struct st_buffer *, char __user *, int);
1971da177e4SLinus Torvalds static void move_buffer_data(struct st_buffer *, int);
1981da177e4SLinus Torvalds 
1996620742fSFUJITA Tomonori static int sgl_map_user_pages(struct st_buffer *, const unsigned int,
2001da177e4SLinus Torvalds 			      unsigned long, size_t, int);
2016620742fSFUJITA Tomonori static int sgl_unmap_user_pages(struct st_buffer *, const unsigned int, int);
2021da177e4SLinus Torvalds 
2031da177e4SLinus Torvalds static int st_probe(struct device *);
2041da177e4SLinus Torvalds static int st_remove(struct device *);
2051da177e4SLinus Torvalds 
2061da177e4SLinus Torvalds static struct scsi_driver st_template = {
2071da177e4SLinus Torvalds 	.gendrv = {
2081da177e4SLinus Torvalds 		.name		= "st",
2093af6b352SChristoph Hellwig 		.owner		= THIS_MODULE,
2101da177e4SLinus Torvalds 		.probe		= st_probe,
2111da177e4SLinus Torvalds 		.remove		= st_remove,
212442d7562SSeymour, Shane M 		.groups		= st_drv_groups,
2131da177e4SLinus Torvalds 	},
2141da177e4SLinus Torvalds };
2151da177e4SLinus Torvalds 
2161da177e4SLinus Torvalds static int st_compression(struct scsi_tape *, int);
2171da177e4SLinus Torvalds 
2181da177e4SLinus Torvalds static int find_partition(struct scsi_tape *);
2191da177e4SLinus Torvalds static int switch_partition(struct scsi_tape *);
2201da177e4SLinus Torvalds 
2211da177e4SLinus Torvalds static int st_int_ioctl(struct scsi_tape *, unsigned int, unsigned long);
2221da177e4SLinus Torvalds 
223f03a5670SKai Makisara static void scsi_tape_release(struct kref *);
224f03a5670SKai Makisara 
225f03a5670SKai Makisara #define to_scsi_tape(obj) container_of(obj, struct scsi_tape, kref)
226f03a5670SKai Makisara 
2270b950672SArjan van de Ven static DEFINE_MUTEX(st_ref_mutex);
2286c648d95SJeff Mahoney static DEFINE_SPINLOCK(st_index_lock);
2296c648d95SJeff Mahoney static DEFINE_SPINLOCK(st_use_lock);
2306c648d95SJeff Mahoney static DEFINE_IDR(st_index_idr);
2316c648d95SJeff Mahoney 
232f03a5670SKai Makisara 
2331da177e4SLinus Torvalds 
2341da177e4SLinus Torvalds #ifndef SIGS_FROM_OSST
2351da177e4SLinus Torvalds #define SIGS_FROM_OSST \
2361da177e4SLinus Torvalds 	{"OnStream", "SC-", "", "osst"}, \
2371da177e4SLinus Torvalds 	{"OnStream", "DI-", "", "osst"}, \
2381da177e4SLinus Torvalds 	{"OnStream", "DP-", "", "osst"}, \
2391da177e4SLinus Torvalds 	{"OnStream", "USB", "", "osst"}, \
2401da177e4SLinus Torvalds 	{"OnStream", "FW-", "", "osst"}
2411da177e4SLinus Torvalds #endif
2421da177e4SLinus Torvalds 
scsi_tape_get(int dev)243f03a5670SKai Makisara static struct scsi_tape *scsi_tape_get(int dev)
244f03a5670SKai Makisara {
245f03a5670SKai Makisara 	struct scsi_tape *STp = NULL;
246f03a5670SKai Makisara 
2470b950672SArjan van de Ven 	mutex_lock(&st_ref_mutex);
2486c648d95SJeff Mahoney 	spin_lock(&st_index_lock);
249f03a5670SKai Makisara 
2506c648d95SJeff Mahoney 	STp = idr_find(&st_index_idr, dev);
251f03a5670SKai Makisara 	if (!STp) goto out;
252f03a5670SKai Makisara 
253f03a5670SKai Makisara 	kref_get(&STp->kref);
254f03a5670SKai Makisara 
255f03a5670SKai Makisara 	if (!STp->device)
256f03a5670SKai Makisara 		goto out_put;
257f03a5670SKai Makisara 
258f03a5670SKai Makisara 	if (scsi_device_get(STp->device))
259f03a5670SKai Makisara 		goto out_put;
260f03a5670SKai Makisara 
261f03a5670SKai Makisara 	goto out;
262f03a5670SKai Makisara 
263f03a5670SKai Makisara out_put:
264f03a5670SKai Makisara 	kref_put(&STp->kref, scsi_tape_release);
265f03a5670SKai Makisara 	STp = NULL;
266f03a5670SKai Makisara out:
2676c648d95SJeff Mahoney 	spin_unlock(&st_index_lock);
2680b950672SArjan van de Ven 	mutex_unlock(&st_ref_mutex);
269f03a5670SKai Makisara 	return STp;
270f03a5670SKai Makisara }
271f03a5670SKai Makisara 
scsi_tape_put(struct scsi_tape * STp)272f03a5670SKai Makisara static void scsi_tape_put(struct scsi_tape *STp)
273f03a5670SKai Makisara {
274f03a5670SKai Makisara 	struct scsi_device *sdev = STp->device;
275f03a5670SKai Makisara 
2760b950672SArjan van de Ven 	mutex_lock(&st_ref_mutex);
277f03a5670SKai Makisara 	kref_put(&STp->kref, scsi_tape_release);
278f03a5670SKai Makisara 	scsi_device_put(sdev);
2790b950672SArjan van de Ven 	mutex_unlock(&st_ref_mutex);
280f03a5670SKai Makisara }
281f03a5670SKai Makisara 
2821da177e4SLinus Torvalds struct st_reject_data {
2831da177e4SLinus Torvalds 	char *vendor;
2841da177e4SLinus Torvalds 	char *model;
2851da177e4SLinus Torvalds 	char *rev;
2861da177e4SLinus Torvalds 	char *driver_hint; /* Name of the correct driver, NULL if unknown */
2871da177e4SLinus Torvalds };
2881da177e4SLinus Torvalds 
2891da177e4SLinus Torvalds static struct st_reject_data reject_list[] = {
2901da177e4SLinus Torvalds 	/* {"XXX", "Yy-", "", NULL},  example */
2911da177e4SLinus Torvalds 	SIGS_FROM_OSST,
2921da177e4SLinus Torvalds 	{NULL, }};
2931da177e4SLinus Torvalds 
2941da177e4SLinus Torvalds /* If the device signature is on the list of incompatible drives, the
2951da177e4SLinus Torvalds    function returns a pointer to the name of the correct driver (if known) */
st_incompatible(struct scsi_device * SDp)2961da177e4SLinus Torvalds static char * st_incompatible(struct scsi_device* SDp)
2971da177e4SLinus Torvalds {
2981da177e4SLinus Torvalds 	struct st_reject_data *rp;
2991da177e4SLinus Torvalds 
3001da177e4SLinus Torvalds 	for (rp=&(reject_list[0]); rp->vendor != NULL; rp++)
3011da177e4SLinus Torvalds 		if (!strncmp(rp->vendor, SDp->vendor, strlen(rp->vendor)) &&
3021da177e4SLinus Torvalds 		    !strncmp(rp->model, SDp->model, strlen(rp->model)) &&
3031da177e4SLinus Torvalds 		    !strncmp(rp->rev, SDp->rev, strlen(rp->rev))) {
3041da177e4SLinus Torvalds 			if (rp->driver_hint)
3051da177e4SLinus Torvalds 				return rp->driver_hint;
3061da177e4SLinus Torvalds 			else
3071da177e4SLinus Torvalds 				return "unknown";
3081da177e4SLinus Torvalds 		}
3091da177e4SLinus Torvalds 	return NULL;
3101da177e4SLinus Torvalds }
3111da177e4SLinus Torvalds 
3121da177e4SLinus Torvalds 
313b30d8bcaSHannes Reinecke #define st_printk(prefix, t, fmt, a...) \
31445938335SChristoph Hellwig 	sdev_prefix_printk(prefix, (t)->device, (t)->name, fmt, ##a)
315b30d8bcaSHannes Reinecke #ifdef DEBUG
316b30d8bcaSHannes Reinecke #define DEBC_printk(t, fmt, a...) \
317b30d8bcaSHannes Reinecke 	if (debugging) { st_printk(ST_DEB_MSG, t, fmt, ##a ); }
318b30d8bcaSHannes Reinecke #else
319b30d8bcaSHannes Reinecke #define DEBC_printk(t, fmt, a...)
320b30d8bcaSHannes Reinecke #endif
3211da177e4SLinus Torvalds 
st_analyze_sense(struct st_request * SRpnt,struct st_cmdstatus * s)3228b05b773SMike Christie static void st_analyze_sense(struct st_request *SRpnt, struct st_cmdstatus *s)
3231da177e4SLinus Torvalds {
3241da177e4SLinus Torvalds 	const u8 *ucp;
3258b05b773SMike Christie 	const u8 *sense = SRpnt->sense;
3261da177e4SLinus Torvalds 
3278b05b773SMike Christie 	s->have_sense = scsi_normalize_sense(SRpnt->sense,
3288b05b773SMike Christie 				SCSI_SENSE_BUFFERSIZE, &s->sense_hdr);
3291da177e4SLinus Torvalds 	s->flags = 0;
3301da177e4SLinus Torvalds 
3311da177e4SLinus Torvalds 	if (s->have_sense) {
3321da177e4SLinus Torvalds 		s->deferred = 0;
3331da177e4SLinus Torvalds 		s->remainder_valid =
3341da177e4SLinus Torvalds 			scsi_get_sense_info_fld(sense, SCSI_SENSE_BUFFERSIZE, &s->uremainder64);
3351da177e4SLinus Torvalds 		switch (sense[0] & 0x7f) {
3361da177e4SLinus Torvalds 		case 0x71:
3371da177e4SLinus Torvalds 			s->deferred = 1;
338df561f66SGustavo A. R. Silva 			fallthrough;
3391da177e4SLinus Torvalds 		case 0x70:
3401da177e4SLinus Torvalds 			s->fixed_format = 1;
3411da177e4SLinus Torvalds 			s->flags = sense[2] & 0xe0;
3421da177e4SLinus Torvalds 			break;
3431da177e4SLinus Torvalds 		case 0x73:
3441da177e4SLinus Torvalds 			s->deferred = 1;
345df561f66SGustavo A. R. Silva 			fallthrough;
3461da177e4SLinus Torvalds 		case 0x72:
3471da177e4SLinus Torvalds 			s->fixed_format = 0;
3481da177e4SLinus Torvalds 			ucp = scsi_sense_desc_find(sense, SCSI_SENSE_BUFFERSIZE, 4);
3491da177e4SLinus Torvalds 			s->flags = ucp ? (ucp[3] & 0xe0) : 0;
3501da177e4SLinus Torvalds 			break;
3511da177e4SLinus Torvalds 		}
3521da177e4SLinus Torvalds 	}
3531da177e4SLinus Torvalds }
3541da177e4SLinus Torvalds 
3551da177e4SLinus Torvalds 
3561da177e4SLinus Torvalds /* Convert the result to success code */
st_chk_result(struct scsi_tape * STp,struct st_request * SRpnt)3578b05b773SMike Christie static int st_chk_result(struct scsi_tape *STp, struct st_request * SRpnt)
3581da177e4SLinus Torvalds {
3598b05b773SMike Christie 	int result = SRpnt->result;
3601da177e4SLinus Torvalds 	u8 scode;
3611da177e4SLinus Torvalds 	DEB(const char *stp;)
36245938335SChristoph Hellwig 	char *name = STp->name;
3631da177e4SLinus Torvalds 	struct st_cmdstatus *cmdstatp;
3641da177e4SLinus Torvalds 
3651da177e4SLinus Torvalds 	if (!result)
3661da177e4SLinus Torvalds 		return 0;
3671da177e4SLinus Torvalds 
3681da177e4SLinus Torvalds 	cmdstatp = &STp->buffer->cmdstat;
369f03a5670SKai Makisara 	st_analyze_sense(SRpnt, cmdstatp);
3701da177e4SLinus Torvalds 
3711da177e4SLinus Torvalds 	if (cmdstatp->have_sense)
3721da177e4SLinus Torvalds 		scode = STp->buffer->cmdstat.sense_hdr.sense_key;
3731da177e4SLinus Torvalds 	else
3741da177e4SLinus Torvalds 		scode = 0;
3751da177e4SLinus Torvalds 
3761da177e4SLinus Torvalds 	DEB(
3771da177e4SLinus Torvalds 	if (debugging) {
378b30d8bcaSHannes Reinecke 		st_printk(ST_DEB_MSG, STp,
379b30d8bcaSHannes Reinecke 			    "Error: %x, cmd: %x %x %x %x %x %x\n", result,
3808b05b773SMike Christie 			    SRpnt->cmd[0], SRpnt->cmd[1], SRpnt->cmd[2],
3818b05b773SMike Christie 			    SRpnt->cmd[3], SRpnt->cmd[4], SRpnt->cmd[5]);
3821da177e4SLinus Torvalds 		if (cmdstatp->have_sense)
383d811b848SHannes Reinecke 			__scsi_print_sense(STp->device, name,
384d811b848SHannes Reinecke 					   SRpnt->sense, SCSI_SENSE_BUFFERSIZE);
3851da177e4SLinus Torvalds 	} ) /* end DEB */
3861da177e4SLinus Torvalds 	if (!debugging) { /* Abnormal conditions for tape */
3871da177e4SLinus Torvalds 		if (!cmdstatp->have_sense)
388b30d8bcaSHannes Reinecke 			st_printk(KERN_WARNING, STp,
38954c29086SHannes Reinecke 			       "Error %x (driver bt 0, host bt 0x%x).\n",
39054c29086SHannes Reinecke 			       result, host_byte(result));
3911da177e4SLinus Torvalds 		else if (cmdstatp->have_sense &&
3921da177e4SLinus Torvalds 			 scode != NO_SENSE &&
3931da177e4SLinus Torvalds 			 scode != RECOVERED_ERROR &&
3941da177e4SLinus Torvalds 			 /* scode != UNIT_ATTENTION && */
3951da177e4SLinus Torvalds 			 scode != BLANK_CHECK &&
3961da177e4SLinus Torvalds 			 scode != VOLUME_OVERFLOW &&
3978b05b773SMike Christie 			 SRpnt->cmd[0] != MODE_SENSE &&
3988b05b773SMike Christie 			 SRpnt->cmd[0] != TEST_UNIT_READY) {
3994e73ea7bSLuben Tuikov 
400d811b848SHannes Reinecke 			__scsi_print_sense(STp->device, name,
401d811b848SHannes Reinecke 					   SRpnt->sense, SCSI_SENSE_BUFFERSIZE);
4021da177e4SLinus Torvalds 		}
4031da177e4SLinus Torvalds 	}
4041da177e4SLinus Torvalds 
4051da177e4SLinus Torvalds 	if (cmdstatp->fixed_format &&
4061da177e4SLinus Torvalds 	    STp->cln_mode >= EXTENDED_SENSE_START) {  /* Only fixed format sense */
4071da177e4SLinus Torvalds 		if (STp->cln_sense_value)
4088b05b773SMike Christie 			STp->cleaning_req |= ((SRpnt->sense[STp->cln_mode] &
4091da177e4SLinus Torvalds 					       STp->cln_sense_mask) == STp->cln_sense_value);
4101da177e4SLinus Torvalds 		else
4118b05b773SMike Christie 			STp->cleaning_req |= ((SRpnt->sense[STp->cln_mode] &
4121da177e4SLinus Torvalds 					       STp->cln_sense_mask) != 0);
4131da177e4SLinus Torvalds 	}
4141da177e4SLinus Torvalds 	if (cmdstatp->have_sense &&
4151da177e4SLinus Torvalds 	    cmdstatp->sense_hdr.asc == 0 && cmdstatp->sense_hdr.ascq == 0x17)
4161da177e4SLinus Torvalds 		STp->cleaning_req = 1; /* ASC and ASCQ => cleaning requested */
4179604eea5SJohn Meneghini 	if (cmdstatp->have_sense && scode == UNIT_ATTENTION && cmdstatp->sense_hdr.asc == 0x29)
4189604eea5SJohn Meneghini 		STp->pos_unknown = 1; /* ASC => power on / reset */
4191da177e4SLinus Torvalds 
4201da177e4SLinus Torvalds 	STp->pos_unknown |= STp->device->was_reset;
4211da177e4SLinus Torvalds 
4221da177e4SLinus Torvalds 	if (cmdstatp->have_sense &&
4231da177e4SLinus Torvalds 	    scode == RECOVERED_ERROR
4241da177e4SLinus Torvalds #if ST_RECOVERED_WRITE_FATAL
4258b05b773SMike Christie 	    && SRpnt->cmd[0] != WRITE_6
4268b05b773SMike Christie 	    && SRpnt->cmd[0] != WRITE_FILEMARKS
4271da177e4SLinus Torvalds #endif
4281da177e4SLinus Torvalds 	    ) {
4291da177e4SLinus Torvalds 		STp->recover_count++;
4301da177e4SLinus Torvalds 		STp->recover_reg++;
4311da177e4SLinus Torvalds 
4321da177e4SLinus Torvalds 		DEB(
4331da177e4SLinus Torvalds 		if (debugging) {
4348b05b773SMike Christie 			if (SRpnt->cmd[0] == READ_6)
4351da177e4SLinus Torvalds 				stp = "read";
4368b05b773SMike Christie 			else if (SRpnt->cmd[0] == WRITE_6)
4371da177e4SLinus Torvalds 				stp = "write";
4381da177e4SLinus Torvalds 			else
4391da177e4SLinus Torvalds 				stp = "ioctl";
440b30d8bcaSHannes Reinecke 			st_printk(ST_DEB_MSG, STp,
441b30d8bcaSHannes Reinecke 				  "Recovered %s error (%d).\n",
442b30d8bcaSHannes Reinecke 				  stp, STp->recover_count);
4431da177e4SLinus Torvalds 		} ) /* end DEB */
4441da177e4SLinus Torvalds 
4451da177e4SLinus Torvalds 		if (cmdstatp->flags == 0)
4461da177e4SLinus Torvalds 			return 0;
4471da177e4SLinus Torvalds 	}
4481da177e4SLinus Torvalds 	return (-EIO);
4491da177e4SLinus Torvalds }
4501da177e4SLinus Torvalds 
st_allocate_request(struct scsi_tape * stp)4514deba245SFUJITA Tomonori static struct st_request *st_allocate_request(struct scsi_tape *stp)
4528b05b773SMike Christie {
4534deba245SFUJITA Tomonori 	struct st_request *streq;
4544deba245SFUJITA Tomonori 
4554deba245SFUJITA Tomonori 	streq = kzalloc(sizeof(*streq), GFP_KERNEL);
4564deba245SFUJITA Tomonori 	if (streq)
4574deba245SFUJITA Tomonori 		streq->stp = stp;
4584deba245SFUJITA Tomonori 	else {
459b30d8bcaSHannes Reinecke 		st_printk(KERN_ERR, stp,
460b30d8bcaSHannes Reinecke 			  "Can't get SCSI request.\n");
4614deba245SFUJITA Tomonori 		if (signal_pending(current))
4624deba245SFUJITA Tomonori 			stp->buffer->syscall_result = -EINTR;
4634deba245SFUJITA Tomonori 		else
4644deba245SFUJITA Tomonori 			stp->buffer->syscall_result = -EBUSY;
4654deba245SFUJITA Tomonori 	}
4664deba245SFUJITA Tomonori 
4674deba245SFUJITA Tomonori 	return streq;
4688b05b773SMike Christie }
4698b05b773SMike Christie 
st_release_request(struct st_request * streq)4708b05b773SMike Christie static void st_release_request(struct st_request *streq)
4718b05b773SMike Christie {
4728b05b773SMike Christie 	kfree(streq);
4731da177e4SLinus Torvalds }
4741da177e4SLinus Torvalds 
st_do_stats(struct scsi_tape * STp,struct request * req)47505545c92SSeymour, Shane M static void st_do_stats(struct scsi_tape *STp, struct request *req)
47605545c92SSeymour, Shane M {
477ce70fd9aSChristoph Hellwig 	struct scsi_cmnd *scmd = blk_mq_rq_to_pdu(req);
47805545c92SSeymour, Shane M 	ktime_t now;
47905545c92SSeymour, Shane M 
48005545c92SSeymour, Shane M 	now = ktime_get();
481ce70fd9aSChristoph Hellwig 	if (scmd->cmnd[0] == WRITE_6) {
48205545c92SSeymour, Shane M 		now = ktime_sub(now, STp->stats->write_time);
48305545c92SSeymour, Shane M 		atomic64_add(ktime_to_ns(now), &STp->stats->tot_write_time);
48405545c92SSeymour, Shane M 		atomic64_add(ktime_to_ns(now), &STp->stats->tot_io_time);
48505545c92SSeymour, Shane M 		atomic64_inc(&STp->stats->write_cnt);
486dbb4c84dSChristoph Hellwig 		if (scmd->result) {
48705545c92SSeymour, Shane M 			atomic64_add(atomic_read(&STp->stats->last_write_size)
48805545c92SSeymour, Shane M 				- STp->buffer->cmdstat.residual,
48905545c92SSeymour, Shane M 				&STp->stats->write_byte_cnt);
49005545c92SSeymour, Shane M 			if (STp->buffer->cmdstat.residual > 0)
49105545c92SSeymour, Shane M 				atomic64_inc(&STp->stats->resid_cnt);
49205545c92SSeymour, Shane M 		} else
49305545c92SSeymour, Shane M 			atomic64_add(atomic_read(&STp->stats->last_write_size),
49405545c92SSeymour, Shane M 				&STp->stats->write_byte_cnt);
495ce70fd9aSChristoph Hellwig 	} else if (scmd->cmnd[0] == READ_6) {
49605545c92SSeymour, Shane M 		now = ktime_sub(now, STp->stats->read_time);
49705545c92SSeymour, Shane M 		atomic64_add(ktime_to_ns(now), &STp->stats->tot_read_time);
49805545c92SSeymour, Shane M 		atomic64_add(ktime_to_ns(now), &STp->stats->tot_io_time);
49905545c92SSeymour, Shane M 		atomic64_inc(&STp->stats->read_cnt);
500dbb4c84dSChristoph Hellwig 		if (scmd->result) {
50105545c92SSeymour, Shane M 			atomic64_add(atomic_read(&STp->stats->last_read_size)
50205545c92SSeymour, Shane M 				- STp->buffer->cmdstat.residual,
50305545c92SSeymour, Shane M 				&STp->stats->read_byte_cnt);
50405545c92SSeymour, Shane M 			if (STp->buffer->cmdstat.residual > 0)
50505545c92SSeymour, Shane M 				atomic64_inc(&STp->stats->resid_cnt);
50605545c92SSeymour, Shane M 		} else
50705545c92SSeymour, Shane M 			atomic64_add(atomic_read(&STp->stats->last_read_size),
50805545c92SSeymour, Shane M 				&STp->stats->read_byte_cnt);
50905545c92SSeymour, Shane M 	} else {
51005545c92SSeymour, Shane M 		now = ktime_sub(now, STp->stats->other_time);
51105545c92SSeymour, Shane M 		atomic64_add(ktime_to_ns(now), &STp->stats->tot_io_time);
51205545c92SSeymour, Shane M 		atomic64_inc(&STp->stats->other_cnt);
51305545c92SSeymour, Shane M 	}
51405545c92SSeymour, Shane M 	atomic64_dec(&STp->stats->in_flight);
51505545c92SSeymour, Shane M }
51605545c92SSeymour, Shane M 
st_scsi_execute_end(struct request * req,blk_status_t status)517de671d61SJens Axboe static enum rq_end_io_ret st_scsi_execute_end(struct request *req,
518de671d61SJens Axboe 					      blk_status_t status)
51913b53b44SFUJITA Tomonori {
5205b794f98SChristoph Hellwig 	struct scsi_cmnd *scmd = blk_mq_rq_to_pdu(req);
52113b53b44SFUJITA Tomonori 	struct st_request *SRpnt = req->end_io_data;
52213b53b44SFUJITA Tomonori 	struct scsi_tape *STp = SRpnt->stp;
523c68bf8eeSPetr Uzel 	struct bio *tmp;
52413b53b44SFUJITA Tomonori 
525dbb4c84dSChristoph Hellwig 	STp->buffer->cmdstat.midlevel_result = SRpnt->result = scmd->result;
526a9a4ea11SChristoph Hellwig 	STp->buffer->cmdstat.residual = scmd->resid_len;
52713b53b44SFUJITA Tomonori 
52805545c92SSeymour, Shane M 	st_do_stats(STp, req);
52905545c92SSeymour, Shane M 
530c68bf8eeSPetr Uzel 	tmp = SRpnt->bio;
5315b794f98SChristoph Hellwig 	if (scmd->sense_len)
5325b794f98SChristoph Hellwig 		memcpy(SRpnt->sense, scmd->sense_buffer, SCSI_SENSE_BUFFERSIZE);
53313b53b44SFUJITA Tomonori 	if (SRpnt->waiting)
53413b53b44SFUJITA Tomonori 		complete(SRpnt->waiting);
53513b53b44SFUJITA Tomonori 
536c68bf8eeSPetr Uzel 	blk_rq_unmap_user(tmp);
5370bf6d96cSChristoph Hellwig 	blk_mq_free_request(req);
538de671d61SJens Axboe 	return RQ_END_IO_NONE;
53913b53b44SFUJITA Tomonori }
54013b53b44SFUJITA Tomonori 
st_scsi_execute(struct st_request * SRpnt,const unsigned char * cmd,int data_direction,void * buffer,unsigned bufflen,int timeout,int retries)54113b53b44SFUJITA Tomonori static int st_scsi_execute(struct st_request *SRpnt, const unsigned char *cmd,
54213b53b44SFUJITA Tomonori 			   int data_direction, void *buffer, unsigned bufflen,
54313b53b44SFUJITA Tomonori 			   int timeout, int retries)
54413b53b44SFUJITA Tomonori {
54513b53b44SFUJITA Tomonori 	struct request *req;
54613b53b44SFUJITA Tomonori 	struct rq_map_data *mdata = &SRpnt->stp->buffer->map_data;
54713b53b44SFUJITA Tomonori 	int err = 0;
54805545c92SSeymour, Shane M 	struct scsi_tape *STp = SRpnt->stp;
549ce70fd9aSChristoph Hellwig 	struct scsi_cmnd *scmd;
55013b53b44SFUJITA Tomonori 
55168ec3b81SChristoph Hellwig 	req = scsi_alloc_request(SRpnt->stp->device->request_queue,
552aebf526bSChristoph Hellwig 			data_direction == DMA_TO_DEVICE ?
553da6269daSChristoph Hellwig 			REQ_OP_DRV_OUT : REQ_OP_DRV_IN, 0);
554a492f075SJoe Lawrence 	if (IS_ERR(req))
55500da6a70SHannes Reinecke 		return PTR_ERR(req);
556ce70fd9aSChristoph Hellwig 	scmd = blk_mq_rq_to_pdu(req);
557e8064021SChristoph Hellwig 	req->rq_flags |= RQF_QUIET;
55813b53b44SFUJITA Tomonori 
55913b53b44SFUJITA Tomonori 	mdata->null_mapped = 1;
56013b53b44SFUJITA Tomonori 
56102ae2c0eSKai Makisara 	if (bufflen) {
56202ae2c0eSKai Makisara 		err = blk_rq_map_user(req->q, req, mdata, NULL, bufflen,
56302ae2c0eSKai Makisara 				      GFP_KERNEL);
56413b53b44SFUJITA Tomonori 		if (err) {
5650bf6d96cSChristoph Hellwig 			blk_mq_free_request(req);
56600da6a70SHannes Reinecke 			return err;
56713b53b44SFUJITA Tomonori 		}
56802ae2c0eSKai Makisara 	}
56913b53b44SFUJITA Tomonori 
57005545c92SSeymour, Shane M 	atomic64_inc(&STp->stats->in_flight);
57105545c92SSeymour, Shane M 	if (cmd[0] == WRITE_6) {
57205545c92SSeymour, Shane M 		atomic_set(&STp->stats->last_write_size, bufflen);
57305545c92SSeymour, Shane M 		STp->stats->write_time = ktime_get();
57405545c92SSeymour, Shane M 	} else if (cmd[0] == READ_6) {
57505545c92SSeymour, Shane M 		atomic_set(&STp->stats->last_read_size, bufflen);
57605545c92SSeymour, Shane M 		STp->stats->read_time = ktime_get();
57705545c92SSeymour, Shane M 	} else {
57805545c92SSeymour, Shane M 		STp->stats->other_time = ktime_get();
57905545c92SSeymour, Shane M 	}
58005545c92SSeymour, Shane M 
58113b53b44SFUJITA Tomonori 	SRpnt->bio = req->bio;
582ce70fd9aSChristoph Hellwig 	scmd->cmd_len = COMMAND_SIZE(cmd[0]);
583ce70fd9aSChristoph Hellwig 	memcpy(scmd->cmnd, cmd, scmd->cmd_len);
58413b53b44SFUJITA Tomonori 	req->timeout = timeout;
5856aded12bSChristoph Hellwig 	scmd->allowed = retries;
586e2e53086SChristoph Hellwig 	req->end_io = st_scsi_execute_end;
58713b53b44SFUJITA Tomonori 	req->end_io_data = SRpnt;
58813b53b44SFUJITA Tomonori 
589e2e53086SChristoph Hellwig 	blk_execute_rq_nowait(req, true);
59013b53b44SFUJITA Tomonori 	return 0;
59113b53b44SFUJITA Tomonori }
59213b53b44SFUJITA Tomonori 
5931da177e4SLinus Torvalds /* Do the scsi command. Waits until command performed if do_wait is true.
5941da177e4SLinus Torvalds    Otherwise write_behind_check() is used to check that the command
5951da177e4SLinus Torvalds    has finished. */
5968b05b773SMike Christie static struct st_request *
st_do_scsi(struct st_request * SRpnt,struct scsi_tape * STp,unsigned char * cmd,int bytes,int direction,int timeout,int retries,int do_wait)5978b05b773SMike Christie st_do_scsi(struct st_request * SRpnt, struct scsi_tape * STp, unsigned char *cmd,
5981da177e4SLinus Torvalds 	   int bytes, int direction, int timeout, int retries, int do_wait)
5991da177e4SLinus Torvalds {
600f03a5670SKai Makisara 	struct completion *waiting;
6016d476267SFUJITA Tomonori 	struct rq_map_data *mdata = &STp->buffer->map_data;
6026d476267SFUJITA Tomonori 	int ret;
6031da177e4SLinus Torvalds 
604f03a5670SKai Makisara 	/* if async, make sure there's no command outstanding */
605f03a5670SKai Makisara 	if (!do_wait && ((STp->buffer)->last_SRpnt)) {
606b30d8bcaSHannes Reinecke 		st_printk(KERN_ERR, STp,
607b30d8bcaSHannes Reinecke 			  "Async command already active.\n");
608f03a5670SKai Makisara 		if (signal_pending(current))
609f03a5670SKai Makisara 			(STp->buffer)->syscall_result = (-EINTR);
610f03a5670SKai Makisara 		else
611f03a5670SKai Makisara 			(STp->buffer)->syscall_result = (-EBUSY);
612f03a5670SKai Makisara 		return NULL;
613f03a5670SKai Makisara 	}
614f03a5670SKai Makisara 
6154deba245SFUJITA Tomonori 	if (!SRpnt) {
6164deba245SFUJITA Tomonori 		SRpnt = st_allocate_request(STp);
6174deba245SFUJITA Tomonori 		if (!SRpnt)
6181da177e4SLinus Torvalds 			return NULL;
6191da177e4SLinus Torvalds 	}
6201da177e4SLinus Torvalds 
621f03a5670SKai Makisara 	/* If async IO, set last_SRpnt. This ptr tells write_behind_check
622f03a5670SKai Makisara 	   which IO is outstanding. It's nulled out when the IO completes. */
623f03a5670SKai Makisara 	if (!do_wait)
624f03a5670SKai Makisara 		(STp->buffer)->last_SRpnt = SRpnt;
625f03a5670SKai Makisara 
626f03a5670SKai Makisara 	waiting = &STp->wait;
627f03a5670SKai Makisara 	init_completion(waiting);
6288b05b773SMike Christie 	SRpnt->waiting = waiting;
6298b05b773SMike Christie 
6306620742fSFUJITA Tomonori 	if (STp->buffer->do_dio) {
631c982c368SFUJITA Tomonori 		mdata->page_order = 0;
6326620742fSFUJITA Tomonori 		mdata->nr_entries = STp->buffer->sg_segs;
6336620742fSFUJITA Tomonori 		mdata->pages = STp->buffer->mapped_pages;
6346620742fSFUJITA Tomonori 	} else {
635c982c368SFUJITA Tomonori 		mdata->page_order = STp->buffer->reserved_page_order;
6366d476267SFUJITA Tomonori 		mdata->nr_entries =
6376d476267SFUJITA Tomonori 			DIV_ROUND_UP(bytes, PAGE_SIZE << mdata->page_order);
638c982c368SFUJITA Tomonori 		mdata->pages = STp->buffer->reserved_pages;
639c982c368SFUJITA Tomonori 		mdata->offset = 0;
6406d476267SFUJITA Tomonori 	}
6416d476267SFUJITA Tomonori 
6428b05b773SMike Christie 	memcpy(SRpnt->cmd, cmd, sizeof(SRpnt->cmd));
6431da177e4SLinus Torvalds 	STp->buffer->cmdstat.have_sense = 0;
6448b05b773SMike Christie 	STp->buffer->syscall_result = 0;
6451da177e4SLinus Torvalds 
6466620742fSFUJITA Tomonori 	ret = st_scsi_execute(SRpnt, cmd, direction, NULL, bytes, timeout,
6476620742fSFUJITA Tomonori 			      retries);
6486d476267SFUJITA Tomonori 	if (ret) {
6498b05b773SMike Christie 		/* could not allocate the buffer or request was too large */
6508b05b773SMike Christie 		(STp->buffer)->syscall_result = (-EBUSY);
651787926b1SKai Makisara 		(STp->buffer)->last_SRpnt = NULL;
6526d476267SFUJITA Tomonori 	} else if (do_wait) {
653f03a5670SKai Makisara 		wait_for_completion(waiting);
6548b05b773SMike Christie 		SRpnt->waiting = NULL;
6551da177e4SLinus Torvalds 		(STp->buffer)->syscall_result = st_chk_result(STp, SRpnt);
6561da177e4SLinus Torvalds 	}
6578b05b773SMike Christie 
6581da177e4SLinus Torvalds 	return SRpnt;
6591da177e4SLinus Torvalds }
6601da177e4SLinus Torvalds 
6611da177e4SLinus Torvalds 
6621da177e4SLinus Torvalds /* Handle the write-behind checking (waits for completion). Returns -ENOSPC if
6631da177e4SLinus Torvalds    write has been correct but EOM early warning reached, -EIO if write ended in
6641da177e4SLinus Torvalds    error or zero if write successful. Asynchronous writes are used only in
6651da177e4SLinus Torvalds    variable block mode. */
write_behind_check(struct scsi_tape * STp)6661da177e4SLinus Torvalds static int write_behind_check(struct scsi_tape * STp)
6671da177e4SLinus Torvalds {
6681da177e4SLinus Torvalds 	int retval = 0;
6691da177e4SLinus Torvalds 	struct st_buffer *STbuffer;
6701da177e4SLinus Torvalds 	struct st_partstat *STps;
6711da177e4SLinus Torvalds 	struct st_cmdstatus *cmdstatp;
6728b05b773SMike Christie 	struct st_request *SRpnt;
6731da177e4SLinus Torvalds 
6741da177e4SLinus Torvalds 	STbuffer = STp->buffer;
6751da177e4SLinus Torvalds 	if (!STbuffer->writing)
6761da177e4SLinus Torvalds 		return 0;
6771da177e4SLinus Torvalds 
6781da177e4SLinus Torvalds 	DEB(
6791da177e4SLinus Torvalds 	if (STp->write_pending)
6801da177e4SLinus Torvalds 		STp->nbr_waits++;
6811da177e4SLinus Torvalds 	else
6821da177e4SLinus Torvalds 		STp->nbr_finished++;
6831da177e4SLinus Torvalds 	) /* end DEB */
6841da177e4SLinus Torvalds 
6851da177e4SLinus Torvalds 	wait_for_completion(&(STp->wait));
686f03a5670SKai Makisara 	SRpnt = STbuffer->last_SRpnt;
687f03a5670SKai Makisara 	STbuffer->last_SRpnt = NULL;
6888b05b773SMike Christie 	SRpnt->waiting = NULL;
6891da177e4SLinus Torvalds 
690f03a5670SKai Makisara 	(STp->buffer)->syscall_result = st_chk_result(STp, SRpnt);
6918b05b773SMike Christie 	st_release_request(SRpnt);
6921da177e4SLinus Torvalds 
6931da177e4SLinus Torvalds 	STbuffer->buffer_bytes -= STbuffer->writing;
6941da177e4SLinus Torvalds 	STps = &(STp->ps[STp->partition]);
6951da177e4SLinus Torvalds 	if (STps->drv_block >= 0) {
6961da177e4SLinus Torvalds 		if (STp->block_size == 0)
6971da177e4SLinus Torvalds 			STps->drv_block++;
6981da177e4SLinus Torvalds 		else
6991da177e4SLinus Torvalds 			STps->drv_block += STbuffer->writing / STp->block_size;
7001da177e4SLinus Torvalds 	}
7011da177e4SLinus Torvalds 
7021da177e4SLinus Torvalds 	cmdstatp = &STbuffer->cmdstat;
7031da177e4SLinus Torvalds 	if (STbuffer->syscall_result) {
7041da177e4SLinus Torvalds 		retval = -EIO;
7051da177e4SLinus Torvalds 		if (cmdstatp->have_sense && !cmdstatp->deferred &&
7061da177e4SLinus Torvalds 		    (cmdstatp->flags & SENSE_EOM) &&
7071da177e4SLinus Torvalds 		    (cmdstatp->sense_hdr.sense_key == NO_SENSE ||
7081da177e4SLinus Torvalds 		     cmdstatp->sense_hdr.sense_key == RECOVERED_ERROR)) {
7091da177e4SLinus Torvalds 			/* EOM at write-behind, has all data been written? */
7101da177e4SLinus Torvalds 			if (!cmdstatp->remainder_valid ||
7111da177e4SLinus Torvalds 			    cmdstatp->uremainder64 == 0)
7121da177e4SLinus Torvalds 				retval = -ENOSPC;
7131da177e4SLinus Torvalds 		}
7141da177e4SLinus Torvalds 		if (retval == -EIO)
7151da177e4SLinus Torvalds 			STps->drv_block = -1;
7161da177e4SLinus Torvalds 	}
7171da177e4SLinus Torvalds 	STbuffer->writing = 0;
7181da177e4SLinus Torvalds 
7191da177e4SLinus Torvalds 	DEB(if (debugging && retval)
720b30d8bcaSHannes Reinecke 		    st_printk(ST_DEB_MSG, STp,
721b30d8bcaSHannes Reinecke 				"Async write error %x, return value %d.\n",
722b30d8bcaSHannes Reinecke 				STbuffer->cmdstat.midlevel_result, retval);) /* end DEB */
7231da177e4SLinus Torvalds 
7241da177e4SLinus Torvalds 	return retval;
7251da177e4SLinus Torvalds }
7261da177e4SLinus Torvalds 
7271da177e4SLinus Torvalds 
7281da177e4SLinus Torvalds /* Step over EOF if it has been inadvertently crossed (ioctl not used because
7291da177e4SLinus Torvalds    it messes up the block number). */
cross_eof(struct scsi_tape * STp,int forward)7301da177e4SLinus Torvalds static int cross_eof(struct scsi_tape * STp, int forward)
7311da177e4SLinus Torvalds {
7328b05b773SMike Christie 	struct st_request *SRpnt;
7331da177e4SLinus Torvalds 	unsigned char cmd[MAX_COMMAND_SIZE];
7341da177e4SLinus Torvalds 
7351da177e4SLinus Torvalds 	cmd[0] = SPACE;
7361da177e4SLinus Torvalds 	cmd[1] = 0x01;		/* Space FileMarks */
7371da177e4SLinus Torvalds 	if (forward) {
7381da177e4SLinus Torvalds 		cmd[2] = cmd[3] = 0;
7391da177e4SLinus Torvalds 		cmd[4] = 1;
7401da177e4SLinus Torvalds 	} else
7411da177e4SLinus Torvalds 		cmd[2] = cmd[3] = cmd[4] = 0xff;	/* -1 filemarks */
7421da177e4SLinus Torvalds 	cmd[5] = 0;
7431da177e4SLinus Torvalds 
744b30d8bcaSHannes Reinecke 	DEBC_printk(STp, "Stepping over filemark %s.\n",
745b30d8bcaSHannes Reinecke 		    forward ? "forward" : "backward");
7461da177e4SLinus Torvalds 
74702ae2c0eSKai Makisara 	SRpnt = st_do_scsi(NULL, STp, cmd, 0, DMA_NONE,
74839ade4b1SFUJITA Tomonori 			   STp->device->request_queue->rq_timeout,
74902ae2c0eSKai Makisara 			   MAX_RETRIES, 1);
75002ae2c0eSKai Makisara 	if (!SRpnt)
75102ae2c0eSKai Makisara 		return (STp->buffer)->syscall_result;
75239ade4b1SFUJITA Tomonori 
75302ae2c0eSKai Makisara 	st_release_request(SRpnt);
75402ae2c0eSKai Makisara 	SRpnt = NULL;
7551da177e4SLinus Torvalds 
7561da177e4SLinus Torvalds 	if ((STp->buffer)->cmdstat.midlevel_result != 0)
757b30d8bcaSHannes Reinecke 		st_printk(KERN_ERR, STp,
758b30d8bcaSHannes Reinecke 			  "Stepping over filemark %s failed.\n",
759b30d8bcaSHannes Reinecke 			  forward ? "forward" : "backward");
7601da177e4SLinus Torvalds 
76102ae2c0eSKai Makisara 	return (STp->buffer)->syscall_result;
7621da177e4SLinus Torvalds }
7631da177e4SLinus Torvalds 
7641da177e4SLinus Torvalds 
7651da177e4SLinus Torvalds /* Flush the write buffer (never need to write if variable blocksize). */
st_flush_write_buffer(struct scsi_tape * STp)7668ef8d594SAdrian Bunk static int st_flush_write_buffer(struct scsi_tape * STp)
7671da177e4SLinus Torvalds {
768786231afSKai Makisara 	int transfer, blks;
7691da177e4SLinus Torvalds 	int result;
7701da177e4SLinus Torvalds 	unsigned char cmd[MAX_COMMAND_SIZE];
7718b05b773SMike Christie 	struct st_request *SRpnt;
7721da177e4SLinus Torvalds 	struct st_partstat *STps;
7731da177e4SLinus Torvalds 
7741da177e4SLinus Torvalds 	result = write_behind_check(STp);
7751da177e4SLinus Torvalds 	if (result)
7761da177e4SLinus Torvalds 		return result;
7771da177e4SLinus Torvalds 
7781da177e4SLinus Torvalds 	result = 0;
7791da177e4SLinus Torvalds 	if (STp->dirty == 1) {
7801da177e4SLinus Torvalds 
781786231afSKai Makisara 		transfer = STp->buffer->buffer_bytes;
782b30d8bcaSHannes Reinecke 		DEBC_printk(STp, "Flushing %d bytes.\n", transfer);
7831da177e4SLinus Torvalds 
7841da177e4SLinus Torvalds 		memset(cmd, 0, MAX_COMMAND_SIZE);
7851da177e4SLinus Torvalds 		cmd[0] = WRITE_6;
7861da177e4SLinus Torvalds 		cmd[1] = 1;
7871da177e4SLinus Torvalds 		blks = transfer / STp->block_size;
7881da177e4SLinus Torvalds 		cmd[2] = blks >> 16;
7891da177e4SLinus Torvalds 		cmd[3] = blks >> 8;
7901da177e4SLinus Torvalds 		cmd[4] = blks;
7911da177e4SLinus Torvalds 
7921da177e4SLinus Torvalds 		SRpnt = st_do_scsi(NULL, STp, cmd, transfer, DMA_TO_DEVICE,
793a02488edSJames Bottomley 				   STp->device->request_queue->rq_timeout,
794a02488edSJames Bottomley 				   MAX_WRITE_RETRIES, 1);
7951da177e4SLinus Torvalds 		if (!SRpnt)
7961da177e4SLinus Torvalds 			return (STp->buffer)->syscall_result;
7971da177e4SLinus Torvalds 
7981da177e4SLinus Torvalds 		STps = &(STp->ps[STp->partition]);
7991da177e4SLinus Torvalds 		if ((STp->buffer)->syscall_result != 0) {
8001da177e4SLinus Torvalds 			struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat;
8011da177e4SLinus Torvalds 
8021da177e4SLinus Torvalds 			if (cmdstatp->have_sense && !cmdstatp->deferred &&
8031da177e4SLinus Torvalds 			    (cmdstatp->flags & SENSE_EOM) &&
8041da177e4SLinus Torvalds 			    (cmdstatp->sense_hdr.sense_key == NO_SENSE ||
8051da177e4SLinus Torvalds 			     cmdstatp->sense_hdr.sense_key == RECOVERED_ERROR) &&
8061da177e4SLinus Torvalds 			    (!cmdstatp->remainder_valid ||
8071da177e4SLinus Torvalds 			     cmdstatp->uremainder64 == 0)) { /* All written at EOM early warning */
8081da177e4SLinus Torvalds 				STp->dirty = 0;
8091da177e4SLinus Torvalds 				(STp->buffer)->buffer_bytes = 0;
8101da177e4SLinus Torvalds 				if (STps->drv_block >= 0)
8111da177e4SLinus Torvalds 					STps->drv_block += blks;
8121da177e4SLinus Torvalds 				result = (-ENOSPC);
8131da177e4SLinus Torvalds 			} else {
814b30d8bcaSHannes Reinecke 				st_printk(KERN_ERR, STp, "Error on flush.\n");
8151da177e4SLinus Torvalds 				STps->drv_block = (-1);
8161da177e4SLinus Torvalds 				result = (-EIO);
8171da177e4SLinus Torvalds 			}
8181da177e4SLinus Torvalds 		} else {
8191da177e4SLinus Torvalds 			if (STps->drv_block >= 0)
8201da177e4SLinus Torvalds 				STps->drv_block += blks;
8211da177e4SLinus Torvalds 			STp->dirty = 0;
8221da177e4SLinus Torvalds 			(STp->buffer)->buffer_bytes = 0;
8231da177e4SLinus Torvalds 		}
8248b05b773SMike Christie 		st_release_request(SRpnt);
8251da177e4SLinus Torvalds 		SRpnt = NULL;
8261da177e4SLinus Torvalds 	}
8271da177e4SLinus Torvalds 	return result;
8281da177e4SLinus Torvalds }
8291da177e4SLinus Torvalds 
8301da177e4SLinus Torvalds 
8311da177e4SLinus Torvalds /* Flush the tape buffer. The tape will be positioned correctly unless
8321da177e4SLinus Torvalds    seek_next is true. */
flush_buffer(struct scsi_tape * STp,int seek_next)8331da177e4SLinus Torvalds static int flush_buffer(struct scsi_tape *STp, int seek_next)
8341da177e4SLinus Torvalds {
8351da177e4SLinus Torvalds 	int backspace, result;
8361da177e4SLinus Torvalds 	struct st_partstat *STps;
8371da177e4SLinus Torvalds 
8386b63cda2SRafael Rocha 	if (STp->ready != ST_READY)
8396b63cda2SRafael Rocha 		return 0;
8406b63cda2SRafael Rocha 
8411da177e4SLinus Torvalds 	/*
8421da177e4SLinus Torvalds 	 * If there was a bus reset, block further access
8431da177e4SLinus Torvalds 	 * to this device.
8441da177e4SLinus Torvalds 	 */
8451da177e4SLinus Torvalds 	if (STp->pos_unknown)
8461da177e4SLinus Torvalds 		return (-EIO);
8471da177e4SLinus Torvalds 
8481da177e4SLinus Torvalds 	STps = &(STp->ps[STp->partition]);
8491da177e4SLinus Torvalds 	if (STps->rw == ST_WRITING)	/* Writing */
8508ef8d594SAdrian Bunk 		return st_flush_write_buffer(STp);
8511da177e4SLinus Torvalds 
8521da177e4SLinus Torvalds 	if (STp->block_size == 0)
8531da177e4SLinus Torvalds 		return 0;
8541da177e4SLinus Torvalds 
8551da177e4SLinus Torvalds 	backspace = ((STp->buffer)->buffer_bytes +
8561da177e4SLinus Torvalds 		     (STp->buffer)->read_pointer) / STp->block_size -
8571da177e4SLinus Torvalds 	    ((STp->buffer)->read_pointer + STp->block_size - 1) /
8581da177e4SLinus Torvalds 	    STp->block_size;
8591da177e4SLinus Torvalds 	(STp->buffer)->buffer_bytes = 0;
8601da177e4SLinus Torvalds 	(STp->buffer)->read_pointer = 0;
8611da177e4SLinus Torvalds 	result = 0;
8621da177e4SLinus Torvalds 	if (!seek_next) {
8631da177e4SLinus Torvalds 		if (STps->eof == ST_FM_HIT) {
8641da177e4SLinus Torvalds 			result = cross_eof(STp, 0);	/* Back over the EOF hit */
8651da177e4SLinus Torvalds 			if (!result)
8661da177e4SLinus Torvalds 				STps->eof = ST_NOEOF;
8671da177e4SLinus Torvalds 			else {
8681da177e4SLinus Torvalds 				if (STps->drv_file >= 0)
8691da177e4SLinus Torvalds 					STps->drv_file++;
8701da177e4SLinus Torvalds 				STps->drv_block = 0;
8711da177e4SLinus Torvalds 			}
8721da177e4SLinus Torvalds 		}
8731da177e4SLinus Torvalds 		if (!result && backspace > 0)
8741da177e4SLinus Torvalds 			result = st_int_ioctl(STp, MTBSR, backspace);
8751da177e4SLinus Torvalds 	} else if (STps->eof == ST_FM_HIT) {
8761da177e4SLinus Torvalds 		if (STps->drv_file >= 0)
8771da177e4SLinus Torvalds 			STps->drv_file++;
8781da177e4SLinus Torvalds 		STps->drv_block = 0;
8791da177e4SLinus Torvalds 		STps->eof = ST_NOEOF;
8801da177e4SLinus Torvalds 	}
8811da177e4SLinus Torvalds 	return result;
8821da177e4SLinus Torvalds 
8831da177e4SLinus Torvalds }
8841da177e4SLinus Torvalds 
8851da177e4SLinus Torvalds /* Set the mode parameters */
set_mode_densblk(struct scsi_tape * STp,struct st_modedef * STm)8861da177e4SLinus Torvalds static int set_mode_densblk(struct scsi_tape * STp, struct st_modedef * STm)
8871da177e4SLinus Torvalds {
8881da177e4SLinus Torvalds 	int set_it = 0;
8891da177e4SLinus Torvalds 	unsigned long arg;
8901da177e4SLinus Torvalds 
8911da177e4SLinus Torvalds 	if (!STp->density_changed &&
8921da177e4SLinus Torvalds 	    STm->default_density >= 0 &&
8931da177e4SLinus Torvalds 	    STm->default_density != STp->density) {
8941da177e4SLinus Torvalds 		arg = STm->default_density;
8951da177e4SLinus Torvalds 		set_it = 1;
8961da177e4SLinus Torvalds 	} else
8971da177e4SLinus Torvalds 		arg = STp->density;
8981da177e4SLinus Torvalds 	arg <<= MT_ST_DENSITY_SHIFT;
8991da177e4SLinus Torvalds 	if (!STp->blksize_changed &&
9001da177e4SLinus Torvalds 	    STm->default_blksize >= 0 &&
9011da177e4SLinus Torvalds 	    STm->default_blksize != STp->block_size) {
9021da177e4SLinus Torvalds 		arg |= STm->default_blksize;
9031da177e4SLinus Torvalds 		set_it = 1;
9041da177e4SLinus Torvalds 	} else
9051da177e4SLinus Torvalds 		arg |= STp->block_size;
9061da177e4SLinus Torvalds 	if (set_it &&
9071da177e4SLinus Torvalds 	    st_int_ioctl(STp, SET_DENS_AND_BLK, arg)) {
908b30d8bcaSHannes Reinecke 		st_printk(KERN_WARNING, STp,
909b30d8bcaSHannes Reinecke 			  "Can't set default block size to %d bytes "
910b30d8bcaSHannes Reinecke 			  "and density %x.\n",
911b30d8bcaSHannes Reinecke 			  STm->default_blksize, STm->default_density);
9121da177e4SLinus Torvalds 		if (modes_defined)
9131da177e4SLinus Torvalds 			return (-EINVAL);
9141da177e4SLinus Torvalds 	}
9151da177e4SLinus Torvalds 	return 0;
9161da177e4SLinus Torvalds }
9171da177e4SLinus Torvalds 
9181da177e4SLinus Torvalds 
9198b05b773SMike Christie /* Lock or unlock the drive door. Don't use when st_request allocated. */
do_door_lock(struct scsi_tape * STp,int do_lock)9201da177e4SLinus Torvalds static int do_door_lock(struct scsi_tape * STp, int do_lock)
9211da177e4SLinus Torvalds {
922dccfa688SChristoph Hellwig 	int retval;
9231da177e4SLinus Torvalds 
924b30d8bcaSHannes Reinecke 	DEBC_printk(STp, "%socking drive door.\n", do_lock ? "L" : "Unl");
925dccfa688SChristoph Hellwig 
926dccfa688SChristoph Hellwig 	retval = scsi_set_medium_removal(STp->device,
927dccfa688SChristoph Hellwig 			do_lock ? SCSI_REMOVAL_PREVENT : SCSI_REMOVAL_ALLOW);
928dccfa688SChristoph Hellwig 	if (!retval)
9291da177e4SLinus Torvalds 		STp->door_locked = do_lock ? ST_LOCKED_EXPLICIT : ST_UNLOCKED;
930dccfa688SChristoph Hellwig 	else
9311da177e4SLinus Torvalds 		STp->door_locked = ST_LOCK_FAILS;
9321da177e4SLinus Torvalds 	return retval;
9331da177e4SLinus Torvalds }
9341da177e4SLinus Torvalds 
9351da177e4SLinus Torvalds 
9361da177e4SLinus Torvalds /* Set the internal state after reset */
reset_state(struct scsi_tape * STp)9371da177e4SLinus Torvalds static void reset_state(struct scsi_tape *STp)
9381da177e4SLinus Torvalds {
9391da177e4SLinus Torvalds 	int i;
9401da177e4SLinus Torvalds 	struct st_partstat *STps;
9411da177e4SLinus Torvalds 
9421da177e4SLinus Torvalds 	STp->pos_unknown = 0;
9431da177e4SLinus Torvalds 	for (i = 0; i < ST_NBR_PARTITIONS; i++) {
9441da177e4SLinus Torvalds 		STps = &(STp->ps[i]);
9451da177e4SLinus Torvalds 		STps->rw = ST_IDLE;
9461da177e4SLinus Torvalds 		STps->eof = ST_NOEOF;
9471da177e4SLinus Torvalds 		STps->at_sm = 0;
9481da177e4SLinus Torvalds 		STps->last_block_valid = 0;
9491da177e4SLinus Torvalds 		STps->drv_block = -1;
9501da177e4SLinus Torvalds 		STps->drv_file = -1;
9511da177e4SLinus Torvalds 	}
9521da177e4SLinus Torvalds 	if (STp->can_partitions) {
9531da177e4SLinus Torvalds 		STp->partition = find_partition(STp);
9541da177e4SLinus Torvalds 		if (STp->partition < 0)
9551da177e4SLinus Torvalds 			STp->partition = 0;
9561da177e4SLinus Torvalds 		STp->new_partition = STp->partition;
9571da177e4SLinus Torvalds 	}
9581da177e4SLinus Torvalds }
9591da177e4SLinus Torvalds 
9601da177e4SLinus Torvalds /* Test if the drive is ready. Returns either one of the codes below or a negative system
9611da177e4SLinus Torvalds    error code. */
9621da177e4SLinus Torvalds #define CHKRES_READY       0
9631da177e4SLinus Torvalds #define CHKRES_NEW_SESSION 1
9641da177e4SLinus Torvalds #define CHKRES_NOT_READY   2
9651da177e4SLinus Torvalds #define CHKRES_NO_TAPE     3
9661da177e4SLinus Torvalds 
9671da177e4SLinus Torvalds #define MAX_ATTENTIONS    10
9681da177e4SLinus Torvalds 
test_ready(struct scsi_tape * STp,int do_wait)9691da177e4SLinus Torvalds static int test_ready(struct scsi_tape *STp, int do_wait)
9701da177e4SLinus Torvalds {
9711da177e4SLinus Torvalds 	int attentions, waits, max_wait, scode;
9721da177e4SLinus Torvalds 	int retval = CHKRES_READY, new_session = 0;
9731da177e4SLinus Torvalds 	unsigned char cmd[MAX_COMMAND_SIZE];
97402ae2c0eSKai Makisara 	struct st_request *SRpnt = NULL;
9751da177e4SLinus Torvalds 	struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat;
9761da177e4SLinus Torvalds 
9771da177e4SLinus Torvalds 	max_wait = do_wait ? ST_BLOCK_SECONDS : 0;
9781da177e4SLinus Torvalds 
9791da177e4SLinus Torvalds 	for (attentions=waits=0; ; ) {
9801da177e4SLinus Torvalds 		memset((void *) &cmd[0], 0, MAX_COMMAND_SIZE);
9811da177e4SLinus Torvalds 		cmd[0] = TEST_UNIT_READY;
98202ae2c0eSKai Makisara 		SRpnt = st_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE,
98302ae2c0eSKai Makisara 				   STp->long_timeout, MAX_READY_RETRIES, 1);
9841da177e4SLinus Torvalds 
98502ae2c0eSKai Makisara 		if (!SRpnt) {
98602ae2c0eSKai Makisara 			retval = (STp->buffer)->syscall_result;
9871da177e4SLinus Torvalds 			break;
98802ae2c0eSKai Makisara 		}
9891da177e4SLinus Torvalds 
9901da177e4SLinus Torvalds 		if (cmdstatp->have_sense) {
9911da177e4SLinus Torvalds 
9921da177e4SLinus Torvalds 			scode = cmdstatp->sense_hdr.sense_key;
9931da177e4SLinus Torvalds 
9941da177e4SLinus Torvalds 			if (scode == UNIT_ATTENTION) { /* New media? */
9951da177e4SLinus Torvalds 				new_session = 1;
9961da177e4SLinus Torvalds 				if (attentions < MAX_ATTENTIONS) {
9971da177e4SLinus Torvalds 					attentions++;
9981da177e4SLinus Torvalds 					continue;
9991da177e4SLinus Torvalds 				}
10001da177e4SLinus Torvalds 				else {
10011da177e4SLinus Torvalds 					retval = (-EIO);
10021da177e4SLinus Torvalds 					break;
10031da177e4SLinus Torvalds 				}
10041da177e4SLinus Torvalds 			}
10051da177e4SLinus Torvalds 
10061da177e4SLinus Torvalds 			if (scode == NOT_READY) {
10071da177e4SLinus Torvalds 				if (waits < max_wait) {
10081da177e4SLinus Torvalds 					if (msleep_interruptible(1000)) {
10091da177e4SLinus Torvalds 						retval = (-EINTR);
10101da177e4SLinus Torvalds 						break;
10111da177e4SLinus Torvalds 					}
10121da177e4SLinus Torvalds 					waits++;
10131da177e4SLinus Torvalds 					continue;
10141da177e4SLinus Torvalds 				}
10151da177e4SLinus Torvalds 				else {
10161da177e4SLinus Torvalds 					if ((STp->device)->scsi_level >= SCSI_2 &&
10171da177e4SLinus Torvalds 					    cmdstatp->sense_hdr.asc == 0x3a)	/* Check ASC */
10181da177e4SLinus Torvalds 						retval = CHKRES_NO_TAPE;
10191da177e4SLinus Torvalds 					else
10201da177e4SLinus Torvalds 						retval = CHKRES_NOT_READY;
10211da177e4SLinus Torvalds 					break;
10221da177e4SLinus Torvalds 				}
10231da177e4SLinus Torvalds 			}
10241da177e4SLinus Torvalds 		}
10251da177e4SLinus Torvalds 
10261da177e4SLinus Torvalds 		retval = (STp->buffer)->syscall_result;
10271da177e4SLinus Torvalds 		if (!retval)
10281da177e4SLinus Torvalds 			retval = new_session ? CHKRES_NEW_SESSION : CHKRES_READY;
10291da177e4SLinus Torvalds 		break;
10301da177e4SLinus Torvalds 	}
1031*7bfa83eeSKai Mäkisara 	if (STp->first_tur) {
1032*7bfa83eeSKai Mäkisara 		/* Don't set pos_unknown right after device recognition */
1033*7bfa83eeSKai Mäkisara 		STp->pos_unknown = 0;
1034*7bfa83eeSKai Mäkisara 		STp->first_tur = 0;
1035*7bfa83eeSKai Mäkisara 	}
10361da177e4SLinus Torvalds 
103702ae2c0eSKai Makisara 	if (SRpnt != NULL)
10388b05b773SMike Christie 		st_release_request(SRpnt);
10391da177e4SLinus Torvalds 	return retval;
10401da177e4SLinus Torvalds }
10411da177e4SLinus Torvalds 
10421da177e4SLinus Torvalds 
10431da177e4SLinus Torvalds /* See if the drive is ready and gather information about the tape. Return values:
10441da177e4SLinus Torvalds    < 0   negative error code from errno.h
10451da177e4SLinus Torvalds    0     drive ready
10461da177e4SLinus Torvalds    1     drive not ready (possibly no tape)
10471da177e4SLinus Torvalds */
check_tape(struct scsi_tape * STp,struct file * filp)10481da177e4SLinus Torvalds static int check_tape(struct scsi_tape *STp, struct file *filp)
10491da177e4SLinus Torvalds {
10501da177e4SLinus Torvalds 	int i, retval, new_session = 0, do_wait;
10511da177e4SLinus Torvalds 	unsigned char cmd[MAX_COMMAND_SIZE], saved_cleaning;
10521da177e4SLinus Torvalds 	unsigned short st_flags = filp->f_flags;
10538b05b773SMike Christie 	struct st_request *SRpnt = NULL;
10541da177e4SLinus Torvalds 	struct st_modedef *STm;
10551da177e4SLinus Torvalds 	struct st_partstat *STps;
1056496ad9aaSAl Viro 	struct inode *inode = file_inode(filp);
10571da177e4SLinus Torvalds 	int mode = TAPE_MODE(inode);
10581da177e4SLinus Torvalds 
10591da177e4SLinus Torvalds 	STp->ready = ST_READY;
10601da177e4SLinus Torvalds 
10611da177e4SLinus Torvalds 	if (mode != STp->current_mode) {
1062b30d8bcaSHannes Reinecke 		DEBC_printk(STp, "Mode change from %d to %d.\n",
1063b30d8bcaSHannes Reinecke 			    STp->current_mode, mode);
10641da177e4SLinus Torvalds 		new_session = 1;
10651da177e4SLinus Torvalds 		STp->current_mode = mode;
10661da177e4SLinus Torvalds 	}
10671da177e4SLinus Torvalds 	STm = &(STp->modes[STp->current_mode]);
10681da177e4SLinus Torvalds 
10691da177e4SLinus Torvalds 	saved_cleaning = STp->cleaning_req;
10701da177e4SLinus Torvalds 	STp->cleaning_req = 0;
10711da177e4SLinus Torvalds 
10721da177e4SLinus Torvalds 	do_wait = ((filp->f_flags & O_NONBLOCK) == 0);
10731da177e4SLinus Torvalds 	retval = test_ready(STp, do_wait);
10741da177e4SLinus Torvalds 
10751da177e4SLinus Torvalds 	if (retval < 0)
10761da177e4SLinus Torvalds 	    goto err_out;
10771da177e4SLinus Torvalds 
10781da177e4SLinus Torvalds 	if (retval == CHKRES_NEW_SESSION) {
10791da177e4SLinus Torvalds 		STp->pos_unknown = 0;
10801da177e4SLinus Torvalds 		STp->partition = STp->new_partition = 0;
10811da177e4SLinus Torvalds 		if (STp->can_partitions)
10821da177e4SLinus Torvalds 			STp->nbr_partitions = 1; /* This guess will be updated later
10831da177e4SLinus Torvalds                                                     if necessary */
10841da177e4SLinus Torvalds 		for (i = 0; i < ST_NBR_PARTITIONS; i++) {
10851da177e4SLinus Torvalds 			STps = &(STp->ps[i]);
10861da177e4SLinus Torvalds 			STps->rw = ST_IDLE;
10871da177e4SLinus Torvalds 			STps->eof = ST_NOEOF;
10881da177e4SLinus Torvalds 			STps->at_sm = 0;
10891da177e4SLinus Torvalds 			STps->last_block_valid = 0;
10901da177e4SLinus Torvalds 			STps->drv_block = 0;
10911da177e4SLinus Torvalds 			STps->drv_file = 0;
10921da177e4SLinus Torvalds 		}
10931da177e4SLinus Torvalds 		new_session = 1;
10941da177e4SLinus Torvalds 	}
10951da177e4SLinus Torvalds 	else {
10961da177e4SLinus Torvalds 		STp->cleaning_req |= saved_cleaning;
10971da177e4SLinus Torvalds 
10981da177e4SLinus Torvalds 		if (retval == CHKRES_NOT_READY || retval == CHKRES_NO_TAPE) {
10991da177e4SLinus Torvalds 			if (retval == CHKRES_NO_TAPE)
11001da177e4SLinus Torvalds 				STp->ready = ST_NO_TAPE;
11011da177e4SLinus Torvalds 			else
11021da177e4SLinus Torvalds 				STp->ready = ST_NOT_READY;
11031da177e4SLinus Torvalds 
11041da177e4SLinus Torvalds 			STp->density = 0;	/* Clear the erroneous "residue" */
11051da177e4SLinus Torvalds 			STp->write_prot = 0;
11061da177e4SLinus Torvalds 			STp->block_size = 0;
11071da177e4SLinus Torvalds 			STp->ps[0].drv_file = STp->ps[0].drv_block = (-1);
11081da177e4SLinus Torvalds 			STp->partition = STp->new_partition = 0;
11091da177e4SLinus Torvalds 			STp->door_locked = ST_UNLOCKED;
11101da177e4SLinus Torvalds 			return CHKRES_NOT_READY;
11111da177e4SLinus Torvalds 		}
11121da177e4SLinus Torvalds 	}
11131da177e4SLinus Torvalds 
11141da177e4SLinus Torvalds 	if (STp->omit_blklims)
11151da177e4SLinus Torvalds 		STp->min_block = STp->max_block = (-1);
11161da177e4SLinus Torvalds 	else {
11171da177e4SLinus Torvalds 		memset((void *) &cmd[0], 0, MAX_COMMAND_SIZE);
11181da177e4SLinus Torvalds 		cmd[0] = READ_BLOCK_LIMITS;
11191da177e4SLinus Torvalds 
112002ae2c0eSKai Makisara 		SRpnt = st_do_scsi(SRpnt, STp, cmd, 6, DMA_FROM_DEVICE,
1121a02488edSJames Bottomley 				   STp->device->request_queue->rq_timeout,
112202ae2c0eSKai Makisara 				   MAX_READY_RETRIES, 1);
112302ae2c0eSKai Makisara 		if (!SRpnt) {
112402ae2c0eSKai Makisara 			retval = (STp->buffer)->syscall_result;
11251da177e4SLinus Torvalds 			goto err_out;
11261da177e4SLinus Torvalds 		}
11271da177e4SLinus Torvalds 
11288b05b773SMike Christie 		if (!SRpnt->result && !STp->buffer->cmdstat.have_sense) {
11291da177e4SLinus Torvalds 			STp->max_block = ((STp->buffer)->b_data[1] << 16) |
11301da177e4SLinus Torvalds 			    ((STp->buffer)->b_data[2] << 8) | (STp->buffer)->b_data[3];
11311da177e4SLinus Torvalds 			STp->min_block = ((STp->buffer)->b_data[4] << 8) |
11321da177e4SLinus Torvalds 			    (STp->buffer)->b_data[5];
11331da177e4SLinus Torvalds 			if ( DEB( debugging || ) !STp->inited)
1134b30d8bcaSHannes Reinecke 				st_printk(KERN_INFO, STp,
1135b30d8bcaSHannes Reinecke 					  "Block limits %d - %d bytes.\n",
11361da177e4SLinus Torvalds 					  STp->min_block, STp->max_block);
11371da177e4SLinus Torvalds 		} else {
11381da177e4SLinus Torvalds 			STp->min_block = STp->max_block = (-1);
1139b30d8bcaSHannes Reinecke 			DEBC_printk(STp, "Can't read block limits.\n");
11401da177e4SLinus Torvalds 		}
11411da177e4SLinus Torvalds 	}
11421da177e4SLinus Torvalds 
11431da177e4SLinus Torvalds 	memset((void *) &cmd[0], 0, MAX_COMMAND_SIZE);
11441da177e4SLinus Torvalds 	cmd[0] = MODE_SENSE;
11451da177e4SLinus Torvalds 	cmd[4] = 12;
11461da177e4SLinus Torvalds 
114702ae2c0eSKai Makisara 	SRpnt = st_do_scsi(SRpnt, STp, cmd, 12, DMA_FROM_DEVICE,
1148a02488edSJames Bottomley 			   STp->device->request_queue->rq_timeout,
114902ae2c0eSKai Makisara 			   MAX_READY_RETRIES, 1);
115002ae2c0eSKai Makisara 	if (!SRpnt) {
115102ae2c0eSKai Makisara 		retval = (STp->buffer)->syscall_result;
11521da177e4SLinus Torvalds 		goto err_out;
11531da177e4SLinus Torvalds 	}
11541da177e4SLinus Torvalds 
11551da177e4SLinus Torvalds 	if ((STp->buffer)->syscall_result != 0) {
1156b30d8bcaSHannes Reinecke 		DEBC_printk(STp, "No Mode Sense.\n");
11571da177e4SLinus Torvalds 		STp->block_size = ST_DEFAULT_BLOCK;	/* Educated guess (?) */
11581da177e4SLinus Torvalds 		(STp->buffer)->syscall_result = 0;	/* Prevent error propagation */
11591da177e4SLinus Torvalds 		STp->drv_write_prot = 0;
11601da177e4SLinus Torvalds 	} else {
1161b30d8bcaSHannes Reinecke 		DEBC_printk(STp,"Mode sense. Length %d, "
1162b30d8bcaSHannes Reinecke 			    "medium %x, WBS %x, BLL %d\n",
1163b30d8bcaSHannes Reinecke 			    (STp->buffer)->b_data[0],
1164b30d8bcaSHannes Reinecke 			    (STp->buffer)->b_data[1],
1165b30d8bcaSHannes Reinecke 			    (STp->buffer)->b_data[2],
1166b30d8bcaSHannes Reinecke 			    (STp->buffer)->b_data[3]);
11671da177e4SLinus Torvalds 
11681da177e4SLinus Torvalds 		if ((STp->buffer)->b_data[3] >= 8) {
11691da177e4SLinus Torvalds 			STp->drv_buffer = ((STp->buffer)->b_data[2] >> 4) & 7;
11701da177e4SLinus Torvalds 			STp->density = (STp->buffer)->b_data[4];
11711da177e4SLinus Torvalds 			STp->block_size = (STp->buffer)->b_data[9] * 65536 +
11721da177e4SLinus Torvalds 			    (STp->buffer)->b_data[10] * 256 + (STp->buffer)->b_data[11];
1173b30d8bcaSHannes Reinecke 			DEBC_printk(STp, "Density %x, tape length: %x, "
1174b30d8bcaSHannes Reinecke 				    "drv buffer: %d\n",
1175b30d8bcaSHannes Reinecke 				    STp->density,
1176b30d8bcaSHannes Reinecke 				    (STp->buffer)->b_data[5] * 65536 +
1177b30d8bcaSHannes Reinecke 				    (STp->buffer)->b_data[6] * 256 +
1178b30d8bcaSHannes Reinecke 				    (STp->buffer)->b_data[7],
1179b30d8bcaSHannes Reinecke 				    STp->drv_buffer);
11801da177e4SLinus Torvalds 		}
11811da177e4SLinus Torvalds 		STp->drv_write_prot = ((STp->buffer)->b_data[2] & 0x80) != 0;
1182c743e44fSLee Duncan 		if (!STp->drv_buffer && STp->immediate_filemark) {
1183b30d8bcaSHannes Reinecke 			st_printk(KERN_WARNING, STp,
1184b30d8bcaSHannes Reinecke 				  "non-buffered tape: disabling "
1185b30d8bcaSHannes Reinecke 				  "writing immediate filemarks\n");
1186c743e44fSLee Duncan 			STp->immediate_filemark = 0;
1187c743e44fSLee Duncan 		}
11881da177e4SLinus Torvalds 	}
11898b05b773SMike Christie 	st_release_request(SRpnt);
11901da177e4SLinus Torvalds 	SRpnt = NULL;
11911da177e4SLinus Torvalds 	STp->inited = 1;
11921da177e4SLinus Torvalds 
11931da177e4SLinus Torvalds 	if (STp->block_size > 0)
11941da177e4SLinus Torvalds 		(STp->buffer)->buffer_blocks =
11951da177e4SLinus Torvalds 			(STp->buffer)->buffer_size / STp->block_size;
11961da177e4SLinus Torvalds 	else
11971da177e4SLinus Torvalds 		(STp->buffer)->buffer_blocks = 1;
11981da177e4SLinus Torvalds 	(STp->buffer)->buffer_bytes = (STp->buffer)->read_pointer = 0;
11991da177e4SLinus Torvalds 
1200b30d8bcaSHannes Reinecke 	DEBC_printk(STp, "Block size: %d, buffer size: %d (%d blocks).\n",
12011da177e4SLinus Torvalds 		    STp->block_size, (STp->buffer)->buffer_size,
1202b30d8bcaSHannes Reinecke 		    (STp->buffer)->buffer_blocks);
12031da177e4SLinus Torvalds 
12041da177e4SLinus Torvalds 	if (STp->drv_write_prot) {
12051da177e4SLinus Torvalds 		STp->write_prot = 1;
12061da177e4SLinus Torvalds 
1207b30d8bcaSHannes Reinecke 		DEBC_printk(STp, "Write protected\n");
12081da177e4SLinus Torvalds 
12091da177e4SLinus Torvalds 		if (do_wait &&
12101da177e4SLinus Torvalds 		    ((st_flags & O_ACCMODE) == O_WRONLY ||
12111da177e4SLinus Torvalds 		     (st_flags & O_ACCMODE) == O_RDWR)) {
12121da177e4SLinus Torvalds 			retval = (-EROFS);
12131da177e4SLinus Torvalds 			goto err_out;
12141da177e4SLinus Torvalds 		}
12151da177e4SLinus Torvalds 	}
12161da177e4SLinus Torvalds 
12171da177e4SLinus Torvalds 	if (STp->can_partitions && STp->nbr_partitions < 1) {
12181da177e4SLinus Torvalds 		/* This code is reached when the device is opened for the first time
12191da177e4SLinus Torvalds 		   after the driver has been initialized with tape in the drive and the
12201da177e4SLinus Torvalds 		   partition support has been enabled. */
1221b30d8bcaSHannes Reinecke 		DEBC_printk(STp, "Updating partition number in status.\n");
12221da177e4SLinus Torvalds 		if ((STp->partition = find_partition(STp)) < 0) {
12231da177e4SLinus Torvalds 			retval = STp->partition;
12241da177e4SLinus Torvalds 			goto err_out;
12251da177e4SLinus Torvalds 		}
12261da177e4SLinus Torvalds 		STp->new_partition = STp->partition;
12271da177e4SLinus Torvalds 		STp->nbr_partitions = 1; /* This guess will be updated when necessary */
12281da177e4SLinus Torvalds 	}
12291da177e4SLinus Torvalds 
12301da177e4SLinus Torvalds 	if (new_session) {	/* Change the drive parameters for the new mode */
12311da177e4SLinus Torvalds 		STp->density_changed = STp->blksize_changed = 0;
12321da177e4SLinus Torvalds 		STp->compression_changed = 0;
12331da177e4SLinus Torvalds 		if (!(STm->defaults_for_writes) &&
12341da177e4SLinus Torvalds 		    (retval = set_mode_densblk(STp, STm)) < 0)
12351da177e4SLinus Torvalds 		    goto err_out;
12361da177e4SLinus Torvalds 
12371da177e4SLinus Torvalds 		if (STp->default_drvbuffer != 0xff) {
12381da177e4SLinus Torvalds 			if (st_int_ioctl(STp, MTSETDRVBUFFER, STp->default_drvbuffer))
1239b30d8bcaSHannes Reinecke 				st_printk(KERN_WARNING, STp,
1240b30d8bcaSHannes Reinecke 					  "Can't set default drive "
1241b30d8bcaSHannes Reinecke 					  "buffering to %d.\n",
1242b30d8bcaSHannes Reinecke 					  STp->default_drvbuffer);
12431da177e4SLinus Torvalds 		}
12441da177e4SLinus Torvalds 	}
12451da177e4SLinus Torvalds 
12461da177e4SLinus Torvalds 	return CHKRES_READY;
12471da177e4SLinus Torvalds 
12481da177e4SLinus Torvalds  err_out:
12491da177e4SLinus Torvalds 	return retval;
12501da177e4SLinus Torvalds }
12511da177e4SLinus Torvalds 
12521da177e4SLinus Torvalds 
1253b3369c68SJonathan Corbet /* Open the device. Needs to take the BKL only because of incrementing the SCSI host
12541da177e4SLinus Torvalds    module count. */
st_open(struct inode * inode,struct file * filp)12551da177e4SLinus Torvalds static int st_open(struct inode *inode, struct file *filp)
12561da177e4SLinus Torvalds {
12571da177e4SLinus Torvalds 	int i, retval = (-EIO);
125846a243f7SOliver Neukum 	int resumed = 0;
12591da177e4SLinus Torvalds 	struct scsi_tape *STp;
12601da177e4SLinus Torvalds 	struct st_partstat *STps;
12611da177e4SLinus Torvalds 	int dev = TAPE_NR(inode);
12621da177e4SLinus Torvalds 
12631da177e4SLinus Torvalds 	/*
12641da177e4SLinus Torvalds 	 * We really want to do nonseekable_open(inode, filp); here, but some
12651da177e4SLinus Torvalds 	 * versions of tar incorrectly call lseek on tapes and bail out if that
12661da177e4SLinus Torvalds 	 * fails.  So we disallow pread() and pwrite(), but permit lseeks.
12671da177e4SLinus Torvalds 	 */
12681da177e4SLinus Torvalds 	filp->f_mode &= ~(FMODE_PREAD | FMODE_PWRITE);
12691da177e4SLinus Torvalds 
1270b3369c68SJonathan Corbet 	if (!(STp = scsi_tape_get(dev))) {
1271f03a5670SKai Makisara 		return -ENXIO;
1272b3369c68SJonathan Corbet 	}
1273f03a5670SKai Makisara 
12741da177e4SLinus Torvalds 	filp->private_data = STp;
12751da177e4SLinus Torvalds 
12766c648d95SJeff Mahoney 	spin_lock(&st_use_lock);
12771da177e4SLinus Torvalds 	if (STp->in_use) {
12786c648d95SJeff Mahoney 		spin_unlock(&st_use_lock);
1279b30d8bcaSHannes Reinecke 		DEBC_printk(STp, "Device already in use.\n");
1280c8c165deSLv Yunlong 		scsi_tape_put(STp);
12811da177e4SLinus Torvalds 		return (-EBUSY);
12821da177e4SLinus Torvalds 	}
12831da177e4SLinus Torvalds 
12841da177e4SLinus Torvalds 	STp->in_use = 1;
12856c648d95SJeff Mahoney 	spin_unlock(&st_use_lock);
12861da177e4SLinus Torvalds 	STp->rew_at_close = STp->autorew_dev = (iminor(inode) & 0x80) == 0;
12871da177e4SLinus Torvalds 
128846a243f7SOliver Neukum 	if (scsi_autopm_get_device(STp->device) < 0) {
128946a243f7SOliver Neukum 		retval = -EIO;
129046a243f7SOliver Neukum 		goto err_out;
129146a243f7SOliver Neukum 	}
129246a243f7SOliver Neukum 	resumed = 1;
12931da177e4SLinus Torvalds 	if (!scsi_block_when_processing_errors(STp->device)) {
12941da177e4SLinus Torvalds 		retval = (-ENXIO);
12951da177e4SLinus Torvalds 		goto err_out;
12961da177e4SLinus Torvalds 	}
12971da177e4SLinus Torvalds 
12981da177e4SLinus Torvalds 	/* See that we have at least a one page buffer available */
1299aaff5ebaSChristoph Hellwig 	if (!enlarge_buffer(STp->buffer, PAGE_SIZE)) {
1300b30d8bcaSHannes Reinecke 		st_printk(KERN_WARNING, STp,
1301b30d8bcaSHannes Reinecke 			  "Can't allocate one page tape buffer.\n");
13021da177e4SLinus Torvalds 		retval = (-EOVERFLOW);
13031da177e4SLinus Torvalds 		goto err_out;
13041da177e4SLinus Torvalds 	}
13051da177e4SLinus Torvalds 
130640f6b36cSKai Makisara 	(STp->buffer)->cleared = 0;
13071da177e4SLinus Torvalds 	(STp->buffer)->writing = 0;
13081da177e4SLinus Torvalds 	(STp->buffer)->syscall_result = 0;
13091da177e4SLinus Torvalds 
13101da177e4SLinus Torvalds 	STp->write_prot = ((filp->f_flags & O_ACCMODE) == O_RDONLY);
13111da177e4SLinus Torvalds 
13121da177e4SLinus Torvalds 	STp->dirty = 0;
13131da177e4SLinus Torvalds 	for (i = 0; i < ST_NBR_PARTITIONS; i++) {
13141da177e4SLinus Torvalds 		STps = &(STp->ps[i]);
13151da177e4SLinus Torvalds 		STps->rw = ST_IDLE;
13161da177e4SLinus Torvalds 	}
13179abe16c6SKai Makisara 	STp->try_dio_now = STp->try_dio;
13181da177e4SLinus Torvalds 	STp->recover_count = 0;
13191da177e4SLinus Torvalds 	DEB( STp->nbr_waits = STp->nbr_finished = 0;
1320deee13dfSKai Makisara 	     STp->nbr_requests = STp->nbr_dio = STp->nbr_pages = 0; )
13211da177e4SLinus Torvalds 
13221da177e4SLinus Torvalds 	retval = check_tape(STp, filp);
13231da177e4SLinus Torvalds 	if (retval < 0)
13241da177e4SLinus Torvalds 		goto err_out;
13251da177e4SLinus Torvalds 	if ((filp->f_flags & O_NONBLOCK) == 0 &&
13261da177e4SLinus Torvalds 	    retval != CHKRES_READY) {
1327413f7327SKai Makisara 		if (STp->ready == NO_TAPE)
1328413f7327SKai Makisara 			retval = (-ENOMEDIUM);
1329413f7327SKai Makisara 		else
13301da177e4SLinus Torvalds 			retval = (-EIO);
13311da177e4SLinus Torvalds 		goto err_out;
13321da177e4SLinus Torvalds 	}
13331da177e4SLinus Torvalds 	return 0;
13341da177e4SLinus Torvalds 
13351da177e4SLinus Torvalds  err_out:
13361da177e4SLinus Torvalds 	normalize_buffer(STp->buffer);
13370644f539SHannes Reinecke 	spin_lock(&st_use_lock);
13381da177e4SLinus Torvalds 	STp->in_use = 0;
13390644f539SHannes Reinecke 	spin_unlock(&st_use_lock);
134046a243f7SOliver Neukum 	if (resumed)
134146a243f7SOliver Neukum 		scsi_autopm_put_device(STp->device);
1342e7ac6c66SSeymour, Shane M 	scsi_tape_put(STp);
13431da177e4SLinus Torvalds 	return retval;
13441da177e4SLinus Torvalds 
13451da177e4SLinus Torvalds }
13461da177e4SLinus Torvalds 
13471da177e4SLinus Torvalds 
13481da177e4SLinus Torvalds /* Flush the tape buffer before close */
st_flush(struct file * filp,fl_owner_t id)134975e1fcc0SMiklos Szeredi static int st_flush(struct file *filp, fl_owner_t id)
13501da177e4SLinus Torvalds {
13511da177e4SLinus Torvalds 	int result = 0, result2;
13521da177e4SLinus Torvalds 	unsigned char cmd[MAX_COMMAND_SIZE];
13538b05b773SMike Christie 	struct st_request *SRpnt;
13541da177e4SLinus Torvalds 	struct scsi_tape *STp = filp->private_data;
13551da177e4SLinus Torvalds 	struct st_modedef *STm = &(STp->modes[STp->current_mode]);
13561da177e4SLinus Torvalds 	struct st_partstat *STps = &(STp->ps[STp->partition]);
13571da177e4SLinus Torvalds 
13581da177e4SLinus Torvalds 	if (file_count(filp) > 1)
13591da177e4SLinus Torvalds 		return 0;
13601da177e4SLinus Torvalds 
13611da177e4SLinus Torvalds 	if (STps->rw == ST_WRITING && !STp->pos_unknown) {
13628ef8d594SAdrian Bunk 		result = st_flush_write_buffer(STp);
13631da177e4SLinus Torvalds 		if (result != 0 && result != (-ENOSPC))
13641da177e4SLinus Torvalds 			goto out;
13651da177e4SLinus Torvalds 	}
13661da177e4SLinus Torvalds 
13671da177e4SLinus Torvalds 	if (STp->can_partitions &&
13681da177e4SLinus Torvalds 	    (result2 = switch_partition(STp)) < 0) {
1369b30d8bcaSHannes Reinecke 		DEBC_printk(STp, "switch_partition at close failed.\n");
13701da177e4SLinus Torvalds 		if (result == 0)
13711da177e4SLinus Torvalds 			result = result2;
13721da177e4SLinus Torvalds 		goto out;
13731da177e4SLinus Torvalds 	}
13741da177e4SLinus Torvalds 
13751da177e4SLinus Torvalds 	DEBC( if (STp->nbr_requests)
1376b30d8bcaSHannes Reinecke 		st_printk(KERN_DEBUG, STp,
1377b30d8bcaSHannes Reinecke 			  "Number of r/w requests %d, dio used in %d, "
1378b30d8bcaSHannes Reinecke 			  "pages %d.\n", STp->nbr_requests, STp->nbr_dio,
1379b30d8bcaSHannes Reinecke 			  STp->nbr_pages));
13801da177e4SLinus Torvalds 
13811da177e4SLinus Torvalds 	if (STps->rw == ST_WRITING && !STp->pos_unknown) {
13821da177e4SLinus Torvalds 		struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat;
13831da177e4SLinus Torvalds 
1384b30d8bcaSHannes Reinecke #if DEBUG
1385b30d8bcaSHannes Reinecke 		DEBC_printk(STp, "Async write waits %d, finished %d.\n",
1386b30d8bcaSHannes Reinecke 			    STp->nbr_waits, STp->nbr_finished);
1387b30d8bcaSHannes Reinecke #endif
13881da177e4SLinus Torvalds 		memset(cmd, 0, MAX_COMMAND_SIZE);
13891da177e4SLinus Torvalds 		cmd[0] = WRITE_FILEMARKS;
1390c743e44fSLee Duncan 		if (STp->immediate_filemark)
1391c743e44fSLee Duncan 			cmd[1] = 1;
13921da177e4SLinus Torvalds 		cmd[4] = 1 + STp->two_fm;
13931da177e4SLinus Torvalds 
139402ae2c0eSKai Makisara 		SRpnt = st_do_scsi(NULL, STp, cmd, 0, DMA_NONE,
1395212cd8bfSFUJITA Tomonori 				   STp->device->request_queue->rq_timeout,
139602ae2c0eSKai Makisara 				   MAX_WRITE_RETRIES, 1);
139702ae2c0eSKai Makisara 		if (!SRpnt) {
139802ae2c0eSKai Makisara 			result = (STp->buffer)->syscall_result;
13991da177e4SLinus Torvalds 			goto out;
14001da177e4SLinus Torvalds 		}
14011da177e4SLinus Torvalds 
14021da177e4SLinus Torvalds 		if (STp->buffer->syscall_result == 0 ||
14031da177e4SLinus Torvalds 		    (cmdstatp->have_sense && !cmdstatp->deferred &&
14041da177e4SLinus Torvalds 		     (cmdstatp->flags & SENSE_EOM) &&
14051da177e4SLinus Torvalds 		     (cmdstatp->sense_hdr.sense_key == NO_SENSE ||
14061da177e4SLinus Torvalds 		      cmdstatp->sense_hdr.sense_key == RECOVERED_ERROR) &&
14071da177e4SLinus Torvalds 		     (!cmdstatp->remainder_valid || cmdstatp->uremainder64 == 0))) {
14081da177e4SLinus Torvalds 			/* Write successful at EOM */
14098b05b773SMike Christie 			st_release_request(SRpnt);
14101da177e4SLinus Torvalds 			SRpnt = NULL;
14111da177e4SLinus Torvalds 			if (STps->drv_file >= 0)
14121da177e4SLinus Torvalds 				STps->drv_file++;
14131da177e4SLinus Torvalds 			STps->drv_block = 0;
14141da177e4SLinus Torvalds 			if (STp->two_fm)
14151da177e4SLinus Torvalds 				cross_eof(STp, 0);
14161da177e4SLinus Torvalds 			STps->eof = ST_FM;
14171da177e4SLinus Torvalds 		}
14181da177e4SLinus Torvalds 		else { /* Write error */
14198b05b773SMike Christie 			st_release_request(SRpnt);
14201da177e4SLinus Torvalds 			SRpnt = NULL;
1421b30d8bcaSHannes Reinecke 			st_printk(KERN_ERR, STp,
1422b30d8bcaSHannes Reinecke 				  "Error on write filemark.\n");
14231da177e4SLinus Torvalds 			if (result == 0)
14241da177e4SLinus Torvalds 				result = (-EIO);
14251da177e4SLinus Torvalds 		}
14261da177e4SLinus Torvalds 
1427b30d8bcaSHannes Reinecke 		DEBC_printk(STp, "Buffer flushed, %d EOF(s) written\n", cmd[4]);
14281da177e4SLinus Torvalds 	} else if (!STp->rew_at_close) {
14291da177e4SLinus Torvalds 		STps = &(STp->ps[STp->partition]);
14301da177e4SLinus Torvalds 		if (!STm->sysv || STps->rw != ST_READING) {
14311da177e4SLinus Torvalds 			if (STp->can_bsr)
14321da177e4SLinus Torvalds 				result = flush_buffer(STp, 0);
14331da177e4SLinus Torvalds 			else if (STps->eof == ST_FM_HIT) {
14341da177e4SLinus Torvalds 				result = cross_eof(STp, 0);
14351da177e4SLinus Torvalds 				if (result) {
14361da177e4SLinus Torvalds 					if (STps->drv_file >= 0)
14371da177e4SLinus Torvalds 						STps->drv_file++;
14381da177e4SLinus Torvalds 					STps->drv_block = 0;
14391da177e4SLinus Torvalds 					STps->eof = ST_FM;
14401da177e4SLinus Torvalds 				} else
14411da177e4SLinus Torvalds 					STps->eof = ST_NOEOF;
14421da177e4SLinus Torvalds 			}
14431da177e4SLinus Torvalds 		} else if ((STps->eof == ST_NOEOF &&
14441da177e4SLinus Torvalds 			    !(result = cross_eof(STp, 1))) ||
14451da177e4SLinus Torvalds 			   STps->eof == ST_FM_HIT) {
14461da177e4SLinus Torvalds 			if (STps->drv_file >= 0)
14471da177e4SLinus Torvalds 				STps->drv_file++;
14481da177e4SLinus Torvalds 			STps->drv_block = 0;
14491da177e4SLinus Torvalds 			STps->eof = ST_FM;
14501da177e4SLinus Torvalds 		}
14511da177e4SLinus Torvalds 	}
14521da177e4SLinus Torvalds 
14531da177e4SLinus Torvalds       out:
14541da177e4SLinus Torvalds 	if (STp->rew_at_close) {
14551da177e4SLinus Torvalds 		result2 = st_int_ioctl(STp, MTREW, 1);
14561da177e4SLinus Torvalds 		if (result == 0)
14571da177e4SLinus Torvalds 			result = result2;
14581da177e4SLinus Torvalds 	}
14591da177e4SLinus Torvalds 	return result;
14601da177e4SLinus Torvalds }
14611da177e4SLinus Torvalds 
14621da177e4SLinus Torvalds 
14631da177e4SLinus Torvalds /* Close the device and release it. BKL is not needed: this is the only thread
14641da177e4SLinus Torvalds    accessing this tape. */
st_release(struct inode * inode,struct file * filp)14651da177e4SLinus Torvalds static int st_release(struct inode *inode, struct file *filp)
14661da177e4SLinus Torvalds {
14671da177e4SLinus Torvalds 	struct scsi_tape *STp = filp->private_data;
14681da177e4SLinus Torvalds 
14691da177e4SLinus Torvalds 	if (STp->door_locked == ST_LOCKED_AUTO)
14701da177e4SLinus Torvalds 		do_door_lock(STp, 0);
14711da177e4SLinus Torvalds 
14721da177e4SLinus Torvalds 	normalize_buffer(STp->buffer);
14736c648d95SJeff Mahoney 	spin_lock(&st_use_lock);
14741da177e4SLinus Torvalds 	STp->in_use = 0;
14756c648d95SJeff Mahoney 	spin_unlock(&st_use_lock);
147646a243f7SOliver Neukum 	scsi_autopm_put_device(STp->device);
1477f03a5670SKai Makisara 	scsi_tape_put(STp);
14781da177e4SLinus Torvalds 
1479ec341439SJason Yan 	return 0;
14801da177e4SLinus Torvalds }
1481ec341439SJason Yan 
14821da177e4SLinus Torvalds /* The checks common to both reading and writing */
rw_checks(struct scsi_tape * STp,struct file * filp,size_t count)14831da177e4SLinus Torvalds static ssize_t rw_checks(struct scsi_tape *STp, struct file *filp, size_t count)
14841da177e4SLinus Torvalds {
14851da177e4SLinus Torvalds 	ssize_t retval = 0;
14861da177e4SLinus Torvalds 
14871da177e4SLinus Torvalds 	/*
14881da177e4SLinus Torvalds 	 * If we are in the middle of error recovery, don't let anyone
14891da177e4SLinus Torvalds 	 * else try and use this device.  Also, if error recovery fails, it
14901da177e4SLinus Torvalds 	 * may try and take the device offline, in which case all further
14911da177e4SLinus Torvalds 	 * access to the device is prohibited.
14921da177e4SLinus Torvalds 	 */
14931da177e4SLinus Torvalds 	if (!scsi_block_when_processing_errors(STp->device)) {
14941da177e4SLinus Torvalds 		retval = (-ENXIO);
14951da177e4SLinus Torvalds 		goto out;
14961da177e4SLinus Torvalds 	}
14971da177e4SLinus Torvalds 
14981da177e4SLinus Torvalds 	if (STp->ready != ST_READY) {
14991da177e4SLinus Torvalds 		if (STp->ready == ST_NO_TAPE)
15001da177e4SLinus Torvalds 			retval = (-ENOMEDIUM);
15011da177e4SLinus Torvalds 		else
15021da177e4SLinus Torvalds 			retval = (-EIO);
15031da177e4SLinus Torvalds 		goto out;
15041da177e4SLinus Torvalds 	}
15051da177e4SLinus Torvalds 
15061da177e4SLinus Torvalds 	if (! STp->modes[STp->current_mode].defined) {
15071da177e4SLinus Torvalds 		retval = (-ENXIO);
15081da177e4SLinus Torvalds 		goto out;
15091da177e4SLinus Torvalds 	}
15101da177e4SLinus Torvalds 
15111da177e4SLinus Torvalds 
15121da177e4SLinus Torvalds 	/*
15131da177e4SLinus Torvalds 	 * If there was a bus reset, block further access
15141da177e4SLinus Torvalds 	 * to this device.
15151da177e4SLinus Torvalds 	 */
15161da177e4SLinus Torvalds 	if (STp->pos_unknown) {
15171da177e4SLinus Torvalds 		retval = (-EIO);
15181da177e4SLinus Torvalds 		goto out;
15191da177e4SLinus Torvalds 	}
15201da177e4SLinus Torvalds 
15211da177e4SLinus Torvalds 	if (count == 0)
15221da177e4SLinus Torvalds 		goto out;
15231da177e4SLinus Torvalds 
15241da177e4SLinus Torvalds 	DEB(
15251da177e4SLinus Torvalds 	if (!STp->in_use) {
1526b30d8bcaSHannes Reinecke 		st_printk(ST_DEB_MSG, STp,
1527b30d8bcaSHannes Reinecke 			  "Incorrect device.\n");
15281da177e4SLinus Torvalds 		retval = (-EIO);
15291da177e4SLinus Torvalds 		goto out;
15301da177e4SLinus Torvalds 	} ) /* end DEB */
15311da177e4SLinus Torvalds 
15321da177e4SLinus Torvalds 	if (STp->can_partitions &&
15331da177e4SLinus Torvalds 	    (retval = switch_partition(STp)) < 0)
15341da177e4SLinus Torvalds 		goto out;
15351da177e4SLinus Torvalds 
15361da177e4SLinus Torvalds 	if (STp->block_size == 0 && STp->max_block > 0 &&
15371da177e4SLinus Torvalds 	    (count < STp->min_block || count > STp->max_block)) {
15381da177e4SLinus Torvalds 		retval = (-EINVAL);
15391da177e4SLinus Torvalds 		goto out;
15401da177e4SLinus Torvalds 	}
15411da177e4SLinus Torvalds 
15421da177e4SLinus Torvalds 	if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED &&
15431da177e4SLinus Torvalds 	    !do_door_lock(STp, 1))
15441da177e4SLinus Torvalds 		STp->door_locked = ST_LOCKED_AUTO;
15451da177e4SLinus Torvalds 
15461da177e4SLinus Torvalds  out:
15471da177e4SLinus Torvalds 	return retval;
15481da177e4SLinus Torvalds }
15491da177e4SLinus Torvalds 
15501da177e4SLinus Torvalds 
setup_buffering(struct scsi_tape * STp,const char __user * buf,size_t count,int is_read)15511da177e4SLinus Torvalds static int setup_buffering(struct scsi_tape *STp, const char __user *buf,
15521da177e4SLinus Torvalds 			   size_t count, int is_read)
15531da177e4SLinus Torvalds {
15541da177e4SLinus Torvalds 	int i, bufsize, retval = 0;
15551da177e4SLinus Torvalds 	struct st_buffer *STbp = STp->buffer;
15561da177e4SLinus Torvalds 
15571da177e4SLinus Torvalds 	if (is_read)
15589abe16c6SKai Makisara 		i = STp->try_dio_now && try_rdio;
15591da177e4SLinus Torvalds 	else
15609abe16c6SKai Makisara 		i = STp->try_dio_now && try_wdio;
15618b05b773SMike Christie 
15621da177e4SLinus Torvalds 	if (i && ((unsigned long)buf & queue_dma_alignment(
15631da177e4SLinus Torvalds 					STp->device->request_queue)) == 0) {
15646620742fSFUJITA Tomonori 		i = sgl_map_user_pages(STbp, STbp->use_sg, (unsigned long)buf,
15656620742fSFUJITA Tomonori 				       count, (is_read ? READ : WRITE));
15661da177e4SLinus Torvalds 		if (i > 0) {
15671da177e4SLinus Torvalds 			STbp->do_dio = i;
15681da177e4SLinus Torvalds 			STbp->buffer_bytes = 0;   /* can be used as transfer counter */
15691da177e4SLinus Torvalds 		}
15701da177e4SLinus Torvalds 		else
15711da177e4SLinus Torvalds 			STbp->do_dio = 0;  /* fall back to buffering with any error */
15721da177e4SLinus Torvalds 		STbp->sg_segs = STbp->do_dio;
15731da177e4SLinus Torvalds 		DEB(
15741da177e4SLinus Torvalds 		     if (STbp->do_dio) {
15751da177e4SLinus Torvalds 			STp->nbr_dio++;
15761da177e4SLinus Torvalds 			STp->nbr_pages += STbp->do_dio;
15771da177e4SLinus Torvalds 		     }
15781da177e4SLinus Torvalds 		)
15791da177e4SLinus Torvalds 	} else
15801da177e4SLinus Torvalds 		STbp->do_dio = 0;
15811da177e4SLinus Torvalds 	DEB( STp->nbr_requests++; )
15821da177e4SLinus Torvalds 
15831da177e4SLinus Torvalds 	if (!STbp->do_dio) {
15841da177e4SLinus Torvalds 		if (STp->block_size)
15851da177e4SLinus Torvalds 			bufsize = STp->block_size > st_fixed_buffer_size ?
15861da177e4SLinus Torvalds 				STp->block_size : st_fixed_buffer_size;
158740f6b36cSKai Makisara 		else {
15881da177e4SLinus Torvalds 			bufsize = count;
158940f6b36cSKai Makisara 			/* Make sure that data from previous user is not leaked even if
159040f6b36cSKai Makisara 			   HBA does not return correct residual */
159140f6b36cSKai Makisara 			if (is_read && STp->sili && !STbp->cleared)
159240f6b36cSKai Makisara 				clear_buffer(STbp);
159340f6b36cSKai Makisara 		}
159440f6b36cSKai Makisara 
15951da177e4SLinus Torvalds 		if (bufsize > STbp->buffer_size &&
1596aaff5ebaSChristoph Hellwig 		    !enlarge_buffer(STbp, bufsize)) {
1597b30d8bcaSHannes Reinecke 			st_printk(KERN_WARNING, STp,
1598b30d8bcaSHannes Reinecke 				  "Can't allocate %d byte tape buffer.\n",
1599b30d8bcaSHannes Reinecke 				  bufsize);
16001da177e4SLinus Torvalds 			retval = (-EOVERFLOW);
16011da177e4SLinus Torvalds 			goto out;
16021da177e4SLinus Torvalds 		}
16031da177e4SLinus Torvalds 		if (STp->block_size)
16041da177e4SLinus Torvalds 			STbp->buffer_blocks = bufsize / STp->block_size;
16051da177e4SLinus Torvalds 	}
16061da177e4SLinus Torvalds 
16071da177e4SLinus Torvalds  out:
16081da177e4SLinus Torvalds 	return retval;
16091da177e4SLinus Torvalds }
16101da177e4SLinus Torvalds 
16111da177e4SLinus Torvalds 
16121da177e4SLinus Torvalds /* Can be called more than once after each setup_buffer() */
release_buffering(struct scsi_tape * STp,int is_read)1613787926b1SKai Makisara static void release_buffering(struct scsi_tape *STp, int is_read)
16141da177e4SLinus Torvalds {
16151da177e4SLinus Torvalds 	struct st_buffer *STbp;
16161da177e4SLinus Torvalds 
16171da177e4SLinus Torvalds 	STbp = STp->buffer;
16181da177e4SLinus Torvalds 	if (STbp->do_dio) {
16196620742fSFUJITA Tomonori 		sgl_unmap_user_pages(STbp, STbp->do_dio, is_read);
16201da177e4SLinus Torvalds 		STbp->do_dio = 0;
1621787926b1SKai Makisara 		STbp->sg_segs = 0;
16221da177e4SLinus Torvalds 	}
16231da177e4SLinus Torvalds }
16241da177e4SLinus Torvalds 
16251da177e4SLinus Torvalds 
16261da177e4SLinus Torvalds /* Write command */
16271da177e4SLinus Torvalds static ssize_t
st_write(struct file * filp,const char __user * buf,size_t count,loff_t * ppos)16281da177e4SLinus Torvalds st_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
16291da177e4SLinus Torvalds {
16301da177e4SLinus Torvalds 	ssize_t total;
16311da177e4SLinus Torvalds 	ssize_t i, do_count, blks, transfer;
16321da177e4SLinus Torvalds 	ssize_t retval;
16331da177e4SLinus Torvalds 	int undone, retry_eot = 0, scode;
16341da177e4SLinus Torvalds 	int async_write;
16351da177e4SLinus Torvalds 	unsigned char cmd[MAX_COMMAND_SIZE];
16361da177e4SLinus Torvalds 	const char __user *b_point;
16378b05b773SMike Christie 	struct st_request *SRpnt = NULL;
16381da177e4SLinus Torvalds 	struct scsi_tape *STp = filp->private_data;
16391da177e4SLinus Torvalds 	struct st_modedef *STm;
16401da177e4SLinus Torvalds 	struct st_partstat *STps;
16411da177e4SLinus Torvalds 	struct st_buffer *STbp;
16421da177e4SLinus Torvalds 
164328f85009SMatthias Kaehlcke 	if (mutex_lock_interruptible(&STp->lock))
16441da177e4SLinus Torvalds 		return -ERESTARTSYS;
16451da177e4SLinus Torvalds 
16461da177e4SLinus Torvalds 	retval = rw_checks(STp, filp, count);
16471da177e4SLinus Torvalds 	if (retval || count == 0)
16481da177e4SLinus Torvalds 		goto out;
16491da177e4SLinus Torvalds 
16501da177e4SLinus Torvalds 	/* Write must be integral number of blocks */
16511da177e4SLinus Torvalds 	if (STp->block_size != 0 && (count % STp->block_size) != 0) {
1652b30d8bcaSHannes Reinecke 		st_printk(KERN_WARNING, STp,
1653b30d8bcaSHannes Reinecke 			  "Write not multiple of tape block size.\n");
16541da177e4SLinus Torvalds 		retval = (-EINVAL);
16551da177e4SLinus Torvalds 		goto out;
16561da177e4SLinus Torvalds 	}
16571da177e4SLinus Torvalds 
16581da177e4SLinus Torvalds 	STm = &(STp->modes[STp->current_mode]);
16591da177e4SLinus Torvalds 	STps = &(STp->ps[STp->partition]);
16601da177e4SLinus Torvalds 
16611da177e4SLinus Torvalds 	if (STp->write_prot) {
16621da177e4SLinus Torvalds 		retval = (-EACCES);
16631da177e4SLinus Torvalds 		goto out;
16641da177e4SLinus Torvalds 	}
16651da177e4SLinus Torvalds 
16661da177e4SLinus Torvalds 
16671da177e4SLinus Torvalds 	if (STps->rw == ST_READING) {
16681da177e4SLinus Torvalds 		retval = flush_buffer(STp, 0);
16691da177e4SLinus Torvalds 		if (retval)
16701da177e4SLinus Torvalds 			goto out;
16711da177e4SLinus Torvalds 		STps->rw = ST_WRITING;
16721da177e4SLinus Torvalds 	} else if (STps->rw != ST_WRITING &&
16731da177e4SLinus Torvalds 		   STps->drv_file == 0 && STps->drv_block == 0) {
16741da177e4SLinus Torvalds 		if ((retval = set_mode_densblk(STp, STm)) < 0)
16751da177e4SLinus Torvalds 			goto out;
16761da177e4SLinus Torvalds 		if (STm->default_compression != ST_DONT_TOUCH &&
16771da177e4SLinus Torvalds 		    !(STp->compression_changed)) {
16781da177e4SLinus Torvalds 			if (st_compression(STp, (STm->default_compression == ST_YES))) {
1679b30d8bcaSHannes Reinecke 				st_printk(KERN_WARNING, STp,
1680b30d8bcaSHannes Reinecke 					  "Can't set default compression.\n");
16811da177e4SLinus Torvalds 				if (modes_defined) {
16821da177e4SLinus Torvalds 					retval = (-EINVAL);
16831da177e4SLinus Torvalds 					goto out;
16841da177e4SLinus Torvalds 				}
16851da177e4SLinus Torvalds 			}
16861da177e4SLinus Torvalds 		}
16871da177e4SLinus Torvalds 	}
16881da177e4SLinus Torvalds 
16891da177e4SLinus Torvalds 	STbp = STp->buffer;
16901da177e4SLinus Torvalds 	i = write_behind_check(STp);
16911da177e4SLinus Torvalds 	if (i) {
16921da177e4SLinus Torvalds 		if (i == -ENOSPC)
16931da177e4SLinus Torvalds 			STps->eof = ST_EOM_OK;
16941da177e4SLinus Torvalds 		else
16951da177e4SLinus Torvalds 			STps->eof = ST_EOM_ERROR;
16961da177e4SLinus Torvalds 	}
16971da177e4SLinus Torvalds 
16981da177e4SLinus Torvalds 	if (STps->eof == ST_EOM_OK) {
16991da177e4SLinus Torvalds 		STps->eof = ST_EOD_1;  /* allow next write */
17001da177e4SLinus Torvalds 		retval = (-ENOSPC);
17011da177e4SLinus Torvalds 		goto out;
17021da177e4SLinus Torvalds 	}
17031da177e4SLinus Torvalds 	else if (STps->eof == ST_EOM_ERROR) {
17041da177e4SLinus Torvalds 		retval = (-EIO);
17051da177e4SLinus Torvalds 		goto out;
17061da177e4SLinus Torvalds 	}
17071da177e4SLinus Torvalds 
17081da177e4SLinus Torvalds 	/* Check the buffer readability in cases where copy_user might catch
17091da177e4SLinus Torvalds 	   the problems after some tape movement. */
17101da177e4SLinus Torvalds 	if (STp->block_size != 0 &&
17111da177e4SLinus Torvalds 	    !STbp->do_dio &&
17121da177e4SLinus Torvalds 	    (copy_from_user(&i, buf, 1) != 0 ||
17131da177e4SLinus Torvalds 	     copy_from_user(&i, buf + count - 1, 1) != 0)) {
17141da177e4SLinus Torvalds 		retval = (-EFAULT);
17151da177e4SLinus Torvalds 		goto out;
17161da177e4SLinus Torvalds 	}
17171da177e4SLinus Torvalds 
17181da177e4SLinus Torvalds 	retval = setup_buffering(STp, buf, count, 0);
17191da177e4SLinus Torvalds 	if (retval)
17201da177e4SLinus Torvalds 		goto out;
17211da177e4SLinus Torvalds 
17221da177e4SLinus Torvalds 	total = count;
17231da177e4SLinus Torvalds 
17241da177e4SLinus Torvalds 	memset(cmd, 0, MAX_COMMAND_SIZE);
17251da177e4SLinus Torvalds 	cmd[0] = WRITE_6;
17261da177e4SLinus Torvalds 	cmd[1] = (STp->block_size != 0);
17271da177e4SLinus Torvalds 
17281da177e4SLinus Torvalds 	STps->rw = ST_WRITING;
17291da177e4SLinus Torvalds 
17301da177e4SLinus Torvalds 	b_point = buf;
17311da177e4SLinus Torvalds 	while (count > 0 && !retry_eot) {
17321da177e4SLinus Torvalds 
17331da177e4SLinus Torvalds 		if (STbp->do_dio) {
17341da177e4SLinus Torvalds 			do_count = count;
17351da177e4SLinus Torvalds 		}
17361da177e4SLinus Torvalds 		else {
17371da177e4SLinus Torvalds 			if (STp->block_size == 0)
17381da177e4SLinus Torvalds 				do_count = count;
17391da177e4SLinus Torvalds 			else {
17401da177e4SLinus Torvalds 				do_count = STbp->buffer_blocks * STp->block_size -
17411da177e4SLinus Torvalds 					STbp->buffer_bytes;
17421da177e4SLinus Torvalds 				if (do_count > count)
17431da177e4SLinus Torvalds 					do_count = count;
17441da177e4SLinus Torvalds 			}
17451da177e4SLinus Torvalds 
17461da177e4SLinus Torvalds 			i = append_to_buffer(b_point, STbp, do_count);
17471da177e4SLinus Torvalds 			if (i) {
17481da177e4SLinus Torvalds 				retval = i;
17491da177e4SLinus Torvalds 				goto out;
17501da177e4SLinus Torvalds 			}
17511da177e4SLinus Torvalds 		}
17521da177e4SLinus Torvalds 		count -= do_count;
17531da177e4SLinus Torvalds 		b_point += do_count;
17541da177e4SLinus Torvalds 
17551da177e4SLinus Torvalds 		async_write = STp->block_size == 0 && !STbp->do_dio &&
17561da177e4SLinus Torvalds 			STm->do_async_writes && STps->eof < ST_EOM_OK;
17571da177e4SLinus Torvalds 
17581da177e4SLinus Torvalds 		if (STp->block_size != 0 && STm->do_buffer_writes &&
17599abe16c6SKai Makisara 		    !(STp->try_dio_now && try_wdio) && STps->eof < ST_EOM_OK &&
17601da177e4SLinus Torvalds 		    STbp->buffer_bytes < STbp->buffer_size) {
17611da177e4SLinus Torvalds 			STp->dirty = 1;
17621da177e4SLinus Torvalds 			/* Don't write a buffer that is not full enough. */
17631da177e4SLinus Torvalds 			if (!async_write && count == 0)
17641da177e4SLinus Torvalds 				break;
17651da177e4SLinus Torvalds 		}
17661da177e4SLinus Torvalds 
17671da177e4SLinus Torvalds 	retry_write:
17681da177e4SLinus Torvalds 		if (STp->block_size == 0)
17691da177e4SLinus Torvalds 			blks = transfer = do_count;
17701da177e4SLinus Torvalds 		else {
17711da177e4SLinus Torvalds 			if (!STbp->do_dio)
17721da177e4SLinus Torvalds 				blks = STbp->buffer_bytes;
17731da177e4SLinus Torvalds 			else
17741da177e4SLinus Torvalds 				blks = do_count;
17751da177e4SLinus Torvalds 			blks /= STp->block_size;
17761da177e4SLinus Torvalds 			transfer = blks * STp->block_size;
17771da177e4SLinus Torvalds 		}
17781da177e4SLinus Torvalds 		cmd[2] = blks >> 16;
17791da177e4SLinus Torvalds 		cmd[3] = blks >> 8;
17801da177e4SLinus Torvalds 		cmd[4] = blks;
17811da177e4SLinus Torvalds 
17821da177e4SLinus Torvalds 		SRpnt = st_do_scsi(SRpnt, STp, cmd, transfer, DMA_TO_DEVICE,
1783a02488edSJames Bottomley 				   STp->device->request_queue->rq_timeout,
1784a02488edSJames Bottomley 				   MAX_WRITE_RETRIES, !async_write);
17851da177e4SLinus Torvalds 		if (!SRpnt) {
17861da177e4SLinus Torvalds 			retval = STbp->syscall_result;
17871da177e4SLinus Torvalds 			goto out;
17881da177e4SLinus Torvalds 		}
17898b05b773SMike Christie 		if (async_write && !STbp->syscall_result) {
17901da177e4SLinus Torvalds 			STbp->writing = transfer;
17911da177e4SLinus Torvalds 			STp->dirty = !(STbp->writing ==
17921da177e4SLinus Torvalds 				       STbp->buffer_bytes);
17931da177e4SLinus Torvalds 			SRpnt = NULL;  /* Prevent releasing this request! */
17941da177e4SLinus Torvalds 			DEB( STp->write_pending = 1; )
17951da177e4SLinus Torvalds 			break;
17961da177e4SLinus Torvalds 		}
17971da177e4SLinus Torvalds 
17981da177e4SLinus Torvalds 		if (STbp->syscall_result != 0) {
17991da177e4SLinus Torvalds 			struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat;
18001da177e4SLinus Torvalds 
1801b30d8bcaSHannes Reinecke 			DEBC_printk(STp, "Error on write:\n");
18021da177e4SLinus Torvalds 			if (cmdstatp->have_sense && (cmdstatp->flags & SENSE_EOM)) {
18031da177e4SLinus Torvalds 				scode = cmdstatp->sense_hdr.sense_key;
18041da177e4SLinus Torvalds 				if (cmdstatp->remainder_valid)
18051da177e4SLinus Torvalds 					undone = (int)cmdstatp->uremainder64;
18061da177e4SLinus Torvalds 				else if (STp->block_size == 0 &&
18071da177e4SLinus Torvalds 					 scode == VOLUME_OVERFLOW)
18081da177e4SLinus Torvalds 					undone = transfer;
18091da177e4SLinus Torvalds 				else
18101da177e4SLinus Torvalds 					undone = 0;
18111da177e4SLinus Torvalds 				if (STp->block_size != 0)
18121da177e4SLinus Torvalds 					undone *= STp->block_size;
18131da177e4SLinus Torvalds 				if (undone <= do_count) {
18141da177e4SLinus Torvalds 					/* Only data from this write is not written */
18151da177e4SLinus Torvalds 					count += undone;
1816626dcb1eSKai Makisara 					b_point -= undone;
18171da177e4SLinus Torvalds 					do_count -= undone;
18181da177e4SLinus Torvalds 					if (STp->block_size)
18191da177e4SLinus Torvalds 						blks = (transfer - undone) / STp->block_size;
18201da177e4SLinus Torvalds 					STps->eof = ST_EOM_OK;
18211da177e4SLinus Torvalds 					/* Continue in fixed block mode if all written
18221da177e4SLinus Torvalds 					   in this request but still something left to write
18231da177e4SLinus Torvalds 					   (retval left to zero)
18241da177e4SLinus Torvalds 					*/
18251da177e4SLinus Torvalds 					if (STp->block_size == 0 ||
18261da177e4SLinus Torvalds 					    undone > 0 || count == 0)
18271da177e4SLinus Torvalds 						retval = (-ENOSPC); /* EOM within current request */
1828b30d8bcaSHannes Reinecke 					DEBC_printk(STp, "EOM with %d "
1829b30d8bcaSHannes Reinecke 						    "bytes unwritten.\n",
1830b30d8bcaSHannes Reinecke 						    (int)count);
18311da177e4SLinus Torvalds 				} else {
18321da177e4SLinus Torvalds 					/* EOT within data buffered earlier (possible only
18331da177e4SLinus Torvalds 					   in fixed block mode without direct i/o) */
18341da177e4SLinus Torvalds 					if (!retry_eot && !cmdstatp->deferred &&
18351da177e4SLinus Torvalds 					    (scode == NO_SENSE || scode == RECOVERED_ERROR)) {
18361da177e4SLinus Torvalds 						move_buffer_data(STp->buffer, transfer - undone);
18371da177e4SLinus Torvalds 						retry_eot = 1;
18381da177e4SLinus Torvalds 						if (STps->drv_block >= 0) {
18391da177e4SLinus Torvalds 							STps->drv_block += (transfer - undone) /
18401da177e4SLinus Torvalds 								STp->block_size;
18411da177e4SLinus Torvalds 						}
18421da177e4SLinus Torvalds 						STps->eof = ST_EOM_OK;
1843b30d8bcaSHannes Reinecke 						DEBC_printk(STp, "Retry "
1844b30d8bcaSHannes Reinecke 							    "write of %d "
1845b30d8bcaSHannes Reinecke 							    "bytes at EOM.\n",
1846b30d8bcaSHannes Reinecke 							    STp->buffer->buffer_bytes);
18471da177e4SLinus Torvalds 						goto retry_write;
18481da177e4SLinus Torvalds 					}
18491da177e4SLinus Torvalds 					else {
18501da177e4SLinus Torvalds 						/* Either error within data buffered by driver or
18511da177e4SLinus Torvalds 						   failed retry */
18521da177e4SLinus Torvalds 						count -= do_count;
18531da177e4SLinus Torvalds 						blks = do_count = 0;
18541da177e4SLinus Torvalds 						STps->eof = ST_EOM_ERROR;
18551da177e4SLinus Torvalds 						STps->drv_block = (-1); /* Too cautious? */
18561da177e4SLinus Torvalds 						retval = (-EIO);	/* EOM for old data */
1857b30d8bcaSHannes Reinecke 						DEBC_printk(STp, "EOM with "
1858b30d8bcaSHannes Reinecke 							    "lost data.\n");
18591da177e4SLinus Torvalds 					}
18601da177e4SLinus Torvalds 				}
18611da177e4SLinus Torvalds 			} else {
18621da177e4SLinus Torvalds 				count += do_count;
18631da177e4SLinus Torvalds 				STps->drv_block = (-1);		/* Too cautious? */
18648b05b773SMike Christie 				retval = STbp->syscall_result;
18651da177e4SLinus Torvalds 			}
18661da177e4SLinus Torvalds 
18671da177e4SLinus Torvalds 		}
18681da177e4SLinus Torvalds 
18691da177e4SLinus Torvalds 		if (STps->drv_block >= 0) {
18701da177e4SLinus Torvalds 			if (STp->block_size == 0)
18711da177e4SLinus Torvalds 				STps->drv_block += (do_count > 0);
18721da177e4SLinus Torvalds 			else
18731da177e4SLinus Torvalds 				STps->drv_block += blks;
18741da177e4SLinus Torvalds 		}
18751da177e4SLinus Torvalds 
18761da177e4SLinus Torvalds 		STbp->buffer_bytes = 0;
18771da177e4SLinus Torvalds 		STp->dirty = 0;
18781da177e4SLinus Torvalds 
18791da177e4SLinus Torvalds 		if (retval || retry_eot) {
18801da177e4SLinus Torvalds 			if (count < total)
18811da177e4SLinus Torvalds 				retval = total - count;
18821da177e4SLinus Torvalds 			goto out;
18831da177e4SLinus Torvalds 		}
18841da177e4SLinus Torvalds 	}
18851da177e4SLinus Torvalds 
18861da177e4SLinus Torvalds 	if (STps->eof == ST_EOD_1)
18871da177e4SLinus Torvalds 		STps->eof = ST_EOM_OK;
18881da177e4SLinus Torvalds 	else if (STps->eof != ST_EOM_OK)
18891da177e4SLinus Torvalds 		STps->eof = ST_NOEOF;
18901da177e4SLinus Torvalds 	retval = total - count;
18911da177e4SLinus Torvalds 
18921da177e4SLinus Torvalds  out:
18931da177e4SLinus Torvalds 	if (SRpnt != NULL)
18948b05b773SMike Christie 		st_release_request(SRpnt);
1895787926b1SKai Makisara 	release_buffering(STp, 0);
189628f85009SMatthias Kaehlcke 	mutex_unlock(&STp->lock);
18971da177e4SLinus Torvalds 
18981da177e4SLinus Torvalds 	return retval;
18991da177e4SLinus Torvalds }
19001da177e4SLinus Torvalds 
19011da177e4SLinus Torvalds /* Read data from the tape. Returns zero in the normal case, one if the
19021da177e4SLinus Torvalds    eof status has changed, and the negative error code in case of a
19031da177e4SLinus Torvalds    fatal error. Otherwise updates the buffer and the eof state.
19041da177e4SLinus Torvalds 
19051da177e4SLinus Torvalds    Does release user buffer mapping if it is set.
19061da177e4SLinus Torvalds */
read_tape(struct scsi_tape * STp,long count,struct st_request ** aSRpnt)19071da177e4SLinus Torvalds static long read_tape(struct scsi_tape *STp, long count,
19088b05b773SMike Christie 		      struct st_request ** aSRpnt)
19091da177e4SLinus Torvalds {
19101da177e4SLinus Torvalds 	int transfer, blks, bytes;
19111da177e4SLinus Torvalds 	unsigned char cmd[MAX_COMMAND_SIZE];
19128b05b773SMike Christie 	struct st_request *SRpnt;
19131da177e4SLinus Torvalds 	struct st_modedef *STm;
19141da177e4SLinus Torvalds 	struct st_partstat *STps;
19151da177e4SLinus Torvalds 	struct st_buffer *STbp;
19161da177e4SLinus Torvalds 	int retval = 0;
19171da177e4SLinus Torvalds 
19181da177e4SLinus Torvalds 	if (count == 0)
19191da177e4SLinus Torvalds 		return 0;
19201da177e4SLinus Torvalds 
19211da177e4SLinus Torvalds 	STm = &(STp->modes[STp->current_mode]);
19221da177e4SLinus Torvalds 	STps = &(STp->ps[STp->partition]);
19231da177e4SLinus Torvalds 	if (STps->eof == ST_FM_HIT)
19241da177e4SLinus Torvalds 		return 1;
19251da177e4SLinus Torvalds 	STbp = STp->buffer;
19261da177e4SLinus Torvalds 
19271da177e4SLinus Torvalds 	if (STp->block_size == 0)
19281da177e4SLinus Torvalds 		blks = bytes = count;
19291da177e4SLinus Torvalds 	else {
19309abe16c6SKai Makisara 		if (!(STp->try_dio_now && try_rdio) && STm->do_read_ahead) {
19311da177e4SLinus Torvalds 			blks = (STp->buffer)->buffer_blocks;
19321da177e4SLinus Torvalds 			bytes = blks * STp->block_size;
19331da177e4SLinus Torvalds 		} else {
19341da177e4SLinus Torvalds 			bytes = count;
19351da177e4SLinus Torvalds 			if (!STbp->do_dio && bytes > (STp->buffer)->buffer_size)
19361da177e4SLinus Torvalds 				bytes = (STp->buffer)->buffer_size;
19371da177e4SLinus Torvalds 			blks = bytes / STp->block_size;
19381da177e4SLinus Torvalds 			bytes = blks * STp->block_size;
19391da177e4SLinus Torvalds 		}
19401da177e4SLinus Torvalds 	}
19411da177e4SLinus Torvalds 
19421da177e4SLinus Torvalds 	memset(cmd, 0, MAX_COMMAND_SIZE);
19431da177e4SLinus Torvalds 	cmd[0] = READ_6;
19441da177e4SLinus Torvalds 	cmd[1] = (STp->block_size != 0);
194540f6b36cSKai Makisara 	if (!cmd[1] && STp->sili)
194640f6b36cSKai Makisara 		cmd[1] |= 2;
19471da177e4SLinus Torvalds 	cmd[2] = blks >> 16;
19481da177e4SLinus Torvalds 	cmd[3] = blks >> 8;
19491da177e4SLinus Torvalds 	cmd[4] = blks;
19501da177e4SLinus Torvalds 
19511da177e4SLinus Torvalds 	SRpnt = *aSRpnt;
19521da177e4SLinus Torvalds 	SRpnt = st_do_scsi(SRpnt, STp, cmd, bytes, DMA_FROM_DEVICE,
1953a02488edSJames Bottomley 			   STp->device->request_queue->rq_timeout,
1954a02488edSJames Bottomley 			   MAX_RETRIES, 1);
1955787926b1SKai Makisara 	release_buffering(STp, 1);
19561da177e4SLinus Torvalds 	*aSRpnt = SRpnt;
19571da177e4SLinus Torvalds 	if (!SRpnt)
19581da177e4SLinus Torvalds 		return STbp->syscall_result;
19591da177e4SLinus Torvalds 
19601da177e4SLinus Torvalds 	STbp->read_pointer = 0;
19611da177e4SLinus Torvalds 	STps->at_sm = 0;
19621da177e4SLinus Torvalds 
19631da177e4SLinus Torvalds 	/* Something to check */
19641da177e4SLinus Torvalds 	if (STbp->syscall_result) {
19651da177e4SLinus Torvalds 		struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat;
19661da177e4SLinus Torvalds 
19671da177e4SLinus Torvalds 		retval = 1;
1968b30d8bcaSHannes Reinecke 		DEBC_printk(STp,
1969b30d8bcaSHannes Reinecke 			    "Sense: %2x %2x %2x %2x %2x %2x %2x %2x\n",
19708b05b773SMike Christie 			    SRpnt->sense[0], SRpnt->sense[1],
19718b05b773SMike Christie 			    SRpnt->sense[2], SRpnt->sense[3],
19728b05b773SMike Christie 			    SRpnt->sense[4], SRpnt->sense[5],
1973b30d8bcaSHannes Reinecke 			    SRpnt->sense[6], SRpnt->sense[7]);
19741da177e4SLinus Torvalds 		if (cmdstatp->have_sense) {
19751da177e4SLinus Torvalds 
19761da177e4SLinus Torvalds 			if (cmdstatp->sense_hdr.sense_key == BLANK_CHECK)
19771da177e4SLinus Torvalds 				cmdstatp->flags &= 0xcf;	/* No need for EOM in this case */
19781da177e4SLinus Torvalds 
19791da177e4SLinus Torvalds 			if (cmdstatp->flags != 0) { /* EOF, EOM, or ILI */
19801da177e4SLinus Torvalds 				/* Compute the residual count */
19811da177e4SLinus Torvalds 				if (cmdstatp->remainder_valid)
19821da177e4SLinus Torvalds 					transfer = (int)cmdstatp->uremainder64;
19831da177e4SLinus Torvalds 				else
19841da177e4SLinus Torvalds 					transfer = 0;
19855e4fabb6SKai Makisara 				if (cmdstatp->sense_hdr.sense_key == MEDIUM_ERROR) {
19865e4fabb6SKai Makisara 					if (STp->block_size == 0)
19871da177e4SLinus Torvalds 						transfer = bytes;
19885e4fabb6SKai Makisara 					/* Some drives set ILI with MEDIUM ERROR */
19895e4fabb6SKai Makisara 					cmdstatp->flags &= ~SENSE_ILI;
19905e4fabb6SKai Makisara 				}
19911da177e4SLinus Torvalds 
19921da177e4SLinus Torvalds 				if (cmdstatp->flags & SENSE_ILI) {	/* ILI */
1993b30d8bcaSHannes Reinecke 					if (STp->block_size == 0 &&
1994b30d8bcaSHannes Reinecke 					    transfer < 0) {
1995b30d8bcaSHannes Reinecke 						st_printk(KERN_NOTICE, STp,
1996b30d8bcaSHannes Reinecke 							  "Failed to read %d "
1997b30d8bcaSHannes Reinecke 							  "byte block with %d "
1998b30d8bcaSHannes Reinecke 							  "byte transfer.\n",
1999b30d8bcaSHannes Reinecke 							  bytes - transfer,
2000b30d8bcaSHannes Reinecke 							  bytes);
20011da177e4SLinus Torvalds 						if (STps->drv_block >= 0)
20021da177e4SLinus Torvalds 							STps->drv_block += 1;
20031da177e4SLinus Torvalds 						STbp->buffer_bytes = 0;
20041da177e4SLinus Torvalds 						return (-ENOMEM);
2005b30d8bcaSHannes Reinecke 					} else if (STp->block_size == 0) {
20061da177e4SLinus Torvalds 						STbp->buffer_bytes = bytes - transfer;
20071da177e4SLinus Torvalds 					} else {
20088b05b773SMike Christie 						st_release_request(SRpnt);
20091da177e4SLinus Torvalds 						SRpnt = *aSRpnt = NULL;
20101da177e4SLinus Torvalds 						if (transfer == blks) {	/* We did not get anything, error */
2011b30d8bcaSHannes Reinecke 							st_printk(KERN_NOTICE, STp,
2012b30d8bcaSHannes Reinecke 								  "Incorrect "
2013b30d8bcaSHannes Reinecke 								  "block size.\n");
20141da177e4SLinus Torvalds 							if (STps->drv_block >= 0)
20151da177e4SLinus Torvalds 								STps->drv_block += blks - transfer + 1;
20161da177e4SLinus Torvalds 							st_int_ioctl(STp, MTBSR, 1);
20171da177e4SLinus Torvalds 							return (-EIO);
20181da177e4SLinus Torvalds 						}
20191da177e4SLinus Torvalds 						/* We have some data, deliver it */
20201da177e4SLinus Torvalds 						STbp->buffer_bytes = (blks - transfer) *
20211da177e4SLinus Torvalds 						    STp->block_size;
2022b30d8bcaSHannes Reinecke 						DEBC_printk(STp, "ILI but "
2023b30d8bcaSHannes Reinecke 							    "enough data "
2024b30d8bcaSHannes Reinecke 							    "received %ld "
2025b30d8bcaSHannes Reinecke 							    "%d.\n", count,
2026b30d8bcaSHannes Reinecke 							    STbp->buffer_bytes);
20271da177e4SLinus Torvalds 						if (STps->drv_block >= 0)
20281da177e4SLinus Torvalds 							STps->drv_block += 1;
20291da177e4SLinus Torvalds 						if (st_int_ioctl(STp, MTBSR, 1))
20301da177e4SLinus Torvalds 							return (-EIO);
20311da177e4SLinus Torvalds 					}
20321da177e4SLinus Torvalds 				} else if (cmdstatp->flags & SENSE_FMK) {	/* FM overrides EOM */
20331da177e4SLinus Torvalds 					if (STps->eof != ST_FM_HIT)
20341da177e4SLinus Torvalds 						STps->eof = ST_FM_HIT;
20351da177e4SLinus Torvalds 					else
20361da177e4SLinus Torvalds 						STps->eof = ST_EOD_2;
20371da177e4SLinus Torvalds 					if (STp->block_size == 0)
20381da177e4SLinus Torvalds 						STbp->buffer_bytes = 0;
20391da177e4SLinus Torvalds 					else
20401da177e4SLinus Torvalds 						STbp->buffer_bytes =
20411da177e4SLinus Torvalds 						    bytes - transfer * STp->block_size;
2042b30d8bcaSHannes Reinecke 					DEBC_printk(STp, "EOF detected (%d "
2043b30d8bcaSHannes Reinecke 						    "bytes read).\n",
2044b30d8bcaSHannes Reinecke 						    STbp->buffer_bytes);
20451da177e4SLinus Torvalds 				} else if (cmdstatp->flags & SENSE_EOM) {
20461da177e4SLinus Torvalds 					if (STps->eof == ST_FM)
20471da177e4SLinus Torvalds 						STps->eof = ST_EOD_1;
20481da177e4SLinus Torvalds 					else
20491da177e4SLinus Torvalds 						STps->eof = ST_EOM_OK;
20501da177e4SLinus Torvalds 					if (STp->block_size == 0)
20511da177e4SLinus Torvalds 						STbp->buffer_bytes = bytes - transfer;
20521da177e4SLinus Torvalds 					else
20531da177e4SLinus Torvalds 						STbp->buffer_bytes =
20541da177e4SLinus Torvalds 						    bytes - transfer * STp->block_size;
20551da177e4SLinus Torvalds 
2056b30d8bcaSHannes Reinecke 					DEBC_printk(STp, "EOM detected (%d "
2057b30d8bcaSHannes Reinecke 						    "bytes read).\n",
2058b30d8bcaSHannes Reinecke 						    STbp->buffer_bytes);
20591da177e4SLinus Torvalds 				}
20601da177e4SLinus Torvalds 			}
20611da177e4SLinus Torvalds 			/* end of EOF, EOM, ILI test */
20621da177e4SLinus Torvalds 			else {	/* nonzero sense key */
2063b30d8bcaSHannes Reinecke 				DEBC_printk(STp, "Tape error while reading.\n");
20641da177e4SLinus Torvalds 				STps->drv_block = (-1);
20651da177e4SLinus Torvalds 				if (STps->eof == ST_FM &&
20661da177e4SLinus Torvalds 				    cmdstatp->sense_hdr.sense_key == BLANK_CHECK) {
2067b30d8bcaSHannes Reinecke 					DEBC_printk(STp, "Zero returned for "
2068b30d8bcaSHannes Reinecke 						    "first BLANK CHECK "
2069b30d8bcaSHannes Reinecke 						    "after EOF.\n");
20701da177e4SLinus Torvalds 					STps->eof = ST_EOD_2;	/* First BLANK_CHECK after FM */
20711da177e4SLinus Torvalds 				} else	/* Some other extended sense code */
20721da177e4SLinus Torvalds 					retval = (-EIO);
20731da177e4SLinus Torvalds 			}
20741da177e4SLinus Torvalds 
20751da177e4SLinus Torvalds 			if (STbp->buffer_bytes < 0)  /* Caused by bogus sense data */
20761da177e4SLinus Torvalds 				STbp->buffer_bytes = 0;
20771da177e4SLinus Torvalds 		}
20781da177e4SLinus Torvalds 		/* End of extended sense test */
20791da177e4SLinus Torvalds 		else {		/* Non-extended sense */
20801da177e4SLinus Torvalds 			retval = STbp->syscall_result;
20811da177e4SLinus Torvalds 		}
20821da177e4SLinus Torvalds 
20831da177e4SLinus Torvalds 	}
20841da177e4SLinus Torvalds 	/* End of error handling */
208540f6b36cSKai Makisara 	else {			/* Read successful */
20861da177e4SLinus Torvalds 		STbp->buffer_bytes = bytes;
208740f6b36cSKai Makisara 		if (STp->sili) /* In fixed block mode residual is always zero here */
208840f6b36cSKai Makisara 			STbp->buffer_bytes -= STp->buffer->cmdstat.residual;
208940f6b36cSKai Makisara 	}
20901da177e4SLinus Torvalds 
20911da177e4SLinus Torvalds 	if (STps->drv_block >= 0) {
20921da177e4SLinus Torvalds 		if (STp->block_size == 0)
20931da177e4SLinus Torvalds 			STps->drv_block++;
20941da177e4SLinus Torvalds 		else
20951da177e4SLinus Torvalds 			STps->drv_block += STbp->buffer_bytes / STp->block_size;
20961da177e4SLinus Torvalds 	}
20971da177e4SLinus Torvalds 	return retval;
20981da177e4SLinus Torvalds }
20991da177e4SLinus Torvalds 
21001da177e4SLinus Torvalds 
21011da177e4SLinus Torvalds /* Read command */
21021da177e4SLinus Torvalds static ssize_t
st_read(struct file * filp,char __user * buf,size_t count,loff_t * ppos)21031da177e4SLinus Torvalds st_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos)
21041da177e4SLinus Torvalds {
21051da177e4SLinus Torvalds 	ssize_t total;
21061da177e4SLinus Torvalds 	ssize_t retval = 0;
21071da177e4SLinus Torvalds 	ssize_t i, transfer;
21081da177e4SLinus Torvalds 	int special, do_dio = 0;
21098b05b773SMike Christie 	struct st_request *SRpnt = NULL;
21101da177e4SLinus Torvalds 	struct scsi_tape *STp = filp->private_data;
21111da177e4SLinus Torvalds 	struct st_modedef *STm;
21121da177e4SLinus Torvalds 	struct st_partstat *STps;
21131da177e4SLinus Torvalds 	struct st_buffer *STbp = STp->buffer;
21141da177e4SLinus Torvalds 
211528f85009SMatthias Kaehlcke 	if (mutex_lock_interruptible(&STp->lock))
21161da177e4SLinus Torvalds 		return -ERESTARTSYS;
21171da177e4SLinus Torvalds 
21181da177e4SLinus Torvalds 	retval = rw_checks(STp, filp, count);
21191da177e4SLinus Torvalds 	if (retval || count == 0)
21201da177e4SLinus Torvalds 		goto out;
21211da177e4SLinus Torvalds 
21221da177e4SLinus Torvalds 	STm = &(STp->modes[STp->current_mode]);
21239abe16c6SKai Makisara 	if (STp->block_size != 0 && (count % STp->block_size) != 0) {
21249abe16c6SKai Makisara 		if (!STm->do_read_ahead) {
21251da177e4SLinus Torvalds 			retval = (-EINVAL);	/* Read must be integral number of blocks */
21261da177e4SLinus Torvalds 			goto out;
21271da177e4SLinus Torvalds 		}
21289abe16c6SKai Makisara 		STp->try_dio_now = 0;  /* Direct i/o can't handle split blocks */
21299abe16c6SKai Makisara 	}
21301da177e4SLinus Torvalds 
21311da177e4SLinus Torvalds 	STps = &(STp->ps[STp->partition]);
21321da177e4SLinus Torvalds 	if (STps->rw == ST_WRITING) {
21331da177e4SLinus Torvalds 		retval = flush_buffer(STp, 0);
21341da177e4SLinus Torvalds 		if (retval)
21351da177e4SLinus Torvalds 			goto out;
21361da177e4SLinus Torvalds 		STps->rw = ST_READING;
21371da177e4SLinus Torvalds 	}
21381da177e4SLinus Torvalds 	DEB(
21391da177e4SLinus Torvalds 	if (debugging && STps->eof != ST_NOEOF)
2140b30d8bcaSHannes Reinecke 		st_printk(ST_DEB_MSG, STp,
2141b30d8bcaSHannes Reinecke 			  "EOF/EOM flag up (%d). Bytes %d\n",
21421da177e4SLinus Torvalds 			  STps->eof, STbp->buffer_bytes);
21431da177e4SLinus Torvalds 	) /* end DEB */
21441da177e4SLinus Torvalds 
21451da177e4SLinus Torvalds 	retval = setup_buffering(STp, buf, count, 1);
21461da177e4SLinus Torvalds 	if (retval)
21471da177e4SLinus Torvalds 		goto out;
21481da177e4SLinus Torvalds 	do_dio = STbp->do_dio;
21491da177e4SLinus Torvalds 
21501da177e4SLinus Torvalds 	if (STbp->buffer_bytes == 0 &&
21511da177e4SLinus Torvalds 	    STps->eof >= ST_EOD_1) {
21521da177e4SLinus Torvalds 		if (STps->eof < ST_EOD) {
21531da177e4SLinus Torvalds 			STps->eof += 1;
21541da177e4SLinus Torvalds 			retval = 0;
21551da177e4SLinus Torvalds 			goto out;
21561da177e4SLinus Torvalds 		}
21571da177e4SLinus Torvalds 		retval = (-EIO);	/* EOM or Blank Check */
21581da177e4SLinus Torvalds 		goto out;
21591da177e4SLinus Torvalds 	}
21601da177e4SLinus Torvalds 
21611da177e4SLinus Torvalds 	if (do_dio) {
21621da177e4SLinus Torvalds 		/* Check the buffer writability before any tape movement. Don't alter
21631da177e4SLinus Torvalds 		   buffer data. */
21641da177e4SLinus Torvalds 		if (copy_from_user(&i, buf, 1) != 0 ||
21651da177e4SLinus Torvalds 		    copy_to_user(buf, &i, 1) != 0 ||
21661da177e4SLinus Torvalds 		    copy_from_user(&i, buf + count - 1, 1) != 0 ||
21671da177e4SLinus Torvalds 		    copy_to_user(buf + count - 1, &i, 1) != 0) {
21681da177e4SLinus Torvalds 			retval = (-EFAULT);
21691da177e4SLinus Torvalds 			goto out;
21701da177e4SLinus Torvalds 		}
21711da177e4SLinus Torvalds 	}
21721da177e4SLinus Torvalds 
21731da177e4SLinus Torvalds 	STps->rw = ST_READING;
21741da177e4SLinus Torvalds 
21751da177e4SLinus Torvalds 
21761da177e4SLinus Torvalds 	/* Loop until enough data in buffer or a special condition found */
21771da177e4SLinus Torvalds 	for (total = 0, special = 0; total < count && !special;) {
21781da177e4SLinus Torvalds 
21791da177e4SLinus Torvalds 		/* Get new data if the buffer is empty */
21801da177e4SLinus Torvalds 		if (STbp->buffer_bytes == 0) {
21811da177e4SLinus Torvalds 			special = read_tape(STp, count - total, &SRpnt);
21821da177e4SLinus Torvalds 			if (special < 0) {	/* No need to continue read */
21831da177e4SLinus Torvalds 				retval = special;
21841da177e4SLinus Torvalds 				goto out;
21851da177e4SLinus Torvalds 			}
21861da177e4SLinus Torvalds 		}
21871da177e4SLinus Torvalds 
21881da177e4SLinus Torvalds 		/* Move the data from driver buffer to user buffer */
21891da177e4SLinus Torvalds 		if (STbp->buffer_bytes > 0) {
21901da177e4SLinus Torvalds 			DEB(
21911da177e4SLinus Torvalds 			if (debugging && STps->eof != ST_NOEOF)
2192b30d8bcaSHannes Reinecke 				st_printk(ST_DEB_MSG, STp,
2193b30d8bcaSHannes Reinecke 					  "EOF up (%d). Left %d, needed %d.\n",
21941da177e4SLinus Torvalds 					  STps->eof, STbp->buffer_bytes,
21951da177e4SLinus Torvalds 					  (int)(count - total));
21961da177e4SLinus Torvalds 			) /* end DEB */
21971da177e4SLinus Torvalds 			transfer = STbp->buffer_bytes < count - total ?
21981da177e4SLinus Torvalds 			    STbp->buffer_bytes : count - total;
21991da177e4SLinus Torvalds 			if (!do_dio) {
22001da177e4SLinus Torvalds 				i = from_buffer(STbp, buf, transfer);
22011da177e4SLinus Torvalds 				if (i) {
22021da177e4SLinus Torvalds 					retval = i;
22031da177e4SLinus Torvalds 					goto out;
22041da177e4SLinus Torvalds 				}
22051da177e4SLinus Torvalds 			}
22061da177e4SLinus Torvalds 			buf += transfer;
22071da177e4SLinus Torvalds 			total += transfer;
22081da177e4SLinus Torvalds 		}
22091da177e4SLinus Torvalds 
22101da177e4SLinus Torvalds 		if (STp->block_size == 0)
22111da177e4SLinus Torvalds 			break;	/* Read only one variable length block */
22121da177e4SLinus Torvalds 
22131da177e4SLinus Torvalds 	}			/* for (total = 0, special = 0;
22141da177e4SLinus Torvalds                                    total < count && !special; ) */
22151da177e4SLinus Torvalds 
22161da177e4SLinus Torvalds 	/* Change the eof state if no data from tape or buffer */
22171da177e4SLinus Torvalds 	if (total == 0) {
22181da177e4SLinus Torvalds 		if (STps->eof == ST_FM_HIT) {
22191da177e4SLinus Torvalds 			STps->eof = ST_FM;
22201da177e4SLinus Torvalds 			STps->drv_block = 0;
22211da177e4SLinus Torvalds 			if (STps->drv_file >= 0)
22221da177e4SLinus Torvalds 				STps->drv_file++;
22231da177e4SLinus Torvalds 		} else if (STps->eof == ST_EOD_1) {
22241da177e4SLinus Torvalds 			STps->eof = ST_EOD_2;
22251da177e4SLinus Torvalds 			STps->drv_block = 0;
22261da177e4SLinus Torvalds 			if (STps->drv_file >= 0)
22271da177e4SLinus Torvalds 				STps->drv_file++;
22281da177e4SLinus Torvalds 		} else if (STps->eof == ST_EOD_2)
22291da177e4SLinus Torvalds 			STps->eof = ST_EOD;
22301da177e4SLinus Torvalds 	} else if (STps->eof == ST_FM)
22311da177e4SLinus Torvalds 		STps->eof = ST_NOEOF;
22321da177e4SLinus Torvalds 	retval = total;
22331da177e4SLinus Torvalds 
22341da177e4SLinus Torvalds  out:
22351da177e4SLinus Torvalds 	if (SRpnt != NULL) {
22368b05b773SMike Christie 		st_release_request(SRpnt);
22371da177e4SLinus Torvalds 		SRpnt = NULL;
22381da177e4SLinus Torvalds 	}
22391da177e4SLinus Torvalds 	if (do_dio) {
2240787926b1SKai Makisara 		release_buffering(STp, 1);
22411da177e4SLinus Torvalds 		STbp->buffer_bytes = 0;
22421da177e4SLinus Torvalds 	}
224328f85009SMatthias Kaehlcke 	mutex_unlock(&STp->lock);
22441da177e4SLinus Torvalds 
22451da177e4SLinus Torvalds 	return retval;
22461da177e4SLinus Torvalds }
22471da177e4SLinus Torvalds 
22481da177e4SLinus Torvalds 
22491da177e4SLinus Torvalds 
DEB(static void st_log_options (struct scsi_tape * STp,struct st_modedef * STm){ if (debugging) { st_printk(KERN_INFO, STp, "Mode %d options: buffer writes: %d, " "async writes: %d, read ahead: %d\\n", STp->current_mode, STm->do_buffer_writes, STm->do_async_writes, STm->do_read_ahead); st_printk(KERN_INFO, STp, "    can bsr: %d, two FMs: %d, " "fast mteom: %d, auto lock: %d,\\n", STp->can_bsr, STp->two_fm, STp->fast_mteom, STp->do_auto_lock); st_printk(KERN_INFO, STp, "    defs for wr: %d, no block limits: %d, " "partitions: %d, s2 log: %d\\n", STm->defaults_for_writes, STp->omit_blklims, STp->can_partitions, STp->scsi2_logical); st_printk(KERN_INFO, STp, "    sysv: %d nowait: %d sili: %d " "nowait_filemark: %d\\n", STm->sysv, STp->immediate, STp->sili, STp->immediate_filemark); st_printk(KERN_INFO, STp, "    debugging: %d\\n", debugging); } } )22501da177e4SLinus Torvalds DEB(
22511da177e4SLinus Torvalds /* Set the driver options */
2252b30d8bcaSHannes Reinecke static void st_log_options(struct scsi_tape * STp, struct st_modedef * STm)
22531da177e4SLinus Torvalds {
22541da177e4SLinus Torvalds 	if (debugging) {
2255b30d8bcaSHannes Reinecke 		st_printk(KERN_INFO, STp,
2256b30d8bcaSHannes Reinecke 			  "Mode %d options: buffer writes: %d, "
2257b30d8bcaSHannes Reinecke 			  "async writes: %d, read ahead: %d\n",
2258b30d8bcaSHannes Reinecke 			  STp->current_mode, STm->do_buffer_writes,
2259b30d8bcaSHannes Reinecke 			  STm->do_async_writes, STm->do_read_ahead);
2260b30d8bcaSHannes Reinecke 		st_printk(KERN_INFO, STp,
2261b30d8bcaSHannes Reinecke 			  "    can bsr: %d, two FMs: %d, "
2262b30d8bcaSHannes Reinecke 			  "fast mteom: %d, auto lock: %d,\n",
2263b30d8bcaSHannes Reinecke 			  STp->can_bsr, STp->two_fm, STp->fast_mteom,
2264b30d8bcaSHannes Reinecke 			  STp->do_auto_lock);
2265b30d8bcaSHannes Reinecke 		st_printk(KERN_INFO, STp,
2266b30d8bcaSHannes Reinecke 			  "    defs for wr: %d, no block limits: %d, "
2267b30d8bcaSHannes Reinecke 			  "partitions: %d, s2 log: %d\n",
2268b30d8bcaSHannes Reinecke 			  STm->defaults_for_writes, STp->omit_blklims,
2269b30d8bcaSHannes Reinecke 			  STp->can_partitions, STp->scsi2_logical);
2270b30d8bcaSHannes Reinecke 		st_printk(KERN_INFO, STp,
2271b30d8bcaSHannes Reinecke 			  "    sysv: %d nowait: %d sili: %d "
2272b30d8bcaSHannes Reinecke 			  "nowait_filemark: %d\n",
2273b30d8bcaSHannes Reinecke 			  STm->sysv, STp->immediate, STp->sili,
2274c743e44fSLee Duncan 			  STp->immediate_filemark);
2275b30d8bcaSHannes Reinecke 		st_printk(KERN_INFO, STp, "    debugging: %d\n", debugging);
22761da177e4SLinus Torvalds 	}
22771da177e4SLinus Torvalds }
22781da177e4SLinus Torvalds 	)
22791da177e4SLinus Torvalds 
22801da177e4SLinus Torvalds 
22811da177e4SLinus Torvalds static int st_set_options(struct scsi_tape *STp, long options)
22821da177e4SLinus Torvalds {
22831da177e4SLinus Torvalds 	int value;
22841da177e4SLinus Torvalds 	long code;
22851da177e4SLinus Torvalds 	struct st_modedef *STm;
22861da177e4SLinus Torvalds 	struct cdev *cd0, *cd1;
2287d6216c47SMaurizio Lombardi 	struct device *d0, *d1;
22881da177e4SLinus Torvalds 
22891da177e4SLinus Torvalds 	STm = &(STp->modes[STp->current_mode]);
22901da177e4SLinus Torvalds 	if (!STm->defined) {
2291d6216c47SMaurizio Lombardi 		cd0 = STm->cdevs[0];
2292d6216c47SMaurizio Lombardi 		cd1 = STm->cdevs[1];
2293d6216c47SMaurizio Lombardi 		d0  = STm->devs[0];
2294d6216c47SMaurizio Lombardi 		d1  = STm->devs[1];
22951da177e4SLinus Torvalds 		memcpy(STm, &(STp->modes[0]), sizeof(struct st_modedef));
2296d6216c47SMaurizio Lombardi 		STm->cdevs[0] = cd0;
2297d6216c47SMaurizio Lombardi 		STm->cdevs[1] = cd1;
2298d6216c47SMaurizio Lombardi 		STm->devs[0]  = d0;
2299d6216c47SMaurizio Lombardi 		STm->devs[1]  = d1;
23001da177e4SLinus Torvalds 		modes_defined = 1;
2301b30d8bcaSHannes Reinecke 		DEBC_printk(STp, "Initialized mode %d definition from mode 0\n",
2302b30d8bcaSHannes Reinecke 			    STp->current_mode);
23031da177e4SLinus Torvalds 	}
23041da177e4SLinus Torvalds 
23051da177e4SLinus Torvalds 	code = options & MT_ST_OPTIONS;
23061da177e4SLinus Torvalds 	if (code == MT_ST_BOOLEANS) {
23071da177e4SLinus Torvalds 		STm->do_buffer_writes = (options & MT_ST_BUFFER_WRITES) != 0;
23081da177e4SLinus Torvalds 		STm->do_async_writes = (options & MT_ST_ASYNC_WRITES) != 0;
23091da177e4SLinus Torvalds 		STm->defaults_for_writes = (options & MT_ST_DEF_WRITES) != 0;
23101da177e4SLinus Torvalds 		STm->do_read_ahead = (options & MT_ST_READ_AHEAD) != 0;
23111da177e4SLinus Torvalds 		STp->two_fm = (options & MT_ST_TWO_FM) != 0;
23121da177e4SLinus Torvalds 		STp->fast_mteom = (options & MT_ST_FAST_MTEOM) != 0;
23131da177e4SLinus Torvalds 		STp->do_auto_lock = (options & MT_ST_AUTO_LOCK) != 0;
23141da177e4SLinus Torvalds 		STp->can_bsr = (options & MT_ST_CAN_BSR) != 0;
23151da177e4SLinus Torvalds 		STp->omit_blklims = (options & MT_ST_NO_BLKLIMS) != 0;
23161da177e4SLinus Torvalds 		if ((STp->device)->scsi_level >= SCSI_2)
23171da177e4SLinus Torvalds 			STp->can_partitions = (options & MT_ST_CAN_PARTITIONS) != 0;
23181da177e4SLinus Torvalds 		STp->scsi2_logical = (options & MT_ST_SCSI2LOGICAL) != 0;
23191da177e4SLinus Torvalds 		STp->immediate = (options & MT_ST_NOWAIT) != 0;
2320c743e44fSLee Duncan 		STp->immediate_filemark = (options & MT_ST_NOWAIT_EOF) != 0;
23211da177e4SLinus Torvalds 		STm->sysv = (options & MT_ST_SYSV) != 0;
232240f6b36cSKai Makisara 		STp->sili = (options & MT_ST_SILI) != 0;
23231da177e4SLinus Torvalds 		DEB( debugging = (options & MT_ST_DEBUGGING) != 0;
2324b30d8bcaSHannes Reinecke 		     st_log_options(STp, STm); )
23251da177e4SLinus Torvalds 	} else if (code == MT_ST_SETBOOLEANS || code == MT_ST_CLEARBOOLEANS) {
23261da177e4SLinus Torvalds 		value = (code == MT_ST_SETBOOLEANS);
23271da177e4SLinus Torvalds 		if ((options & MT_ST_BUFFER_WRITES) != 0)
23281da177e4SLinus Torvalds 			STm->do_buffer_writes = value;
23291da177e4SLinus Torvalds 		if ((options & MT_ST_ASYNC_WRITES) != 0)
23301da177e4SLinus Torvalds 			STm->do_async_writes = value;
23311da177e4SLinus Torvalds 		if ((options & MT_ST_DEF_WRITES) != 0)
23321da177e4SLinus Torvalds 			STm->defaults_for_writes = value;
23331da177e4SLinus Torvalds 		if ((options & MT_ST_READ_AHEAD) != 0)
23341da177e4SLinus Torvalds 			STm->do_read_ahead = value;
23351da177e4SLinus Torvalds 		if ((options & MT_ST_TWO_FM) != 0)
23361da177e4SLinus Torvalds 			STp->two_fm = value;
23371da177e4SLinus Torvalds 		if ((options & MT_ST_FAST_MTEOM) != 0)
23381da177e4SLinus Torvalds 			STp->fast_mteom = value;
23391da177e4SLinus Torvalds 		if ((options & MT_ST_AUTO_LOCK) != 0)
23401da177e4SLinus Torvalds 			STp->do_auto_lock = value;
23411da177e4SLinus Torvalds 		if ((options & MT_ST_CAN_BSR) != 0)
23421da177e4SLinus Torvalds 			STp->can_bsr = value;
23431da177e4SLinus Torvalds 		if ((options & MT_ST_NO_BLKLIMS) != 0)
23441da177e4SLinus Torvalds 			STp->omit_blklims = value;
23451da177e4SLinus Torvalds 		if ((STp->device)->scsi_level >= SCSI_2 &&
23461da177e4SLinus Torvalds 		    (options & MT_ST_CAN_PARTITIONS) != 0)
23471da177e4SLinus Torvalds 			STp->can_partitions = value;
23481da177e4SLinus Torvalds 		if ((options & MT_ST_SCSI2LOGICAL) != 0)
23491da177e4SLinus Torvalds 			STp->scsi2_logical = value;
23501da177e4SLinus Torvalds 		if ((options & MT_ST_NOWAIT) != 0)
23511da177e4SLinus Torvalds 			STp->immediate = value;
2352c743e44fSLee Duncan 		if ((options & MT_ST_NOWAIT_EOF) != 0)
2353c743e44fSLee Duncan 			STp->immediate_filemark = value;
23541da177e4SLinus Torvalds 		if ((options & MT_ST_SYSV) != 0)
23551da177e4SLinus Torvalds 			STm->sysv = value;
235640f6b36cSKai Makisara 		if ((options & MT_ST_SILI) != 0)
235740f6b36cSKai Makisara 			STp->sili = value;
23581da177e4SLinus Torvalds 		DEB(
23591da177e4SLinus Torvalds 		if ((options & MT_ST_DEBUGGING) != 0)
23601da177e4SLinus Torvalds 			debugging = value;
2361b30d8bcaSHannes Reinecke 			st_log_options(STp, STm); )
23621da177e4SLinus Torvalds 	} else if (code == MT_ST_WRITE_THRESHOLD) {
23631da177e4SLinus Torvalds 		/* Retained for compatibility */
23641da177e4SLinus Torvalds 	} else if (code == MT_ST_DEF_BLKSIZE) {
23651da177e4SLinus Torvalds 		value = (options & ~MT_ST_OPTIONS);
23661da177e4SLinus Torvalds 		if (value == ~MT_ST_OPTIONS) {
23671da177e4SLinus Torvalds 			STm->default_blksize = (-1);
2368b30d8bcaSHannes Reinecke 			DEBC_printk(STp, "Default block size disabled.\n");
23691da177e4SLinus Torvalds 		} else {
23701da177e4SLinus Torvalds 			STm->default_blksize = value;
2371b30d8bcaSHannes Reinecke 			DEBC_printk(STp,"Default block size set to "
2372b30d8bcaSHannes Reinecke 				    "%d bytes.\n", STm->default_blksize);
23731da177e4SLinus Torvalds 			if (STp->ready == ST_READY) {
23741da177e4SLinus Torvalds 				STp->blksize_changed = 0;
23751da177e4SLinus Torvalds 				set_mode_densblk(STp, STm);
23761da177e4SLinus Torvalds 			}
23771da177e4SLinus Torvalds 		}
23781da177e4SLinus Torvalds 	} else if (code == MT_ST_TIMEOUTS) {
23791da177e4SLinus Torvalds 		value = (options & ~MT_ST_OPTIONS);
23801da177e4SLinus Torvalds 		if ((value & MT_ST_SET_LONG_TIMEOUT) != 0) {
23811da177e4SLinus Torvalds 			STp->long_timeout = (value & ~MT_ST_SET_LONG_TIMEOUT) * HZ;
2382b30d8bcaSHannes Reinecke 			DEBC_printk(STp, "Long timeout set to %d seconds.\n",
2383b30d8bcaSHannes Reinecke 				    (value & ~MT_ST_SET_LONG_TIMEOUT));
23841da177e4SLinus Torvalds 		} else {
2385a02488edSJames Bottomley 			blk_queue_rq_timeout(STp->device->request_queue,
2386a02488edSJames Bottomley 					     value * HZ);
2387b30d8bcaSHannes Reinecke 			DEBC_printk(STp, "Normal timeout set to %d seconds.\n",
2388b30d8bcaSHannes Reinecke 				    value);
23891da177e4SLinus Torvalds 		}
23901da177e4SLinus Torvalds 	} else if (code == MT_ST_SET_CLN) {
23911da177e4SLinus Torvalds 		value = (options & ~MT_ST_OPTIONS) & 0xff;
23921da177e4SLinus Torvalds 		if (value != 0 &&
2393832151f4SRoel Kluin 			(value < EXTENDED_SENSE_START ||
2394832151f4SRoel Kluin 				value >= SCSI_SENSE_BUFFERSIZE))
23951da177e4SLinus Torvalds 			return (-EINVAL);
23961da177e4SLinus Torvalds 		STp->cln_mode = value;
23971da177e4SLinus Torvalds 		STp->cln_sense_mask = (options >> 8) & 0xff;
23981da177e4SLinus Torvalds 		STp->cln_sense_value = (options >> 16) & 0xff;
2399b30d8bcaSHannes Reinecke 		st_printk(KERN_INFO, STp,
2400b30d8bcaSHannes Reinecke 			  "Cleaning request mode %d, mask %02x, value %02x\n",
2401b30d8bcaSHannes Reinecke 			  value, STp->cln_sense_mask, STp->cln_sense_value);
24021da177e4SLinus Torvalds 	} else if (code == MT_ST_DEF_OPTIONS) {
24031da177e4SLinus Torvalds 		code = (options & ~MT_ST_CLEAR_DEFAULT);
24041da177e4SLinus Torvalds 		value = (options & MT_ST_CLEAR_DEFAULT);
24051da177e4SLinus Torvalds 		if (code == MT_ST_DEF_DENSITY) {
24061da177e4SLinus Torvalds 			if (value == MT_ST_CLEAR_DEFAULT) {
24071da177e4SLinus Torvalds 				STm->default_density = (-1);
2408b30d8bcaSHannes Reinecke 				DEBC_printk(STp,
2409b30d8bcaSHannes Reinecke 					    "Density default disabled.\n");
24101da177e4SLinus Torvalds 			} else {
24111da177e4SLinus Torvalds 				STm->default_density = value & 0xff;
2412b30d8bcaSHannes Reinecke 				DEBC_printk(STp, "Density default set to %x\n",
2413b30d8bcaSHannes Reinecke 					    STm->default_density);
24141da177e4SLinus Torvalds 				if (STp->ready == ST_READY) {
24151da177e4SLinus Torvalds 					STp->density_changed = 0;
24161da177e4SLinus Torvalds 					set_mode_densblk(STp, STm);
24171da177e4SLinus Torvalds 				}
24181da177e4SLinus Torvalds 			}
24191da177e4SLinus Torvalds 		} else if (code == MT_ST_DEF_DRVBUFFER) {
24201da177e4SLinus Torvalds 			if (value == MT_ST_CLEAR_DEFAULT) {
24211da177e4SLinus Torvalds 				STp->default_drvbuffer = 0xff;
2422b30d8bcaSHannes Reinecke 				DEBC_printk(STp,
2423b30d8bcaSHannes Reinecke 					    "Drive buffer default disabled.\n");
24241da177e4SLinus Torvalds 			} else {
24251da177e4SLinus Torvalds 				STp->default_drvbuffer = value & 7;
2426b30d8bcaSHannes Reinecke 				DEBC_printk(STp,
2427b30d8bcaSHannes Reinecke 					    "Drive buffer default set to %x\n",
2428b30d8bcaSHannes Reinecke 					    STp->default_drvbuffer);
24291da177e4SLinus Torvalds 				if (STp->ready == ST_READY)
24301da177e4SLinus Torvalds 					st_int_ioctl(STp, MTSETDRVBUFFER, STp->default_drvbuffer);
24311da177e4SLinus Torvalds 			}
24321da177e4SLinus Torvalds 		} else if (code == MT_ST_DEF_COMPRESSION) {
24331da177e4SLinus Torvalds 			if (value == MT_ST_CLEAR_DEFAULT) {
24341da177e4SLinus Torvalds 				STm->default_compression = ST_DONT_TOUCH;
2435b30d8bcaSHannes Reinecke 				DEBC_printk(STp,
2436b30d8bcaSHannes Reinecke 					    "Compression default disabled.\n");
24371da177e4SLinus Torvalds 			} else {
24381da177e4SLinus Torvalds 				if ((value & 0xff00) != 0) {
24391da177e4SLinus Torvalds 					STp->c_algo = (value & 0xff00) >> 8;
2440b30d8bcaSHannes Reinecke 					DEBC_printk(STp, "Compression "
2441b30d8bcaSHannes Reinecke 						    "algorithm set to 0x%x.\n",
2442b30d8bcaSHannes Reinecke 						    STp->c_algo);
24431da177e4SLinus Torvalds 				}
24441da177e4SLinus Torvalds 				if ((value & 0xff) != 0xff) {
24451da177e4SLinus Torvalds 					STm->default_compression = (value & 1 ? ST_YES : ST_NO);
2446b30d8bcaSHannes Reinecke 					DEBC_printk(STp, "Compression default "
2447b30d8bcaSHannes Reinecke 						    "set to %x\n",
2448b30d8bcaSHannes Reinecke 						    (value & 1));
24491da177e4SLinus Torvalds 					if (STp->ready == ST_READY) {
24501da177e4SLinus Torvalds 						STp->compression_changed = 0;
24511da177e4SLinus Torvalds 						st_compression(STp, (STm->default_compression == ST_YES));
24521da177e4SLinus Torvalds 					}
24531da177e4SLinus Torvalds 				}
24541da177e4SLinus Torvalds 			}
24551da177e4SLinus Torvalds 		}
24561da177e4SLinus Torvalds 	} else
24571da177e4SLinus Torvalds 		return (-EIO);
24581da177e4SLinus Torvalds 
24591da177e4SLinus Torvalds 	return 0;
24601da177e4SLinus Torvalds }
24611da177e4SLinus Torvalds 
24621da177e4SLinus Torvalds #define MODE_HEADER_LENGTH  4
24631da177e4SLinus Torvalds 
24641da177e4SLinus Torvalds /* Mode header and page byte offsets */
24651da177e4SLinus Torvalds #define MH_OFF_DATA_LENGTH     0
24661da177e4SLinus Torvalds #define MH_OFF_MEDIUM_TYPE     1
24671da177e4SLinus Torvalds #define MH_OFF_DEV_SPECIFIC    2
24681da177e4SLinus Torvalds #define MH_OFF_BDESCS_LENGTH   3
24691da177e4SLinus Torvalds #define MP_OFF_PAGE_NBR        0
24701da177e4SLinus Torvalds #define MP_OFF_PAGE_LENGTH     1
24711da177e4SLinus Torvalds 
24721da177e4SLinus Torvalds /* Mode header and page bit masks */
24731da177e4SLinus Torvalds #define MH_BIT_WP              0x80
24741da177e4SLinus Torvalds #define MP_MSK_PAGE_NBR        0x3f
24751da177e4SLinus Torvalds 
24761da177e4SLinus Torvalds /* Don't return block descriptors */
24771da177e4SLinus Torvalds #define MODE_SENSE_OMIT_BDESCS 0x08
24781da177e4SLinus Torvalds 
24791da177e4SLinus Torvalds #define MODE_SELECT_PAGE_FORMAT 0x10
24801da177e4SLinus Torvalds 
24811da177e4SLinus Torvalds /* Read a mode page into the tape buffer. The block descriptors are included
24821da177e4SLinus Torvalds    if incl_block_descs is true. The page control is ored to the page number
24831da177e4SLinus Torvalds    parameter, if necessary. */
read_mode_page(struct scsi_tape * STp,int page,int omit_block_descs)24841da177e4SLinus Torvalds static int read_mode_page(struct scsi_tape *STp, int page, int omit_block_descs)
24851da177e4SLinus Torvalds {
24861da177e4SLinus Torvalds 	unsigned char cmd[MAX_COMMAND_SIZE];
24878ecf0d99SFUJITA Tomonori 	struct st_request *SRpnt;
24881da177e4SLinus Torvalds 
24891da177e4SLinus Torvalds 	memset(cmd, 0, MAX_COMMAND_SIZE);
24901da177e4SLinus Torvalds 	cmd[0] = MODE_SENSE;
24911da177e4SLinus Torvalds 	if (omit_block_descs)
24921da177e4SLinus Torvalds 		cmd[1] = MODE_SENSE_OMIT_BDESCS;
24931da177e4SLinus Torvalds 	cmd[2] = page;
24941da177e4SLinus Torvalds 	cmd[4] = 255;
24951da177e4SLinus Torvalds 
249602ae2c0eSKai Makisara 	SRpnt = st_do_scsi(NULL, STp, cmd, cmd[4], DMA_FROM_DEVICE,
249702ae2c0eSKai Makisara 			   STp->device->request_queue->rq_timeout, 0, 1);
249802ae2c0eSKai Makisara 	if (SRpnt == NULL)
249902ae2c0eSKai Makisara 		return (STp->buffer)->syscall_result;
25001da177e4SLinus Torvalds 
25018b05b773SMike Christie 	st_release_request(SRpnt);
25021da177e4SLinus Torvalds 
250302ae2c0eSKai Makisara 	return STp->buffer->syscall_result;
25041da177e4SLinus Torvalds }
25051da177e4SLinus Torvalds 
25061da177e4SLinus Torvalds 
25071da177e4SLinus Torvalds /* Send the mode page in the tape buffer to the drive. Assumes that the mode data
25081da177e4SLinus Torvalds    in the buffer is correctly formatted. The long timeout is used if slow is non-zero. */
write_mode_page(struct scsi_tape * STp,int page,int slow)25091da177e4SLinus Torvalds static int write_mode_page(struct scsi_tape *STp, int page, int slow)
25101da177e4SLinus Torvalds {
251102ae2c0eSKai Makisara 	int pgo;
25121da177e4SLinus Torvalds 	unsigned char cmd[MAX_COMMAND_SIZE];
251318c87015SFUJITA Tomonori 	struct st_request *SRpnt;
251402ae2c0eSKai Makisara 	int timeout;
25151da177e4SLinus Torvalds 
25161da177e4SLinus Torvalds 	memset(cmd, 0, MAX_COMMAND_SIZE);
25171da177e4SLinus Torvalds 	cmd[0] = MODE_SELECT;
25181da177e4SLinus Torvalds 	cmd[1] = MODE_SELECT_PAGE_FORMAT;
25191da177e4SLinus Torvalds 	pgo = MODE_HEADER_LENGTH + (STp->buffer)->b_data[MH_OFF_BDESCS_LENGTH];
25201da177e4SLinus Torvalds 	cmd[4] = pgo + (STp->buffer)->b_data[pgo + MP_OFF_PAGE_LENGTH] + 2;
25211da177e4SLinus Torvalds 
25221da177e4SLinus Torvalds 	/* Clear reserved fields */
25231da177e4SLinus Torvalds 	(STp->buffer)->b_data[MH_OFF_DATA_LENGTH] = 0;
25241da177e4SLinus Torvalds 	(STp->buffer)->b_data[MH_OFF_MEDIUM_TYPE] = 0;
25251da177e4SLinus Torvalds 	(STp->buffer)->b_data[MH_OFF_DEV_SPECIFIC] &= ~MH_BIT_WP;
25261da177e4SLinus Torvalds 	(STp->buffer)->b_data[pgo + MP_OFF_PAGE_NBR] &= MP_MSK_PAGE_NBR;
25271da177e4SLinus Torvalds 
252802ae2c0eSKai Makisara 	timeout = slow ?
252902ae2c0eSKai Makisara 		STp->long_timeout : STp->device->request_queue->rq_timeout;
253002ae2c0eSKai Makisara 	SRpnt = st_do_scsi(NULL, STp, cmd, cmd[4], DMA_TO_DEVICE,
253102ae2c0eSKai Makisara 			   timeout, 0, 1);
253202ae2c0eSKai Makisara 	if (SRpnt == NULL)
253302ae2c0eSKai Makisara 		return (STp->buffer)->syscall_result;
25341da177e4SLinus Torvalds 
25358b05b773SMike Christie 	st_release_request(SRpnt);
25361da177e4SLinus Torvalds 
253702ae2c0eSKai Makisara 	return STp->buffer->syscall_result;
25381da177e4SLinus Torvalds }
25391da177e4SLinus Torvalds 
25401da177e4SLinus Torvalds 
25411da177e4SLinus Torvalds #define COMPRESSION_PAGE        0x0f
25421da177e4SLinus Torvalds #define COMPRESSION_PAGE_LENGTH 16
25431da177e4SLinus Torvalds 
25441da177e4SLinus Torvalds #define CP_OFF_DCE_DCC          2
25451da177e4SLinus Torvalds #define CP_OFF_C_ALGO           7
25461da177e4SLinus Torvalds 
25471da177e4SLinus Torvalds #define DCE_MASK  0x80
25481da177e4SLinus Torvalds #define DCC_MASK  0x40
25491da177e4SLinus Torvalds #define RED_MASK  0x60
25501da177e4SLinus Torvalds 
25511da177e4SLinus Torvalds 
25521da177e4SLinus Torvalds /* Control the compression with mode page 15. Algorithm not changed if zero.
25531da177e4SLinus Torvalds 
25541da177e4SLinus Torvalds    The block descriptors are read and written because Sony SDT-7000 does not
25551da177e4SLinus Torvalds    work without this (suggestion from Michael Schaefer <Michael.Schaefer@dlr.de>).
25561da177e4SLinus Torvalds    Including block descriptors should not cause any harm to other drives. */
25571da177e4SLinus Torvalds 
st_compression(struct scsi_tape * STp,int state)25581da177e4SLinus Torvalds static int st_compression(struct scsi_tape * STp, int state)
25591da177e4SLinus Torvalds {
25601da177e4SLinus Torvalds 	int retval;
25611da177e4SLinus Torvalds 	int mpoffs;  /* Offset to mode page start */
25621da177e4SLinus Torvalds 	unsigned char *b_data = (STp->buffer)->b_data;
25631da177e4SLinus Torvalds 
25641da177e4SLinus Torvalds 	if (STp->ready != ST_READY)
25651da177e4SLinus Torvalds 		return (-EIO);
25661da177e4SLinus Torvalds 
25671da177e4SLinus Torvalds 	/* Read the current page contents */
25681da177e4SLinus Torvalds 	retval = read_mode_page(STp, COMPRESSION_PAGE, 0);
25691da177e4SLinus Torvalds 	if (retval) {
2570b30d8bcaSHannes Reinecke 		DEBC_printk(STp, "Compression mode page not supported.\n");
25711da177e4SLinus Torvalds 		return (-EIO);
25721da177e4SLinus Torvalds 	}
25731da177e4SLinus Torvalds 
25741da177e4SLinus Torvalds 	mpoffs = MODE_HEADER_LENGTH + b_data[MH_OFF_BDESCS_LENGTH];
2575b30d8bcaSHannes Reinecke 	DEBC_printk(STp, "Compression state is %d.\n",
2576b30d8bcaSHannes Reinecke 		    (b_data[mpoffs + CP_OFF_DCE_DCC] & DCE_MASK ? 1 : 0));
25771da177e4SLinus Torvalds 
25781da177e4SLinus Torvalds 	/* Check if compression can be changed */
25791da177e4SLinus Torvalds 	if ((b_data[mpoffs + CP_OFF_DCE_DCC] & DCC_MASK) == 0) {
2580b30d8bcaSHannes Reinecke 		DEBC_printk(STp, "Compression not supported.\n");
25811da177e4SLinus Torvalds 		return (-EIO);
25821da177e4SLinus Torvalds 	}
25831da177e4SLinus Torvalds 
25841da177e4SLinus Torvalds 	/* Do the change */
25851da177e4SLinus Torvalds 	if (state) {
25861da177e4SLinus Torvalds 		b_data[mpoffs + CP_OFF_DCE_DCC] |= DCE_MASK;
25871da177e4SLinus Torvalds 		if (STp->c_algo != 0)
25881da177e4SLinus Torvalds 			b_data[mpoffs + CP_OFF_C_ALGO] = STp->c_algo;
25891da177e4SLinus Torvalds 	}
25901da177e4SLinus Torvalds 	else {
25911da177e4SLinus Torvalds 		b_data[mpoffs + CP_OFF_DCE_DCC] &= ~DCE_MASK;
25921da177e4SLinus Torvalds 		if (STp->c_algo != 0)
25931da177e4SLinus Torvalds 			b_data[mpoffs + CP_OFF_C_ALGO] = 0; /* no compression */
25941da177e4SLinus Torvalds 	}
25951da177e4SLinus Torvalds 
25961da177e4SLinus Torvalds 	retval = write_mode_page(STp, COMPRESSION_PAGE, 0);
25971da177e4SLinus Torvalds 	if (retval) {
2598b30d8bcaSHannes Reinecke 		DEBC_printk(STp, "Compression change failed.\n");
25991da177e4SLinus Torvalds 		return (-EIO);
26001da177e4SLinus Torvalds 	}
2601b30d8bcaSHannes Reinecke 	DEBC_printk(STp, "Compression state changed to %d.\n", state);
26021da177e4SLinus Torvalds 
26031da177e4SLinus Torvalds 	STp->compression_changed = 1;
26041da177e4SLinus Torvalds 	return 0;
26051da177e4SLinus Torvalds }
26061da177e4SLinus Torvalds 
26071da177e4SLinus Torvalds 
26081da177e4SLinus Torvalds /* Process the load and unload commands (does unload if the load code is zero) */
do_load_unload(struct scsi_tape * STp,struct file * filp,int load_code)26091da177e4SLinus Torvalds static int do_load_unload(struct scsi_tape *STp, struct file *filp, int load_code)
26101da177e4SLinus Torvalds {
26111da177e4SLinus Torvalds 	int retval = (-EIO), timeout;
26121da177e4SLinus Torvalds 	unsigned char cmd[MAX_COMMAND_SIZE];
26131da177e4SLinus Torvalds 	struct st_partstat *STps;
26148b05b773SMike Christie 	struct st_request *SRpnt;
26151da177e4SLinus Torvalds 
26161da177e4SLinus Torvalds 	if (STp->ready != ST_READY && !load_code) {
26171da177e4SLinus Torvalds 		if (STp->ready == ST_NO_TAPE)
26181da177e4SLinus Torvalds 			return (-ENOMEDIUM);
26191da177e4SLinus Torvalds 		else
26201da177e4SLinus Torvalds 			return (-EIO);
26211da177e4SLinus Torvalds 	}
26221da177e4SLinus Torvalds 
26231da177e4SLinus Torvalds 	memset(cmd, 0, MAX_COMMAND_SIZE);
26241da177e4SLinus Torvalds 	cmd[0] = START_STOP;
26251da177e4SLinus Torvalds 	if (load_code)
26261da177e4SLinus Torvalds 		cmd[4] |= 1;
26271da177e4SLinus Torvalds 	/*
26281da177e4SLinus Torvalds 	 * If arg >= 1 && arg <= 6 Enhanced load/unload in HP C1553A
26291da177e4SLinus Torvalds 	 */
26301da177e4SLinus Torvalds 	if (load_code >= 1 + MT_ST_HPLOADER_OFFSET
26311da177e4SLinus Torvalds 	    && load_code <= 6 + MT_ST_HPLOADER_OFFSET) {
2632b30d8bcaSHannes Reinecke 		DEBC_printk(STp, " Enhanced %sload slot %2d.\n",
2633b30d8bcaSHannes Reinecke 			    (cmd[4]) ? "" : "un",
2634b30d8bcaSHannes Reinecke 			    load_code - MT_ST_HPLOADER_OFFSET);
26351da177e4SLinus Torvalds 		cmd[3] = load_code - MT_ST_HPLOADER_OFFSET; /* MediaID field of C1553A */
26361da177e4SLinus Torvalds 	}
26371da177e4SLinus Torvalds 	if (STp->immediate) {
26381da177e4SLinus Torvalds 		cmd[1] = 1;	/* Don't wait for completion */
2639a02488edSJames Bottomley 		timeout = STp->device->request_queue->rq_timeout;
26401da177e4SLinus Torvalds 	}
26411da177e4SLinus Torvalds 	else
26421da177e4SLinus Torvalds 		timeout = STp->long_timeout;
26431da177e4SLinus Torvalds 
26441da177e4SLinus Torvalds 	DEBC(
26451da177e4SLinus Torvalds 		if (!load_code)
2646b30d8bcaSHannes Reinecke 			st_printk(ST_DEB_MSG, STp, "Unloading tape.\n");
26471da177e4SLinus Torvalds 		else
2648b30d8bcaSHannes Reinecke 			st_printk(ST_DEB_MSG, STp, "Loading tape.\n");
26491da177e4SLinus Torvalds 		);
26501da177e4SLinus Torvalds 
265102ae2c0eSKai Makisara 	SRpnt = st_do_scsi(NULL, STp, cmd, 0, DMA_NONE,
265202ae2c0eSKai Makisara 			   timeout, MAX_RETRIES, 1);
26531da177e4SLinus Torvalds 	if (!SRpnt)
265402ae2c0eSKai Makisara 		return (STp->buffer)->syscall_result;
26551da177e4SLinus Torvalds 
26561da177e4SLinus Torvalds 	retval = (STp->buffer)->syscall_result;
265702ae2c0eSKai Makisara 	st_release_request(SRpnt);
26581da177e4SLinus Torvalds 
26591da177e4SLinus Torvalds 	if (!retval) {	/* SCSI command successful */
26601da177e4SLinus Torvalds 
26611da177e4SLinus Torvalds 		if (!load_code) {
26621da177e4SLinus Torvalds 			STp->rew_at_close = 0;
26631da177e4SLinus Torvalds 			STp->ready = ST_NO_TAPE;
26641da177e4SLinus Torvalds 		}
26651da177e4SLinus Torvalds 		else {
26661da177e4SLinus Torvalds 			STp->rew_at_close = STp->autorew_dev;
26671da177e4SLinus Torvalds 			retval = check_tape(STp, filp);
26681da177e4SLinus Torvalds 			if (retval > 0)
26691da177e4SLinus Torvalds 				retval = 0;
26701da177e4SLinus Torvalds 		}
26711da177e4SLinus Torvalds 	}
26721da177e4SLinus Torvalds 	else {
26731da177e4SLinus Torvalds 		STps = &(STp->ps[STp->partition]);
26741da177e4SLinus Torvalds 		STps->drv_file = STps->drv_block = (-1);
26751da177e4SLinus Torvalds 	}
26761da177e4SLinus Torvalds 
26771da177e4SLinus Torvalds 	return retval;
26781da177e4SLinus Torvalds }
26791da177e4SLinus Torvalds 
26801da177e4SLinus Torvalds #if DEBUG
26811da177e4SLinus Torvalds #define ST_DEB_FORWARD  0
26821da177e4SLinus Torvalds #define ST_DEB_BACKWARD 1
deb_space_print(struct scsi_tape * STp,int direction,char * units,unsigned char * cmd)2683b30d8bcaSHannes Reinecke static void deb_space_print(struct scsi_tape *STp, int direction, char *units, unsigned char *cmd)
26841da177e4SLinus Torvalds {
26851da177e4SLinus Torvalds 	s32 sc;
26861da177e4SLinus Torvalds 
2687b30d8bcaSHannes Reinecke 	if (!debugging)
2688b30d8bcaSHannes Reinecke 		return;
2689b30d8bcaSHannes Reinecke 
269035b703dbSBart Van Assche 	sc = sign_extend32(get_unaligned_be24(&cmd[2]), 23);
26911da177e4SLinus Torvalds 	if (direction)
26921da177e4SLinus Torvalds 		sc = -sc;
2693b30d8bcaSHannes Reinecke 	st_printk(ST_DEB_MSG, STp, "Spacing tape %s over %d %s.\n",
26941da177e4SLinus Torvalds 		  direction ? "backward" : "forward", sc, units);
26951da177e4SLinus Torvalds }
2696b30d8bcaSHannes Reinecke #else
2697b30d8bcaSHannes Reinecke #define ST_DEB_FORWARD  0
2698b30d8bcaSHannes Reinecke #define ST_DEB_BACKWARD 1
deb_space_print(struct scsi_tape * STp,int direction,char * units,unsigned char * cmd)2699b30d8bcaSHannes Reinecke static void deb_space_print(struct scsi_tape *STp, int direction, char *units, unsigned char *cmd) {}
27001da177e4SLinus Torvalds #endif
27011da177e4SLinus Torvalds 
27021da177e4SLinus Torvalds 
27031da177e4SLinus Torvalds /* Internal ioctl function */
st_int_ioctl(struct scsi_tape * STp,unsigned int cmd_in,unsigned long arg)27041da177e4SLinus Torvalds static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned long arg)
27051da177e4SLinus Torvalds {
27061da177e4SLinus Torvalds 	int timeout;
27071da177e4SLinus Torvalds 	long ltmp;
27081da177e4SLinus Torvalds 	int ioctl_result;
27091da177e4SLinus Torvalds 	int chg_eof = 1;
27101da177e4SLinus Torvalds 	unsigned char cmd[MAX_COMMAND_SIZE];
27118b05b773SMike Christie 	struct st_request *SRpnt;
27121da177e4SLinus Torvalds 	struct st_partstat *STps;
27131da177e4SLinus Torvalds 	int fileno, blkno, at_sm, undone;
27141da177e4SLinus Torvalds 	int datalen = 0, direction = DMA_NONE;
27151da177e4SLinus Torvalds 
27161da177e4SLinus Torvalds 	WARN_ON(STp->buffer->do_dio != 0);
27171da177e4SLinus Torvalds 	if (STp->ready != ST_READY) {
27181da177e4SLinus Torvalds 		if (STp->ready == ST_NO_TAPE)
27191da177e4SLinus Torvalds 			return (-ENOMEDIUM);
27201da177e4SLinus Torvalds 		else
27211da177e4SLinus Torvalds 			return (-EIO);
27221da177e4SLinus Torvalds 	}
27231da177e4SLinus Torvalds 	timeout = STp->long_timeout;
27241da177e4SLinus Torvalds 	STps = &(STp->ps[STp->partition]);
27251da177e4SLinus Torvalds 	fileno = STps->drv_file;
27261da177e4SLinus Torvalds 	blkno = STps->drv_block;
27271da177e4SLinus Torvalds 	at_sm = STps->at_sm;
27281da177e4SLinus Torvalds 
27291da177e4SLinus Torvalds 	memset(cmd, 0, MAX_COMMAND_SIZE);
27301da177e4SLinus Torvalds 	switch (cmd_in) {
27311da177e4SLinus Torvalds 	case MTFSFM:
27321da177e4SLinus Torvalds 		chg_eof = 0;	/* Changed from the FSF after this */
2733df561f66SGustavo A. R. Silva 		fallthrough;
27341da177e4SLinus Torvalds 	case MTFSF:
27351da177e4SLinus Torvalds 		cmd[0] = SPACE;
27361da177e4SLinus Torvalds 		cmd[1] = 0x01;	/* Space FileMarks */
27371da177e4SLinus Torvalds 		cmd[2] = (arg >> 16);
27381da177e4SLinus Torvalds 		cmd[3] = (arg >> 8);
27391da177e4SLinus Torvalds 		cmd[4] = arg;
2740b30d8bcaSHannes Reinecke 		deb_space_print(STp, ST_DEB_FORWARD, "filemarks", cmd);
27411da177e4SLinus Torvalds 		if (fileno >= 0)
27421da177e4SLinus Torvalds 			fileno += arg;
27431da177e4SLinus Torvalds 		blkno = 0;
27441da177e4SLinus Torvalds 		at_sm &= (arg == 0);
27451da177e4SLinus Torvalds 		break;
27461da177e4SLinus Torvalds 	case MTBSFM:
27471da177e4SLinus Torvalds 		chg_eof = 0;	/* Changed from the FSF after this */
2748df561f66SGustavo A. R. Silva 		fallthrough;
27491da177e4SLinus Torvalds 	case MTBSF:
27501da177e4SLinus Torvalds 		cmd[0] = SPACE;
27511da177e4SLinus Torvalds 		cmd[1] = 0x01;	/* Space FileMarks */
27521da177e4SLinus Torvalds 		ltmp = (-arg);
27531da177e4SLinus Torvalds 		cmd[2] = (ltmp >> 16);
27541da177e4SLinus Torvalds 		cmd[3] = (ltmp >> 8);
27551da177e4SLinus Torvalds 		cmd[4] = ltmp;
2756b30d8bcaSHannes Reinecke 		deb_space_print(STp, ST_DEB_BACKWARD, "filemarks", cmd);
27571da177e4SLinus Torvalds 		if (fileno >= 0)
27581da177e4SLinus Torvalds 			fileno -= arg;
27591da177e4SLinus Torvalds 		blkno = (-1);	/* We can't know the block number */
27601da177e4SLinus Torvalds 		at_sm &= (arg == 0);
27611da177e4SLinus Torvalds 		break;
27621da177e4SLinus Torvalds 	case MTFSR:
27631da177e4SLinus Torvalds 		cmd[0] = SPACE;
27641da177e4SLinus Torvalds 		cmd[1] = 0x00;	/* Space Blocks */
27651da177e4SLinus Torvalds 		cmd[2] = (arg >> 16);
27661da177e4SLinus Torvalds 		cmd[3] = (arg >> 8);
27671da177e4SLinus Torvalds 		cmd[4] = arg;
2768b30d8bcaSHannes Reinecke 		deb_space_print(STp, ST_DEB_FORWARD, "blocks", cmd);
27691da177e4SLinus Torvalds 		if (blkno >= 0)
27701da177e4SLinus Torvalds 			blkno += arg;
27711da177e4SLinus Torvalds 		at_sm &= (arg == 0);
27721da177e4SLinus Torvalds 		break;
27731da177e4SLinus Torvalds 	case MTBSR:
27741da177e4SLinus Torvalds 		cmd[0] = SPACE;
27751da177e4SLinus Torvalds 		cmd[1] = 0x00;	/* Space Blocks */
27761da177e4SLinus Torvalds 		ltmp = (-arg);
27771da177e4SLinus Torvalds 		cmd[2] = (ltmp >> 16);
27781da177e4SLinus Torvalds 		cmd[3] = (ltmp >> 8);
27791da177e4SLinus Torvalds 		cmd[4] = ltmp;
2780b30d8bcaSHannes Reinecke 		deb_space_print(STp, ST_DEB_BACKWARD, "blocks", cmd);
27811da177e4SLinus Torvalds 		if (blkno >= 0)
27821da177e4SLinus Torvalds 			blkno -= arg;
27831da177e4SLinus Torvalds 		at_sm &= (arg == 0);
27841da177e4SLinus Torvalds 		break;
27851da177e4SLinus Torvalds 	case MTFSS:
27861da177e4SLinus Torvalds 		cmd[0] = SPACE;
27871da177e4SLinus Torvalds 		cmd[1] = 0x04;	/* Space Setmarks */
27881da177e4SLinus Torvalds 		cmd[2] = (arg >> 16);
27891da177e4SLinus Torvalds 		cmd[3] = (arg >> 8);
27901da177e4SLinus Torvalds 		cmd[4] = arg;
2791b30d8bcaSHannes Reinecke 		deb_space_print(STp, ST_DEB_FORWARD, "setmarks", cmd);
27921da177e4SLinus Torvalds 		if (arg != 0) {
27931da177e4SLinus Torvalds 			blkno = fileno = (-1);
27941da177e4SLinus Torvalds 			at_sm = 1;
27951da177e4SLinus Torvalds 		}
27961da177e4SLinus Torvalds 		break;
27971da177e4SLinus Torvalds 	case MTBSS:
27981da177e4SLinus Torvalds 		cmd[0] = SPACE;
27991da177e4SLinus Torvalds 		cmd[1] = 0x04;	/* Space Setmarks */
28001da177e4SLinus Torvalds 		ltmp = (-arg);
28011da177e4SLinus Torvalds 		cmd[2] = (ltmp >> 16);
28021da177e4SLinus Torvalds 		cmd[3] = (ltmp >> 8);
28031da177e4SLinus Torvalds 		cmd[4] = ltmp;
2804b30d8bcaSHannes Reinecke 		deb_space_print(STp, ST_DEB_BACKWARD, "setmarks", cmd);
28051da177e4SLinus Torvalds 		if (arg != 0) {
28061da177e4SLinus Torvalds 			blkno = fileno = (-1);
28071da177e4SLinus Torvalds 			at_sm = 1;
28081da177e4SLinus Torvalds 		}
28091da177e4SLinus Torvalds 		break;
28101da177e4SLinus Torvalds 	case MTWEOF:
28113e51d3c9SKai Makisara 	case MTWEOFI:
28121da177e4SLinus Torvalds 	case MTWSM:
28131da177e4SLinus Torvalds 		if (STp->write_prot)
28141da177e4SLinus Torvalds 			return (-EACCES);
28151da177e4SLinus Torvalds 		cmd[0] = WRITE_FILEMARKS;
28161da177e4SLinus Torvalds 		if (cmd_in == MTWSM)
28171da177e4SLinus Torvalds 			cmd[1] = 2;
2818c743e44fSLee Duncan 		if (cmd_in == MTWEOFI ||
2819c743e44fSLee Duncan 		    (cmd_in == MTWEOF && STp->immediate_filemark))
28203e51d3c9SKai Makisara 			cmd[1] |= 1;
28211da177e4SLinus Torvalds 		cmd[2] = (arg >> 16);
28221da177e4SLinus Torvalds 		cmd[3] = (arg >> 8);
28231da177e4SLinus Torvalds 		cmd[4] = arg;
2824a02488edSJames Bottomley 		timeout = STp->device->request_queue->rq_timeout;
28251da177e4SLinus Torvalds 		DEBC(
28263e51d3c9SKai Makisara 			if (cmd_in != MTWSM)
2827b30d8bcaSHannes Reinecke 				st_printk(ST_DEB_MSG, STp,
2828b30d8bcaSHannes Reinecke 					  "Writing %d filemarks.\n",
2829b30d8bcaSHannes Reinecke 					  cmd[2] * 65536 +
2830b30d8bcaSHannes Reinecke 					  cmd[3] * 256 +
2831b30d8bcaSHannes Reinecke 					  cmd[4]);
28321da177e4SLinus Torvalds 			else
2833b30d8bcaSHannes Reinecke 				st_printk(ST_DEB_MSG, STp,
2834b30d8bcaSHannes Reinecke 					  "Writing %d setmarks.\n",
2835b30d8bcaSHannes Reinecke 					  cmd[2] * 65536 +
2836b30d8bcaSHannes Reinecke 					  cmd[3] * 256 +
2837b30d8bcaSHannes Reinecke 					  cmd[4]);
28381da177e4SLinus Torvalds 		)
28391da177e4SLinus Torvalds 		if (fileno >= 0)
28401da177e4SLinus Torvalds 			fileno += arg;
28411da177e4SLinus Torvalds 		blkno = 0;
28421da177e4SLinus Torvalds 		at_sm = (cmd_in == MTWSM);
28431da177e4SLinus Torvalds 		break;
28441da177e4SLinus Torvalds 	case MTREW:
28451da177e4SLinus Torvalds 		cmd[0] = REZERO_UNIT;
28461da177e4SLinus Torvalds 		if (STp->immediate) {
28471da177e4SLinus Torvalds 			cmd[1] = 1;	/* Don't wait for completion */
2848a02488edSJames Bottomley 			timeout = STp->device->request_queue->rq_timeout;
28491da177e4SLinus Torvalds 		}
2850b30d8bcaSHannes Reinecke 		DEBC_printk(STp, "Rewinding tape.\n");
28511da177e4SLinus Torvalds 		fileno = blkno = at_sm = 0;
28521da177e4SLinus Torvalds 		break;
28531da177e4SLinus Torvalds 	case MTNOP:
2854b30d8bcaSHannes Reinecke 		DEBC_printk(STp, "No op on tape.\n");
28551da177e4SLinus Torvalds 		return 0;	/* Should do something ? */
28561da177e4SLinus Torvalds 	case MTRETEN:
28571da177e4SLinus Torvalds 		cmd[0] = START_STOP;
28581da177e4SLinus Torvalds 		if (STp->immediate) {
28591da177e4SLinus Torvalds 			cmd[1] = 1;	/* Don't wait for completion */
2860a02488edSJames Bottomley 			timeout = STp->device->request_queue->rq_timeout;
28611da177e4SLinus Torvalds 		}
28621da177e4SLinus Torvalds 		cmd[4] = 3;
2863b30d8bcaSHannes Reinecke 		DEBC_printk(STp, "Retensioning tape.\n");
28641da177e4SLinus Torvalds 		fileno = blkno = at_sm = 0;
28651da177e4SLinus Torvalds 		break;
28661da177e4SLinus Torvalds 	case MTEOM:
28671da177e4SLinus Torvalds 		if (!STp->fast_mteom) {
28681da177e4SLinus Torvalds 			/* space to the end of tape */
28691da177e4SLinus Torvalds 			ioctl_result = st_int_ioctl(STp, MTFSF, 0x7fffff);
28701da177e4SLinus Torvalds 			fileno = STps->drv_file;
28711da177e4SLinus Torvalds 			if (STps->eof >= ST_EOD_1)
28721da177e4SLinus Torvalds 				return 0;
28731da177e4SLinus Torvalds 			/* The next lines would hide the number of spaced FileMarks
28741da177e4SLinus Torvalds 			   That's why I inserted the previous lines. I had no luck
28751da177e4SLinus Torvalds 			   with detecting EOM with FSF, so we go now to EOM.
28761da177e4SLinus Torvalds 			   Joerg Weule */
28771da177e4SLinus Torvalds 		} else
28781da177e4SLinus Torvalds 			fileno = (-1);
28791da177e4SLinus Torvalds 		cmd[0] = SPACE;
28801da177e4SLinus Torvalds 		cmd[1] = 3;
2881b30d8bcaSHannes Reinecke 		DEBC_printk(STp, "Spacing to end of recorded medium.\n");
28821da177e4SLinus Torvalds 		blkno = -1;
28831da177e4SLinus Torvalds 		at_sm = 0;
28841da177e4SLinus Torvalds 		break;
28851da177e4SLinus Torvalds 	case MTERASE:
28861da177e4SLinus Torvalds 		if (STp->write_prot)
28871da177e4SLinus Torvalds 			return (-EACCES);
28881da177e4SLinus Torvalds 		cmd[0] = ERASE;
28891da177e4SLinus Torvalds 		cmd[1] = (arg ? 1 : 0);	/* Long erase with non-zero argument */
28901da177e4SLinus Torvalds 		if (STp->immediate) {
28911da177e4SLinus Torvalds 			cmd[1] |= 2;	/* Don't wait for completion */
2892a02488edSJames Bottomley 			timeout = STp->device->request_queue->rq_timeout;
28931da177e4SLinus Torvalds 		}
28941da177e4SLinus Torvalds 		else
28951da177e4SLinus Torvalds 			timeout = STp->long_timeout * 8;
28961da177e4SLinus Torvalds 
2897b30d8bcaSHannes Reinecke 		DEBC_printk(STp, "Erasing tape.\n");
28981da177e4SLinus Torvalds 		fileno = blkno = at_sm = 0;
28991da177e4SLinus Torvalds 		break;
29001da177e4SLinus Torvalds 	case MTSETBLK:		/* Set block length */
29011da177e4SLinus Torvalds 	case MTSETDENSITY:	/* Set tape density */
29021da177e4SLinus Torvalds 	case MTSETDRVBUFFER:	/* Set drive buffering */
29031da177e4SLinus Torvalds 	case SET_DENS_AND_BLK:	/* Set density and block size */
29041da177e4SLinus Torvalds 		chg_eof = 0;
29051da177e4SLinus Torvalds 		if (STp->dirty || (STp->buffer)->buffer_bytes != 0)
29061da177e4SLinus Torvalds 			return (-EIO);	/* Not allowed if data in buffer */
29071da177e4SLinus Torvalds 		if ((cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) &&
29081da177e4SLinus Torvalds 		    (arg & MT_ST_BLKSIZE_MASK) != 0 &&
29091da177e4SLinus Torvalds 		    STp->max_block > 0 &&
29101da177e4SLinus Torvalds 		    ((arg & MT_ST_BLKSIZE_MASK) < STp->min_block ||
29111da177e4SLinus Torvalds 		     (arg & MT_ST_BLKSIZE_MASK) > STp->max_block)) {
2912b30d8bcaSHannes Reinecke 			st_printk(KERN_WARNING, STp, "Illegal block size.\n");
29131da177e4SLinus Torvalds 			return (-EINVAL);
29141da177e4SLinus Torvalds 		}
29151da177e4SLinus Torvalds 		cmd[0] = MODE_SELECT;
29161da177e4SLinus Torvalds 		if ((STp->use_pf & USE_PF))
29171da177e4SLinus Torvalds 			cmd[1] = MODE_SELECT_PAGE_FORMAT;
29181da177e4SLinus Torvalds 		cmd[4] = datalen = 12;
29191da177e4SLinus Torvalds 		direction = DMA_TO_DEVICE;
29201da177e4SLinus Torvalds 
29211da177e4SLinus Torvalds 		memset((STp->buffer)->b_data, 0, 12);
29221da177e4SLinus Torvalds 		if (cmd_in == MTSETDRVBUFFER)
29231da177e4SLinus Torvalds 			(STp->buffer)->b_data[2] = (arg & 7) << 4;
29241da177e4SLinus Torvalds 		else
29251da177e4SLinus Torvalds 			(STp->buffer)->b_data[2] =
29261da177e4SLinus Torvalds 			    STp->drv_buffer << 4;
29271da177e4SLinus Torvalds 		(STp->buffer)->b_data[3] = 8;	/* block descriptor length */
29281da177e4SLinus Torvalds 		if (cmd_in == MTSETDENSITY) {
29291da177e4SLinus Torvalds 			(STp->buffer)->b_data[4] = arg;
29301da177e4SLinus Torvalds 			STp->density_changed = 1;	/* At least we tried ;-) */
29311da177e4SLinus Torvalds 		} else if (cmd_in == SET_DENS_AND_BLK)
29321da177e4SLinus Torvalds 			(STp->buffer)->b_data[4] = arg >> 24;
29331da177e4SLinus Torvalds 		else
29341da177e4SLinus Torvalds 			(STp->buffer)->b_data[4] = STp->density;
29351da177e4SLinus Torvalds 		if (cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) {
29361da177e4SLinus Torvalds 			ltmp = arg & MT_ST_BLKSIZE_MASK;
29371da177e4SLinus Torvalds 			if (cmd_in == MTSETBLK)
29381da177e4SLinus Torvalds 				STp->blksize_changed = 1; /* At least we tried ;-) */
29391da177e4SLinus Torvalds 		} else
29401da177e4SLinus Torvalds 			ltmp = STp->block_size;
29411da177e4SLinus Torvalds 		(STp->buffer)->b_data[9] = (ltmp >> 16);
29421da177e4SLinus Torvalds 		(STp->buffer)->b_data[10] = (ltmp >> 8);
29431da177e4SLinus Torvalds 		(STp->buffer)->b_data[11] = ltmp;
2944a02488edSJames Bottomley 		timeout = STp->device->request_queue->rq_timeout;
29451da177e4SLinus Torvalds 		DEBC(
29461da177e4SLinus Torvalds 			if (cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK)
2947b30d8bcaSHannes Reinecke 				st_printk(ST_DEB_MSG, STp,
2948b30d8bcaSHannes Reinecke 					  "Setting block size to %d bytes.\n",
29491da177e4SLinus Torvalds 					  (STp->buffer)->b_data[9] * 65536 +
29501da177e4SLinus Torvalds 					  (STp->buffer)->b_data[10] * 256 +
29511da177e4SLinus Torvalds 					  (STp->buffer)->b_data[11]);
29521da177e4SLinus Torvalds 			if (cmd_in == MTSETDENSITY || cmd_in == SET_DENS_AND_BLK)
2953b30d8bcaSHannes Reinecke 				st_printk(ST_DEB_MSG, STp,
2954b30d8bcaSHannes Reinecke 					  "Setting density code to %x.\n",
29551da177e4SLinus Torvalds 					  (STp->buffer)->b_data[4]);
29561da177e4SLinus Torvalds 			if (cmd_in == MTSETDRVBUFFER)
2957b30d8bcaSHannes Reinecke 				st_printk(ST_DEB_MSG, STp,
2958b30d8bcaSHannes Reinecke 					  "Setting drive buffer code to %d.\n",
29591da177e4SLinus Torvalds 					  ((STp->buffer)->b_data[2] >> 4) & 7);
29601da177e4SLinus Torvalds 		)
29611da177e4SLinus Torvalds 		break;
29621da177e4SLinus Torvalds 	default:
29631da177e4SLinus Torvalds 		return (-ENOSYS);
29641da177e4SLinus Torvalds 	}
29651da177e4SLinus Torvalds 
296602ae2c0eSKai Makisara 	SRpnt = st_do_scsi(NULL, STp, cmd, datalen, direction,
296702ae2c0eSKai Makisara 			   timeout, MAX_RETRIES, 1);
29681da177e4SLinus Torvalds 	if (!SRpnt)
29691da177e4SLinus Torvalds 		return (STp->buffer)->syscall_result;
29701da177e4SLinus Torvalds 
29711da177e4SLinus Torvalds 	ioctl_result = (STp->buffer)->syscall_result;
29721da177e4SLinus Torvalds 
29731da177e4SLinus Torvalds 	if (!ioctl_result) {	/* SCSI command successful */
29748b05b773SMike Christie 		st_release_request(SRpnt);
29751da177e4SLinus Torvalds 		SRpnt = NULL;
29761da177e4SLinus Torvalds 		STps->drv_block = blkno;
29771da177e4SLinus Torvalds 		STps->drv_file = fileno;
29781da177e4SLinus Torvalds 		STps->at_sm = at_sm;
29791da177e4SLinus Torvalds 
29801da177e4SLinus Torvalds 		if (cmd_in == MTBSFM)
29811da177e4SLinus Torvalds 			ioctl_result = st_int_ioctl(STp, MTFSF, 1);
29821da177e4SLinus Torvalds 		else if (cmd_in == MTFSFM)
29831da177e4SLinus Torvalds 			ioctl_result = st_int_ioctl(STp, MTBSF, 1);
29841da177e4SLinus Torvalds 
29851da177e4SLinus Torvalds 		if (cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) {
29861da177e4SLinus Torvalds 			STp->block_size = arg & MT_ST_BLKSIZE_MASK;
29871da177e4SLinus Torvalds 			if (STp->block_size != 0) {
29881da177e4SLinus Torvalds 				(STp->buffer)->buffer_blocks =
29891da177e4SLinus Torvalds 				    (STp->buffer)->buffer_size / STp->block_size;
29901da177e4SLinus Torvalds 			}
29911da177e4SLinus Torvalds 			(STp->buffer)->buffer_bytes = (STp->buffer)->read_pointer = 0;
29921da177e4SLinus Torvalds 			if (cmd_in == SET_DENS_AND_BLK)
29931da177e4SLinus Torvalds 				STp->density = arg >> MT_ST_DENSITY_SHIFT;
29941da177e4SLinus Torvalds 		} else if (cmd_in == MTSETDRVBUFFER)
29951da177e4SLinus Torvalds 			STp->drv_buffer = (arg & 7);
29961da177e4SLinus Torvalds 		else if (cmd_in == MTSETDENSITY)
29971da177e4SLinus Torvalds 			STp->density = arg;
29981da177e4SLinus Torvalds 
29991da177e4SLinus Torvalds 		if (cmd_in == MTEOM)
30001da177e4SLinus Torvalds 			STps->eof = ST_EOD;
30011da177e4SLinus Torvalds 		else if (cmd_in == MTFSF)
30021da177e4SLinus Torvalds 			STps->eof = ST_FM;
30031da177e4SLinus Torvalds 		else if (chg_eof)
30041da177e4SLinus Torvalds 			STps->eof = ST_NOEOF;
30051da177e4SLinus Torvalds 
30063e51d3c9SKai Makisara 		if (cmd_in == MTWEOF || cmd_in == MTWEOFI)
30073e51d3c9SKai Makisara 			STps->rw = ST_IDLE;  /* prevent automatic WEOF at close */
30081da177e4SLinus Torvalds 	} else { /* SCSI command was not completely successful. Don't return
30091da177e4SLinus Torvalds                     from this block without releasing the SCSI command block! */
30101da177e4SLinus Torvalds 		struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat;
30111da177e4SLinus Torvalds 
30121da177e4SLinus Torvalds 		if (cmdstatp->flags & SENSE_EOM) {
30131da177e4SLinus Torvalds 			if (cmd_in != MTBSF && cmd_in != MTBSFM &&
30141da177e4SLinus Torvalds 			    cmd_in != MTBSR && cmd_in != MTBSS)
30151da177e4SLinus Torvalds 				STps->eof = ST_EOM_OK;
30161da177e4SLinus Torvalds 			STps->drv_block = 0;
30171da177e4SLinus Torvalds 		}
30181da177e4SLinus Torvalds 
30191da177e4SLinus Torvalds 		if (cmdstatp->remainder_valid)
30201da177e4SLinus Torvalds 			undone = (int)cmdstatp->uremainder64;
30211da177e4SLinus Torvalds 		else
30221da177e4SLinus Torvalds 			undone = 0;
30231da177e4SLinus Torvalds 
30243e51d3c9SKai Makisara 		if ((cmd_in == MTWEOF || cmd_in == MTWEOFI) &&
30251da177e4SLinus Torvalds 		    cmdstatp->have_sense &&
302691614c05SKai Makisara 		    (cmdstatp->flags & SENSE_EOM)) {
302791614c05SKai Makisara 			if (cmdstatp->sense_hdr.sense_key == NO_SENSE ||
302891614c05SKai Makisara 			    cmdstatp->sense_hdr.sense_key == RECOVERED_ERROR) {
302991614c05SKai Makisara 				ioctl_result = 0;	/* EOF(s) written successfully at EOM */
30301da177e4SLinus Torvalds 				STps->eof = ST_NOEOF;
303191614c05SKai Makisara 			} else {  /* Writing EOF(s) failed */
303291614c05SKai Makisara 				if (fileno >= 0)
303391614c05SKai Makisara 					fileno -= undone;
303491614c05SKai Makisara 				if (undone < arg)
303591614c05SKai Makisara 					STps->eof = ST_NOEOF;
303691614c05SKai Makisara 			}
303791614c05SKai Makisara 			STps->drv_file = fileno;
30381da177e4SLinus Torvalds 		} else if ((cmd_in == MTFSF) || (cmd_in == MTFSFM)) {
30391da177e4SLinus Torvalds 			if (fileno >= 0)
30401da177e4SLinus Torvalds 				STps->drv_file = fileno - undone;
30411da177e4SLinus Torvalds 			else
30421da177e4SLinus Torvalds 				STps->drv_file = fileno;
30431da177e4SLinus Torvalds 			STps->drv_block = -1;
30441da177e4SLinus Torvalds 			STps->eof = ST_NOEOF;
30451da177e4SLinus Torvalds 		} else if ((cmd_in == MTBSF) || (cmd_in == MTBSFM)) {
30461da177e4SLinus Torvalds 			if (arg > 0 && undone < 0)  /* Some drives get this wrong */
30471da177e4SLinus Torvalds 				undone = (-undone);
30481da177e4SLinus Torvalds 			if (STps->drv_file >= 0)
30491da177e4SLinus Torvalds 				STps->drv_file = fileno + undone;
30501da177e4SLinus Torvalds 			STps->drv_block = 0;
30511da177e4SLinus Torvalds 			STps->eof = ST_NOEOF;
30521da177e4SLinus Torvalds 		} else if (cmd_in == MTFSR) {
30531da177e4SLinus Torvalds 			if (cmdstatp->flags & SENSE_FMK) {	/* Hit filemark */
30541da177e4SLinus Torvalds 				if (STps->drv_file >= 0)
30551da177e4SLinus Torvalds 					STps->drv_file++;
30561da177e4SLinus Torvalds 				STps->drv_block = 0;
30571da177e4SLinus Torvalds 				STps->eof = ST_FM;
30581da177e4SLinus Torvalds 			} else {
30591da177e4SLinus Torvalds 				if (blkno >= undone)
30601da177e4SLinus Torvalds 					STps->drv_block = blkno - undone;
30611da177e4SLinus Torvalds 				else
30621da177e4SLinus Torvalds 					STps->drv_block = (-1);
30631da177e4SLinus Torvalds 				STps->eof = ST_NOEOF;
30641da177e4SLinus Torvalds 			}
30651da177e4SLinus Torvalds 		} else if (cmd_in == MTBSR) {
30661da177e4SLinus Torvalds 			if (cmdstatp->flags & SENSE_FMK) {	/* Hit filemark */
30671da177e4SLinus Torvalds 				STps->drv_file--;
30681da177e4SLinus Torvalds 				STps->drv_block = (-1);
30691da177e4SLinus Torvalds 			} else {
30701da177e4SLinus Torvalds 				if (arg > 0 && undone < 0)  /* Some drives get this wrong */
30711da177e4SLinus Torvalds 					undone = (-undone);
30721da177e4SLinus Torvalds 				if (STps->drv_block >= 0)
30731da177e4SLinus Torvalds 					STps->drv_block = blkno + undone;
30741da177e4SLinus Torvalds 			}
30751da177e4SLinus Torvalds 			STps->eof = ST_NOEOF;
30761da177e4SLinus Torvalds 		} else if (cmd_in == MTEOM) {
30771da177e4SLinus Torvalds 			STps->drv_file = (-1);
30781da177e4SLinus Torvalds 			STps->drv_block = (-1);
30791da177e4SLinus Torvalds 			STps->eof = ST_EOD;
30801da177e4SLinus Torvalds 		} else if (cmd_in == MTSETBLK ||
30811da177e4SLinus Torvalds 			   cmd_in == MTSETDENSITY ||
30821da177e4SLinus Torvalds 			   cmd_in == MTSETDRVBUFFER ||
30831da177e4SLinus Torvalds 			   cmd_in == SET_DENS_AND_BLK) {
30841da177e4SLinus Torvalds 			if (cmdstatp->sense_hdr.sense_key == ILLEGAL_REQUEST &&
30851da177e4SLinus Torvalds 			    !(STp->use_pf & PF_TESTED)) {
30861da177e4SLinus Torvalds 				/* Try the other possible state of Page Format if not
30871da177e4SLinus Torvalds 				   already tried */
30881da2019fSKai Makisara 				STp->use_pf = (STp->use_pf ^ USE_PF) | PF_TESTED;
30898b05b773SMike Christie 				st_release_request(SRpnt);
30901da177e4SLinus Torvalds 				SRpnt = NULL;
30911da177e4SLinus Torvalds 				return st_int_ioctl(STp, cmd_in, arg);
30921da177e4SLinus Torvalds 			}
30931da177e4SLinus Torvalds 		} else if (chg_eof)
30941da177e4SLinus Torvalds 			STps->eof = ST_NOEOF;
30951da177e4SLinus Torvalds 
30961da177e4SLinus Torvalds 		if (cmdstatp->sense_hdr.sense_key == BLANK_CHECK)
30971da177e4SLinus Torvalds 			STps->eof = ST_EOD;
30981da177e4SLinus Torvalds 
30998b05b773SMike Christie 		st_release_request(SRpnt);
31001da177e4SLinus Torvalds 		SRpnt = NULL;
31011da177e4SLinus Torvalds 	}
31021da177e4SLinus Torvalds 
31031da177e4SLinus Torvalds 	return ioctl_result;
31041da177e4SLinus Torvalds }
31051da177e4SLinus Torvalds 
31061da177e4SLinus Torvalds 
31071da177e4SLinus Torvalds /* Get the tape position. If bt == 2, arg points into a kernel space mt_loc
31081da177e4SLinus Torvalds    structure. */
31091da177e4SLinus Torvalds 
get_location(struct scsi_tape * STp,unsigned int * block,int * partition,int logical)31101da177e4SLinus Torvalds static int get_location(struct scsi_tape *STp, unsigned int *block, int *partition,
31111da177e4SLinus Torvalds 			int logical)
31121da177e4SLinus Torvalds {
31131da177e4SLinus Torvalds 	int result;
31141da177e4SLinus Torvalds 	unsigned char scmd[MAX_COMMAND_SIZE];
31158b05b773SMike Christie 	struct st_request *SRpnt;
31161da177e4SLinus Torvalds 
31171da177e4SLinus Torvalds 	if (STp->ready != ST_READY)
31181da177e4SLinus Torvalds 		return (-EIO);
31191da177e4SLinus Torvalds 
31201da177e4SLinus Torvalds 	memset(scmd, 0, MAX_COMMAND_SIZE);
31211da177e4SLinus Torvalds 	if ((STp->device)->scsi_level < SCSI_2) {
31221da177e4SLinus Torvalds 		scmd[0] = QFA_REQUEST_BLOCK;
31231da177e4SLinus Torvalds 		scmd[4] = 3;
31241da177e4SLinus Torvalds 	} else {
31251da177e4SLinus Torvalds 		scmd[0] = READ_POSITION;
31261da177e4SLinus Torvalds 		if (!logical && !STp->scsi2_logical)
31271da177e4SLinus Torvalds 			scmd[1] = 1;
31281da177e4SLinus Torvalds 	}
312902ae2c0eSKai Makisara 	SRpnt = st_do_scsi(NULL, STp, scmd, 20, DMA_FROM_DEVICE,
31307a31ec3cSFUJITA Tomonori 			   STp->device->request_queue->rq_timeout,
313102ae2c0eSKai Makisara 			   MAX_READY_RETRIES, 1);
313202ae2c0eSKai Makisara 	if (!SRpnt)
313302ae2c0eSKai Makisara 		return (STp->buffer)->syscall_result;
31341da177e4SLinus Torvalds 
31351da177e4SLinus Torvalds 	if ((STp->buffer)->syscall_result != 0 ||
31361da177e4SLinus Torvalds 	    (STp->device->scsi_level >= SCSI_2 &&
31371da177e4SLinus Torvalds 	     ((STp->buffer)->b_data[0] & 4) != 0)) {
31381da177e4SLinus Torvalds 		*block = *partition = 0;
3139b30d8bcaSHannes Reinecke 		DEBC_printk(STp, " Can't read tape position.\n");
31401da177e4SLinus Torvalds 		result = (-EIO);
31411da177e4SLinus Torvalds 	} else {
31421da177e4SLinus Torvalds 		result = 0;
31431da177e4SLinus Torvalds 		if ((STp->device)->scsi_level < SCSI_2) {
31441da177e4SLinus Torvalds 			*block = ((STp->buffer)->b_data[0] << 16)
31451da177e4SLinus Torvalds 			    + ((STp->buffer)->b_data[1] << 8)
31461da177e4SLinus Torvalds 			    + (STp->buffer)->b_data[2];
31471da177e4SLinus Torvalds 			*partition = 0;
31481da177e4SLinus Torvalds 		} else {
31491da177e4SLinus Torvalds 			*block = ((STp->buffer)->b_data[4] << 24)
31501da177e4SLinus Torvalds 			    + ((STp->buffer)->b_data[5] << 16)
31511da177e4SLinus Torvalds 			    + ((STp->buffer)->b_data[6] << 8)
31521da177e4SLinus Torvalds 			    + (STp->buffer)->b_data[7];
31531da177e4SLinus Torvalds 			*partition = (STp->buffer)->b_data[1];
31541da177e4SLinus Torvalds 			if (((STp->buffer)->b_data[0] & 0x80) &&
31551da177e4SLinus Torvalds 			    (STp->buffer)->b_data[1] == 0)	/* BOP of partition 0 */
31561da177e4SLinus Torvalds 				STp->ps[0].drv_block = STp->ps[0].drv_file = 0;
31571da177e4SLinus Torvalds 		}
3158b30d8bcaSHannes Reinecke 		DEBC_printk(STp, "Got tape pos. blk %d part %d.\n",
3159b30d8bcaSHannes Reinecke 			    *block, *partition);
31601da177e4SLinus Torvalds 	}
31618b05b773SMike Christie 	st_release_request(SRpnt);
31621da177e4SLinus Torvalds 	SRpnt = NULL;
31631da177e4SLinus Torvalds 
31641da177e4SLinus Torvalds 	return result;
31651da177e4SLinus Torvalds }
31661da177e4SLinus Torvalds 
31671da177e4SLinus Torvalds 
31681da177e4SLinus Torvalds /* Set the tape block and partition. Negative partition means that only the
31691da177e4SLinus Torvalds    block should be set in vendor specific way. */
set_location(struct scsi_tape * STp,unsigned int block,int partition,int logical)31701da177e4SLinus Torvalds static int set_location(struct scsi_tape *STp, unsigned int block, int partition,
31711da177e4SLinus Torvalds 			int logical)
31721da177e4SLinus Torvalds {
31731da177e4SLinus Torvalds 	struct st_partstat *STps;
31741da177e4SLinus Torvalds 	int result, p;
31751da177e4SLinus Torvalds 	unsigned int blk;
31761da177e4SLinus Torvalds 	int timeout;
31771da177e4SLinus Torvalds 	unsigned char scmd[MAX_COMMAND_SIZE];
31788b05b773SMike Christie 	struct st_request *SRpnt;
31791da177e4SLinus Torvalds 
31801da177e4SLinus Torvalds 	if (STp->ready != ST_READY)
31811da177e4SLinus Torvalds 		return (-EIO);
31821da177e4SLinus Torvalds 	timeout = STp->long_timeout;
31831da177e4SLinus Torvalds 	STps = &(STp->ps[STp->partition]);
31841da177e4SLinus Torvalds 
3185b30d8bcaSHannes Reinecke 	DEBC_printk(STp, "Setting block to %d and partition to %d.\n",
3186b30d8bcaSHannes Reinecke 		    block, partition);
31871da177e4SLinus Torvalds 	DEB(if (partition < 0)
31881da177e4SLinus Torvalds 		return (-EIO); )
31891da177e4SLinus Torvalds 
31901da177e4SLinus Torvalds 	/* Update the location at the partition we are leaving */
31911da177e4SLinus Torvalds 	if ((!STp->can_partitions && partition != 0) ||
31921da177e4SLinus Torvalds 	    partition >= ST_NBR_PARTITIONS)
31931da177e4SLinus Torvalds 		return (-EINVAL);
31941da177e4SLinus Torvalds 	if (partition != STp->partition) {
31951da177e4SLinus Torvalds 		if (get_location(STp, &blk, &p, 1))
31961da177e4SLinus Torvalds 			STps->last_block_valid = 0;
31971da177e4SLinus Torvalds 		else {
31981da177e4SLinus Torvalds 			STps->last_block_valid = 1;
31991da177e4SLinus Torvalds 			STps->last_block_visited = blk;
3200b30d8bcaSHannes Reinecke 			DEBC_printk(STp, "Visited block %d for "
3201b30d8bcaSHannes Reinecke 				    "partition %d saved.\n",
3202b30d8bcaSHannes Reinecke 				    blk, STp->partition);
32031da177e4SLinus Torvalds 		}
32041da177e4SLinus Torvalds 	}
32051da177e4SLinus Torvalds 
32061da177e4SLinus Torvalds 	memset(scmd, 0, MAX_COMMAND_SIZE);
32071da177e4SLinus Torvalds 	if ((STp->device)->scsi_level < SCSI_2) {
32081da177e4SLinus Torvalds 		scmd[0] = QFA_SEEK_BLOCK;
32091da177e4SLinus Torvalds 		scmd[2] = (block >> 16);
32101da177e4SLinus Torvalds 		scmd[3] = (block >> 8);
32111da177e4SLinus Torvalds 		scmd[4] = block;
32121da177e4SLinus Torvalds 		scmd[5] = 0;
32131da177e4SLinus Torvalds 	} else {
32141da177e4SLinus Torvalds 		scmd[0] = SEEK_10;
32151da177e4SLinus Torvalds 		scmd[3] = (block >> 24);
32161da177e4SLinus Torvalds 		scmd[4] = (block >> 16);
32171da177e4SLinus Torvalds 		scmd[5] = (block >> 8);
32181da177e4SLinus Torvalds 		scmd[6] = block;
32191da177e4SLinus Torvalds 		if (!logical && !STp->scsi2_logical)
32201da177e4SLinus Torvalds 			scmd[1] = 4;
32211da177e4SLinus Torvalds 		if (STp->partition != partition) {
32221da177e4SLinus Torvalds 			scmd[1] |= 2;
32231da177e4SLinus Torvalds 			scmd[8] = partition;
3224b30d8bcaSHannes Reinecke 			DEBC_printk(STp, "Trying to change partition "
3225b30d8bcaSHannes Reinecke 				    "from %d to %d\n", STp->partition,
3226b30d8bcaSHannes Reinecke 				    partition);
32271da177e4SLinus Torvalds 		}
32281da177e4SLinus Torvalds 	}
32291da177e4SLinus Torvalds 	if (STp->immediate) {
32301da177e4SLinus Torvalds 		scmd[1] |= 1;		/* Don't wait for completion */
3231a02488edSJames Bottomley 		timeout = STp->device->request_queue->rq_timeout;
32321da177e4SLinus Torvalds 	}
32331da177e4SLinus Torvalds 
323402ae2c0eSKai Makisara 	SRpnt = st_do_scsi(NULL, STp, scmd, 0, DMA_NONE,
323502ae2c0eSKai Makisara 			   timeout, MAX_READY_RETRIES, 1);
32361da177e4SLinus Torvalds 	if (!SRpnt)
323702ae2c0eSKai Makisara 		return (STp->buffer)->syscall_result;
32381da177e4SLinus Torvalds 
32391da177e4SLinus Torvalds 	STps->drv_block = STps->drv_file = (-1);
32401da177e4SLinus Torvalds 	STps->eof = ST_NOEOF;
32411da177e4SLinus Torvalds 	if ((STp->buffer)->syscall_result != 0) {
32421da177e4SLinus Torvalds 		result = (-EIO);
32431da177e4SLinus Torvalds 		if (STp->can_partitions &&
32441da177e4SLinus Torvalds 		    (STp->device)->scsi_level >= SCSI_2 &&
32451da177e4SLinus Torvalds 		    (p = find_partition(STp)) >= 0)
32461da177e4SLinus Torvalds 			STp->partition = p;
32471da177e4SLinus Torvalds 	} else {
32481da177e4SLinus Torvalds 		if (STp->can_partitions) {
32491da177e4SLinus Torvalds 			STp->partition = partition;
32501da177e4SLinus Torvalds 			STps = &(STp->ps[partition]);
32511da177e4SLinus Torvalds 			if (!STps->last_block_valid ||
32521da177e4SLinus Torvalds 			    STps->last_block_visited != block) {
32531da177e4SLinus Torvalds 				STps->at_sm = 0;
32541da177e4SLinus Torvalds 				STps->rw = ST_IDLE;
32551da177e4SLinus Torvalds 			}
32561da177e4SLinus Torvalds 		} else
32571da177e4SLinus Torvalds 			STps->at_sm = 0;
32581da177e4SLinus Torvalds 		if (block == 0)
32591da177e4SLinus Torvalds 			STps->drv_block = STps->drv_file = 0;
32601da177e4SLinus Torvalds 		result = 0;
32611da177e4SLinus Torvalds 	}
326202ae2c0eSKai Makisara 
32638b05b773SMike Christie 	st_release_request(SRpnt);
32641da177e4SLinus Torvalds 	SRpnt = NULL;
32651da177e4SLinus Torvalds 
32661da177e4SLinus Torvalds 	return result;
32671da177e4SLinus Torvalds }
32681da177e4SLinus Torvalds 
32691da177e4SLinus Torvalds 
32701da177e4SLinus Torvalds /* Find the current partition number for the drive status. Called from open and
32711da177e4SLinus Torvalds    returns either partition number of negative error code. */
find_partition(struct scsi_tape * STp)32721da177e4SLinus Torvalds static int find_partition(struct scsi_tape *STp)
32731da177e4SLinus Torvalds {
32741da177e4SLinus Torvalds 	int i, partition;
32751da177e4SLinus Torvalds 	unsigned int block;
32761da177e4SLinus Torvalds 
32771da177e4SLinus Torvalds 	if ((i = get_location(STp, &block, &partition, 1)) < 0)
32781da177e4SLinus Torvalds 		return i;
32791da177e4SLinus Torvalds 	if (partition >= ST_NBR_PARTITIONS)
32801da177e4SLinus Torvalds 		return (-EIO);
32811da177e4SLinus Torvalds 	return partition;
32821da177e4SLinus Torvalds }
32831da177e4SLinus Torvalds 
32841da177e4SLinus Torvalds 
32851da177e4SLinus Torvalds /* Change the partition if necessary */
switch_partition(struct scsi_tape * STp)32861da177e4SLinus Torvalds static int switch_partition(struct scsi_tape *STp)
32871da177e4SLinus Torvalds {
32881da177e4SLinus Torvalds 	struct st_partstat *STps;
32891da177e4SLinus Torvalds 
32901da177e4SLinus Torvalds 	if (STp->partition == STp->new_partition)
32911da177e4SLinus Torvalds 		return 0;
32921da177e4SLinus Torvalds 	STps = &(STp->ps[STp->new_partition]);
32931da177e4SLinus Torvalds 	if (!STps->last_block_valid)
32941da177e4SLinus Torvalds 		STps->last_block_visited = 0;
32951da177e4SLinus Torvalds 	return set_location(STp, STps->last_block_visited, STp->new_partition, 1);
32961da177e4SLinus Torvalds }
32971da177e4SLinus Torvalds 
32981da177e4SLinus Torvalds /* Functions for reading and writing the medium partition mode page. */
32991da177e4SLinus Torvalds 
33001da177e4SLinus Torvalds #define PART_PAGE   0x11
33011da177e4SLinus Torvalds #define PART_PAGE_FIXED_LENGTH 8
33021da177e4SLinus Torvalds 
33031da177e4SLinus Torvalds #define PP_OFF_MAX_ADD_PARTS   2
33041da177e4SLinus Torvalds #define PP_OFF_NBR_ADD_PARTS   3
33051da177e4SLinus Torvalds #define PP_OFF_FLAGS           4
33061da177e4SLinus Torvalds #define PP_OFF_PART_UNITS      6
33071da177e4SLinus Torvalds #define PP_OFF_RESERVED        7
33081da177e4SLinus Torvalds 
33091da177e4SLinus Torvalds #define PP_BIT_IDP             0x20
33108038e645SKai Makisara #define PP_BIT_FDP             0x80
33111da177e4SLinus Torvalds #define PP_MSK_PSUM_MB         0x10
33128038e645SKai Makisara #define PP_MSK_PSUM_UNITS      0x18
33138038e645SKai Makisara #define PP_MSK_POFM            0x04
33141da177e4SLinus Torvalds 
33151da177e4SLinus Torvalds /* Get the number of partitions on the tape. As a side effect reads the
33161da177e4SLinus Torvalds    mode page into the tape buffer. */
nbr_partitions(struct scsi_tape * STp)33171da177e4SLinus Torvalds static int nbr_partitions(struct scsi_tape *STp)
33181da177e4SLinus Torvalds {
33191da177e4SLinus Torvalds 	int result;
33201da177e4SLinus Torvalds 
33211da177e4SLinus Torvalds 	if (STp->ready != ST_READY)
33221da177e4SLinus Torvalds 		return (-EIO);
33231da177e4SLinus Torvalds 
33241da177e4SLinus Torvalds 	result = read_mode_page(STp, PART_PAGE, 1);
33251da177e4SLinus Torvalds 
33261da177e4SLinus Torvalds 	if (result) {
3327b30d8bcaSHannes Reinecke 		DEBC_printk(STp, "Can't read medium partition page.\n");
33281da177e4SLinus Torvalds 		result = (-EIO);
33291da177e4SLinus Torvalds 	} else {
33301da177e4SLinus Torvalds 		result = (STp->buffer)->b_data[MODE_HEADER_LENGTH +
33311da177e4SLinus Torvalds 					      PP_OFF_NBR_ADD_PARTS] + 1;
3332b30d8bcaSHannes Reinecke 		DEBC_printk(STp, "Number of partitions %d.\n", result);
33331da177e4SLinus Torvalds 	}
33341da177e4SLinus Torvalds 
33351da177e4SLinus Torvalds 	return result;
33361da177e4SLinus Torvalds }
33371da177e4SLinus Torvalds 
33381da177e4SLinus Torvalds 
format_medium(struct scsi_tape * STp,int format)33398038e645SKai Makisara static int format_medium(struct scsi_tape *STp, int format)
33408038e645SKai Makisara {
33418038e645SKai Makisara 	int result = 0;
33428038e645SKai Makisara 	int timeout = STp->long_timeout;
33438038e645SKai Makisara 	unsigned char scmd[MAX_COMMAND_SIZE];
33448038e645SKai Makisara 	struct st_request *SRpnt;
33458038e645SKai Makisara 
33468038e645SKai Makisara 	memset(scmd, 0, MAX_COMMAND_SIZE);
33478038e645SKai Makisara 	scmd[0] = FORMAT_UNIT;
33488038e645SKai Makisara 	scmd[2] = format;
33498038e645SKai Makisara 	if (STp->immediate) {
33508038e645SKai Makisara 		scmd[1] |= 1;		/* Don't wait for completion */
33518038e645SKai Makisara 		timeout = STp->device->request_queue->rq_timeout;
33528038e645SKai Makisara 	}
33538038e645SKai Makisara 	DEBC_printk(STp, "Sending FORMAT MEDIUM\n");
33548038e645SKai Makisara 	SRpnt = st_do_scsi(NULL, STp, scmd, 0, DMA_NONE,
33558038e645SKai Makisara 			   timeout, MAX_RETRIES, 1);
33568038e645SKai Makisara 	if (!SRpnt)
33578038e645SKai Makisara 		result = STp->buffer->syscall_result;
33588038e645SKai Makisara 	return result;
33598038e645SKai Makisara }
33608038e645SKai Makisara 
33618038e645SKai Makisara 
33621da177e4SLinus Torvalds /* Partition the tape into two partitions if size > 0 or one partition if
33631da177e4SLinus Torvalds    size == 0.
33641da177e4SLinus Torvalds 
33651da177e4SLinus Torvalds    The block descriptors are read and written because Sony SDT-7000 does not
33661da177e4SLinus Torvalds    work without this (suggestion from Michael Schaefer <Michael.Schaefer@dlr.de>).
33671da177e4SLinus Torvalds 
33681da177e4SLinus Torvalds    My HP C1533A drive returns only one partition size field. This is used to
33691da177e4SLinus Torvalds    set the size of partition 1. There is no size field for the default partition.
33701da177e4SLinus Torvalds    Michael Schaefer's Sony SDT-7000 returns two descriptors and the second is
33711da177e4SLinus Torvalds    used to set the size of partition 1 (this is what the SCSI-3 standard specifies).
33721da177e4SLinus Torvalds    The following algorithm is used to accommodate both drives: if the number of
33731da177e4SLinus Torvalds    partition size fields is greater than the maximum number of additional partitions
33741da177e4SLinus Torvalds    in the mode page, the second field is used. Otherwise the first field is used.
33751da177e4SLinus Torvalds 
33761da177e4SLinus Torvalds    For Seagate DDS drives the page length must be 8 when no partitions is defined
33771da177e4SLinus Torvalds    and 10 when 1 partition is defined (information from Eric Lee Green). This is
33781da177e4SLinus Torvalds    is acceptable also to some other old drives and enforced if the first partition
33791da177e4SLinus Torvalds    size field is used for the first additional partition size.
33808038e645SKai Makisara 
33818038e645SKai Makisara    For drives that advertize SCSI-3 or newer, use the SSC-3 methods.
33821da177e4SLinus Torvalds  */
partition_tape(struct scsi_tape * STp,int size)33831da177e4SLinus Torvalds static int partition_tape(struct scsi_tape *STp, int size)
33841da177e4SLinus Torvalds {
33851da177e4SLinus Torvalds 	int result;
33868038e645SKai Makisara 	int target_partition;
33878038e645SKai Makisara 	bool scsi3 = STp->device->scsi_level >= SCSI_3, needs_format = false;
33881da177e4SLinus Torvalds 	int pgo, psd_cnt, psdo;
33898038e645SKai Makisara 	int psum = PP_MSK_PSUM_MB, units = 0;
33901da177e4SLinus Torvalds 	unsigned char *bp;
33911da177e4SLinus Torvalds 
33921da177e4SLinus Torvalds 	result = read_mode_page(STp, PART_PAGE, 0);
33931da177e4SLinus Torvalds 	if (result) {
3394b30d8bcaSHannes Reinecke 		DEBC_printk(STp, "Can't read partition mode page.\n");
33951da177e4SLinus Torvalds 		return result;
33961da177e4SLinus Torvalds 	}
33978038e645SKai Makisara 	target_partition = 1;
33988038e645SKai Makisara 	if (size < 0) {
33998038e645SKai Makisara 		target_partition = 0;
34008038e645SKai Makisara 		size = -size;
34018038e645SKai Makisara 	}
34028038e645SKai Makisara 
34031da177e4SLinus Torvalds 	/* The mode page is in the buffer. Let's modify it and write it. */
34041da177e4SLinus Torvalds 	bp = (STp->buffer)->b_data;
34051da177e4SLinus Torvalds 	pgo = MODE_HEADER_LENGTH + bp[MH_OFF_BDESCS_LENGTH];
3406b30d8bcaSHannes Reinecke 	DEBC_printk(STp, "Partition page length is %d bytes.\n",
3407b30d8bcaSHannes Reinecke 		    bp[pgo + MP_OFF_PAGE_LENGTH] + 2);
34081da177e4SLinus Torvalds 
34091da177e4SLinus Torvalds 	psd_cnt = (bp[pgo + MP_OFF_PAGE_LENGTH] + 2 - PART_PAGE_FIXED_LENGTH) / 2;
34108038e645SKai Makisara 
34118038e645SKai Makisara 	if (scsi3) {
34128038e645SKai Makisara 		needs_format = (bp[pgo + PP_OFF_FLAGS] & PP_MSK_POFM) != 0;
34138038e645SKai Makisara 		if (needs_format && size == 0) {
34148038e645SKai Makisara 			/* No need to write the mode page when clearing
34158038e645SKai Makisara 			 *  partitioning
34168038e645SKai Makisara 			 */
34178038e645SKai Makisara 			DEBC_printk(STp, "Formatting tape with one partition.\n");
34188038e645SKai Makisara 			result = format_medium(STp, 0);
34198038e645SKai Makisara 			goto out;
34208038e645SKai Makisara 		}
34218038e645SKai Makisara 		if (needs_format)  /* Leave the old value for HP DATs claiming SCSI_3 */
34228038e645SKai Makisara 			psd_cnt = 2;
34238038e645SKai Makisara 		if ((bp[pgo + PP_OFF_FLAGS] & PP_MSK_PSUM_UNITS) == PP_MSK_PSUM_UNITS) {
34248038e645SKai Makisara 			/* Use units scaling for large partitions if the device
34258038e645SKai Makisara 			 * suggests it and no precision lost. Required for IBM
34268038e645SKai Makisara 			 * TS1140/50 drives that don't support MB units.
34278038e645SKai Makisara 			 */
34288038e645SKai Makisara 			if (size >= 1000 && (size % 1000) == 0) {
34298038e645SKai Makisara 				size /= 1000;
34308038e645SKai Makisara 				psum = PP_MSK_PSUM_UNITS;
34318038e645SKai Makisara 				units = 9; /* GB */
34328038e645SKai Makisara 			}
34338038e645SKai Makisara 		}
34348038e645SKai Makisara 		/* Try it anyway if too large to specify in MB */
34358038e645SKai Makisara 		if (psum == PP_MSK_PSUM_MB && size >= 65534) {
34368038e645SKai Makisara 			size /= 1000;
34378038e645SKai Makisara 			psum = PP_MSK_PSUM_UNITS;
34388038e645SKai Makisara 			units = 9;  /* GB */
34398038e645SKai Makisara 		}
34408038e645SKai Makisara 	}
34418038e645SKai Makisara 
34428038e645SKai Makisara 	if (size >= 65535 ||  /* Does not fit into two bytes */
34438038e645SKai Makisara 	    (target_partition == 0 && psd_cnt < 2)) {
34448038e645SKai Makisara 		result = -EINVAL;
34458038e645SKai Makisara 		goto out;
34468038e645SKai Makisara 	}
34478038e645SKai Makisara 
34481da177e4SLinus Torvalds 	psdo = pgo + PART_PAGE_FIXED_LENGTH;
34498038e645SKai Makisara 	/* The second condition is for HP DDS which use only one partition size
34508038e645SKai Makisara 	 * descriptor
34518038e645SKai Makisara 	 */
34528038e645SKai Makisara 	if (target_partition > 0 &&
34538038e645SKai Makisara 	    (psd_cnt > bp[pgo + PP_OFF_MAX_ADD_PARTS] ||
34548038e645SKai Makisara 	     bp[pgo + PP_OFF_MAX_ADD_PARTS] != 1)) {
34558038e645SKai Makisara 		bp[psdo] = bp[psdo + 1] = 0xff;  /* Rest to partition 0 */
34561da177e4SLinus Torvalds 		psdo += 2;
34571da177e4SLinus Torvalds 	}
34581da177e4SLinus Torvalds 	memset(bp + psdo, 0, bp[pgo + PP_OFF_NBR_ADD_PARTS] * 2);
34591da177e4SLinus Torvalds 
3460b30d8bcaSHannes Reinecke 	DEBC_printk(STp, "psd_cnt %d, max.parts %d, nbr_parts %d\n",
34611da177e4SLinus Torvalds 		    psd_cnt, bp[pgo + PP_OFF_MAX_ADD_PARTS],
3462b30d8bcaSHannes Reinecke 		    bp[pgo + PP_OFF_NBR_ADD_PARTS]);
34631da177e4SLinus Torvalds 
34648038e645SKai Makisara 	if (size == 0) {
34651da177e4SLinus Torvalds 		bp[pgo + PP_OFF_NBR_ADD_PARTS] = 0;
34661da177e4SLinus Torvalds 		if (psd_cnt <= bp[pgo + PP_OFF_MAX_ADD_PARTS])
34671da177e4SLinus Torvalds 		    bp[pgo + MP_OFF_PAGE_LENGTH] = 6;
3468b30d8bcaSHannes Reinecke 		DEBC_printk(STp, "Formatting tape with one partition.\n");
34691da177e4SLinus Torvalds 	} else {
34701da177e4SLinus Torvalds 		bp[psdo] = (size >> 8) & 0xff;
34711da177e4SLinus Torvalds 		bp[psdo + 1] = size & 0xff;
34728038e645SKai Makisara 		if (target_partition == 0)
34738038e645SKai Makisara 			bp[psdo + 2] = bp[psdo + 3] = 0xff;
34741da177e4SLinus Torvalds 		bp[pgo + 3] = 1;
34751da177e4SLinus Torvalds 		if (bp[pgo + MP_OFF_PAGE_LENGTH] < 8)
34761da177e4SLinus Torvalds 		    bp[pgo + MP_OFF_PAGE_LENGTH] = 8;
34778038e645SKai Makisara 		DEBC_printk(STp,
34788038e645SKai Makisara 			    "Formatting tape with two partitions (%i = %d MB).\n",
34798038e645SKai Makisara 			    target_partition, units > 0 ? size * 1000 : size);
34801da177e4SLinus Torvalds 	}
34811da177e4SLinus Torvalds 	bp[pgo + PP_OFF_PART_UNITS] = 0;
34821da177e4SLinus Torvalds 	bp[pgo + PP_OFF_RESERVED] = 0;
34838038e645SKai Makisara 	if (size != 1 || units != 0) {
34848038e645SKai Makisara 		bp[pgo + PP_OFF_FLAGS] = PP_BIT_IDP | psum |
34858038e645SKai Makisara 			(bp[pgo + PP_OFF_FLAGS] & 0x07);
34868038e645SKai Makisara 		bp[pgo + PP_OFF_PART_UNITS] = units;
34878038e645SKai Makisara 	} else
34888038e645SKai Makisara 		bp[pgo + PP_OFF_FLAGS] = PP_BIT_FDP |
34898038e645SKai Makisara 			(bp[pgo + PP_OFF_FLAGS] & 0x1f);
34908038e645SKai Makisara 	bp[pgo + MP_OFF_PAGE_LENGTH] = 6 + psd_cnt * 2;
34911da177e4SLinus Torvalds 
34921da177e4SLinus Torvalds 	result = write_mode_page(STp, PART_PAGE, 1);
34938038e645SKai Makisara 
34948038e645SKai Makisara 	if (!result && needs_format)
34958038e645SKai Makisara 		result = format_medium(STp, 1);
34968038e645SKai Makisara 
34971da177e4SLinus Torvalds 	if (result) {
3498b30d8bcaSHannes Reinecke 		st_printk(KERN_INFO, STp, "Partitioning of tape failed.\n");
34991da177e4SLinus Torvalds 		result = (-EIO);
35001da177e4SLinus Torvalds 	}
35011da177e4SLinus Torvalds 
35028038e645SKai Makisara out:
35031da177e4SLinus Torvalds 	return result;
35041da177e4SLinus Torvalds }
35051da177e4SLinus Torvalds 
35061da177e4SLinus Torvalds 
35071da177e4SLinus Torvalds 
35081da177e4SLinus Torvalds /* The ioctl command */
st_ioctl(struct file * file,unsigned int cmd_in,unsigned long arg)3509dba7688fSChristoph Hellwig static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
35101da177e4SLinus Torvalds {
3511dba7688fSChristoph Hellwig 	void __user *p = (void __user *)arg;
35121da177e4SLinus Torvalds 	int i, cmd_nr, cmd_type, bt;
35131da177e4SLinus Torvalds 	int retval = 0;
35141da177e4SLinus Torvalds 	unsigned int blk;
3515338368f7SKai Mäkisara 	bool cmd_mtiocget;
35161da177e4SLinus Torvalds 	struct scsi_tape *STp = file->private_data;
35171da177e4SLinus Torvalds 	struct st_modedef *STm;
35181da177e4SLinus Torvalds 	struct st_partstat *STps;
35191da177e4SLinus Torvalds 
352028f85009SMatthias Kaehlcke 	if (mutex_lock_interruptible(&STp->lock))
35211da177e4SLinus Torvalds 		return -ERESTARTSYS;
35221da177e4SLinus Torvalds 
35231da177e4SLinus Torvalds 	DEB(
35241da177e4SLinus Torvalds 	if (debugging && !STp->in_use) {
3525b30d8bcaSHannes Reinecke 		st_printk(ST_DEB_MSG, STp, "Incorrect device.\n");
35261da177e4SLinus Torvalds 		retval = (-EIO);
35271da177e4SLinus Torvalds 		goto out;
35281da177e4SLinus Torvalds 	} ) /* end DEB */
35291da177e4SLinus Torvalds 
35301da177e4SLinus Torvalds 	STm = &(STp->modes[STp->current_mode]);
35311da177e4SLinus Torvalds 	STps = &(STp->ps[STp->partition]);
35321da177e4SLinus Torvalds 
35331da177e4SLinus Torvalds 	/*
35341da177e4SLinus Torvalds 	 * If we are in the middle of error recovery, don't let anyone
35351da177e4SLinus Torvalds 	 * else try and use this device.  Also, if error recovery fails, it
35361da177e4SLinus Torvalds 	 * may try and take the device offline, in which case all further
35371da177e4SLinus Torvalds 	 * access to the device is prohibited.
35381da177e4SLinus Torvalds 	 */
3539906d15fbSChristoph Hellwig 	retval = scsi_ioctl_block_when_processing_errors(STp->device, cmd_in,
354083ff6fe8SAl Viro 			file->f_flags & O_NDELAY);
3541906d15fbSChristoph Hellwig 	if (retval)
35421da177e4SLinus Torvalds 		goto out;
35431da177e4SLinus Torvalds 
35441da177e4SLinus Torvalds 	cmd_type = _IOC_TYPE(cmd_in);
35451da177e4SLinus Torvalds 	cmd_nr = _IOC_NR(cmd_in);
35461da177e4SLinus Torvalds 
35471da177e4SLinus Torvalds 	if (cmd_type == _IOC_TYPE(MTIOCTOP) && cmd_nr == _IOC_NR(MTIOCTOP)) {
35481da177e4SLinus Torvalds 		struct mtop mtc;
35491da177e4SLinus Torvalds 
35501da177e4SLinus Torvalds 		if (_IOC_SIZE(cmd_in) != sizeof(mtc)) {
35511da177e4SLinus Torvalds 			retval = (-EINVAL);
35521da177e4SLinus Torvalds 			goto out;
35531da177e4SLinus Torvalds 		}
35541da177e4SLinus Torvalds 
35551da177e4SLinus Torvalds 		i = copy_from_user(&mtc, p, sizeof(struct mtop));
35561da177e4SLinus Torvalds 		if (i) {
35571da177e4SLinus Torvalds 			retval = (-EFAULT);
35581da177e4SLinus Torvalds 			goto out;
35591da177e4SLinus Torvalds 		}
35601da177e4SLinus Torvalds 
35611da177e4SLinus Torvalds 		if (mtc.mt_op == MTSETDRVBUFFER && !capable(CAP_SYS_ADMIN)) {
3562b30d8bcaSHannes Reinecke 			st_printk(KERN_WARNING, STp,
3563b30d8bcaSHannes Reinecke 				  "MTSETDRVBUFFER only allowed for root.\n");
35641da177e4SLinus Torvalds 			retval = (-EPERM);
35651da177e4SLinus Torvalds 			goto out;
35661da177e4SLinus Torvalds 		}
35671da177e4SLinus Torvalds 		if (!STm->defined &&
35681da177e4SLinus Torvalds 		    (mtc.mt_op != MTSETDRVBUFFER &&
35691da177e4SLinus Torvalds 		     (mtc.mt_count & MT_ST_OPTIONS) == 0)) {
35701da177e4SLinus Torvalds 			retval = (-ENXIO);
35711da177e4SLinus Torvalds 			goto out;
35721da177e4SLinus Torvalds 		}
35731da177e4SLinus Torvalds 
35741da177e4SLinus Torvalds 		if (!STp->pos_unknown) {
35751da177e4SLinus Torvalds 
35761da177e4SLinus Torvalds 			if (STps->eof == ST_FM_HIT) {
35771da177e4SLinus Torvalds 				if (mtc.mt_op == MTFSF || mtc.mt_op == MTFSFM ||
35781da177e4SLinus Torvalds                                     mtc.mt_op == MTEOM) {
35791da177e4SLinus Torvalds 					mtc.mt_count -= 1;
35801da177e4SLinus Torvalds 					if (STps->drv_file >= 0)
35811da177e4SLinus Torvalds 						STps->drv_file += 1;
35821da177e4SLinus Torvalds 				} else if (mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM) {
35831da177e4SLinus Torvalds 					mtc.mt_count += 1;
35841da177e4SLinus Torvalds 					if (STps->drv_file >= 0)
35851da177e4SLinus Torvalds 						STps->drv_file += 1;
35861da177e4SLinus Torvalds 				}
35871da177e4SLinus Torvalds 			}
35881da177e4SLinus Torvalds 
35891da177e4SLinus Torvalds 			if (mtc.mt_op == MTSEEK) {
35901da177e4SLinus Torvalds 				/* Old position must be restored if partition will be
35911da177e4SLinus Torvalds                                    changed */
35921da177e4SLinus Torvalds 				i = !STp->can_partitions ||
35931da177e4SLinus Torvalds 				    (STp->new_partition != STp->partition);
35941da177e4SLinus Torvalds 			} else {
35951da177e4SLinus Torvalds 				i = mtc.mt_op == MTREW || mtc.mt_op == MTOFFL ||
35961da177e4SLinus Torvalds 				    mtc.mt_op == MTRETEN || mtc.mt_op == MTEOM ||
35971da177e4SLinus Torvalds 				    mtc.mt_op == MTLOCK || mtc.mt_op == MTLOAD ||
35981da177e4SLinus Torvalds 				    mtc.mt_op == MTFSF || mtc.mt_op == MTFSFM ||
35991da177e4SLinus Torvalds 				    mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM ||
36001da177e4SLinus Torvalds 				    mtc.mt_op == MTCOMPRESSION;
36011da177e4SLinus Torvalds 			}
36021da177e4SLinus Torvalds 			i = flush_buffer(STp, i);
36031da177e4SLinus Torvalds 			if (i < 0) {
36041da177e4SLinus Torvalds 				retval = i;
36051da177e4SLinus Torvalds 				goto out;
36061da177e4SLinus Torvalds 			}
36071da177e4SLinus Torvalds 			if (STps->rw == ST_WRITING &&
36081da177e4SLinus Torvalds 			    (mtc.mt_op == MTREW || mtc.mt_op == MTOFFL ||
36091da177e4SLinus Torvalds 			     mtc.mt_op == MTSEEK ||
36101da177e4SLinus Torvalds 			     mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM)) {
36111da177e4SLinus Torvalds 				i = st_int_ioctl(STp, MTWEOF, 1);
36121da177e4SLinus Torvalds 				if (i < 0) {
36131da177e4SLinus Torvalds 					retval = i;
36141da177e4SLinus Torvalds 					goto out;
36151da177e4SLinus Torvalds 				}
36161da177e4SLinus Torvalds 				if (mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM)
36171da177e4SLinus Torvalds 					mtc.mt_count++;
36181da177e4SLinus Torvalds 				STps->rw = ST_IDLE;
36191da177e4SLinus Torvalds 			     }
36201da177e4SLinus Torvalds 
36211da177e4SLinus Torvalds 		} else {
36221da177e4SLinus Torvalds 			/*
36231da177e4SLinus Torvalds 			 * If there was a bus reset, block further access
36241da177e4SLinus Torvalds 			 * to this device.  If the user wants to rewind the tape,
36251da177e4SLinus Torvalds 			 * then reset the flag and allow access again.
36261da177e4SLinus Torvalds 			 */
36271da177e4SLinus Torvalds 			if (mtc.mt_op != MTREW &&
36281da177e4SLinus Torvalds 			    mtc.mt_op != MTOFFL &&
3629338368f7SKai Mäkisara 			    mtc.mt_op != MTLOAD &&
36301da177e4SLinus Torvalds 			    mtc.mt_op != MTRETEN &&
36311da177e4SLinus Torvalds 			    mtc.mt_op != MTERASE &&
36321da177e4SLinus Torvalds 			    mtc.mt_op != MTSEEK &&
36331da177e4SLinus Torvalds 			    mtc.mt_op != MTEOM) {
36341da177e4SLinus Torvalds 				retval = (-EIO);
36351da177e4SLinus Torvalds 				goto out;
36361da177e4SLinus Torvalds 			}
36371da177e4SLinus Torvalds 			reset_state(STp);
36381da177e4SLinus Torvalds 			/* remove this when the midlevel properly clears was_reset */
36391da177e4SLinus Torvalds 			STp->device->was_reset = 0;
36401da177e4SLinus Torvalds 		}
36411da177e4SLinus Torvalds 
36421da177e4SLinus Torvalds 		if (mtc.mt_op != MTNOP && mtc.mt_op != MTSETBLK &&
36431da177e4SLinus Torvalds 		    mtc.mt_op != MTSETDENSITY && mtc.mt_op != MTWSM &&
36441da177e4SLinus Torvalds 		    mtc.mt_op != MTSETDRVBUFFER && mtc.mt_op != MTSETPART)
36451da177e4SLinus Torvalds 			STps->rw = ST_IDLE;	/* Prevent automatic WEOF and fsf */
36461da177e4SLinus Torvalds 
36471da177e4SLinus Torvalds 		if (mtc.mt_op == MTOFFL && STp->door_locked != ST_UNLOCKED)
36481da177e4SLinus Torvalds 			do_door_lock(STp, 0);	/* Ignore result! */
36491da177e4SLinus Torvalds 
36501da177e4SLinus Torvalds 		if (mtc.mt_op == MTSETDRVBUFFER &&
36511da177e4SLinus Torvalds 		    (mtc.mt_count & MT_ST_OPTIONS) != 0) {
36521da177e4SLinus Torvalds 			retval = st_set_options(STp, mtc.mt_count);
36531da177e4SLinus Torvalds 			goto out;
36541da177e4SLinus Torvalds 		}
36551da177e4SLinus Torvalds 
36561da177e4SLinus Torvalds 		if (mtc.mt_op == MTSETPART) {
36571da177e4SLinus Torvalds 			if (!STp->can_partitions ||
36581da177e4SLinus Torvalds 			    mtc.mt_count < 0 || mtc.mt_count >= ST_NBR_PARTITIONS) {
36591da177e4SLinus Torvalds 				retval = (-EINVAL);
36601da177e4SLinus Torvalds 				goto out;
36611da177e4SLinus Torvalds 			}
36621da177e4SLinus Torvalds 			if (mtc.mt_count >= STp->nbr_partitions &&
36631da177e4SLinus Torvalds 			    (STp->nbr_partitions = nbr_partitions(STp)) < 0) {
36641da177e4SLinus Torvalds 				retval = (-EIO);
36651da177e4SLinus Torvalds 				goto out;
36661da177e4SLinus Torvalds 			}
36671da177e4SLinus Torvalds 			if (mtc.mt_count >= STp->nbr_partitions) {
36681da177e4SLinus Torvalds 				retval = (-EINVAL);
36691da177e4SLinus Torvalds 				goto out;
36701da177e4SLinus Torvalds 			}
36711da177e4SLinus Torvalds 			STp->new_partition = mtc.mt_count;
36721da177e4SLinus Torvalds 			retval = 0;
36731da177e4SLinus Torvalds 			goto out;
36741da177e4SLinus Torvalds 		}
36751da177e4SLinus Torvalds 
36761da177e4SLinus Torvalds 		if (mtc.mt_op == MTMKPART) {
36771da177e4SLinus Torvalds 			if (!STp->can_partitions) {
36781da177e4SLinus Torvalds 				retval = (-EINVAL);
36791da177e4SLinus Torvalds 				goto out;
36801da177e4SLinus Torvalds 			}
36818038e645SKai Makisara 			i = do_load_unload(STp, file, 1);
36828038e645SKai Makisara 			if (i < 0) {
36838038e645SKai Makisara 				retval = i;
36848038e645SKai Makisara 				goto out;
36858038e645SKai Makisara 			}
36868038e645SKai Makisara 			i = partition_tape(STp, mtc.mt_count);
36878038e645SKai Makisara 			if (i < 0) {
36881da177e4SLinus Torvalds 				retval = i;
36891da177e4SLinus Torvalds 				goto out;
36901da177e4SLinus Torvalds 			}
36911da177e4SLinus Torvalds 			for (i = 0; i < ST_NBR_PARTITIONS; i++) {
36921da177e4SLinus Torvalds 				STp->ps[i].rw = ST_IDLE;
36931da177e4SLinus Torvalds 				STp->ps[i].at_sm = 0;
36941da177e4SLinus Torvalds 				STp->ps[i].last_block_valid = 0;
36951da177e4SLinus Torvalds 			}
36961da177e4SLinus Torvalds 			STp->partition = STp->new_partition = 0;
36978038e645SKai Makisara 			STp->nbr_partitions = mtc.mt_count != 0 ? 2 : 1;
36981da177e4SLinus Torvalds 			STps->drv_block = STps->drv_file = 0;
36991da177e4SLinus Torvalds 			retval = 0;
37001da177e4SLinus Torvalds 			goto out;
37011da177e4SLinus Torvalds 		}
37021da177e4SLinus Torvalds 
37031da177e4SLinus Torvalds 		if (mtc.mt_op == MTSEEK) {
37041da177e4SLinus Torvalds 			i = set_location(STp, mtc.mt_count, STp->new_partition, 0);
37051da177e4SLinus Torvalds 			if (!STp->can_partitions)
37061da177e4SLinus Torvalds 				STp->ps[0].rw = ST_IDLE;
37071da177e4SLinus Torvalds 			retval = i;
37081da177e4SLinus Torvalds 			goto out;
37091da177e4SLinus Torvalds 		}
37101da177e4SLinus Torvalds 
37111da177e4SLinus Torvalds 		if (mtc.mt_op == MTUNLOAD || mtc.mt_op == MTOFFL) {
37121da177e4SLinus Torvalds 			retval = do_load_unload(STp, file, 0);
37131da177e4SLinus Torvalds 			goto out;
37141da177e4SLinus Torvalds 		}
37151da177e4SLinus Torvalds 
37161da177e4SLinus Torvalds 		if (mtc.mt_op == MTLOAD) {
37171da177e4SLinus Torvalds 			retval = do_load_unload(STp, file, max(1, mtc.mt_count));
37181da177e4SLinus Torvalds 			goto out;
37191da177e4SLinus Torvalds 		}
37201da177e4SLinus Torvalds 
37211da177e4SLinus Torvalds 		if (mtc.mt_op == MTLOCK || mtc.mt_op == MTUNLOCK) {
37221da177e4SLinus Torvalds 			retval = do_door_lock(STp, (mtc.mt_op == MTLOCK));
37231da177e4SLinus Torvalds 			goto out;
37241da177e4SLinus Torvalds 		}
37251da177e4SLinus Torvalds 
37261da177e4SLinus Torvalds 		if (STp->can_partitions && STp->ready == ST_READY &&
37271da177e4SLinus Torvalds 		    (i = switch_partition(STp)) < 0) {
37281da177e4SLinus Torvalds 			retval = i;
37291da177e4SLinus Torvalds 			goto out;
37301da177e4SLinus Torvalds 		}
37311da177e4SLinus Torvalds 
37321da177e4SLinus Torvalds 		if (mtc.mt_op == MTCOMPRESSION)
37331da177e4SLinus Torvalds 			retval = st_compression(STp, (mtc.mt_count & 1));
37341da177e4SLinus Torvalds 		else
37351da177e4SLinus Torvalds 			retval = st_int_ioctl(STp, mtc.mt_op, mtc.mt_count);
37361da177e4SLinus Torvalds 		goto out;
37371da177e4SLinus Torvalds 	}
37381da177e4SLinus Torvalds 	if (!STm->defined) {
37391da177e4SLinus Torvalds 		retval = (-ENXIO);
37401da177e4SLinus Torvalds 		goto out;
37411da177e4SLinus Torvalds 	}
37421da177e4SLinus Torvalds 
3743338368f7SKai Mäkisara 	cmd_mtiocget = cmd_type == _IOC_TYPE(MTIOCGET) && cmd_nr == _IOC_NR(MTIOCGET);
3744338368f7SKai Mäkisara 
37451da177e4SLinus Torvalds 	if ((i = flush_buffer(STp, 0)) < 0) {
3746338368f7SKai Mäkisara 		if (cmd_mtiocget && STp->pos_unknown) {
3747338368f7SKai Mäkisara 			/* flush fails -> modify status accordingly */
3748338368f7SKai Mäkisara 			reset_state(STp);
3749338368f7SKai Mäkisara 			STp->pos_unknown = 1;
3750338368f7SKai Mäkisara 		} else { /* return error */
37511da177e4SLinus Torvalds 			retval = i;
37521da177e4SLinus Torvalds 			goto out;
37531da177e4SLinus Torvalds 		}
3754338368f7SKai Mäkisara 	} else { /* flush_buffer succeeds */
3755338368f7SKai Mäkisara 		if (STp->can_partitions) {
3756338368f7SKai Mäkisara 			i = switch_partition(STp);
3757338368f7SKai Mäkisara 			if (i < 0) {
37581da177e4SLinus Torvalds 				retval = i;
37591da177e4SLinus Torvalds 				goto out;
37601da177e4SLinus Torvalds 			}
3761338368f7SKai Mäkisara 		}
3762338368f7SKai Mäkisara 	}
37631da177e4SLinus Torvalds 
3764338368f7SKai Mäkisara 	if (cmd_mtiocget) {
37651da177e4SLinus Torvalds 		struct mtget mt_status;
37661da177e4SLinus Torvalds 
37671da177e4SLinus Torvalds 		if (_IOC_SIZE(cmd_in) != sizeof(struct mtget)) {
37681da177e4SLinus Torvalds 			 retval = (-EINVAL);
37691da177e4SLinus Torvalds 			 goto out;
37701da177e4SLinus Torvalds 		}
37711da177e4SLinus Torvalds 
37721da177e4SLinus Torvalds 		mt_status.mt_type = STp->tape_type;
37731da177e4SLinus Torvalds 		mt_status.mt_dsreg =
37741da177e4SLinus Torvalds 		    ((STp->block_size << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK) |
37751da177e4SLinus Torvalds 		    ((STp->density << MT_ST_DENSITY_SHIFT) & MT_ST_DENSITY_MASK);
37761da177e4SLinus Torvalds 		mt_status.mt_blkno = STps->drv_block;
37771da177e4SLinus Torvalds 		mt_status.mt_fileno = STps->drv_file;
37780e5642e7SKai Mäkisara 		if (STp->block_size != 0 && mt_status.mt_blkno >= 0) {
37791da177e4SLinus Torvalds 			if (STps->rw == ST_WRITING)
37801da177e4SLinus Torvalds 				mt_status.mt_blkno +=
37811da177e4SLinus Torvalds 				    (STp->buffer)->buffer_bytes / STp->block_size;
37821da177e4SLinus Torvalds 			else if (STps->rw == ST_READING)
37831da177e4SLinus Torvalds 				mt_status.mt_blkno -=
37841da177e4SLinus Torvalds                                         ((STp->buffer)->buffer_bytes +
37851da177e4SLinus Torvalds                                          STp->block_size - 1) / STp->block_size;
37861da177e4SLinus Torvalds 		}
37871da177e4SLinus Torvalds 
37881da177e4SLinus Torvalds 		mt_status.mt_gstat = 0;
37891da177e4SLinus Torvalds 		if (STp->drv_write_prot)
37901da177e4SLinus Torvalds 			mt_status.mt_gstat |= GMT_WR_PROT(0xffffffff);
37911da177e4SLinus Torvalds 		if (mt_status.mt_blkno == 0) {
37921da177e4SLinus Torvalds 			if (mt_status.mt_fileno == 0)
37931da177e4SLinus Torvalds 				mt_status.mt_gstat |= GMT_BOT(0xffffffff);
37941da177e4SLinus Torvalds 			else
37951da177e4SLinus Torvalds 				mt_status.mt_gstat |= GMT_EOF(0xffffffff);
37961da177e4SLinus Torvalds 		}
37971da177e4SLinus Torvalds 		mt_status.mt_erreg = (STp->recover_reg << MT_ST_SOFTERR_SHIFT);
37981da177e4SLinus Torvalds 		mt_status.mt_resid = STp->partition;
37991da177e4SLinus Torvalds 		if (STps->eof == ST_EOM_OK || STps->eof == ST_EOM_ERROR)
38001da177e4SLinus Torvalds 			mt_status.mt_gstat |= GMT_EOT(0xffffffff);
38011da177e4SLinus Torvalds 		else if (STps->eof >= ST_EOM_OK)
38021da177e4SLinus Torvalds 			mt_status.mt_gstat |= GMT_EOD(0xffffffff);
38031da177e4SLinus Torvalds 		if (STp->density == 1)
38041da177e4SLinus Torvalds 			mt_status.mt_gstat |= GMT_D_800(0xffffffff);
38051da177e4SLinus Torvalds 		else if (STp->density == 2)
38061da177e4SLinus Torvalds 			mt_status.mt_gstat |= GMT_D_1600(0xffffffff);
38071da177e4SLinus Torvalds 		else if (STp->density == 3)
38081da177e4SLinus Torvalds 			mt_status.mt_gstat |= GMT_D_6250(0xffffffff);
38091da177e4SLinus Torvalds 		if (STp->ready == ST_READY)
38101da177e4SLinus Torvalds 			mt_status.mt_gstat |= GMT_ONLINE(0xffffffff);
38111da177e4SLinus Torvalds 		if (STp->ready == ST_NO_TAPE)
38121da177e4SLinus Torvalds 			mt_status.mt_gstat |= GMT_DR_OPEN(0xffffffff);
38131da177e4SLinus Torvalds 		if (STps->at_sm)
38141da177e4SLinus Torvalds 			mt_status.mt_gstat |= GMT_SM(0xffffffff);
38151da177e4SLinus Torvalds 		if (STm->do_async_writes ||
38161da177e4SLinus Torvalds                     (STm->do_buffer_writes && STp->block_size != 0) ||
38171da177e4SLinus Torvalds 		    STp->drv_buffer != 0)
38181da177e4SLinus Torvalds 			mt_status.mt_gstat |= GMT_IM_REP_EN(0xffffffff);
38191da177e4SLinus Torvalds 		if (STp->cleaning_req)
38201da177e4SLinus Torvalds 			mt_status.mt_gstat |= GMT_CLN(0xffffffff);
38211da177e4SLinus Torvalds 
38221207045dSArnd Bergmann 		retval = put_user_mtget(p, &mt_status);
38231207045dSArnd Bergmann 		if (retval)
38241da177e4SLinus Torvalds 			goto out;
38251da177e4SLinus Torvalds 
38261da177e4SLinus Torvalds 		STp->recover_reg = 0;		/* Clear after read */
38271da177e4SLinus Torvalds 		goto out;
38281da177e4SLinus Torvalds 	}			/* End of MTIOCGET */
38291da177e4SLinus Torvalds 	if (cmd_type == _IOC_TYPE(MTIOCPOS) && cmd_nr == _IOC_NR(MTIOCPOS)) {
38301da177e4SLinus Torvalds 		struct mtpos mt_pos;
38311da177e4SLinus Torvalds 		if (_IOC_SIZE(cmd_in) != sizeof(struct mtpos)) {
38321da177e4SLinus Torvalds 			 retval = (-EINVAL);
38331da177e4SLinus Torvalds 			 goto out;
38341da177e4SLinus Torvalds 		}
38351da177e4SLinus Torvalds 		if ((i = get_location(STp, &blk, &bt, 0)) < 0) {
38361da177e4SLinus Torvalds 			retval = i;
38371da177e4SLinus Torvalds 			goto out;
38381da177e4SLinus Torvalds 		}
38391da177e4SLinus Torvalds 		mt_pos.mt_blkno = blk;
38401207045dSArnd Bergmann 		retval = put_user_mtpos(p, &mt_pos);
38411da177e4SLinus Torvalds 		goto out;
38421da177e4SLinus Torvalds 	}
384328f85009SMatthias Kaehlcke 	mutex_unlock(&STp->lock);
3844dba7688fSChristoph Hellwig 
38451da177e4SLinus Torvalds 	switch (cmd_in) {
3846dba7688fSChristoph Hellwig 	case SG_IO:
3847dba7688fSChristoph Hellwig 	case SCSI_IOCTL_SEND_COMMAND:
3848dba7688fSChristoph Hellwig 	case CDROM_SEND_PACKET:
3849dba7688fSChristoph Hellwig 		if (!capable(CAP_SYS_RAWIO))
3850dba7688fSChristoph Hellwig 			return -EPERM;
38516a2ea0d3SNathan Chancellor 		break;
3852dba7688fSChristoph Hellwig 	default:
3853dba7688fSChristoph Hellwig 		break;
3854dba7688fSChristoph Hellwig 	}
3855dba7688fSChristoph Hellwig 
38562e80089cSChristoph Hellwig 	retval = scsi_ioctl(STp->device, file->f_mode & FMODE_WRITE, cmd_in, p);
3857dba7688fSChristoph Hellwig 	if (!retval && cmd_in == SCSI_IOCTL_STOP_UNIT) {
3858d320a955SArnd Bergmann 		/* unload */
3859d320a955SArnd Bergmann 		STp->rew_at_close = 0;
3860d320a955SArnd Bergmann 		STp->ready = ST_NO_TAPE;
3861d320a955SArnd Bergmann 	}
3862d320a955SArnd Bergmann 	return retval;
3863d320a955SArnd Bergmann 
38641da177e4SLinus Torvalds  out:
386528f85009SMatthias Kaehlcke 	mutex_unlock(&STp->lock);
38661da177e4SLinus Torvalds 	return retval;
38671da177e4SLinus Torvalds }
38681da177e4SLinus Torvalds 
38691da177e4SLinus Torvalds #ifdef CONFIG_COMPAT
st_compat_ioctl(struct file * file,unsigned int cmd_in,unsigned long arg)38701207045dSArnd Bergmann static long st_compat_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
38711da177e4SLinus Torvalds {
38721207045dSArnd Bergmann 	/* argument conversion is handled using put_user_mtpos/put_user_mtget */
38731207045dSArnd Bergmann 	switch (cmd_in) {
38741207045dSArnd Bergmann 	case MTIOCPOS32:
3875dba7688fSChristoph Hellwig 		cmd_in = MTIOCPOS;
3876dba7688fSChristoph Hellwig 		break;
38771207045dSArnd Bergmann 	case MTIOCGET32:
3878dba7688fSChristoph Hellwig 		cmd_in = MTIOCGET;
3879dba7688fSChristoph Hellwig 		break;
38801207045dSArnd Bergmann 	}
38811207045dSArnd Bergmann 
3882dba7688fSChristoph Hellwig 	return st_ioctl(file, cmd_in, arg);
38831da177e4SLinus Torvalds }
38841da177e4SLinus Torvalds #endif
38851da177e4SLinus Torvalds 
38861da177e4SLinus Torvalds 
38871da177e4SLinus Torvalds 
38881da177e4SLinus Torvalds /* Try to allocate a new tape buffer. Calling function must not hold
38891da177e4SLinus Torvalds    dev_arr_lock. */
new_tape_buffer(int max_sg)3890aaff5ebaSChristoph Hellwig static struct st_buffer *new_tape_buffer(int max_sg)
38911da177e4SLinus Torvalds {
38921da177e4SLinus Torvalds 	struct st_buffer *tb;
38931da177e4SLinus Torvalds 
38944011f076SJia-Ju Bai 	tb = kzalloc(sizeof(struct st_buffer), GFP_KERNEL);
38951da177e4SLinus Torvalds 	if (!tb) {
38961da177e4SLinus Torvalds 		printk(KERN_NOTICE "st: Can't allocate new tape buffer.\n");
38971da177e4SLinus Torvalds 		return NULL;
38981da177e4SLinus Torvalds 	}
38991ac63cf5SFUJITA Tomonori 	tb->frp_segs = 0;
39001da177e4SLinus Torvalds 	tb->use_sg = max_sg;
3901f409d6ccSFUJITA Tomonori 	tb->buffer_size = 0;
39021da177e4SLinus Torvalds 
39036396bb22SKees Cook 	tb->reserved_pages = kcalloc(max_sg, sizeof(struct page *),
39044011f076SJia-Ju Bai 				     GFP_KERNEL);
3905d0e1ae31SFUJITA Tomonori 	if (!tb->reserved_pages) {
3906d0e1ae31SFUJITA Tomonori 		kfree(tb);
3907d0e1ae31SFUJITA Tomonori 		return NULL;
3908d0e1ae31SFUJITA Tomonori 	}
3909d0e1ae31SFUJITA Tomonori 
39101da177e4SLinus Torvalds 	return tb;
39111da177e4SLinus Torvalds }
39121da177e4SLinus Torvalds 
39131da177e4SLinus Torvalds 
39141da177e4SLinus Torvalds /* Try to allocate enough space in the tape buffer */
39158f78fc5eSKai Makisara #define ST_MAX_ORDER 6
39168f78fc5eSKai Makisara 
enlarge_buffer(struct st_buffer * STbuffer,int new_size)3917aaff5ebaSChristoph Hellwig static int enlarge_buffer(struct st_buffer * STbuffer, int new_size)
39181da177e4SLinus Torvalds {
3919769989a4SBodo Stroesser 	int segs, max_segs, b_size, order, got;
3920c53033f6SAl Viro 	gfp_t priority;
39211da177e4SLinus Torvalds 
39221da177e4SLinus Torvalds 	if (new_size <= STbuffer->buffer_size)
39231da177e4SLinus Torvalds 		return 1;
39241da177e4SLinus Torvalds 
39251da177e4SLinus Torvalds 	if (STbuffer->buffer_size <= PAGE_SIZE)
39261da177e4SLinus Torvalds 		normalize_buffer(STbuffer);  /* Avoid extra segment */
39271da177e4SLinus Torvalds 
39281da177e4SLinus Torvalds 	max_segs = STbuffer->use_sg;
39291da177e4SLinus Torvalds 
39301da177e4SLinus Torvalds 	priority = GFP_KERNEL | __GFP_NOWARN;
39319c905966SFUJITA Tomonori 
393208c95832SFUJITA Tomonori 	if (STbuffer->cleared)
393308c95832SFUJITA Tomonori 		priority |= __GFP_ZERO;
393408c95832SFUJITA Tomonori 
39359c905966SFUJITA Tomonori 	if (STbuffer->frp_segs) {
3936c982c368SFUJITA Tomonori 		order = STbuffer->reserved_page_order;
393708c95832SFUJITA Tomonori 		b_size = PAGE_SIZE << order;
39389c905966SFUJITA Tomonori 	} else {
39399c905966SFUJITA Tomonori 		for (b_size = PAGE_SIZE, order = 0;
394046081b16SFUJITA Tomonori 		     order < ST_MAX_ORDER &&
394146081b16SFUJITA Tomonori 			     max_segs * (PAGE_SIZE << order) < new_size;
39428f78fc5eSKai Makisara 		     order++, b_size *= 2)
39431da177e4SLinus Torvalds 			;  /* empty */
3944373daacfSKai Makisara 		STbuffer->reserved_page_order = order;
39459c905966SFUJITA Tomonori 	}
39468f78fc5eSKai Makisara 	if (max_segs * (PAGE_SIZE << order) < new_size) {
39478f78fc5eSKai Makisara 		if (order == ST_MAX_ORDER)
39488f78fc5eSKai Makisara 			return 0;
39498f78fc5eSKai Makisara 		normalize_buffer(STbuffer);
3950aaff5ebaSChristoph Hellwig 		return enlarge_buffer(STbuffer, new_size);
39518f78fc5eSKai Makisara 	}
39521da177e4SLinus Torvalds 
39531da177e4SLinus Torvalds 	for (segs = STbuffer->frp_segs, got = STbuffer->buffer_size;
39541da177e4SLinus Torvalds 	     segs < max_segs && got < new_size;) {
395508c95832SFUJITA Tomonori 		struct page *page;
395608c95832SFUJITA Tomonori 
395708c95832SFUJITA Tomonori 		page = alloc_pages(priority, order);
395808c95832SFUJITA Tomonori 		if (!page) {
39591da177e4SLinus Torvalds 			DEB(STbuffer->buffer_size = got);
39601da177e4SLinus Torvalds 			normalize_buffer(STbuffer);
39611da177e4SLinus Torvalds 			return 0;
39621da177e4SLinus Torvalds 		}
396308c95832SFUJITA Tomonori 
39641da177e4SLinus Torvalds 		STbuffer->frp_segs += 1;
39651da177e4SLinus Torvalds 		got += b_size;
39661da177e4SLinus Torvalds 		STbuffer->buffer_size = got;
396708c95832SFUJITA Tomonori 		STbuffer->reserved_pages[segs] = page;
39681da177e4SLinus Torvalds 		segs++;
39691da177e4SLinus Torvalds 	}
397008c95832SFUJITA Tomonori 	STbuffer->b_data = page_address(STbuffer->reserved_pages[0]);
39711da177e4SLinus Torvalds 
39721da177e4SLinus Torvalds 	return 1;
39731da177e4SLinus Torvalds }
39741da177e4SLinus Torvalds 
39751da177e4SLinus Torvalds 
397640f6b36cSKai Makisara /* Make sure that no data from previous user is in the internal buffer */
clear_buffer(struct st_buffer * st_bp)397740f6b36cSKai Makisara static void clear_buffer(struct st_buffer * st_bp)
397840f6b36cSKai Makisara {
397940f6b36cSKai Makisara 	int i;
398040f6b36cSKai Makisara 
398140f6b36cSKai Makisara 	for (i=0; i < st_bp->frp_segs; i++)
398208c95832SFUJITA Tomonori 		memset(page_address(st_bp->reserved_pages[i]), 0,
3983c982c368SFUJITA Tomonori 		       PAGE_SIZE << st_bp->reserved_page_order);
398440f6b36cSKai Makisara 	st_bp->cleared = 1;
398540f6b36cSKai Makisara }
398640f6b36cSKai Makisara 
398740f6b36cSKai Makisara 
39881da177e4SLinus Torvalds /* Release the extra buffer */
normalize_buffer(struct st_buffer * STbuffer)39891da177e4SLinus Torvalds static void normalize_buffer(struct st_buffer * STbuffer)
39901da177e4SLinus Torvalds {
3991c982c368SFUJITA Tomonori 	int i, order = STbuffer->reserved_page_order;
39921da177e4SLinus Torvalds 
39931ac63cf5SFUJITA Tomonori 	for (i = 0; i < STbuffer->frp_segs; i++) {
399408c95832SFUJITA Tomonori 		__free_pages(STbuffer->reserved_pages[i], order);
399508c95832SFUJITA Tomonori 		STbuffer->buffer_size -= (PAGE_SIZE << order);
39961da177e4SLinus Torvalds 	}
39971ac63cf5SFUJITA Tomonori 	STbuffer->frp_segs = 0;
39988b05b773SMike Christie 	STbuffer->sg_segs = 0;
3999c982c368SFUJITA Tomonori 	STbuffer->reserved_page_order = 0;
4000d0e1ae31SFUJITA Tomonori 	STbuffer->map_data.offset = 0;
40011da177e4SLinus Torvalds }
40021da177e4SLinus Torvalds 
40031da177e4SLinus Torvalds 
40041da177e4SLinus Torvalds /* Move data from the user buffer to the tape buffer. Returns zero (success) or
40051da177e4SLinus Torvalds    negative error code. */
append_to_buffer(const char __user * ubp,struct st_buffer * st_bp,int do_count)40061da177e4SLinus Torvalds static int append_to_buffer(const char __user *ubp, struct st_buffer * st_bp, int do_count)
40071da177e4SLinus Torvalds {
40081da177e4SLinus Torvalds 	int i, cnt, res, offset;
4009c982c368SFUJITA Tomonori 	int length = PAGE_SIZE << st_bp->reserved_page_order;
40101da177e4SLinus Torvalds 
40111da177e4SLinus Torvalds 	for (i = 0, offset = st_bp->buffer_bytes;
401208c95832SFUJITA Tomonori 	     i < st_bp->frp_segs && offset >= length; i++)
401308c95832SFUJITA Tomonori 		offset -= length;
40141da177e4SLinus Torvalds 	if (i == st_bp->frp_segs) {	/* Should never happen */
40151da177e4SLinus Torvalds 		printk(KERN_WARNING "st: append_to_buffer offset overflow.\n");
40161da177e4SLinus Torvalds 		return (-EIO);
40171da177e4SLinus Torvalds 	}
40181da177e4SLinus Torvalds 	for (; i < st_bp->frp_segs && do_count > 0; i++) {
401908c95832SFUJITA Tomonori 		struct page *page = st_bp->reserved_pages[i];
402008c95832SFUJITA Tomonori 		cnt = length - offset < do_count ? length - offset : do_count;
402108c95832SFUJITA Tomonori 		res = copy_from_user(page_address(page) + offset, ubp, cnt);
40221da177e4SLinus Torvalds 		if (res)
40231da177e4SLinus Torvalds 			return (-EFAULT);
40241da177e4SLinus Torvalds 		do_count -= cnt;
40251da177e4SLinus Torvalds 		st_bp->buffer_bytes += cnt;
40261da177e4SLinus Torvalds 		ubp += cnt;
40271da177e4SLinus Torvalds 		offset = 0;
40281da177e4SLinus Torvalds 	}
40291da177e4SLinus Torvalds 	if (do_count) /* Should never happen */
40301da177e4SLinus Torvalds 		return (-EIO);
40311da177e4SLinus Torvalds 
40321da177e4SLinus Torvalds 	return 0;
40331da177e4SLinus Torvalds }
40341da177e4SLinus Torvalds 
40351da177e4SLinus Torvalds 
40361da177e4SLinus Torvalds /* Move data from the tape buffer to the user buffer. Returns zero (success) or
40371da177e4SLinus Torvalds    negative error code. */
from_buffer(struct st_buffer * st_bp,char __user * ubp,int do_count)40381da177e4SLinus Torvalds static int from_buffer(struct st_buffer * st_bp, char __user *ubp, int do_count)
40391da177e4SLinus Torvalds {
40401da177e4SLinus Torvalds 	int i, cnt, res, offset;
4041c982c368SFUJITA Tomonori 	int length = PAGE_SIZE << st_bp->reserved_page_order;
40421da177e4SLinus Torvalds 
40431da177e4SLinus Torvalds 	for (i = 0, offset = st_bp->read_pointer;
404408c95832SFUJITA Tomonori 	     i < st_bp->frp_segs && offset >= length; i++)
404508c95832SFUJITA Tomonori 		offset -= length;
40461da177e4SLinus Torvalds 	if (i == st_bp->frp_segs) {	/* Should never happen */
40471da177e4SLinus Torvalds 		printk(KERN_WARNING "st: from_buffer offset overflow.\n");
40481da177e4SLinus Torvalds 		return (-EIO);
40491da177e4SLinus Torvalds 	}
40501da177e4SLinus Torvalds 	for (; i < st_bp->frp_segs && do_count > 0; i++) {
405108c95832SFUJITA Tomonori 		struct page *page = st_bp->reserved_pages[i];
405208c95832SFUJITA Tomonori 		cnt = length - offset < do_count ? length - offset : do_count;
405308c95832SFUJITA Tomonori 		res = copy_to_user(ubp, page_address(page) + offset, cnt);
40541da177e4SLinus Torvalds 		if (res)
40551da177e4SLinus Torvalds 			return (-EFAULT);
40561da177e4SLinus Torvalds 		do_count -= cnt;
40571da177e4SLinus Torvalds 		st_bp->buffer_bytes -= cnt;
40581da177e4SLinus Torvalds 		st_bp->read_pointer += cnt;
40591da177e4SLinus Torvalds 		ubp += cnt;
40601da177e4SLinus Torvalds 		offset = 0;
40611da177e4SLinus Torvalds 	}
40621da177e4SLinus Torvalds 	if (do_count) /* Should never happen */
40631da177e4SLinus Torvalds 		return (-EIO);
40641da177e4SLinus Torvalds 
40651da177e4SLinus Torvalds 	return 0;
40661da177e4SLinus Torvalds }
40671da177e4SLinus Torvalds 
40681da177e4SLinus Torvalds 
40691da177e4SLinus Torvalds /* Move data towards start of buffer */
move_buffer_data(struct st_buffer * st_bp,int offset)40701da177e4SLinus Torvalds static void move_buffer_data(struct st_buffer * st_bp, int offset)
40711da177e4SLinus Torvalds {
40721da177e4SLinus Torvalds 	int src_seg, dst_seg, src_offset = 0, dst_offset;
40731da177e4SLinus Torvalds 	int count, total;
4074c982c368SFUJITA Tomonori 	int length = PAGE_SIZE << st_bp->reserved_page_order;
40751da177e4SLinus Torvalds 
40761da177e4SLinus Torvalds 	if (offset == 0)
40771da177e4SLinus Torvalds 		return;
40781da177e4SLinus Torvalds 
40791da177e4SLinus Torvalds 	total=st_bp->buffer_bytes - offset;
40801da177e4SLinus Torvalds 	for (src_seg=0; src_seg < st_bp->frp_segs; src_seg++) {
40811da177e4SLinus Torvalds 		src_offset = offset;
408208c95832SFUJITA Tomonori 		if (src_offset < length)
40831da177e4SLinus Torvalds 			break;
408408c95832SFUJITA Tomonori 		offset -= length;
40851da177e4SLinus Torvalds 	}
40861da177e4SLinus Torvalds 
40871da177e4SLinus Torvalds 	st_bp->buffer_bytes = st_bp->read_pointer = total;
40881da177e4SLinus Torvalds 	for (dst_seg=dst_offset=0; total > 0; ) {
408908c95832SFUJITA Tomonori 		struct page *dpage = st_bp->reserved_pages[dst_seg];
409008c95832SFUJITA Tomonori 		struct page *spage = st_bp->reserved_pages[src_seg];
409108c95832SFUJITA Tomonori 
409208c95832SFUJITA Tomonori 		count = min(length - dst_offset, length - src_offset);
409308c95832SFUJITA Tomonori 		memmove(page_address(dpage) + dst_offset,
409408c95832SFUJITA Tomonori 			page_address(spage) + src_offset, count);
40951da177e4SLinus Torvalds 		src_offset += count;
409608c95832SFUJITA Tomonori 		if (src_offset >= length) {
40971da177e4SLinus Torvalds 			src_seg++;
40981da177e4SLinus Torvalds 			src_offset = 0;
40991da177e4SLinus Torvalds 		}
41001da177e4SLinus Torvalds 		dst_offset += count;
410108c95832SFUJITA Tomonori 		if (dst_offset >= length) {
41021da177e4SLinus Torvalds 			dst_seg++;
41031da177e4SLinus Torvalds 			dst_offset = 0;
41041da177e4SLinus Torvalds 		}
41051da177e4SLinus Torvalds 		total -= count;
41061da177e4SLinus Torvalds 	}
41071da177e4SLinus Torvalds }
41081da177e4SLinus Torvalds 
41091da177e4SLinus Torvalds /* Validate the options from command line or module parameters */
validate_options(void)41101da177e4SLinus Torvalds static void validate_options(void)
41111da177e4SLinus Torvalds {
41121da177e4SLinus Torvalds 	if (buffer_kbs > 0)
41131da177e4SLinus Torvalds 		st_fixed_buffer_size = buffer_kbs * ST_KILOBYTE;
41141da177e4SLinus Torvalds 	if (max_sg_segs >= ST_FIRST_SG)
41151da177e4SLinus Torvalds 		st_max_sg_segs = max_sg_segs;
41161da177e4SLinus Torvalds }
41171da177e4SLinus Torvalds 
41181da177e4SLinus Torvalds #ifndef MODULE
41191da177e4SLinus Torvalds /* Set the boot options. Syntax is defined in Documenation/scsi/st.txt.
41201da177e4SLinus Torvalds  */
st_setup(char * str)41211da177e4SLinus Torvalds static int __init st_setup(char *str)
41221da177e4SLinus Torvalds {
41231da177e4SLinus Torvalds 	int i, len, ints[5];
41241da177e4SLinus Torvalds 	char *stp;
41251da177e4SLinus Torvalds 
41261da177e4SLinus Torvalds 	stp = get_options(str, ARRAY_SIZE(ints), ints);
41271da177e4SLinus Torvalds 
41281da177e4SLinus Torvalds 	if (ints[0] > 0) {
41291da177e4SLinus Torvalds 		for (i = 0; i < ints[0] && i < ARRAY_SIZE(parms); i++)
41301da177e4SLinus Torvalds 			if (parms[i].val)
41311da177e4SLinus Torvalds 				*parms[i].val = ints[i + 1];
41321da177e4SLinus Torvalds 	} else {
41331da177e4SLinus Torvalds 		while (stp != NULL) {
41341da177e4SLinus Torvalds 			for (i = 0; i < ARRAY_SIZE(parms); i++) {
41351da177e4SLinus Torvalds 				len = strlen(parms[i].name);
41361da177e4SLinus Torvalds 				if (!strncmp(stp, parms[i].name, len) &&
41371da177e4SLinus Torvalds 				    (*(stp + len) == ':' || *(stp + len) == '=')) {
41381da177e4SLinus Torvalds 					if (parms[i].val)
41391da177e4SLinus Torvalds 						*parms[i].val =
41401da177e4SLinus Torvalds 							simple_strtoul(stp + len + 1, NULL, 0);
41411da177e4SLinus Torvalds 					else
41421da177e4SLinus Torvalds 						printk(KERN_WARNING "st: Obsolete parameter %s\n",
41431da177e4SLinus Torvalds 						       parms[i].name);
41441da177e4SLinus Torvalds 					break;
41451da177e4SLinus Torvalds 				}
41461da177e4SLinus Torvalds 			}
41476391a113STobias Klauser 			if (i >= ARRAY_SIZE(parms))
41481da177e4SLinus Torvalds 				 printk(KERN_WARNING "st: invalid parameter in '%s'\n",
41491da177e4SLinus Torvalds 					stp);
41501da177e4SLinus Torvalds 			stp = strchr(stp, ',');
41511da177e4SLinus Torvalds 			if (stp)
41521da177e4SLinus Torvalds 				stp++;
41531da177e4SLinus Torvalds 		}
41541da177e4SLinus Torvalds 	}
41551da177e4SLinus Torvalds 
41561da177e4SLinus Torvalds 	validate_options();
41571da177e4SLinus Torvalds 
41581da177e4SLinus Torvalds 	return 1;
41591da177e4SLinus Torvalds }
41601da177e4SLinus Torvalds 
41611da177e4SLinus Torvalds __setup("st=", st_setup);
41621da177e4SLinus Torvalds 
41631da177e4SLinus Torvalds #endif
41641da177e4SLinus Torvalds 
416500977a59SArjan van de Ven static const struct file_operations st_fops =
41661da177e4SLinus Torvalds {
41671da177e4SLinus Torvalds 	.owner =	THIS_MODULE,
41681da177e4SLinus Torvalds 	.read =		st_read,
41691da177e4SLinus Torvalds 	.write =	st_write,
4170fd66c1b4SKai Makisara 	.unlocked_ioctl = st_ioctl,
41711da177e4SLinus Torvalds #ifdef CONFIG_COMPAT
41721da177e4SLinus Torvalds 	.compat_ioctl = st_compat_ioctl,
41731da177e4SLinus Torvalds #endif
41741da177e4SLinus Torvalds 	.open =		st_open,
41751da177e4SLinus Torvalds 	.flush =	st_flush,
41761da177e4SLinus Torvalds 	.release =	st_release,
4177b4d878e2SJan Blunck 	.llseek =	noop_llseek,
41781da177e4SLinus Torvalds };
41791da177e4SLinus Torvalds 
create_one_cdev(struct scsi_tape * tape,int mode,int rew)418026898afdSJeff Mahoney static int create_one_cdev(struct scsi_tape *tape, int mode, int rew)
418126898afdSJeff Mahoney {
418226898afdSJeff Mahoney 	int i, error;
418326898afdSJeff Mahoney 	dev_t cdev_devno;
418426898afdSJeff Mahoney 	struct cdev *cdev;
418526898afdSJeff Mahoney 	struct device *dev;
418626898afdSJeff Mahoney 	struct st_modedef *STm = &(tape->modes[mode]);
418726898afdSJeff Mahoney 	char name[10];
418826898afdSJeff Mahoney 	int dev_num = tape->index;
418926898afdSJeff Mahoney 
419026898afdSJeff Mahoney 	cdev_devno = MKDEV(SCSI_TAPE_MAJOR, TAPE_MINOR(dev_num, mode, rew));
419126898afdSJeff Mahoney 
419226898afdSJeff Mahoney 	cdev = cdev_alloc();
419326898afdSJeff Mahoney 	if (!cdev) {
419426898afdSJeff Mahoney 		pr_err("st%d: out of memory. Device not attached.\n", dev_num);
419526898afdSJeff Mahoney 		error = -ENOMEM;
419626898afdSJeff Mahoney 		goto out;
419726898afdSJeff Mahoney 	}
419826898afdSJeff Mahoney 	cdev->owner = THIS_MODULE;
419926898afdSJeff Mahoney 	cdev->ops = &st_fops;
4200ab08ee14SMaurizio Lombardi 	STm->cdevs[rew] = cdev;
420126898afdSJeff Mahoney 
420226898afdSJeff Mahoney 	error = cdev_add(cdev, cdev_devno, 1);
420326898afdSJeff Mahoney 	if (error) {
420426898afdSJeff Mahoney 		pr_err("st%d: Can't add %s-rewind mode %d\n", dev_num,
420526898afdSJeff Mahoney 		       rew ? "non" : "auto", mode);
420626898afdSJeff Mahoney 		pr_err("st%d: Device not attached.\n", dev_num);
420726898afdSJeff Mahoney 		goto out_free;
420826898afdSJeff Mahoney 	}
420926898afdSJeff Mahoney 
421026898afdSJeff Mahoney 	i = mode << (4 - ST_NBR_MODE_BITS);
421126898afdSJeff Mahoney 	snprintf(name, 10, "%s%s%s", rew ? "n" : "",
421245938335SChristoph Hellwig 		 tape->name, st_formats[i]);
421326898afdSJeff Mahoney 
421426898afdSJeff Mahoney 	dev = device_create(&st_sysfs_class, &tape->device->sdev_gendev,
421526898afdSJeff Mahoney 			    cdev_devno, &tape->modes[mode], "%s", name);
421626898afdSJeff Mahoney 	if (IS_ERR(dev)) {
421726898afdSJeff Mahoney 		pr_err("st%d: device_create failed\n", dev_num);
421826898afdSJeff Mahoney 		error = PTR_ERR(dev);
421926898afdSJeff Mahoney 		goto out_free;
422026898afdSJeff Mahoney 	}
422126898afdSJeff Mahoney 
422226898afdSJeff Mahoney 	STm->devs[rew] = dev;
422326898afdSJeff Mahoney 
422426898afdSJeff Mahoney 	return 0;
422526898afdSJeff Mahoney out_free:
422626898afdSJeff Mahoney 	cdev_del(STm->cdevs[rew]);
422726898afdSJeff Mahoney out:
4228ab08ee14SMaurizio Lombardi 	STm->cdevs[rew] = NULL;
4229ab08ee14SMaurizio Lombardi 	STm->devs[rew] = NULL;
423026898afdSJeff Mahoney 	return error;
423126898afdSJeff Mahoney }
423226898afdSJeff Mahoney 
create_cdevs(struct scsi_tape * tape)423326898afdSJeff Mahoney static int create_cdevs(struct scsi_tape *tape)
423426898afdSJeff Mahoney {
423526898afdSJeff Mahoney 	int mode, error;
423626898afdSJeff Mahoney 	for (mode = 0; mode < ST_NBR_MODES; ++mode) {
423726898afdSJeff Mahoney 		error = create_one_cdev(tape, mode, 0);
423826898afdSJeff Mahoney 		if (error)
423926898afdSJeff Mahoney 			return error;
424026898afdSJeff Mahoney 		error = create_one_cdev(tape, mode, 1);
424126898afdSJeff Mahoney 		if (error)
424226898afdSJeff Mahoney 			return error;
424326898afdSJeff Mahoney 	}
424426898afdSJeff Mahoney 
424526898afdSJeff Mahoney 	return sysfs_create_link(&tape->device->sdev_gendev.kobj,
424626898afdSJeff Mahoney 				 &tape->modes[0].devs[0]->kobj, "tape");
424726898afdSJeff Mahoney }
424826898afdSJeff Mahoney 
remove_cdevs(struct scsi_tape * tape)424926898afdSJeff Mahoney static void remove_cdevs(struct scsi_tape *tape)
425026898afdSJeff Mahoney {
425126898afdSJeff Mahoney 	int mode, rew;
425226898afdSJeff Mahoney 	sysfs_remove_link(&tape->device->sdev_gendev.kobj, "tape");
425326898afdSJeff Mahoney 	for (mode = 0; mode < ST_NBR_MODES; mode++) {
425426898afdSJeff Mahoney 		struct st_modedef *STm = &(tape->modes[mode]);
425526898afdSJeff Mahoney 		for (rew = 0; rew < 2; rew++) {
425626898afdSJeff Mahoney 			if (STm->cdevs[rew])
425726898afdSJeff Mahoney 				cdev_del(STm->cdevs[rew]);
425826898afdSJeff Mahoney 			if (STm->devs[rew])
425926898afdSJeff Mahoney 				device_unregister(STm->devs[rew]);
426026898afdSJeff Mahoney 		}
426126898afdSJeff Mahoney 	}
426226898afdSJeff Mahoney }
426326898afdSJeff Mahoney 
st_probe(struct device * dev)42641da177e4SLinus Torvalds static int st_probe(struct device *dev)
42651da177e4SLinus Torvalds {
42661da177e4SLinus Torvalds 	struct scsi_device *SDp = to_scsi_device(dev);
42671da177e4SLinus Torvalds 	struct scsi_tape *tpnt = NULL;
42681da177e4SLinus Torvalds 	struct st_modedef *STm;
42691da177e4SLinus Torvalds 	struct st_partstat *STps;
42701da177e4SLinus Torvalds 	struct st_buffer *buffer;
4271b98c52b5STejun Heo 	int i, error;
42721da177e4SLinus Torvalds 
42731da177e4SLinus Torvalds 	if (SDp->type != TYPE_TAPE)
42741da177e4SLinus Torvalds 		return -ENODEV;
4275f0ee639aSColin Ian King 	if (st_incompatible(SDp)) {
4276b30d8bcaSHannes Reinecke 		sdev_printk(KERN_INFO, SDp,
42774e3ea141SHannes Reinecke 			    "OnStream tapes are no longer supported;\n");
42784e3ea141SHannes Reinecke 		sdev_printk(KERN_INFO, SDp,
42794e3ea141SHannes Reinecke 			    "please mail to linux-scsi@vger.kernel.org.\n");
42801da177e4SLinus Torvalds 		return -ENODEV;
42811da177e4SLinus Torvalds 	}
42821da177e4SLinus Torvalds 
42836fe8c1dbSSubhash Jadavani 	scsi_autopm_get_device(SDp);
42848a78362cSMartin K. Petersen 	i = queue_max_segments(SDp->request_queue);
42851da177e4SLinus Torvalds 	if (st_max_sg_segs < i)
42861da177e4SLinus Torvalds 		i = st_max_sg_segs;
4287aaff5ebaSChristoph Hellwig 	buffer = new_tape_buffer(i);
42881da177e4SLinus Torvalds 	if (buffer == NULL) {
4289b30d8bcaSHannes Reinecke 		sdev_printk(KERN_ERR, SDp,
4290b30d8bcaSHannes Reinecke 			    "st: Can't allocate new tape buffer. "
4291b30d8bcaSHannes Reinecke 			    "Device not attached.\n");
42921da177e4SLinus Torvalds 		goto out;
42931da177e4SLinus Torvalds 	}
42941da177e4SLinus Torvalds 
42951f618aacSJia-Ju Bai 	tpnt = kzalloc(sizeof(struct scsi_tape), GFP_KERNEL);
42961da177e4SLinus Torvalds 	if (tpnt == NULL) {
4297b30d8bcaSHannes Reinecke 		sdev_printk(KERN_ERR, SDp,
4298b30d8bcaSHannes Reinecke 			    "st: Can't allocate device descriptor.\n");
429945938335SChristoph Hellwig 		goto out_buffer_free;
43001da177e4SLinus Torvalds 	}
4301f03a5670SKai Makisara 	kref_init(&tpnt->kref);
43021da177e4SLinus Torvalds 
43031da177e4SLinus Torvalds 	tpnt->device = SDp;
43041da177e4SLinus Torvalds 	if (SDp->scsi_level <= 2)
43051da177e4SLinus Torvalds 		tpnt->tape_type = MT_ISSCSI1;
43061da177e4SLinus Torvalds 	else
43071da177e4SLinus Torvalds 		tpnt->tape_type = MT_ISSCSI2;
43081da177e4SLinus Torvalds 
43091da177e4SLinus Torvalds 	tpnt->buffer = buffer;
4310f03a5670SKai Makisara 	tpnt->buffer->last_SRpnt = NULL;
43111da177e4SLinus Torvalds 
43121da177e4SLinus Torvalds 	tpnt->inited = 0;
43131da177e4SLinus Torvalds 	tpnt->dirty = 0;
43141da177e4SLinus Torvalds 	tpnt->in_use = 0;
43151da177e4SLinus Torvalds 	tpnt->drv_buffer = 1;	/* Try buffering if no mode sense */
43161da177e4SLinus Torvalds 	tpnt->use_pf = (SDp->scsi_level >= SCSI_2);
43171da177e4SLinus Torvalds 	tpnt->density = 0;
43181da177e4SLinus Torvalds 	tpnt->do_auto_lock = ST_AUTO_LOCK;
43191da177e4SLinus Torvalds 	tpnt->can_bsr = (SDp->scsi_level > 2 ? 1 : ST_IN_FILE_POS); /* BSR mandatory in SCSI3 */
43201da177e4SLinus Torvalds 	tpnt->can_partitions = 0;
43211da177e4SLinus Torvalds 	tpnt->two_fm = ST_TWO_FM;
43221da177e4SLinus Torvalds 	tpnt->fast_mteom = ST_FAST_MTEOM;
43231da177e4SLinus Torvalds 	tpnt->scsi2_logical = ST_SCSI2LOGICAL;
432440f6b36cSKai Makisara 	tpnt->sili = ST_SILI;
43251da177e4SLinus Torvalds 	tpnt->immediate = ST_NOWAIT;
4326c743e44fSLee Duncan 	tpnt->immediate_filemark = 0;
43271da177e4SLinus Torvalds 	tpnt->default_drvbuffer = 0xff;		/* No forced buffering */
43281da177e4SLinus Torvalds 	tpnt->partition = 0;
43291da177e4SLinus Torvalds 	tpnt->new_partition = 0;
43301da177e4SLinus Torvalds 	tpnt->nbr_partitions = 0;
4331a02488edSJames Bottomley 	blk_queue_rq_timeout(tpnt->device->request_queue, ST_TIMEOUT);
43321da177e4SLinus Torvalds 	tpnt->long_timeout = ST_LONG_TIMEOUT;
4333aaff5ebaSChristoph Hellwig 	tpnt->try_dio = try_direct_io;
4334*7bfa83eeSKai Mäkisara 	tpnt->first_tur = 1;
43351da177e4SLinus Torvalds 
43361da177e4SLinus Torvalds 	for (i = 0; i < ST_NBR_MODES; i++) {
43371da177e4SLinus Torvalds 		STm = &(tpnt->modes[i]);
43381da177e4SLinus Torvalds 		STm->defined = 0;
43391da177e4SLinus Torvalds 		STm->sysv = ST_SYSV;
43401da177e4SLinus Torvalds 		STm->defaults_for_writes = 0;
43411da177e4SLinus Torvalds 		STm->do_async_writes = ST_ASYNC_WRITES;
43421da177e4SLinus Torvalds 		STm->do_buffer_writes = ST_BUFFER_WRITES;
43431da177e4SLinus Torvalds 		STm->do_read_ahead = ST_READ_AHEAD;
43441da177e4SLinus Torvalds 		STm->default_compression = ST_DONT_TOUCH;
43451da177e4SLinus Torvalds 		STm->default_blksize = (-1);	/* No forced size */
43461da177e4SLinus Torvalds 		STm->default_density = (-1);	/* No forced density */
43476c648d95SJeff Mahoney 		STm->tape = tpnt;
43481da177e4SLinus Torvalds 	}
43491da177e4SLinus Torvalds 
43501da177e4SLinus Torvalds 	for (i = 0; i < ST_NBR_PARTITIONS; i++) {
43511da177e4SLinus Torvalds 		STps = &(tpnt->ps[i]);
43521da177e4SLinus Torvalds 		STps->rw = ST_IDLE;
43531da177e4SLinus Torvalds 		STps->eof = ST_NOEOF;
43541da177e4SLinus Torvalds 		STps->at_sm = 0;
43551da177e4SLinus Torvalds 		STps->last_block_valid = 0;
43561da177e4SLinus Torvalds 		STps->drv_block = (-1);
43571da177e4SLinus Torvalds 		STps->drv_file = (-1);
43581da177e4SLinus Torvalds 	}
43591da177e4SLinus Torvalds 
43601da177e4SLinus Torvalds 	tpnt->current_mode = 0;
43611da177e4SLinus Torvalds 	tpnt->modes[0].defined = 1;
43621da177e4SLinus Torvalds 
43631da177e4SLinus Torvalds 	tpnt->density_changed = tpnt->compression_changed =
43641da177e4SLinus Torvalds 	    tpnt->blksize_changed = 0;
436528f85009SMatthias Kaehlcke 	mutex_init(&tpnt->lock);
43661da177e4SLinus Torvalds 
4367b98c52b5STejun Heo 	idr_preload(GFP_KERNEL);
43686c648d95SJeff Mahoney 	spin_lock(&st_index_lock);
4369b98c52b5STejun Heo 	error = idr_alloc(&st_index_idr, tpnt, 0, ST_MAX_TAPES + 1, GFP_NOWAIT);
43706c648d95SJeff Mahoney 	spin_unlock(&st_index_lock);
4371b98c52b5STejun Heo 	idr_preload_end();
4372b98c52b5STejun Heo 	if (error < 0) {
43736c648d95SJeff Mahoney 		pr_warn("st: idr allocation failed: %d\n", error);
437445938335SChristoph Hellwig 		goto out_free_tape;
43756c648d95SJeff Mahoney 	}
4376b98c52b5STejun Heo 	tpnt->index = error;
437745938335SChristoph Hellwig 	sprintf(tpnt->name, "st%d", tpnt->index);
437805545c92SSeymour, Shane M 	tpnt->stats = kzalloc(sizeof(struct scsi_tape_stats), GFP_KERNEL);
437905545c92SSeymour, Shane M 	if (tpnt->stats == NULL) {
438005545c92SSeymour, Shane M 		sdev_printk(KERN_ERR, SDp,
438105545c92SSeymour, Shane M 			    "st: Can't allocate statistics.\n");
438205545c92SSeymour, Shane M 		goto out_idr_remove;
438305545c92SSeymour, Shane M 	}
43846c648d95SJeff Mahoney 
43856c648d95SJeff Mahoney 	dev_set_drvdata(dev, tpnt);
43861da177e4SLinus Torvalds 
43871da177e4SLinus Torvalds 
438826898afdSJeff Mahoney 	error = create_cdevs(tpnt);
438913026a6bSJeff Garzik 	if (error)
439026898afdSJeff Mahoney 		goto out_remove_devs;
439146a243f7SOliver Neukum 	scsi_autopm_put_device(SDp);
43921da177e4SLinus Torvalds 
439342252854SKai Makisara 	sdev_printk(KERN_NOTICE, SDp,
439445938335SChristoph Hellwig 		    "Attached scsi tape %s\n", tpnt->name);
439542252854SKai Makisara 	sdev_printk(KERN_INFO, SDp, "%s: try direct i/o: %s (alignment %d B)\n",
439645938335SChristoph Hellwig 		    tpnt->name, tpnt->try_dio ? "yes" : "no",
43978b05b773SMike Christie 		    queue_dma_alignment(SDp->request_queue) + 1);
43981da177e4SLinus Torvalds 
43991da177e4SLinus Torvalds 	return 0;
44001da177e4SLinus Torvalds 
440126898afdSJeff Mahoney out_remove_devs:
440226898afdSJeff Mahoney 	remove_cdevs(tpnt);
440305545c92SSeymour, Shane M 	kfree(tpnt->stats);
440405545c92SSeymour, Shane M out_idr_remove:
44056c648d95SJeff Mahoney 	spin_lock(&st_index_lock);
4406b98c52b5STejun Heo 	idr_remove(&st_index_idr, tpnt->index);
44076c648d95SJeff Mahoney 	spin_unlock(&st_index_lock);
440845938335SChristoph Hellwig out_free_tape:
44091da177e4SLinus Torvalds 	kfree(tpnt);
44101da177e4SLinus Torvalds out_buffer_free:
44111da177e4SLinus Torvalds 	kfree(buffer);
44121da177e4SLinus Torvalds out:
44136fe8c1dbSSubhash Jadavani 	scsi_autopm_put_device(SDp);
44141da177e4SLinus Torvalds 	return -ENODEV;
44151da177e4SLinus Torvalds };
44161da177e4SLinus Torvalds 
44171da177e4SLinus Torvalds 
st_remove(struct device * dev)44181da177e4SLinus Torvalds static int st_remove(struct device *dev)
44191da177e4SLinus Torvalds {
44206c648d95SJeff Mahoney 	struct scsi_tape *tpnt = dev_get_drvdata(dev);
44216c648d95SJeff Mahoney 	int index = tpnt->index;
44221da177e4SLinus Torvalds 
44236c648d95SJeff Mahoney 	scsi_autopm_get_device(to_scsi_device(dev));
442426898afdSJeff Mahoney 	remove_cdevs(tpnt);
4425f03a5670SKai Makisara 
44260b950672SArjan van de Ven 	mutex_lock(&st_ref_mutex);
4427f03a5670SKai Makisara 	kref_put(&tpnt->kref, scsi_tape_release);
44280b950672SArjan van de Ven 	mutex_unlock(&st_ref_mutex);
44296c648d95SJeff Mahoney 	spin_lock(&st_index_lock);
44306c648d95SJeff Mahoney 	idr_remove(&st_index_idr, index);
44316c648d95SJeff Mahoney 	spin_unlock(&st_index_lock);
4432f03a5670SKai Makisara 	return 0;
4433f03a5670SKai Makisara }
4434f03a5670SKai Makisara 
4435f03a5670SKai Makisara /**
4436f03a5670SKai Makisara  *      scsi_tape_release - Called to free the Scsi_Tape structure
4437f03a5670SKai Makisara  *      @kref: pointer to embedded kref
4438f03a5670SKai Makisara  *
44390b950672SArjan van de Ven  *      st_ref_mutex must be held entering this routine.  Because it is
4440f03a5670SKai Makisara  *      called on last put, you should always use the scsi_tape_get()
4441f03a5670SKai Makisara  *      scsi_tape_put() helpers which manipulate the semaphore directly
4442f03a5670SKai Makisara  *      and never do a direct kref_put().
4443f03a5670SKai Makisara  **/
scsi_tape_release(struct kref * kref)4444f03a5670SKai Makisara static void scsi_tape_release(struct kref *kref)
4445f03a5670SKai Makisara {
4446f03a5670SKai Makisara 	struct scsi_tape *tpnt = to_scsi_tape(kref);
4447f03a5670SKai Makisara 
44481da177e4SLinus Torvalds 	tpnt->device = NULL;
44491da177e4SLinus Torvalds 
44501da177e4SLinus Torvalds 	if (tpnt->buffer) {
44511da177e4SLinus Torvalds 		normalize_buffer(tpnt->buffer);
4452d0e1ae31SFUJITA Tomonori 		kfree(tpnt->buffer->reserved_pages);
44531da177e4SLinus Torvalds 		kfree(tpnt->buffer);
44541da177e4SLinus Torvalds 	}
44551da177e4SLinus Torvalds 
445605545c92SSeymour, Shane M 	kfree(tpnt->stats);
4457f03a5670SKai Makisara 	kfree(tpnt);
4458f03a5670SKai Makisara 	return;
44591da177e4SLinus Torvalds }
44601da177e4SLinus Torvalds 
4461af23782bSJeff Mahoney static struct class st_sysfs_class = {
4462af23782bSJeff Mahoney 	.name = "scsi_tape",
4463c69c6be5SGreg Kroah-Hartman 	.dev_groups = st_dev_groups,
4464af23782bSJeff Mahoney };
4465af23782bSJeff Mahoney 
init_st(void)44661da177e4SLinus Torvalds static int __init init_st(void)
44671da177e4SLinus Torvalds {
446813026a6bSJeff Garzik 	int err;
446913026a6bSJeff Garzik 
44701da177e4SLinus Torvalds 	validate_options();
44711da177e4SLinus Torvalds 
447213026a6bSJeff Garzik 	printk(KERN_INFO "st: Version %s, fixed bufsize %d, s/g segs %d\n",
44731da177e4SLinus Torvalds 		verstr, st_fixed_buffer_size, st_max_sg_segs);
44741da177e4SLinus Torvalds 
44752bec708aSLaurence Oberman 	debugging = (debug_flag > 0) ? debug_flag : NO_DEBUG;
44762bec708aSLaurence Oberman 	if (debugging) {
44772bec708aSLaurence Oberman 		printk(KERN_INFO "st: Debugging enabled debug_flag = %d\n",
44782bec708aSLaurence Oberman 			debugging);
44792bec708aSLaurence Oberman 	}
44802bec708aSLaurence Oberman 
4481af23782bSJeff Mahoney 	err = class_register(&st_sysfs_class);
4482af23782bSJeff Mahoney 	if (err) {
4483af23782bSJeff Mahoney 		pr_err("Unable register sysfs class for SCSI tapes\n");
4484af23782bSJeff Mahoney 		return err;
44851da177e4SLinus Torvalds 	}
44861da177e4SLinus Torvalds 
448713026a6bSJeff Garzik 	err = register_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0),
448813026a6bSJeff Garzik 				     ST_MAX_TAPE_ENTRIES, "st");
448913026a6bSJeff Garzik 	if (err) {
449013026a6bSJeff Garzik 		printk(KERN_ERR "Unable to get major %d for SCSI tapes\n",
449113026a6bSJeff Garzik 		       SCSI_TAPE_MAJOR);
449213026a6bSJeff Garzik 		goto err_class;
44931da177e4SLinus Torvalds 	}
449413026a6bSJeff Garzik 
449513026a6bSJeff Garzik 	err = scsi_register_driver(&st_template.gendrv);
449613026a6bSJeff Garzik 	if (err)
449713026a6bSJeff Garzik 		goto err_chrdev;
449813026a6bSJeff Garzik 
449913026a6bSJeff Garzik 	return 0;
450013026a6bSJeff Garzik 
450113026a6bSJeff Garzik err_chrdev:
45021da177e4SLinus Torvalds 	unregister_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0),
45031da177e4SLinus Torvalds 				 ST_MAX_TAPE_ENTRIES);
450413026a6bSJeff Garzik err_class:
4505af23782bSJeff Mahoney 	class_unregister(&st_sysfs_class);
450613026a6bSJeff Garzik 	return err;
45071da177e4SLinus Torvalds }
45081da177e4SLinus Torvalds 
exit_st(void)45091da177e4SLinus Torvalds static void __exit exit_st(void)
45101da177e4SLinus Torvalds {
45111da177e4SLinus Torvalds 	scsi_unregister_driver(&st_template.gendrv);
45121da177e4SLinus Torvalds 	unregister_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0),
45131da177e4SLinus Torvalds 				 ST_MAX_TAPE_ENTRIES);
4514af23782bSJeff Mahoney 	class_unregister(&st_sysfs_class);
45152d3a5d21SJohannes Thumshirn 	idr_destroy(&st_index_idr);
45161da177e4SLinus Torvalds 	printk(KERN_INFO "st: Unloaded.\n");
45171da177e4SLinus Torvalds }
45181da177e4SLinus Torvalds 
45191da177e4SLinus Torvalds module_init(init_st);
45201da177e4SLinus Torvalds module_exit(exit_st);
45211da177e4SLinus Torvalds 
45221da177e4SLinus Torvalds 
45231da177e4SLinus Torvalds /* The sysfs driver interface. Read-only at the moment */
try_direct_io_show(struct device_driver * ddp,char * buf)452410978e48SSeymour, Shane M static ssize_t try_direct_io_show(struct device_driver *ddp, char *buf)
45251da177e4SLinus Torvalds {
452610978e48SSeymour, Shane M 	return scnprintf(buf, PAGE_SIZE, "%d\n", try_direct_io);
45271da177e4SLinus Torvalds }
452810978e48SSeymour, Shane M static DRIVER_ATTR_RO(try_direct_io);
45291da177e4SLinus Torvalds 
fixed_buffer_size_show(struct device_driver * ddp,char * buf)453010978e48SSeymour, Shane M static ssize_t fixed_buffer_size_show(struct device_driver *ddp, char *buf)
45311da177e4SLinus Torvalds {
453210978e48SSeymour, Shane M 	return scnprintf(buf, PAGE_SIZE, "%d\n", st_fixed_buffer_size);
45331da177e4SLinus Torvalds }
453410978e48SSeymour, Shane M static DRIVER_ATTR_RO(fixed_buffer_size);
45351da177e4SLinus Torvalds 
max_sg_segs_show(struct device_driver * ddp,char * buf)453610978e48SSeymour, Shane M static ssize_t max_sg_segs_show(struct device_driver *ddp, char *buf)
45371da177e4SLinus Torvalds {
453810978e48SSeymour, Shane M 	return scnprintf(buf, PAGE_SIZE, "%d\n", st_max_sg_segs);
45391da177e4SLinus Torvalds }
454010978e48SSeymour, Shane M static DRIVER_ATTR_RO(max_sg_segs);
45411da177e4SLinus Torvalds 
version_show(struct device_driver * ddd,char * buf)454210978e48SSeymour, Shane M static ssize_t version_show(struct device_driver *ddd, char *buf)
45431da177e4SLinus Torvalds {
454410978e48SSeymour, Shane M 	return scnprintf(buf, PAGE_SIZE, "[%s]\n", verstr);
45451da177e4SLinus Torvalds }
454610978e48SSeymour, Shane M static DRIVER_ATTR_RO(version);
45471da177e4SLinus Torvalds 
4548d9b43a10SSeymour, Shane M #if DEBUG
debug_flag_store(struct device_driver * ddp,const char * buf,size_t count)4549d9b43a10SSeymour, Shane M static ssize_t debug_flag_store(struct device_driver *ddp,
4550d9b43a10SSeymour, Shane M 	const char *buf, size_t count)
4551d9b43a10SSeymour, Shane M {
4552d9b43a10SSeymour, Shane M /* We only care what the first byte of the data is the rest is unused.
4553d9b43a10SSeymour, Shane M  * if it's a '1' we turn on debug and if it's a '0' we disable it. All
4554d9b43a10SSeymour, Shane M  * other values have -EINVAL returned if they are passed in.
4555d9b43a10SSeymour, Shane M  */
4556d9b43a10SSeymour, Shane M 	if (count > 0) {
4557d9b43a10SSeymour, Shane M 		if (buf[0] == '0') {
4558d9b43a10SSeymour, Shane M 			debugging = NO_DEBUG;
4559d9b43a10SSeymour, Shane M 			return count;
4560d9b43a10SSeymour, Shane M 		} else if (buf[0] == '1') {
4561d9b43a10SSeymour, Shane M 			debugging = 1;
4562d9b43a10SSeymour, Shane M 			return count;
4563d9b43a10SSeymour, Shane M 		}
4564d9b43a10SSeymour, Shane M 	}
4565d9b43a10SSeymour, Shane M 	return -EINVAL;
4566d9b43a10SSeymour, Shane M }
4567d9b43a10SSeymour, Shane M 
debug_flag_show(struct device_driver * ddp,char * buf)4568d9b43a10SSeymour, Shane M static ssize_t debug_flag_show(struct device_driver *ddp, char *buf)
4569d9b43a10SSeymour, Shane M {
4570d9b43a10SSeymour, Shane M 	return scnprintf(buf, PAGE_SIZE, "%d\n", debugging);
4571d9b43a10SSeymour, Shane M }
4572d9b43a10SSeymour, Shane M static DRIVER_ATTR_RW(debug_flag);
4573d9b43a10SSeymour, Shane M #endif
4574d9b43a10SSeymour, Shane M 
4575442d7562SSeymour, Shane M static struct attribute *st_drv_attrs[] = {
4576442d7562SSeymour, Shane M 	&driver_attr_try_direct_io.attr,
4577442d7562SSeymour, Shane M 	&driver_attr_fixed_buffer_size.attr,
4578442d7562SSeymour, Shane M 	&driver_attr_max_sg_segs.attr,
4579442d7562SSeymour, Shane M 	&driver_attr_version.attr,
4580d9b43a10SSeymour, Shane M #if DEBUG
4581d9b43a10SSeymour, Shane M 	&driver_attr_debug_flag.attr,
4582d9b43a10SSeymour, Shane M #endif
4583442d7562SSeymour, Shane M 	NULL,
4584442d7562SSeymour, Shane M };
4585442d7562SSeymour, Shane M ATTRIBUTE_GROUPS(st_drv);
45861da177e4SLinus Torvalds 
45871da177e4SLinus Torvalds /* The sysfs simple class interface */
4588ee959b00STony Jones static ssize_t
defined_show(struct device * dev,struct device_attribute * attr,char * buf)4589af23782bSJeff Mahoney defined_show(struct device *dev, struct device_attribute *attr, char *buf)
45901da177e4SLinus Torvalds {
45917d15d6a4SJames Bottomley 	struct st_modedef *STm = dev_get_drvdata(dev);
45921da177e4SLinus Torvalds 	ssize_t l = 0;
45931da177e4SLinus Torvalds 
45941da177e4SLinus Torvalds 	l = snprintf(buf, PAGE_SIZE, "%d\n", STm->defined);
45951da177e4SLinus Torvalds 	return l;
45961da177e4SLinus Torvalds }
4597c69c6be5SGreg Kroah-Hartman static DEVICE_ATTR_RO(defined);
45981da177e4SLinus Torvalds 
4599ee959b00STony Jones static ssize_t
default_blksize_show(struct device * dev,struct device_attribute * attr,char * buf)4600af23782bSJeff Mahoney default_blksize_show(struct device *dev, struct device_attribute *attr,
4601af23782bSJeff Mahoney 		     char *buf)
46021da177e4SLinus Torvalds {
46037d15d6a4SJames Bottomley 	struct st_modedef *STm = dev_get_drvdata(dev);
46041da177e4SLinus Torvalds 	ssize_t l = 0;
46051da177e4SLinus Torvalds 
46061da177e4SLinus Torvalds 	l = snprintf(buf, PAGE_SIZE, "%d\n", STm->default_blksize);
46071da177e4SLinus Torvalds 	return l;
46081da177e4SLinus Torvalds }
4609c69c6be5SGreg Kroah-Hartman static DEVICE_ATTR_RO(default_blksize);
46101da177e4SLinus Torvalds 
4611ee959b00STony Jones static ssize_t
default_density_show(struct device * dev,struct device_attribute * attr,char * buf)4612af23782bSJeff Mahoney default_density_show(struct device *dev, struct device_attribute *attr,
4613af23782bSJeff Mahoney 		     char *buf)
46141da177e4SLinus Torvalds {
46157d15d6a4SJames Bottomley 	struct st_modedef *STm = dev_get_drvdata(dev);
46161da177e4SLinus Torvalds 	ssize_t l = 0;
46171da177e4SLinus Torvalds 	char *fmt;
46181da177e4SLinus Torvalds 
46191da177e4SLinus Torvalds 	fmt = STm->default_density >= 0 ? "0x%02x\n" : "%d\n";
46201da177e4SLinus Torvalds 	l = snprintf(buf, PAGE_SIZE, fmt, STm->default_density);
46211da177e4SLinus Torvalds 	return l;
46221da177e4SLinus Torvalds }
4623c69c6be5SGreg Kroah-Hartman static DEVICE_ATTR_RO(default_density);
46241da177e4SLinus Torvalds 
4625ee959b00STony Jones static ssize_t
default_compression_show(struct device * dev,struct device_attribute * attr,char * buf)4626af23782bSJeff Mahoney default_compression_show(struct device *dev, struct device_attribute *attr,
4627ee959b00STony Jones 			 char *buf)
46281da177e4SLinus Torvalds {
46297d15d6a4SJames Bottomley 	struct st_modedef *STm = dev_get_drvdata(dev);
46301da177e4SLinus Torvalds 	ssize_t l = 0;
46311da177e4SLinus Torvalds 
46321da177e4SLinus Torvalds 	l = snprintf(buf, PAGE_SIZE, "%d\n", STm->default_compression - 1);
46331da177e4SLinus Torvalds 	return l;
46341da177e4SLinus Torvalds }
4635c69c6be5SGreg Kroah-Hartman static DEVICE_ATTR_RO(default_compression);
46361da177e4SLinus Torvalds 
4637ee959b00STony Jones static ssize_t
options_show(struct device * dev,struct device_attribute * attr,char * buf)4638af23782bSJeff Mahoney options_show(struct device *dev, struct device_attribute *attr, char *buf)
4639b174be02SKai Makisara {
46407d15d6a4SJames Bottomley 	struct st_modedef *STm = dev_get_drvdata(dev);
46416c648d95SJeff Mahoney 	struct scsi_tape *STp = STm->tape;
46426c648d95SJeff Mahoney 	int options;
4643b174be02SKai Makisara 	ssize_t l = 0;
4644b174be02SKai Makisara 
4645b174be02SKai Makisara 	options = STm->do_buffer_writes ? MT_ST_BUFFER_WRITES : 0;
4646b174be02SKai Makisara 	options |= STm->do_async_writes ? MT_ST_ASYNC_WRITES : 0;
4647b174be02SKai Makisara 	options |= STm->do_read_ahead ? MT_ST_READ_AHEAD : 0;
4648b174be02SKai Makisara 	DEB( options |= debugging ? MT_ST_DEBUGGING : 0 );
4649b174be02SKai Makisara 	options |= STp->two_fm ? MT_ST_TWO_FM : 0;
4650b174be02SKai Makisara 	options |= STp->fast_mteom ? MT_ST_FAST_MTEOM : 0;
4651b174be02SKai Makisara 	options |= STm->defaults_for_writes ? MT_ST_DEF_WRITES : 0;
4652b174be02SKai Makisara 	options |= STp->can_bsr ? MT_ST_CAN_BSR : 0;
4653b174be02SKai Makisara 	options |= STp->omit_blklims ? MT_ST_NO_BLKLIMS : 0;
4654b174be02SKai Makisara 	options |= STp->can_partitions ? MT_ST_CAN_PARTITIONS : 0;
4655b174be02SKai Makisara 	options |= STp->scsi2_logical ? MT_ST_SCSI2LOGICAL : 0;
4656b174be02SKai Makisara 	options |= STm->sysv ? MT_ST_SYSV : 0;
4657b174be02SKai Makisara 	options |= STp->immediate ? MT_ST_NOWAIT : 0;
4658c743e44fSLee Duncan 	options |= STp->immediate_filemark ? MT_ST_NOWAIT_EOF : 0;
4659b174be02SKai Makisara 	options |= STp->sili ? MT_ST_SILI : 0;
4660b174be02SKai Makisara 
4661b174be02SKai Makisara 	l = snprintf(buf, PAGE_SIZE, "0x%08x\n", options);
4662b174be02SKai Makisara 	return l;
4663b174be02SKai Makisara }
4664c69c6be5SGreg Kroah-Hartman static DEVICE_ATTR_RO(options);
4665b174be02SKai Makisara 
466605545c92SSeymour, Shane M /* Support for tape stats */
466705545c92SSeymour, Shane M 
466805545c92SSeymour, Shane M /**
466905545c92SSeymour, Shane M  * read_cnt_show - return read count - count of reads made from tape drive
467005545c92SSeymour, Shane M  * @dev: struct device
467105545c92SSeymour, Shane M  * @attr: attribute structure
467205545c92SSeymour, Shane M  * @buf: buffer to return formatted data in
467305545c92SSeymour, Shane M  */
read_cnt_show(struct device * dev,struct device_attribute * attr,char * buf)467405545c92SSeymour, Shane M static ssize_t read_cnt_show(struct device *dev,
467505545c92SSeymour, Shane M 	struct device_attribute *attr, char *buf)
467605545c92SSeymour, Shane M {
467705545c92SSeymour, Shane M 	struct st_modedef *STm = dev_get_drvdata(dev);
467805545c92SSeymour, Shane M 
467905545c92SSeymour, Shane M 	return sprintf(buf, "%lld",
468005545c92SSeymour, Shane M 		       (long long)atomic64_read(&STm->tape->stats->read_cnt));
468105545c92SSeymour, Shane M }
468205545c92SSeymour, Shane M static DEVICE_ATTR_RO(read_cnt);
468305545c92SSeymour, Shane M 
468405545c92SSeymour, Shane M /**
468505545c92SSeymour, Shane M  * read_byte_cnt_show - return read byte count - tape drives
468605545c92SSeymour, Shane M  * may use blocks less than 512 bytes this gives the raw byte count of
468705545c92SSeymour, Shane M  * of data read from the tape drive.
468805545c92SSeymour, Shane M  * @dev: struct device
468905545c92SSeymour, Shane M  * @attr: attribute structure
469005545c92SSeymour, Shane M  * @buf: buffer to return formatted data in
469105545c92SSeymour, Shane M  */
read_byte_cnt_show(struct device * dev,struct device_attribute * attr,char * buf)469205545c92SSeymour, Shane M static ssize_t read_byte_cnt_show(struct device *dev,
469305545c92SSeymour, Shane M 	struct device_attribute *attr, char *buf)
469405545c92SSeymour, Shane M {
469505545c92SSeymour, Shane M 	struct st_modedef *STm = dev_get_drvdata(dev);
469605545c92SSeymour, Shane M 
469705545c92SSeymour, Shane M 	return sprintf(buf, "%lld",
469805545c92SSeymour, Shane M 		       (long long)atomic64_read(&STm->tape->stats->read_byte_cnt));
469905545c92SSeymour, Shane M }
470005545c92SSeymour, Shane M static DEVICE_ATTR_RO(read_byte_cnt);
470105545c92SSeymour, Shane M 
470205545c92SSeymour, Shane M /**
4703e2dca2a2SRandy Dunlap  * read_ns_show - return read ns - overall time spent waiting on reads in ns.
470405545c92SSeymour, Shane M  * @dev: struct device
470505545c92SSeymour, Shane M  * @attr: attribute structure
470605545c92SSeymour, Shane M  * @buf: buffer to return formatted data in
470705545c92SSeymour, Shane M  */
read_ns_show(struct device * dev,struct device_attribute * attr,char * buf)470805545c92SSeymour, Shane M static ssize_t read_ns_show(struct device *dev,
470905545c92SSeymour, Shane M 	struct device_attribute *attr, char *buf)
471005545c92SSeymour, Shane M {
471105545c92SSeymour, Shane M 	struct st_modedef *STm = dev_get_drvdata(dev);
471205545c92SSeymour, Shane M 
471305545c92SSeymour, Shane M 	return sprintf(buf, "%lld",
471405545c92SSeymour, Shane M 		       (long long)atomic64_read(&STm->tape->stats->tot_read_time));
471505545c92SSeymour, Shane M }
471605545c92SSeymour, Shane M static DEVICE_ATTR_RO(read_ns);
471705545c92SSeymour, Shane M 
471805545c92SSeymour, Shane M /**
471905545c92SSeymour, Shane M  * write_cnt_show - write count - number of user calls
472005545c92SSeymour, Shane M  * to write(2) that have written data to tape.
472105545c92SSeymour, Shane M  * @dev: struct device
472205545c92SSeymour, Shane M  * @attr: attribute structure
472305545c92SSeymour, Shane M  * @buf: buffer to return formatted data in
472405545c92SSeymour, Shane M  */
write_cnt_show(struct device * dev,struct device_attribute * attr,char * buf)472505545c92SSeymour, Shane M static ssize_t write_cnt_show(struct device *dev,
472605545c92SSeymour, Shane M 	struct device_attribute *attr, char *buf)
472705545c92SSeymour, Shane M {
472805545c92SSeymour, Shane M 	struct st_modedef *STm = dev_get_drvdata(dev);
472905545c92SSeymour, Shane M 
473005545c92SSeymour, Shane M 	return sprintf(buf, "%lld",
473105545c92SSeymour, Shane M 		       (long long)atomic64_read(&STm->tape->stats->write_cnt));
473205545c92SSeymour, Shane M }
473305545c92SSeymour, Shane M static DEVICE_ATTR_RO(write_cnt);
473405545c92SSeymour, Shane M 
473505545c92SSeymour, Shane M /**
473605545c92SSeymour, Shane M  * write_byte_cnt_show - write byte count - raw count of
473705545c92SSeymour, Shane M  * bytes written to tape.
473805545c92SSeymour, Shane M  * @dev: struct device
473905545c92SSeymour, Shane M  * @attr: attribute structure
474005545c92SSeymour, Shane M  * @buf: buffer to return formatted data in
474105545c92SSeymour, Shane M  */
write_byte_cnt_show(struct device * dev,struct device_attribute * attr,char * buf)474205545c92SSeymour, Shane M static ssize_t write_byte_cnt_show(struct device *dev,
474305545c92SSeymour, Shane M 	struct device_attribute *attr, char *buf)
474405545c92SSeymour, Shane M {
474505545c92SSeymour, Shane M 	struct st_modedef *STm = dev_get_drvdata(dev);
474605545c92SSeymour, Shane M 
474705545c92SSeymour, Shane M 	return sprintf(buf, "%lld",
474805545c92SSeymour, Shane M 		       (long long)atomic64_read(&STm->tape->stats->write_byte_cnt));
474905545c92SSeymour, Shane M }
475005545c92SSeymour, Shane M static DEVICE_ATTR_RO(write_byte_cnt);
475105545c92SSeymour, Shane M 
475205545c92SSeymour, Shane M /**
475305545c92SSeymour, Shane M  * write_ns_show - write ns - number of nanoseconds waiting on write
475405545c92SSeymour, Shane M  * requests to complete.
475505545c92SSeymour, Shane M  * @dev: struct device
475605545c92SSeymour, Shane M  * @attr: attribute structure
475705545c92SSeymour, Shane M  * @buf: buffer to return formatted data in
475805545c92SSeymour, Shane M  */
write_ns_show(struct device * dev,struct device_attribute * attr,char * buf)475905545c92SSeymour, Shane M static ssize_t write_ns_show(struct device *dev,
476005545c92SSeymour, Shane M 	struct device_attribute *attr, char *buf)
476105545c92SSeymour, Shane M {
476205545c92SSeymour, Shane M 	struct st_modedef *STm = dev_get_drvdata(dev);
476305545c92SSeymour, Shane M 
476405545c92SSeymour, Shane M 	return sprintf(buf, "%lld",
476505545c92SSeymour, Shane M 		       (long long)atomic64_read(&STm->tape->stats->tot_write_time));
476605545c92SSeymour, Shane M }
476705545c92SSeymour, Shane M static DEVICE_ATTR_RO(write_ns);
476805545c92SSeymour, Shane M 
476905545c92SSeymour, Shane M /**
477005545c92SSeymour, Shane M  * in_flight_show - number of I/Os currently in flight -
477105545c92SSeymour, Shane M  * in most cases this will be either 0 or 1. It may be higher if someone
477205545c92SSeymour, Shane M  * has also issued other SCSI commands such as via an ioctl.
477305545c92SSeymour, Shane M  * @dev: struct device
477405545c92SSeymour, Shane M  * @attr: attribute structure
477505545c92SSeymour, Shane M  * @buf: buffer to return formatted data in
477605545c92SSeymour, Shane M  */
in_flight_show(struct device * dev,struct device_attribute * attr,char * buf)477705545c92SSeymour, Shane M static ssize_t in_flight_show(struct device *dev,
477805545c92SSeymour, Shane M 	struct device_attribute *attr, char *buf)
477905545c92SSeymour, Shane M {
478005545c92SSeymour, Shane M 	struct st_modedef *STm = dev_get_drvdata(dev);
478105545c92SSeymour, Shane M 
478205545c92SSeymour, Shane M 	return sprintf(buf, "%lld",
478305545c92SSeymour, Shane M 		       (long long)atomic64_read(&STm->tape->stats->in_flight));
478405545c92SSeymour, Shane M }
478505545c92SSeymour, Shane M static DEVICE_ATTR_RO(in_flight);
478605545c92SSeymour, Shane M 
478705545c92SSeymour, Shane M /**
478805545c92SSeymour, Shane M  * io_ns_show - io wait ns - this is the number of ns spent
478905545c92SSeymour, Shane M  * waiting on all I/O to complete. This includes tape movement commands
479005545c92SSeymour, Shane M  * such as rewinding, seeking to end of file or tape, it also includes
479105545c92SSeymour, Shane M  * read and write. To determine the time spent on tape movement
479205545c92SSeymour, Shane M  * subtract the read and write ns from this value.
479305545c92SSeymour, Shane M  * @dev: struct device
479405545c92SSeymour, Shane M  * @attr: attribute structure
479505545c92SSeymour, Shane M  * @buf: buffer to return formatted data in
479605545c92SSeymour, Shane M  */
io_ns_show(struct device * dev,struct device_attribute * attr,char * buf)479705545c92SSeymour, Shane M static ssize_t io_ns_show(struct device *dev,
479805545c92SSeymour, Shane M 	struct device_attribute *attr, char *buf)
479905545c92SSeymour, Shane M {
480005545c92SSeymour, Shane M 	struct st_modedef *STm = dev_get_drvdata(dev);
480105545c92SSeymour, Shane M 
480205545c92SSeymour, Shane M 	return sprintf(buf, "%lld",
480305545c92SSeymour, Shane M 		       (long long)atomic64_read(&STm->tape->stats->tot_io_time));
480405545c92SSeymour, Shane M }
480505545c92SSeymour, Shane M static DEVICE_ATTR_RO(io_ns);
480605545c92SSeymour, Shane M 
480705545c92SSeymour, Shane M /**
480805545c92SSeymour, Shane M  * other_cnt_show - other io count - this is the number of
480905545c92SSeymour, Shane M  * I/O requests other than read and write requests.
481005545c92SSeymour, Shane M  * Typically these are tape movement requests but will include driver
481105545c92SSeymour, Shane M  * tape movement. This includes only requests issued by the st driver.
481205545c92SSeymour, Shane M  * @dev: struct device
481305545c92SSeymour, Shane M  * @attr: attribute structure
481405545c92SSeymour, Shane M  * @buf: buffer to return formatted data in
481505545c92SSeymour, Shane M  */
other_cnt_show(struct device * dev,struct device_attribute * attr,char * buf)481605545c92SSeymour, Shane M static ssize_t other_cnt_show(struct device *dev,
481705545c92SSeymour, Shane M 	struct device_attribute *attr, char *buf)
481805545c92SSeymour, Shane M {
481905545c92SSeymour, Shane M 	struct st_modedef *STm = dev_get_drvdata(dev);
482005545c92SSeymour, Shane M 
482105545c92SSeymour, Shane M 	return sprintf(buf, "%lld",
482205545c92SSeymour, Shane M 		       (long long)atomic64_read(&STm->tape->stats->other_cnt));
482305545c92SSeymour, Shane M }
482405545c92SSeymour, Shane M static DEVICE_ATTR_RO(other_cnt);
482505545c92SSeymour, Shane M 
482605545c92SSeymour, Shane M /**
482705545c92SSeymour, Shane M  * resid_cnt_show - A count of the number of times we get a residual
482805545c92SSeymour, Shane M  * count - this should indicate someone issuing reads larger than the
482905545c92SSeymour, Shane M  * block size on tape.
483005545c92SSeymour, Shane M  * @dev: struct device
483105545c92SSeymour, Shane M  * @attr: attribute structure
483205545c92SSeymour, Shane M  * @buf: buffer to return formatted data in
483305545c92SSeymour, Shane M  */
resid_cnt_show(struct device * dev,struct device_attribute * attr,char * buf)483405545c92SSeymour, Shane M static ssize_t resid_cnt_show(struct device *dev,
483505545c92SSeymour, Shane M 	struct device_attribute *attr, char *buf)
483605545c92SSeymour, Shane M {
483705545c92SSeymour, Shane M 	struct st_modedef *STm = dev_get_drvdata(dev);
483805545c92SSeymour, Shane M 
483905545c92SSeymour, Shane M 	return sprintf(buf, "%lld",
484005545c92SSeymour, Shane M 		       (long long)atomic64_read(&STm->tape->stats->resid_cnt));
484105545c92SSeymour, Shane M }
484205545c92SSeymour, Shane M static DEVICE_ATTR_RO(resid_cnt);
484305545c92SSeymour, Shane M 
4844c69c6be5SGreg Kroah-Hartman static struct attribute *st_dev_attrs[] = {
4845c69c6be5SGreg Kroah-Hartman 	&dev_attr_defined.attr,
4846c69c6be5SGreg Kroah-Hartman 	&dev_attr_default_blksize.attr,
4847c69c6be5SGreg Kroah-Hartman 	&dev_attr_default_density.attr,
4848c69c6be5SGreg Kroah-Hartman 	&dev_attr_default_compression.attr,
4849c69c6be5SGreg Kroah-Hartman 	&dev_attr_options.attr,
4850c69c6be5SGreg Kroah-Hartman 	NULL,
4851af23782bSJeff Mahoney };
485205545c92SSeymour, Shane M 
485305545c92SSeymour, Shane M static struct attribute *st_stats_attrs[] = {
485405545c92SSeymour, Shane M 	&dev_attr_read_cnt.attr,
485505545c92SSeymour, Shane M 	&dev_attr_read_byte_cnt.attr,
485605545c92SSeymour, Shane M 	&dev_attr_read_ns.attr,
485705545c92SSeymour, Shane M 	&dev_attr_write_cnt.attr,
485805545c92SSeymour, Shane M 	&dev_attr_write_byte_cnt.attr,
485905545c92SSeymour, Shane M 	&dev_attr_write_ns.attr,
486005545c92SSeymour, Shane M 	&dev_attr_in_flight.attr,
486105545c92SSeymour, Shane M 	&dev_attr_io_ns.attr,
486205545c92SSeymour, Shane M 	&dev_attr_other_cnt.attr,
486305545c92SSeymour, Shane M 	&dev_attr_resid_cnt.attr,
486405545c92SSeymour, Shane M 	NULL,
486505545c92SSeymour, Shane M };
486605545c92SSeymour, Shane M 
486705545c92SSeymour, Shane M static struct attribute_group stats_group = {
486805545c92SSeymour, Shane M 	.name = "stats",
486905545c92SSeymour, Shane M 	.attrs = st_stats_attrs,
487005545c92SSeymour, Shane M };
487105545c92SSeymour, Shane M 
487205545c92SSeymour, Shane M static struct attribute_group st_group = {
487305545c92SSeymour, Shane M 	.attrs = st_dev_attrs,
487405545c92SSeymour, Shane M };
487505545c92SSeymour, Shane M 
487605545c92SSeymour, Shane M static const struct attribute_group *st_dev_groups[] = {
487705545c92SSeymour, Shane M 	&st_group,
487805545c92SSeymour, Shane M 	&stats_group,
487905545c92SSeymour, Shane M 	NULL,
488005545c92SSeymour, Shane M };
4881b174be02SKai Makisara 
48821da177e4SLinus Torvalds /* The following functions may be useful for a larger audience. */
sgl_map_user_pages(struct st_buffer * STbp,const unsigned int max_pages,unsigned long uaddr,size_t count,int rw)48836620742fSFUJITA Tomonori static int sgl_map_user_pages(struct st_buffer *STbp,
48846620742fSFUJITA Tomonori 			      const unsigned int max_pages, unsigned long uaddr,
48856620742fSFUJITA Tomonori 			      size_t count, int rw)
48861da177e4SLinus Torvalds {
488707542b83SJames Bottomley 	unsigned long end = (uaddr + count + PAGE_SIZE - 1) >> PAGE_SHIFT;
488807542b83SJames Bottomley 	unsigned long start = uaddr >> PAGE_SHIFT;
488907542b83SJames Bottomley 	const int nr_pages = end - start;
489008e9cbe7SJohn Hubbard 	int res, i;
48911da177e4SLinus Torvalds 	struct page **pages;
48926620742fSFUJITA Tomonori 	struct rq_map_data *mdata = &STbp->map_data;
48931da177e4SLinus Torvalds 
48941da177e4SLinus Torvalds 	/* User attempted Overflow! */
48951da177e4SLinus Torvalds 	if ((uaddr + count) < uaddr)
48961da177e4SLinus Torvalds 		return -EINVAL;
48971da177e4SLinus Torvalds 
48981da177e4SLinus Torvalds 	/* Too big */
48991da177e4SLinus Torvalds         if (nr_pages > max_pages)
49001da177e4SLinus Torvalds 		return -ENOMEM;
49011da177e4SLinus Torvalds 
49021da177e4SLinus Torvalds 	/* Hmm? */
49031da177e4SLinus Torvalds 	if (count == 0)
49041da177e4SLinus Torvalds 		return 0;
49051da177e4SLinus Torvalds 
49066da2ec56SKees Cook 	pages = kmalloc_array(max_pages, sizeof(*pages), GFP_KERNEL);
49076da2ec56SKees Cook 	if (pages == NULL)
49081da177e4SLinus Torvalds 		return -ENOMEM;
49091da177e4SLinus Torvalds 
49101da177e4SLinus Torvalds         /* Try to fault in all of the necessary pages */
49111da177e4SLinus Torvalds         /* rw==READ means read from drive, write into memory area */
491208e9cbe7SJohn Hubbard 	res = pin_user_pages_fast(uaddr, nr_pages, rw == READ ? FOLL_WRITE : 0,
491373b0140bSIra Weiny 				  pages);
49141da177e4SLinus Torvalds 
49151da177e4SLinus Torvalds 	/* Errors and no page mapped should return here */
49161da177e4SLinus Torvalds 	if (res < nr_pages)
49171da177e4SLinus Torvalds 		goto out_unmap;
49181da177e4SLinus Torvalds 
49191da177e4SLinus Torvalds         for (i=0; i < nr_pages; i++) {
49201da177e4SLinus Torvalds                 /* FIXME: flush superflous for rw==READ,
49211da177e4SLinus Torvalds                  * probably wrong function for rw==WRITE
49221da177e4SLinus Torvalds                  */
49231da177e4SLinus Torvalds 		flush_dcache_page(pages[i]);
49241da177e4SLinus Torvalds         }
49251da177e4SLinus Torvalds 
49266620742fSFUJITA Tomonori 	mdata->offset = uaddr & ~PAGE_MASK;
49276620742fSFUJITA Tomonori 	STbp->mapped_pages = pages;
49281da177e4SLinus Torvalds 
49291da177e4SLinus Torvalds 	return nr_pages;
49301da177e4SLinus Torvalds  out_unmap:
49311da177e4SLinus Torvalds 	if (res > 0) {
493208e9cbe7SJohn Hubbard 		unpin_user_pages(pages, res);
49336bc733e9SHugh Dickins 		res = 0;
49341da177e4SLinus Torvalds 	}
49351da177e4SLinus Torvalds 	kfree(pages);
49361da177e4SLinus Torvalds 	return res;
49371da177e4SLinus Torvalds }
49381da177e4SLinus Torvalds 
49391da177e4SLinus Torvalds 
49401da177e4SLinus Torvalds /* And unmap them... */
sgl_unmap_user_pages(struct st_buffer * STbp,const unsigned int nr_pages,int dirtied)49416620742fSFUJITA Tomonori static int sgl_unmap_user_pages(struct st_buffer *STbp,
49426620742fSFUJITA Tomonori 				const unsigned int nr_pages, int dirtied)
49431da177e4SLinus Torvalds {
494408e9cbe7SJohn Hubbard 	/* FIXME: cache flush missing for rw==READ */
494508e9cbe7SJohn Hubbard 	unpin_user_pages_dirty_lock(STbp->mapped_pages, nr_pages, dirtied);
49461da177e4SLinus Torvalds 
49476620742fSFUJITA Tomonori 	kfree(STbp->mapped_pages);
49486620742fSFUJITA Tomonori 	STbp->mapped_pages = NULL;
49491da177e4SLinus Torvalds 
49501da177e4SLinus Torvalds 	return 0;
49511da177e4SLinus Torvalds }
4952