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 */
417*9604eea5SJohn Meneghini if (cmdstatp->have_sense && scode == UNIT_ATTENTION && cmdstatp->sense_hdr.asc == 0x29)
418*9604eea5SJohn 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
8381da177e4SLinus Torvalds /*
8391da177e4SLinus Torvalds * If there was a bus reset, block further access
8401da177e4SLinus Torvalds * to this device.
8411da177e4SLinus Torvalds */
8421da177e4SLinus Torvalds if (STp->pos_unknown)
8431da177e4SLinus Torvalds return (-EIO);
8441da177e4SLinus Torvalds
8451da177e4SLinus Torvalds if (STp->ready != ST_READY)
8461da177e4SLinus Torvalds return 0;
8471da177e4SLinus Torvalds STps = &(STp->ps[STp->partition]);
8481da177e4SLinus Torvalds if (STps->rw == ST_WRITING) /* Writing */
8498ef8d594SAdrian Bunk return st_flush_write_buffer(STp);
8501da177e4SLinus Torvalds
8511da177e4SLinus Torvalds if (STp->block_size == 0)
8521da177e4SLinus Torvalds return 0;
8531da177e4SLinus Torvalds
8541da177e4SLinus Torvalds backspace = ((STp->buffer)->buffer_bytes +
8551da177e4SLinus Torvalds (STp->buffer)->read_pointer) / STp->block_size -
8561da177e4SLinus Torvalds ((STp->buffer)->read_pointer + STp->block_size - 1) /
8571da177e4SLinus Torvalds STp->block_size;
8581da177e4SLinus Torvalds (STp->buffer)->buffer_bytes = 0;
8591da177e4SLinus Torvalds (STp->buffer)->read_pointer = 0;
8601da177e4SLinus Torvalds result = 0;
8611da177e4SLinus Torvalds if (!seek_next) {
8621da177e4SLinus Torvalds if (STps->eof == ST_FM_HIT) {
8631da177e4SLinus Torvalds result = cross_eof(STp, 0); /* Back over the EOF hit */
8641da177e4SLinus Torvalds if (!result)
8651da177e4SLinus Torvalds STps->eof = ST_NOEOF;
8661da177e4SLinus Torvalds else {
8671da177e4SLinus Torvalds if (STps->drv_file >= 0)
8681da177e4SLinus Torvalds STps->drv_file++;
8691da177e4SLinus Torvalds STps->drv_block = 0;
8701da177e4SLinus Torvalds }
8711da177e4SLinus Torvalds }
8721da177e4SLinus Torvalds if (!result && backspace > 0)
8731da177e4SLinus Torvalds result = st_int_ioctl(STp, MTBSR, backspace);
8741da177e4SLinus Torvalds } else if (STps->eof == ST_FM_HIT) {
8751da177e4SLinus Torvalds if (STps->drv_file >= 0)
8761da177e4SLinus Torvalds STps->drv_file++;
8771da177e4SLinus Torvalds STps->drv_block = 0;
8781da177e4SLinus Torvalds STps->eof = ST_NOEOF;
8791da177e4SLinus Torvalds }
8801da177e4SLinus Torvalds return result;
8811da177e4SLinus Torvalds
8821da177e4SLinus Torvalds }
8831da177e4SLinus Torvalds
8841da177e4SLinus Torvalds /* Set the mode parameters */
set_mode_densblk(struct scsi_tape * STp,struct st_modedef * STm)8851da177e4SLinus Torvalds static int set_mode_densblk(struct scsi_tape * STp, struct st_modedef * STm)
8861da177e4SLinus Torvalds {
8871da177e4SLinus Torvalds int set_it = 0;
8881da177e4SLinus Torvalds unsigned long arg;
8891da177e4SLinus Torvalds
8901da177e4SLinus Torvalds if (!STp->density_changed &&
8911da177e4SLinus Torvalds STm->default_density >= 0 &&
8921da177e4SLinus Torvalds STm->default_density != STp->density) {
8931da177e4SLinus Torvalds arg = STm->default_density;
8941da177e4SLinus Torvalds set_it = 1;
8951da177e4SLinus Torvalds } else
8961da177e4SLinus Torvalds arg = STp->density;
8971da177e4SLinus Torvalds arg <<= MT_ST_DENSITY_SHIFT;
8981da177e4SLinus Torvalds if (!STp->blksize_changed &&
8991da177e4SLinus Torvalds STm->default_blksize >= 0 &&
9001da177e4SLinus Torvalds STm->default_blksize != STp->block_size) {
9011da177e4SLinus Torvalds arg |= STm->default_blksize;
9021da177e4SLinus Torvalds set_it = 1;
9031da177e4SLinus Torvalds } else
9041da177e4SLinus Torvalds arg |= STp->block_size;
9051da177e4SLinus Torvalds if (set_it &&
9061da177e4SLinus Torvalds st_int_ioctl(STp, SET_DENS_AND_BLK, arg)) {
907b30d8bcaSHannes Reinecke st_printk(KERN_WARNING, STp,
908b30d8bcaSHannes Reinecke "Can't set default block size to %d bytes "
909b30d8bcaSHannes Reinecke "and density %x.\n",
910b30d8bcaSHannes Reinecke STm->default_blksize, STm->default_density);
9111da177e4SLinus Torvalds if (modes_defined)
9121da177e4SLinus Torvalds return (-EINVAL);
9131da177e4SLinus Torvalds }
9141da177e4SLinus Torvalds return 0;
9151da177e4SLinus Torvalds }
9161da177e4SLinus Torvalds
9171da177e4SLinus Torvalds
9188b05b773SMike Christie /* Lock or unlock the drive door. Don't use when st_request allocated. */
do_door_lock(struct scsi_tape * STp,int do_lock)9191da177e4SLinus Torvalds static int do_door_lock(struct scsi_tape * STp, int do_lock)
9201da177e4SLinus Torvalds {
921dccfa688SChristoph Hellwig int retval;
9221da177e4SLinus Torvalds
923b30d8bcaSHannes Reinecke DEBC_printk(STp, "%socking drive door.\n", do_lock ? "L" : "Unl");
924dccfa688SChristoph Hellwig
925dccfa688SChristoph Hellwig retval = scsi_set_medium_removal(STp->device,
926dccfa688SChristoph Hellwig do_lock ? SCSI_REMOVAL_PREVENT : SCSI_REMOVAL_ALLOW);
927dccfa688SChristoph Hellwig if (!retval)
9281da177e4SLinus Torvalds STp->door_locked = do_lock ? ST_LOCKED_EXPLICIT : ST_UNLOCKED;
929dccfa688SChristoph Hellwig else
9301da177e4SLinus Torvalds STp->door_locked = ST_LOCK_FAILS;
9311da177e4SLinus Torvalds return retval;
9321da177e4SLinus Torvalds }
9331da177e4SLinus Torvalds
9341da177e4SLinus Torvalds
9351da177e4SLinus Torvalds /* Set the internal state after reset */
reset_state(struct scsi_tape * STp)9361da177e4SLinus Torvalds static void reset_state(struct scsi_tape *STp)
9371da177e4SLinus Torvalds {
9381da177e4SLinus Torvalds int i;
9391da177e4SLinus Torvalds struct st_partstat *STps;
9401da177e4SLinus Torvalds
9411da177e4SLinus Torvalds STp->pos_unknown = 0;
9421da177e4SLinus Torvalds for (i = 0; i < ST_NBR_PARTITIONS; i++) {
9431da177e4SLinus Torvalds STps = &(STp->ps[i]);
9441da177e4SLinus Torvalds STps->rw = ST_IDLE;
9451da177e4SLinus Torvalds STps->eof = ST_NOEOF;
9461da177e4SLinus Torvalds STps->at_sm = 0;
9471da177e4SLinus Torvalds STps->last_block_valid = 0;
9481da177e4SLinus Torvalds STps->drv_block = -1;
9491da177e4SLinus Torvalds STps->drv_file = -1;
9501da177e4SLinus Torvalds }
9511da177e4SLinus Torvalds if (STp->can_partitions) {
9521da177e4SLinus Torvalds STp->partition = find_partition(STp);
9531da177e4SLinus Torvalds if (STp->partition < 0)
9541da177e4SLinus Torvalds STp->partition = 0;
9551da177e4SLinus Torvalds STp->new_partition = STp->partition;
9561da177e4SLinus Torvalds }
9571da177e4SLinus Torvalds }
9581da177e4SLinus Torvalds
9591da177e4SLinus Torvalds /* Test if the drive is ready. Returns either one of the codes below or a negative system
9601da177e4SLinus Torvalds error code. */
9611da177e4SLinus Torvalds #define CHKRES_READY 0
9621da177e4SLinus Torvalds #define CHKRES_NEW_SESSION 1
9631da177e4SLinus Torvalds #define CHKRES_NOT_READY 2
9641da177e4SLinus Torvalds #define CHKRES_NO_TAPE 3
9651da177e4SLinus Torvalds
9661da177e4SLinus Torvalds #define MAX_ATTENTIONS 10
9671da177e4SLinus Torvalds
test_ready(struct scsi_tape * STp,int do_wait)9681da177e4SLinus Torvalds static int test_ready(struct scsi_tape *STp, int do_wait)
9691da177e4SLinus Torvalds {
9701da177e4SLinus Torvalds int attentions, waits, max_wait, scode;
9711da177e4SLinus Torvalds int retval = CHKRES_READY, new_session = 0;
9721da177e4SLinus Torvalds unsigned char cmd[MAX_COMMAND_SIZE];
97302ae2c0eSKai Makisara struct st_request *SRpnt = NULL;
9741da177e4SLinus Torvalds struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat;
9751da177e4SLinus Torvalds
9761da177e4SLinus Torvalds max_wait = do_wait ? ST_BLOCK_SECONDS : 0;
9771da177e4SLinus Torvalds
9781da177e4SLinus Torvalds for (attentions=waits=0; ; ) {
9791da177e4SLinus Torvalds memset((void *) &cmd[0], 0, MAX_COMMAND_SIZE);
9801da177e4SLinus Torvalds cmd[0] = TEST_UNIT_READY;
98102ae2c0eSKai Makisara SRpnt = st_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE,
98202ae2c0eSKai Makisara STp->long_timeout, MAX_READY_RETRIES, 1);
9831da177e4SLinus Torvalds
98402ae2c0eSKai Makisara if (!SRpnt) {
98502ae2c0eSKai Makisara retval = (STp->buffer)->syscall_result;
9861da177e4SLinus Torvalds break;
98702ae2c0eSKai Makisara }
9881da177e4SLinus Torvalds
9891da177e4SLinus Torvalds if (cmdstatp->have_sense) {
9901da177e4SLinus Torvalds
9911da177e4SLinus Torvalds scode = cmdstatp->sense_hdr.sense_key;
9921da177e4SLinus Torvalds
9931da177e4SLinus Torvalds if (scode == UNIT_ATTENTION) { /* New media? */
9941da177e4SLinus Torvalds new_session = 1;
9951da177e4SLinus Torvalds if (attentions < MAX_ATTENTIONS) {
9961da177e4SLinus Torvalds attentions++;
9971da177e4SLinus Torvalds continue;
9981da177e4SLinus Torvalds }
9991da177e4SLinus Torvalds else {
10001da177e4SLinus Torvalds retval = (-EIO);
10011da177e4SLinus Torvalds break;
10021da177e4SLinus Torvalds }
10031da177e4SLinus Torvalds }
10041da177e4SLinus Torvalds
10051da177e4SLinus Torvalds if (scode == NOT_READY) {
10061da177e4SLinus Torvalds if (waits < max_wait) {
10071da177e4SLinus Torvalds if (msleep_interruptible(1000)) {
10081da177e4SLinus Torvalds retval = (-EINTR);
10091da177e4SLinus Torvalds break;
10101da177e4SLinus Torvalds }
10111da177e4SLinus Torvalds waits++;
10121da177e4SLinus Torvalds continue;
10131da177e4SLinus Torvalds }
10141da177e4SLinus Torvalds else {
10151da177e4SLinus Torvalds if ((STp->device)->scsi_level >= SCSI_2 &&
10161da177e4SLinus Torvalds cmdstatp->sense_hdr.asc == 0x3a) /* Check ASC */
10171da177e4SLinus Torvalds retval = CHKRES_NO_TAPE;
10181da177e4SLinus Torvalds else
10191da177e4SLinus Torvalds retval = CHKRES_NOT_READY;
10201da177e4SLinus Torvalds break;
10211da177e4SLinus Torvalds }
10221da177e4SLinus Torvalds }
10231da177e4SLinus Torvalds }
10241da177e4SLinus Torvalds
10251da177e4SLinus Torvalds retval = (STp->buffer)->syscall_result;
10261da177e4SLinus Torvalds if (!retval)
10271da177e4SLinus Torvalds retval = new_session ? CHKRES_NEW_SESSION : CHKRES_READY;
10281da177e4SLinus Torvalds break;
10291da177e4SLinus Torvalds }
10301da177e4SLinus Torvalds
103102ae2c0eSKai Makisara if (SRpnt != NULL)
10328b05b773SMike Christie st_release_request(SRpnt);
10331da177e4SLinus Torvalds return retval;
10341da177e4SLinus Torvalds }
10351da177e4SLinus Torvalds
10361da177e4SLinus Torvalds
10371da177e4SLinus Torvalds /* See if the drive is ready and gather information about the tape. Return values:
10381da177e4SLinus Torvalds < 0 negative error code from errno.h
10391da177e4SLinus Torvalds 0 drive ready
10401da177e4SLinus Torvalds 1 drive not ready (possibly no tape)
10411da177e4SLinus Torvalds */
check_tape(struct scsi_tape * STp,struct file * filp)10421da177e4SLinus Torvalds static int check_tape(struct scsi_tape *STp, struct file *filp)
10431da177e4SLinus Torvalds {
10441da177e4SLinus Torvalds int i, retval, new_session = 0, do_wait;
10451da177e4SLinus Torvalds unsigned char cmd[MAX_COMMAND_SIZE], saved_cleaning;
10461da177e4SLinus Torvalds unsigned short st_flags = filp->f_flags;
10478b05b773SMike Christie struct st_request *SRpnt = NULL;
10481da177e4SLinus Torvalds struct st_modedef *STm;
10491da177e4SLinus Torvalds struct st_partstat *STps;
1050496ad9aaSAl Viro struct inode *inode = file_inode(filp);
10511da177e4SLinus Torvalds int mode = TAPE_MODE(inode);
10521da177e4SLinus Torvalds
10531da177e4SLinus Torvalds STp->ready = ST_READY;
10541da177e4SLinus Torvalds
10551da177e4SLinus Torvalds if (mode != STp->current_mode) {
1056b30d8bcaSHannes Reinecke DEBC_printk(STp, "Mode change from %d to %d.\n",
1057b30d8bcaSHannes Reinecke STp->current_mode, mode);
10581da177e4SLinus Torvalds new_session = 1;
10591da177e4SLinus Torvalds STp->current_mode = mode;
10601da177e4SLinus Torvalds }
10611da177e4SLinus Torvalds STm = &(STp->modes[STp->current_mode]);
10621da177e4SLinus Torvalds
10631da177e4SLinus Torvalds saved_cleaning = STp->cleaning_req;
10641da177e4SLinus Torvalds STp->cleaning_req = 0;
10651da177e4SLinus Torvalds
10661da177e4SLinus Torvalds do_wait = ((filp->f_flags & O_NONBLOCK) == 0);
10671da177e4SLinus Torvalds retval = test_ready(STp, do_wait);
10681da177e4SLinus Torvalds
10691da177e4SLinus Torvalds if (retval < 0)
10701da177e4SLinus Torvalds goto err_out;
10711da177e4SLinus Torvalds
10721da177e4SLinus Torvalds if (retval == CHKRES_NEW_SESSION) {
10731da177e4SLinus Torvalds STp->pos_unknown = 0;
10741da177e4SLinus Torvalds STp->partition = STp->new_partition = 0;
10751da177e4SLinus Torvalds if (STp->can_partitions)
10761da177e4SLinus Torvalds STp->nbr_partitions = 1; /* This guess will be updated later
10771da177e4SLinus Torvalds if necessary */
10781da177e4SLinus Torvalds for (i = 0; i < ST_NBR_PARTITIONS; i++) {
10791da177e4SLinus Torvalds STps = &(STp->ps[i]);
10801da177e4SLinus Torvalds STps->rw = ST_IDLE;
10811da177e4SLinus Torvalds STps->eof = ST_NOEOF;
10821da177e4SLinus Torvalds STps->at_sm = 0;
10831da177e4SLinus Torvalds STps->last_block_valid = 0;
10841da177e4SLinus Torvalds STps->drv_block = 0;
10851da177e4SLinus Torvalds STps->drv_file = 0;
10861da177e4SLinus Torvalds }
10871da177e4SLinus Torvalds new_session = 1;
10881da177e4SLinus Torvalds }
10891da177e4SLinus Torvalds else {
10901da177e4SLinus Torvalds STp->cleaning_req |= saved_cleaning;
10911da177e4SLinus Torvalds
10921da177e4SLinus Torvalds if (retval == CHKRES_NOT_READY || retval == CHKRES_NO_TAPE) {
10931da177e4SLinus Torvalds if (retval == CHKRES_NO_TAPE)
10941da177e4SLinus Torvalds STp->ready = ST_NO_TAPE;
10951da177e4SLinus Torvalds else
10961da177e4SLinus Torvalds STp->ready = ST_NOT_READY;
10971da177e4SLinus Torvalds
10981da177e4SLinus Torvalds STp->density = 0; /* Clear the erroneous "residue" */
10991da177e4SLinus Torvalds STp->write_prot = 0;
11001da177e4SLinus Torvalds STp->block_size = 0;
11011da177e4SLinus Torvalds STp->ps[0].drv_file = STp->ps[0].drv_block = (-1);
11021da177e4SLinus Torvalds STp->partition = STp->new_partition = 0;
11031da177e4SLinus Torvalds STp->door_locked = ST_UNLOCKED;
11041da177e4SLinus Torvalds return CHKRES_NOT_READY;
11051da177e4SLinus Torvalds }
11061da177e4SLinus Torvalds }
11071da177e4SLinus Torvalds
11081da177e4SLinus Torvalds if (STp->omit_blklims)
11091da177e4SLinus Torvalds STp->min_block = STp->max_block = (-1);
11101da177e4SLinus Torvalds else {
11111da177e4SLinus Torvalds memset((void *) &cmd[0], 0, MAX_COMMAND_SIZE);
11121da177e4SLinus Torvalds cmd[0] = READ_BLOCK_LIMITS;
11131da177e4SLinus Torvalds
111402ae2c0eSKai Makisara SRpnt = st_do_scsi(SRpnt, STp, cmd, 6, DMA_FROM_DEVICE,
1115a02488edSJames Bottomley STp->device->request_queue->rq_timeout,
111602ae2c0eSKai Makisara MAX_READY_RETRIES, 1);
111702ae2c0eSKai Makisara if (!SRpnt) {
111802ae2c0eSKai Makisara retval = (STp->buffer)->syscall_result;
11191da177e4SLinus Torvalds goto err_out;
11201da177e4SLinus Torvalds }
11211da177e4SLinus Torvalds
11228b05b773SMike Christie if (!SRpnt->result && !STp->buffer->cmdstat.have_sense) {
11231da177e4SLinus Torvalds STp->max_block = ((STp->buffer)->b_data[1] << 16) |
11241da177e4SLinus Torvalds ((STp->buffer)->b_data[2] << 8) | (STp->buffer)->b_data[3];
11251da177e4SLinus Torvalds STp->min_block = ((STp->buffer)->b_data[4] << 8) |
11261da177e4SLinus Torvalds (STp->buffer)->b_data[5];
11271da177e4SLinus Torvalds if ( DEB( debugging || ) !STp->inited)
1128b30d8bcaSHannes Reinecke st_printk(KERN_INFO, STp,
1129b30d8bcaSHannes Reinecke "Block limits %d - %d bytes.\n",
11301da177e4SLinus Torvalds STp->min_block, STp->max_block);
11311da177e4SLinus Torvalds } else {
11321da177e4SLinus Torvalds STp->min_block = STp->max_block = (-1);
1133b30d8bcaSHannes Reinecke DEBC_printk(STp, "Can't read block limits.\n");
11341da177e4SLinus Torvalds }
11351da177e4SLinus Torvalds }
11361da177e4SLinus Torvalds
11371da177e4SLinus Torvalds memset((void *) &cmd[0], 0, MAX_COMMAND_SIZE);
11381da177e4SLinus Torvalds cmd[0] = MODE_SENSE;
11391da177e4SLinus Torvalds cmd[4] = 12;
11401da177e4SLinus Torvalds
114102ae2c0eSKai Makisara SRpnt = st_do_scsi(SRpnt, STp, cmd, 12, DMA_FROM_DEVICE,
1142a02488edSJames Bottomley STp->device->request_queue->rq_timeout,
114302ae2c0eSKai Makisara MAX_READY_RETRIES, 1);
114402ae2c0eSKai Makisara if (!SRpnt) {
114502ae2c0eSKai Makisara retval = (STp->buffer)->syscall_result;
11461da177e4SLinus Torvalds goto err_out;
11471da177e4SLinus Torvalds }
11481da177e4SLinus Torvalds
11491da177e4SLinus Torvalds if ((STp->buffer)->syscall_result != 0) {
1150b30d8bcaSHannes Reinecke DEBC_printk(STp, "No Mode Sense.\n");
11511da177e4SLinus Torvalds STp->block_size = ST_DEFAULT_BLOCK; /* Educated guess (?) */
11521da177e4SLinus Torvalds (STp->buffer)->syscall_result = 0; /* Prevent error propagation */
11531da177e4SLinus Torvalds STp->drv_write_prot = 0;
11541da177e4SLinus Torvalds } else {
1155b30d8bcaSHannes Reinecke DEBC_printk(STp,"Mode sense. Length %d, "
1156b30d8bcaSHannes Reinecke "medium %x, WBS %x, BLL %d\n",
1157b30d8bcaSHannes Reinecke (STp->buffer)->b_data[0],
1158b30d8bcaSHannes Reinecke (STp->buffer)->b_data[1],
1159b30d8bcaSHannes Reinecke (STp->buffer)->b_data[2],
1160b30d8bcaSHannes Reinecke (STp->buffer)->b_data[3]);
11611da177e4SLinus Torvalds
11621da177e4SLinus Torvalds if ((STp->buffer)->b_data[3] >= 8) {
11631da177e4SLinus Torvalds STp->drv_buffer = ((STp->buffer)->b_data[2] >> 4) & 7;
11641da177e4SLinus Torvalds STp->density = (STp->buffer)->b_data[4];
11651da177e4SLinus Torvalds STp->block_size = (STp->buffer)->b_data[9] * 65536 +
11661da177e4SLinus Torvalds (STp->buffer)->b_data[10] * 256 + (STp->buffer)->b_data[11];
1167b30d8bcaSHannes Reinecke DEBC_printk(STp, "Density %x, tape length: %x, "
1168b30d8bcaSHannes Reinecke "drv buffer: %d\n",
1169b30d8bcaSHannes Reinecke STp->density,
1170b30d8bcaSHannes Reinecke (STp->buffer)->b_data[5] * 65536 +
1171b30d8bcaSHannes Reinecke (STp->buffer)->b_data[6] * 256 +
1172b30d8bcaSHannes Reinecke (STp->buffer)->b_data[7],
1173b30d8bcaSHannes Reinecke STp->drv_buffer);
11741da177e4SLinus Torvalds }
11751da177e4SLinus Torvalds STp->drv_write_prot = ((STp->buffer)->b_data[2] & 0x80) != 0;
1176c743e44fSLee Duncan if (!STp->drv_buffer && STp->immediate_filemark) {
1177b30d8bcaSHannes Reinecke st_printk(KERN_WARNING, STp,
1178b30d8bcaSHannes Reinecke "non-buffered tape: disabling "
1179b30d8bcaSHannes Reinecke "writing immediate filemarks\n");
1180c743e44fSLee Duncan STp->immediate_filemark = 0;
1181c743e44fSLee Duncan }
11821da177e4SLinus Torvalds }
11838b05b773SMike Christie st_release_request(SRpnt);
11841da177e4SLinus Torvalds SRpnt = NULL;
11851da177e4SLinus Torvalds STp->inited = 1;
11861da177e4SLinus Torvalds
11871da177e4SLinus Torvalds if (STp->block_size > 0)
11881da177e4SLinus Torvalds (STp->buffer)->buffer_blocks =
11891da177e4SLinus Torvalds (STp->buffer)->buffer_size / STp->block_size;
11901da177e4SLinus Torvalds else
11911da177e4SLinus Torvalds (STp->buffer)->buffer_blocks = 1;
11921da177e4SLinus Torvalds (STp->buffer)->buffer_bytes = (STp->buffer)->read_pointer = 0;
11931da177e4SLinus Torvalds
1194b30d8bcaSHannes Reinecke DEBC_printk(STp, "Block size: %d, buffer size: %d (%d blocks).\n",
11951da177e4SLinus Torvalds STp->block_size, (STp->buffer)->buffer_size,
1196b30d8bcaSHannes Reinecke (STp->buffer)->buffer_blocks);
11971da177e4SLinus Torvalds
11981da177e4SLinus Torvalds if (STp->drv_write_prot) {
11991da177e4SLinus Torvalds STp->write_prot = 1;
12001da177e4SLinus Torvalds
1201b30d8bcaSHannes Reinecke DEBC_printk(STp, "Write protected\n");
12021da177e4SLinus Torvalds
12031da177e4SLinus Torvalds if (do_wait &&
12041da177e4SLinus Torvalds ((st_flags & O_ACCMODE) == O_WRONLY ||
12051da177e4SLinus Torvalds (st_flags & O_ACCMODE) == O_RDWR)) {
12061da177e4SLinus Torvalds retval = (-EROFS);
12071da177e4SLinus Torvalds goto err_out;
12081da177e4SLinus Torvalds }
12091da177e4SLinus Torvalds }
12101da177e4SLinus Torvalds
12111da177e4SLinus Torvalds if (STp->can_partitions && STp->nbr_partitions < 1) {
12121da177e4SLinus Torvalds /* This code is reached when the device is opened for the first time
12131da177e4SLinus Torvalds after the driver has been initialized with tape in the drive and the
12141da177e4SLinus Torvalds partition support has been enabled. */
1215b30d8bcaSHannes Reinecke DEBC_printk(STp, "Updating partition number in status.\n");
12161da177e4SLinus Torvalds if ((STp->partition = find_partition(STp)) < 0) {
12171da177e4SLinus Torvalds retval = STp->partition;
12181da177e4SLinus Torvalds goto err_out;
12191da177e4SLinus Torvalds }
12201da177e4SLinus Torvalds STp->new_partition = STp->partition;
12211da177e4SLinus Torvalds STp->nbr_partitions = 1; /* This guess will be updated when necessary */
12221da177e4SLinus Torvalds }
12231da177e4SLinus Torvalds
12241da177e4SLinus Torvalds if (new_session) { /* Change the drive parameters for the new mode */
12251da177e4SLinus Torvalds STp->density_changed = STp->blksize_changed = 0;
12261da177e4SLinus Torvalds STp->compression_changed = 0;
12271da177e4SLinus Torvalds if (!(STm->defaults_for_writes) &&
12281da177e4SLinus Torvalds (retval = set_mode_densblk(STp, STm)) < 0)
12291da177e4SLinus Torvalds goto err_out;
12301da177e4SLinus Torvalds
12311da177e4SLinus Torvalds if (STp->default_drvbuffer != 0xff) {
12321da177e4SLinus Torvalds if (st_int_ioctl(STp, MTSETDRVBUFFER, STp->default_drvbuffer))
1233b30d8bcaSHannes Reinecke st_printk(KERN_WARNING, STp,
1234b30d8bcaSHannes Reinecke "Can't set default drive "
1235b30d8bcaSHannes Reinecke "buffering to %d.\n",
1236b30d8bcaSHannes Reinecke STp->default_drvbuffer);
12371da177e4SLinus Torvalds }
12381da177e4SLinus Torvalds }
12391da177e4SLinus Torvalds
12401da177e4SLinus Torvalds return CHKRES_READY;
12411da177e4SLinus Torvalds
12421da177e4SLinus Torvalds err_out:
12431da177e4SLinus Torvalds return retval;
12441da177e4SLinus Torvalds }
12451da177e4SLinus Torvalds
12461da177e4SLinus Torvalds
1247b3369c68SJonathan Corbet /* Open the device. Needs to take the BKL only because of incrementing the SCSI host
12481da177e4SLinus Torvalds module count. */
st_open(struct inode * inode,struct file * filp)12491da177e4SLinus Torvalds static int st_open(struct inode *inode, struct file *filp)
12501da177e4SLinus Torvalds {
12511da177e4SLinus Torvalds int i, retval = (-EIO);
125246a243f7SOliver Neukum int resumed = 0;
12531da177e4SLinus Torvalds struct scsi_tape *STp;
12541da177e4SLinus Torvalds struct st_partstat *STps;
12551da177e4SLinus Torvalds int dev = TAPE_NR(inode);
12561da177e4SLinus Torvalds
12571da177e4SLinus Torvalds /*
12581da177e4SLinus Torvalds * We really want to do nonseekable_open(inode, filp); here, but some
12591da177e4SLinus Torvalds * versions of tar incorrectly call lseek on tapes and bail out if that
12601da177e4SLinus Torvalds * fails. So we disallow pread() and pwrite(), but permit lseeks.
12611da177e4SLinus Torvalds */
12621da177e4SLinus Torvalds filp->f_mode &= ~(FMODE_PREAD | FMODE_PWRITE);
12631da177e4SLinus Torvalds
1264b3369c68SJonathan Corbet if (!(STp = scsi_tape_get(dev))) {
1265f03a5670SKai Makisara return -ENXIO;
1266b3369c68SJonathan Corbet }
1267f03a5670SKai Makisara
12681da177e4SLinus Torvalds filp->private_data = STp;
12691da177e4SLinus Torvalds
12706c648d95SJeff Mahoney spin_lock(&st_use_lock);
12711da177e4SLinus Torvalds if (STp->in_use) {
12726c648d95SJeff Mahoney spin_unlock(&st_use_lock);
1273b30d8bcaSHannes Reinecke DEBC_printk(STp, "Device already in use.\n");
1274c8c165deSLv Yunlong scsi_tape_put(STp);
12751da177e4SLinus Torvalds return (-EBUSY);
12761da177e4SLinus Torvalds }
12771da177e4SLinus Torvalds
12781da177e4SLinus Torvalds STp->in_use = 1;
12796c648d95SJeff Mahoney spin_unlock(&st_use_lock);
12801da177e4SLinus Torvalds STp->rew_at_close = STp->autorew_dev = (iminor(inode) & 0x80) == 0;
12811da177e4SLinus Torvalds
128246a243f7SOliver Neukum if (scsi_autopm_get_device(STp->device) < 0) {
128346a243f7SOliver Neukum retval = -EIO;
128446a243f7SOliver Neukum goto err_out;
128546a243f7SOliver Neukum }
128646a243f7SOliver Neukum resumed = 1;
12871da177e4SLinus Torvalds if (!scsi_block_when_processing_errors(STp->device)) {
12881da177e4SLinus Torvalds retval = (-ENXIO);
12891da177e4SLinus Torvalds goto err_out;
12901da177e4SLinus Torvalds }
12911da177e4SLinus Torvalds
12921da177e4SLinus Torvalds /* See that we have at least a one page buffer available */
1293aaff5ebaSChristoph Hellwig if (!enlarge_buffer(STp->buffer, PAGE_SIZE)) {
1294b30d8bcaSHannes Reinecke st_printk(KERN_WARNING, STp,
1295b30d8bcaSHannes Reinecke "Can't allocate one page tape buffer.\n");
12961da177e4SLinus Torvalds retval = (-EOVERFLOW);
12971da177e4SLinus Torvalds goto err_out;
12981da177e4SLinus Torvalds }
12991da177e4SLinus Torvalds
130040f6b36cSKai Makisara (STp->buffer)->cleared = 0;
13011da177e4SLinus Torvalds (STp->buffer)->writing = 0;
13021da177e4SLinus Torvalds (STp->buffer)->syscall_result = 0;
13031da177e4SLinus Torvalds
13041da177e4SLinus Torvalds STp->write_prot = ((filp->f_flags & O_ACCMODE) == O_RDONLY);
13051da177e4SLinus Torvalds
13061da177e4SLinus Torvalds STp->dirty = 0;
13071da177e4SLinus Torvalds for (i = 0; i < ST_NBR_PARTITIONS; i++) {
13081da177e4SLinus Torvalds STps = &(STp->ps[i]);
13091da177e4SLinus Torvalds STps->rw = ST_IDLE;
13101da177e4SLinus Torvalds }
13119abe16c6SKai Makisara STp->try_dio_now = STp->try_dio;
13121da177e4SLinus Torvalds STp->recover_count = 0;
13131da177e4SLinus Torvalds DEB( STp->nbr_waits = STp->nbr_finished = 0;
1314deee13dfSKai Makisara STp->nbr_requests = STp->nbr_dio = STp->nbr_pages = 0; )
13151da177e4SLinus Torvalds
13161da177e4SLinus Torvalds retval = check_tape(STp, filp);
13171da177e4SLinus Torvalds if (retval < 0)
13181da177e4SLinus Torvalds goto err_out;
13191da177e4SLinus Torvalds if ((filp->f_flags & O_NONBLOCK) == 0 &&
13201da177e4SLinus Torvalds retval != CHKRES_READY) {
1321413f7327SKai Makisara if (STp->ready == NO_TAPE)
1322413f7327SKai Makisara retval = (-ENOMEDIUM);
1323413f7327SKai Makisara else
13241da177e4SLinus Torvalds retval = (-EIO);
13251da177e4SLinus Torvalds goto err_out;
13261da177e4SLinus Torvalds }
13271da177e4SLinus Torvalds return 0;
13281da177e4SLinus Torvalds
13291da177e4SLinus Torvalds err_out:
13301da177e4SLinus Torvalds normalize_buffer(STp->buffer);
13310644f539SHannes Reinecke spin_lock(&st_use_lock);
13321da177e4SLinus Torvalds STp->in_use = 0;
13330644f539SHannes Reinecke spin_unlock(&st_use_lock);
133446a243f7SOliver Neukum if (resumed)
133546a243f7SOliver Neukum scsi_autopm_put_device(STp->device);
1336e7ac6c66SSeymour, Shane M scsi_tape_put(STp);
13371da177e4SLinus Torvalds return retval;
13381da177e4SLinus Torvalds
13391da177e4SLinus Torvalds }
13401da177e4SLinus Torvalds
13411da177e4SLinus Torvalds
13421da177e4SLinus Torvalds /* Flush the tape buffer before close */
st_flush(struct file * filp,fl_owner_t id)134375e1fcc0SMiklos Szeredi static int st_flush(struct file *filp, fl_owner_t id)
13441da177e4SLinus Torvalds {
13451da177e4SLinus Torvalds int result = 0, result2;
13461da177e4SLinus Torvalds unsigned char cmd[MAX_COMMAND_SIZE];
13478b05b773SMike Christie struct st_request *SRpnt;
13481da177e4SLinus Torvalds struct scsi_tape *STp = filp->private_data;
13491da177e4SLinus Torvalds struct st_modedef *STm = &(STp->modes[STp->current_mode]);
13501da177e4SLinus Torvalds struct st_partstat *STps = &(STp->ps[STp->partition]);
13511da177e4SLinus Torvalds
13521da177e4SLinus Torvalds if (file_count(filp) > 1)
13531da177e4SLinus Torvalds return 0;
13541da177e4SLinus Torvalds
13551da177e4SLinus Torvalds if (STps->rw == ST_WRITING && !STp->pos_unknown) {
13568ef8d594SAdrian Bunk result = st_flush_write_buffer(STp);
13571da177e4SLinus Torvalds if (result != 0 && result != (-ENOSPC))
13581da177e4SLinus Torvalds goto out;
13591da177e4SLinus Torvalds }
13601da177e4SLinus Torvalds
13611da177e4SLinus Torvalds if (STp->can_partitions &&
13621da177e4SLinus Torvalds (result2 = switch_partition(STp)) < 0) {
1363b30d8bcaSHannes Reinecke DEBC_printk(STp, "switch_partition at close failed.\n");
13641da177e4SLinus Torvalds if (result == 0)
13651da177e4SLinus Torvalds result = result2;
13661da177e4SLinus Torvalds goto out;
13671da177e4SLinus Torvalds }
13681da177e4SLinus Torvalds
13691da177e4SLinus Torvalds DEBC( if (STp->nbr_requests)
1370b30d8bcaSHannes Reinecke st_printk(KERN_DEBUG, STp,
1371b30d8bcaSHannes Reinecke "Number of r/w requests %d, dio used in %d, "
1372b30d8bcaSHannes Reinecke "pages %d.\n", STp->nbr_requests, STp->nbr_dio,
1373b30d8bcaSHannes Reinecke STp->nbr_pages));
13741da177e4SLinus Torvalds
13751da177e4SLinus Torvalds if (STps->rw == ST_WRITING && !STp->pos_unknown) {
13761da177e4SLinus Torvalds struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat;
13771da177e4SLinus Torvalds
1378b30d8bcaSHannes Reinecke #if DEBUG
1379b30d8bcaSHannes Reinecke DEBC_printk(STp, "Async write waits %d, finished %d.\n",
1380b30d8bcaSHannes Reinecke STp->nbr_waits, STp->nbr_finished);
1381b30d8bcaSHannes Reinecke #endif
13821da177e4SLinus Torvalds memset(cmd, 0, MAX_COMMAND_SIZE);
13831da177e4SLinus Torvalds cmd[0] = WRITE_FILEMARKS;
1384c743e44fSLee Duncan if (STp->immediate_filemark)
1385c743e44fSLee Duncan cmd[1] = 1;
13861da177e4SLinus Torvalds cmd[4] = 1 + STp->two_fm;
13871da177e4SLinus Torvalds
138802ae2c0eSKai Makisara SRpnt = st_do_scsi(NULL, STp, cmd, 0, DMA_NONE,
1389212cd8bfSFUJITA Tomonori STp->device->request_queue->rq_timeout,
139002ae2c0eSKai Makisara MAX_WRITE_RETRIES, 1);
139102ae2c0eSKai Makisara if (!SRpnt) {
139202ae2c0eSKai Makisara result = (STp->buffer)->syscall_result;
13931da177e4SLinus Torvalds goto out;
13941da177e4SLinus Torvalds }
13951da177e4SLinus Torvalds
13961da177e4SLinus Torvalds if (STp->buffer->syscall_result == 0 ||
13971da177e4SLinus Torvalds (cmdstatp->have_sense && !cmdstatp->deferred &&
13981da177e4SLinus Torvalds (cmdstatp->flags & SENSE_EOM) &&
13991da177e4SLinus Torvalds (cmdstatp->sense_hdr.sense_key == NO_SENSE ||
14001da177e4SLinus Torvalds cmdstatp->sense_hdr.sense_key == RECOVERED_ERROR) &&
14011da177e4SLinus Torvalds (!cmdstatp->remainder_valid || cmdstatp->uremainder64 == 0))) {
14021da177e4SLinus Torvalds /* Write successful at EOM */
14038b05b773SMike Christie st_release_request(SRpnt);
14041da177e4SLinus Torvalds SRpnt = NULL;
14051da177e4SLinus Torvalds if (STps->drv_file >= 0)
14061da177e4SLinus Torvalds STps->drv_file++;
14071da177e4SLinus Torvalds STps->drv_block = 0;
14081da177e4SLinus Torvalds if (STp->two_fm)
14091da177e4SLinus Torvalds cross_eof(STp, 0);
14101da177e4SLinus Torvalds STps->eof = ST_FM;
14111da177e4SLinus Torvalds }
14121da177e4SLinus Torvalds else { /* Write error */
14138b05b773SMike Christie st_release_request(SRpnt);
14141da177e4SLinus Torvalds SRpnt = NULL;
1415b30d8bcaSHannes Reinecke st_printk(KERN_ERR, STp,
1416b30d8bcaSHannes Reinecke "Error on write filemark.\n");
14171da177e4SLinus Torvalds if (result == 0)
14181da177e4SLinus Torvalds result = (-EIO);
14191da177e4SLinus Torvalds }
14201da177e4SLinus Torvalds
1421b30d8bcaSHannes Reinecke DEBC_printk(STp, "Buffer flushed, %d EOF(s) written\n", cmd[4]);
14221da177e4SLinus Torvalds } else if (!STp->rew_at_close) {
14231da177e4SLinus Torvalds STps = &(STp->ps[STp->partition]);
14241da177e4SLinus Torvalds if (!STm->sysv || STps->rw != ST_READING) {
14251da177e4SLinus Torvalds if (STp->can_bsr)
14261da177e4SLinus Torvalds result = flush_buffer(STp, 0);
14271da177e4SLinus Torvalds else if (STps->eof == ST_FM_HIT) {
14281da177e4SLinus Torvalds result = cross_eof(STp, 0);
14291da177e4SLinus Torvalds if (result) {
14301da177e4SLinus Torvalds if (STps->drv_file >= 0)
14311da177e4SLinus Torvalds STps->drv_file++;
14321da177e4SLinus Torvalds STps->drv_block = 0;
14331da177e4SLinus Torvalds STps->eof = ST_FM;
14341da177e4SLinus Torvalds } else
14351da177e4SLinus Torvalds STps->eof = ST_NOEOF;
14361da177e4SLinus Torvalds }
14371da177e4SLinus Torvalds } else if ((STps->eof == ST_NOEOF &&
14381da177e4SLinus Torvalds !(result = cross_eof(STp, 1))) ||
14391da177e4SLinus Torvalds STps->eof == ST_FM_HIT) {
14401da177e4SLinus Torvalds if (STps->drv_file >= 0)
14411da177e4SLinus Torvalds STps->drv_file++;
14421da177e4SLinus Torvalds STps->drv_block = 0;
14431da177e4SLinus Torvalds STps->eof = ST_FM;
14441da177e4SLinus Torvalds }
14451da177e4SLinus Torvalds }
14461da177e4SLinus Torvalds
14471da177e4SLinus Torvalds out:
14481da177e4SLinus Torvalds if (STp->rew_at_close) {
14491da177e4SLinus Torvalds result2 = st_int_ioctl(STp, MTREW, 1);
14501da177e4SLinus Torvalds if (result == 0)
14511da177e4SLinus Torvalds result = result2;
14521da177e4SLinus Torvalds }
14531da177e4SLinus Torvalds return result;
14541da177e4SLinus Torvalds }
14551da177e4SLinus Torvalds
14561da177e4SLinus Torvalds
14571da177e4SLinus Torvalds /* Close the device and release it. BKL is not needed: this is the only thread
14581da177e4SLinus Torvalds accessing this tape. */
st_release(struct inode * inode,struct file * filp)14591da177e4SLinus Torvalds static int st_release(struct inode *inode, struct file *filp)
14601da177e4SLinus Torvalds {
14611da177e4SLinus Torvalds struct scsi_tape *STp = filp->private_data;
14621da177e4SLinus Torvalds
14631da177e4SLinus Torvalds if (STp->door_locked == ST_LOCKED_AUTO)
14641da177e4SLinus Torvalds do_door_lock(STp, 0);
14651da177e4SLinus Torvalds
14661da177e4SLinus Torvalds normalize_buffer(STp->buffer);
14676c648d95SJeff Mahoney spin_lock(&st_use_lock);
14681da177e4SLinus Torvalds STp->in_use = 0;
14696c648d95SJeff Mahoney spin_unlock(&st_use_lock);
147046a243f7SOliver Neukum scsi_autopm_put_device(STp->device);
1471f03a5670SKai Makisara scsi_tape_put(STp);
14721da177e4SLinus Torvalds
1473ec341439SJason Yan return 0;
14741da177e4SLinus Torvalds }
1475ec341439SJason Yan
14761da177e4SLinus Torvalds /* The checks common to both reading and writing */
rw_checks(struct scsi_tape * STp,struct file * filp,size_t count)14771da177e4SLinus Torvalds static ssize_t rw_checks(struct scsi_tape *STp, struct file *filp, size_t count)
14781da177e4SLinus Torvalds {
14791da177e4SLinus Torvalds ssize_t retval = 0;
14801da177e4SLinus Torvalds
14811da177e4SLinus Torvalds /*
14821da177e4SLinus Torvalds * If we are in the middle of error recovery, don't let anyone
14831da177e4SLinus Torvalds * else try and use this device. Also, if error recovery fails, it
14841da177e4SLinus Torvalds * may try and take the device offline, in which case all further
14851da177e4SLinus Torvalds * access to the device is prohibited.
14861da177e4SLinus Torvalds */
14871da177e4SLinus Torvalds if (!scsi_block_when_processing_errors(STp->device)) {
14881da177e4SLinus Torvalds retval = (-ENXIO);
14891da177e4SLinus Torvalds goto out;
14901da177e4SLinus Torvalds }
14911da177e4SLinus Torvalds
14921da177e4SLinus Torvalds if (STp->ready != ST_READY) {
14931da177e4SLinus Torvalds if (STp->ready == ST_NO_TAPE)
14941da177e4SLinus Torvalds retval = (-ENOMEDIUM);
14951da177e4SLinus Torvalds else
14961da177e4SLinus Torvalds retval = (-EIO);
14971da177e4SLinus Torvalds goto out;
14981da177e4SLinus Torvalds }
14991da177e4SLinus Torvalds
15001da177e4SLinus Torvalds if (! STp->modes[STp->current_mode].defined) {
15011da177e4SLinus Torvalds retval = (-ENXIO);
15021da177e4SLinus Torvalds goto out;
15031da177e4SLinus Torvalds }
15041da177e4SLinus Torvalds
15051da177e4SLinus Torvalds
15061da177e4SLinus Torvalds /*
15071da177e4SLinus Torvalds * If there was a bus reset, block further access
15081da177e4SLinus Torvalds * to this device.
15091da177e4SLinus Torvalds */
15101da177e4SLinus Torvalds if (STp->pos_unknown) {
15111da177e4SLinus Torvalds retval = (-EIO);
15121da177e4SLinus Torvalds goto out;
15131da177e4SLinus Torvalds }
15141da177e4SLinus Torvalds
15151da177e4SLinus Torvalds if (count == 0)
15161da177e4SLinus Torvalds goto out;
15171da177e4SLinus Torvalds
15181da177e4SLinus Torvalds DEB(
15191da177e4SLinus Torvalds if (!STp->in_use) {
1520b30d8bcaSHannes Reinecke st_printk(ST_DEB_MSG, STp,
1521b30d8bcaSHannes Reinecke "Incorrect device.\n");
15221da177e4SLinus Torvalds retval = (-EIO);
15231da177e4SLinus Torvalds goto out;
15241da177e4SLinus Torvalds } ) /* end DEB */
15251da177e4SLinus Torvalds
15261da177e4SLinus Torvalds if (STp->can_partitions &&
15271da177e4SLinus Torvalds (retval = switch_partition(STp)) < 0)
15281da177e4SLinus Torvalds goto out;
15291da177e4SLinus Torvalds
15301da177e4SLinus Torvalds if (STp->block_size == 0 && STp->max_block > 0 &&
15311da177e4SLinus Torvalds (count < STp->min_block || count > STp->max_block)) {
15321da177e4SLinus Torvalds retval = (-EINVAL);
15331da177e4SLinus Torvalds goto out;
15341da177e4SLinus Torvalds }
15351da177e4SLinus Torvalds
15361da177e4SLinus Torvalds if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED &&
15371da177e4SLinus Torvalds !do_door_lock(STp, 1))
15381da177e4SLinus Torvalds STp->door_locked = ST_LOCKED_AUTO;
15391da177e4SLinus Torvalds
15401da177e4SLinus Torvalds out:
15411da177e4SLinus Torvalds return retval;
15421da177e4SLinus Torvalds }
15431da177e4SLinus Torvalds
15441da177e4SLinus Torvalds
setup_buffering(struct scsi_tape * STp,const char __user * buf,size_t count,int is_read)15451da177e4SLinus Torvalds static int setup_buffering(struct scsi_tape *STp, const char __user *buf,
15461da177e4SLinus Torvalds size_t count, int is_read)
15471da177e4SLinus Torvalds {
15481da177e4SLinus Torvalds int i, bufsize, retval = 0;
15491da177e4SLinus Torvalds struct st_buffer *STbp = STp->buffer;
15501da177e4SLinus Torvalds
15511da177e4SLinus Torvalds if (is_read)
15529abe16c6SKai Makisara i = STp->try_dio_now && try_rdio;
15531da177e4SLinus Torvalds else
15549abe16c6SKai Makisara i = STp->try_dio_now && try_wdio;
15558b05b773SMike Christie
15561da177e4SLinus Torvalds if (i && ((unsigned long)buf & queue_dma_alignment(
15571da177e4SLinus Torvalds STp->device->request_queue)) == 0) {
15586620742fSFUJITA Tomonori i = sgl_map_user_pages(STbp, STbp->use_sg, (unsigned long)buf,
15596620742fSFUJITA Tomonori count, (is_read ? READ : WRITE));
15601da177e4SLinus Torvalds if (i > 0) {
15611da177e4SLinus Torvalds STbp->do_dio = i;
15621da177e4SLinus Torvalds STbp->buffer_bytes = 0; /* can be used as transfer counter */
15631da177e4SLinus Torvalds }
15641da177e4SLinus Torvalds else
15651da177e4SLinus Torvalds STbp->do_dio = 0; /* fall back to buffering with any error */
15661da177e4SLinus Torvalds STbp->sg_segs = STbp->do_dio;
15671da177e4SLinus Torvalds DEB(
15681da177e4SLinus Torvalds if (STbp->do_dio) {
15691da177e4SLinus Torvalds STp->nbr_dio++;
15701da177e4SLinus Torvalds STp->nbr_pages += STbp->do_dio;
15711da177e4SLinus Torvalds }
15721da177e4SLinus Torvalds )
15731da177e4SLinus Torvalds } else
15741da177e4SLinus Torvalds STbp->do_dio = 0;
15751da177e4SLinus Torvalds DEB( STp->nbr_requests++; )
15761da177e4SLinus Torvalds
15771da177e4SLinus Torvalds if (!STbp->do_dio) {
15781da177e4SLinus Torvalds if (STp->block_size)
15791da177e4SLinus Torvalds bufsize = STp->block_size > st_fixed_buffer_size ?
15801da177e4SLinus Torvalds STp->block_size : st_fixed_buffer_size;
158140f6b36cSKai Makisara else {
15821da177e4SLinus Torvalds bufsize = count;
158340f6b36cSKai Makisara /* Make sure that data from previous user is not leaked even if
158440f6b36cSKai Makisara HBA does not return correct residual */
158540f6b36cSKai Makisara if (is_read && STp->sili && !STbp->cleared)
158640f6b36cSKai Makisara clear_buffer(STbp);
158740f6b36cSKai Makisara }
158840f6b36cSKai Makisara
15891da177e4SLinus Torvalds if (bufsize > STbp->buffer_size &&
1590aaff5ebaSChristoph Hellwig !enlarge_buffer(STbp, bufsize)) {
1591b30d8bcaSHannes Reinecke st_printk(KERN_WARNING, STp,
1592b30d8bcaSHannes Reinecke "Can't allocate %d byte tape buffer.\n",
1593b30d8bcaSHannes Reinecke bufsize);
15941da177e4SLinus Torvalds retval = (-EOVERFLOW);
15951da177e4SLinus Torvalds goto out;
15961da177e4SLinus Torvalds }
15971da177e4SLinus Torvalds if (STp->block_size)
15981da177e4SLinus Torvalds STbp->buffer_blocks = bufsize / STp->block_size;
15991da177e4SLinus Torvalds }
16001da177e4SLinus Torvalds
16011da177e4SLinus Torvalds out:
16021da177e4SLinus Torvalds return retval;
16031da177e4SLinus Torvalds }
16041da177e4SLinus Torvalds
16051da177e4SLinus Torvalds
16061da177e4SLinus Torvalds /* Can be called more than once after each setup_buffer() */
release_buffering(struct scsi_tape * STp,int is_read)1607787926b1SKai Makisara static void release_buffering(struct scsi_tape *STp, int is_read)
16081da177e4SLinus Torvalds {
16091da177e4SLinus Torvalds struct st_buffer *STbp;
16101da177e4SLinus Torvalds
16111da177e4SLinus Torvalds STbp = STp->buffer;
16121da177e4SLinus Torvalds if (STbp->do_dio) {
16136620742fSFUJITA Tomonori sgl_unmap_user_pages(STbp, STbp->do_dio, is_read);
16141da177e4SLinus Torvalds STbp->do_dio = 0;
1615787926b1SKai Makisara STbp->sg_segs = 0;
16161da177e4SLinus Torvalds }
16171da177e4SLinus Torvalds }
16181da177e4SLinus Torvalds
16191da177e4SLinus Torvalds
16201da177e4SLinus Torvalds /* Write command */
16211da177e4SLinus Torvalds static ssize_t
st_write(struct file * filp,const char __user * buf,size_t count,loff_t * ppos)16221da177e4SLinus Torvalds st_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
16231da177e4SLinus Torvalds {
16241da177e4SLinus Torvalds ssize_t total;
16251da177e4SLinus Torvalds ssize_t i, do_count, blks, transfer;
16261da177e4SLinus Torvalds ssize_t retval;
16271da177e4SLinus Torvalds int undone, retry_eot = 0, scode;
16281da177e4SLinus Torvalds int async_write;
16291da177e4SLinus Torvalds unsigned char cmd[MAX_COMMAND_SIZE];
16301da177e4SLinus Torvalds const char __user *b_point;
16318b05b773SMike Christie struct st_request *SRpnt = NULL;
16321da177e4SLinus Torvalds struct scsi_tape *STp = filp->private_data;
16331da177e4SLinus Torvalds struct st_modedef *STm;
16341da177e4SLinus Torvalds struct st_partstat *STps;
16351da177e4SLinus Torvalds struct st_buffer *STbp;
16361da177e4SLinus Torvalds
163728f85009SMatthias Kaehlcke if (mutex_lock_interruptible(&STp->lock))
16381da177e4SLinus Torvalds return -ERESTARTSYS;
16391da177e4SLinus Torvalds
16401da177e4SLinus Torvalds retval = rw_checks(STp, filp, count);
16411da177e4SLinus Torvalds if (retval || count == 0)
16421da177e4SLinus Torvalds goto out;
16431da177e4SLinus Torvalds
16441da177e4SLinus Torvalds /* Write must be integral number of blocks */
16451da177e4SLinus Torvalds if (STp->block_size != 0 && (count % STp->block_size) != 0) {
1646b30d8bcaSHannes Reinecke st_printk(KERN_WARNING, STp,
1647b30d8bcaSHannes Reinecke "Write not multiple of tape block size.\n");
16481da177e4SLinus Torvalds retval = (-EINVAL);
16491da177e4SLinus Torvalds goto out;
16501da177e4SLinus Torvalds }
16511da177e4SLinus Torvalds
16521da177e4SLinus Torvalds STm = &(STp->modes[STp->current_mode]);
16531da177e4SLinus Torvalds STps = &(STp->ps[STp->partition]);
16541da177e4SLinus Torvalds
16551da177e4SLinus Torvalds if (STp->write_prot) {
16561da177e4SLinus Torvalds retval = (-EACCES);
16571da177e4SLinus Torvalds goto out;
16581da177e4SLinus Torvalds }
16591da177e4SLinus Torvalds
16601da177e4SLinus Torvalds
16611da177e4SLinus Torvalds if (STps->rw == ST_READING) {
16621da177e4SLinus Torvalds retval = flush_buffer(STp, 0);
16631da177e4SLinus Torvalds if (retval)
16641da177e4SLinus Torvalds goto out;
16651da177e4SLinus Torvalds STps->rw = ST_WRITING;
16661da177e4SLinus Torvalds } else if (STps->rw != ST_WRITING &&
16671da177e4SLinus Torvalds STps->drv_file == 0 && STps->drv_block == 0) {
16681da177e4SLinus Torvalds if ((retval = set_mode_densblk(STp, STm)) < 0)
16691da177e4SLinus Torvalds goto out;
16701da177e4SLinus Torvalds if (STm->default_compression != ST_DONT_TOUCH &&
16711da177e4SLinus Torvalds !(STp->compression_changed)) {
16721da177e4SLinus Torvalds if (st_compression(STp, (STm->default_compression == ST_YES))) {
1673b30d8bcaSHannes Reinecke st_printk(KERN_WARNING, STp,
1674b30d8bcaSHannes Reinecke "Can't set default compression.\n");
16751da177e4SLinus Torvalds if (modes_defined) {
16761da177e4SLinus Torvalds retval = (-EINVAL);
16771da177e4SLinus Torvalds goto out;
16781da177e4SLinus Torvalds }
16791da177e4SLinus Torvalds }
16801da177e4SLinus Torvalds }
16811da177e4SLinus Torvalds }
16821da177e4SLinus Torvalds
16831da177e4SLinus Torvalds STbp = STp->buffer;
16841da177e4SLinus Torvalds i = write_behind_check(STp);
16851da177e4SLinus Torvalds if (i) {
16861da177e4SLinus Torvalds if (i == -ENOSPC)
16871da177e4SLinus Torvalds STps->eof = ST_EOM_OK;
16881da177e4SLinus Torvalds else
16891da177e4SLinus Torvalds STps->eof = ST_EOM_ERROR;
16901da177e4SLinus Torvalds }
16911da177e4SLinus Torvalds
16921da177e4SLinus Torvalds if (STps->eof == ST_EOM_OK) {
16931da177e4SLinus Torvalds STps->eof = ST_EOD_1; /* allow next write */
16941da177e4SLinus Torvalds retval = (-ENOSPC);
16951da177e4SLinus Torvalds goto out;
16961da177e4SLinus Torvalds }
16971da177e4SLinus Torvalds else if (STps->eof == ST_EOM_ERROR) {
16981da177e4SLinus Torvalds retval = (-EIO);
16991da177e4SLinus Torvalds goto out;
17001da177e4SLinus Torvalds }
17011da177e4SLinus Torvalds
17021da177e4SLinus Torvalds /* Check the buffer readability in cases where copy_user might catch
17031da177e4SLinus Torvalds the problems after some tape movement. */
17041da177e4SLinus Torvalds if (STp->block_size != 0 &&
17051da177e4SLinus Torvalds !STbp->do_dio &&
17061da177e4SLinus Torvalds (copy_from_user(&i, buf, 1) != 0 ||
17071da177e4SLinus Torvalds copy_from_user(&i, buf + count - 1, 1) != 0)) {
17081da177e4SLinus Torvalds retval = (-EFAULT);
17091da177e4SLinus Torvalds goto out;
17101da177e4SLinus Torvalds }
17111da177e4SLinus Torvalds
17121da177e4SLinus Torvalds retval = setup_buffering(STp, buf, count, 0);
17131da177e4SLinus Torvalds if (retval)
17141da177e4SLinus Torvalds goto out;
17151da177e4SLinus Torvalds
17161da177e4SLinus Torvalds total = count;
17171da177e4SLinus Torvalds
17181da177e4SLinus Torvalds memset(cmd, 0, MAX_COMMAND_SIZE);
17191da177e4SLinus Torvalds cmd[0] = WRITE_6;
17201da177e4SLinus Torvalds cmd[1] = (STp->block_size != 0);
17211da177e4SLinus Torvalds
17221da177e4SLinus Torvalds STps->rw = ST_WRITING;
17231da177e4SLinus Torvalds
17241da177e4SLinus Torvalds b_point = buf;
17251da177e4SLinus Torvalds while (count > 0 && !retry_eot) {
17261da177e4SLinus Torvalds
17271da177e4SLinus Torvalds if (STbp->do_dio) {
17281da177e4SLinus Torvalds do_count = count;
17291da177e4SLinus Torvalds }
17301da177e4SLinus Torvalds else {
17311da177e4SLinus Torvalds if (STp->block_size == 0)
17321da177e4SLinus Torvalds do_count = count;
17331da177e4SLinus Torvalds else {
17341da177e4SLinus Torvalds do_count = STbp->buffer_blocks * STp->block_size -
17351da177e4SLinus Torvalds STbp->buffer_bytes;
17361da177e4SLinus Torvalds if (do_count > count)
17371da177e4SLinus Torvalds do_count = count;
17381da177e4SLinus Torvalds }
17391da177e4SLinus Torvalds
17401da177e4SLinus Torvalds i = append_to_buffer(b_point, STbp, do_count);
17411da177e4SLinus Torvalds if (i) {
17421da177e4SLinus Torvalds retval = i;
17431da177e4SLinus Torvalds goto out;
17441da177e4SLinus Torvalds }
17451da177e4SLinus Torvalds }
17461da177e4SLinus Torvalds count -= do_count;
17471da177e4SLinus Torvalds b_point += do_count;
17481da177e4SLinus Torvalds
17491da177e4SLinus Torvalds async_write = STp->block_size == 0 && !STbp->do_dio &&
17501da177e4SLinus Torvalds STm->do_async_writes && STps->eof < ST_EOM_OK;
17511da177e4SLinus Torvalds
17521da177e4SLinus Torvalds if (STp->block_size != 0 && STm->do_buffer_writes &&
17539abe16c6SKai Makisara !(STp->try_dio_now && try_wdio) && STps->eof < ST_EOM_OK &&
17541da177e4SLinus Torvalds STbp->buffer_bytes < STbp->buffer_size) {
17551da177e4SLinus Torvalds STp->dirty = 1;
17561da177e4SLinus Torvalds /* Don't write a buffer that is not full enough. */
17571da177e4SLinus Torvalds if (!async_write && count == 0)
17581da177e4SLinus Torvalds break;
17591da177e4SLinus Torvalds }
17601da177e4SLinus Torvalds
17611da177e4SLinus Torvalds retry_write:
17621da177e4SLinus Torvalds if (STp->block_size == 0)
17631da177e4SLinus Torvalds blks = transfer = do_count;
17641da177e4SLinus Torvalds else {
17651da177e4SLinus Torvalds if (!STbp->do_dio)
17661da177e4SLinus Torvalds blks = STbp->buffer_bytes;
17671da177e4SLinus Torvalds else
17681da177e4SLinus Torvalds blks = do_count;
17691da177e4SLinus Torvalds blks /= STp->block_size;
17701da177e4SLinus Torvalds transfer = blks * STp->block_size;
17711da177e4SLinus Torvalds }
17721da177e4SLinus Torvalds cmd[2] = blks >> 16;
17731da177e4SLinus Torvalds cmd[3] = blks >> 8;
17741da177e4SLinus Torvalds cmd[4] = blks;
17751da177e4SLinus Torvalds
17761da177e4SLinus Torvalds SRpnt = st_do_scsi(SRpnt, STp, cmd, transfer, DMA_TO_DEVICE,
1777a02488edSJames Bottomley STp->device->request_queue->rq_timeout,
1778a02488edSJames Bottomley MAX_WRITE_RETRIES, !async_write);
17791da177e4SLinus Torvalds if (!SRpnt) {
17801da177e4SLinus Torvalds retval = STbp->syscall_result;
17811da177e4SLinus Torvalds goto out;
17821da177e4SLinus Torvalds }
17838b05b773SMike Christie if (async_write && !STbp->syscall_result) {
17841da177e4SLinus Torvalds STbp->writing = transfer;
17851da177e4SLinus Torvalds STp->dirty = !(STbp->writing ==
17861da177e4SLinus Torvalds STbp->buffer_bytes);
17871da177e4SLinus Torvalds SRpnt = NULL; /* Prevent releasing this request! */
17881da177e4SLinus Torvalds DEB( STp->write_pending = 1; )
17891da177e4SLinus Torvalds break;
17901da177e4SLinus Torvalds }
17911da177e4SLinus Torvalds
17921da177e4SLinus Torvalds if (STbp->syscall_result != 0) {
17931da177e4SLinus Torvalds struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat;
17941da177e4SLinus Torvalds
1795b30d8bcaSHannes Reinecke DEBC_printk(STp, "Error on write:\n");
17961da177e4SLinus Torvalds if (cmdstatp->have_sense && (cmdstatp->flags & SENSE_EOM)) {
17971da177e4SLinus Torvalds scode = cmdstatp->sense_hdr.sense_key;
17981da177e4SLinus Torvalds if (cmdstatp->remainder_valid)
17991da177e4SLinus Torvalds undone = (int)cmdstatp->uremainder64;
18001da177e4SLinus Torvalds else if (STp->block_size == 0 &&
18011da177e4SLinus Torvalds scode == VOLUME_OVERFLOW)
18021da177e4SLinus Torvalds undone = transfer;
18031da177e4SLinus Torvalds else
18041da177e4SLinus Torvalds undone = 0;
18051da177e4SLinus Torvalds if (STp->block_size != 0)
18061da177e4SLinus Torvalds undone *= STp->block_size;
18071da177e4SLinus Torvalds if (undone <= do_count) {
18081da177e4SLinus Torvalds /* Only data from this write is not written */
18091da177e4SLinus Torvalds count += undone;
1810626dcb1eSKai Makisara b_point -= undone;
18111da177e4SLinus Torvalds do_count -= undone;
18121da177e4SLinus Torvalds if (STp->block_size)
18131da177e4SLinus Torvalds blks = (transfer - undone) / STp->block_size;
18141da177e4SLinus Torvalds STps->eof = ST_EOM_OK;
18151da177e4SLinus Torvalds /* Continue in fixed block mode if all written
18161da177e4SLinus Torvalds in this request but still something left to write
18171da177e4SLinus Torvalds (retval left to zero)
18181da177e4SLinus Torvalds */
18191da177e4SLinus Torvalds if (STp->block_size == 0 ||
18201da177e4SLinus Torvalds undone > 0 || count == 0)
18211da177e4SLinus Torvalds retval = (-ENOSPC); /* EOM within current request */
1822b30d8bcaSHannes Reinecke DEBC_printk(STp, "EOM with %d "
1823b30d8bcaSHannes Reinecke "bytes unwritten.\n",
1824b30d8bcaSHannes Reinecke (int)count);
18251da177e4SLinus Torvalds } else {
18261da177e4SLinus Torvalds /* EOT within data buffered earlier (possible only
18271da177e4SLinus Torvalds in fixed block mode without direct i/o) */
18281da177e4SLinus Torvalds if (!retry_eot && !cmdstatp->deferred &&
18291da177e4SLinus Torvalds (scode == NO_SENSE || scode == RECOVERED_ERROR)) {
18301da177e4SLinus Torvalds move_buffer_data(STp->buffer, transfer - undone);
18311da177e4SLinus Torvalds retry_eot = 1;
18321da177e4SLinus Torvalds if (STps->drv_block >= 0) {
18331da177e4SLinus Torvalds STps->drv_block += (transfer - undone) /
18341da177e4SLinus Torvalds STp->block_size;
18351da177e4SLinus Torvalds }
18361da177e4SLinus Torvalds STps->eof = ST_EOM_OK;
1837b30d8bcaSHannes Reinecke DEBC_printk(STp, "Retry "
1838b30d8bcaSHannes Reinecke "write of %d "
1839b30d8bcaSHannes Reinecke "bytes at EOM.\n",
1840b30d8bcaSHannes Reinecke STp->buffer->buffer_bytes);
18411da177e4SLinus Torvalds goto retry_write;
18421da177e4SLinus Torvalds }
18431da177e4SLinus Torvalds else {
18441da177e4SLinus Torvalds /* Either error within data buffered by driver or
18451da177e4SLinus Torvalds failed retry */
18461da177e4SLinus Torvalds count -= do_count;
18471da177e4SLinus Torvalds blks = do_count = 0;
18481da177e4SLinus Torvalds STps->eof = ST_EOM_ERROR;
18491da177e4SLinus Torvalds STps->drv_block = (-1); /* Too cautious? */
18501da177e4SLinus Torvalds retval = (-EIO); /* EOM for old data */
1851b30d8bcaSHannes Reinecke DEBC_printk(STp, "EOM with "
1852b30d8bcaSHannes Reinecke "lost data.\n");
18531da177e4SLinus Torvalds }
18541da177e4SLinus Torvalds }
18551da177e4SLinus Torvalds } else {
18561da177e4SLinus Torvalds count += do_count;
18571da177e4SLinus Torvalds STps->drv_block = (-1); /* Too cautious? */
18588b05b773SMike Christie retval = STbp->syscall_result;
18591da177e4SLinus Torvalds }
18601da177e4SLinus Torvalds
18611da177e4SLinus Torvalds }
18621da177e4SLinus Torvalds
18631da177e4SLinus Torvalds if (STps->drv_block >= 0) {
18641da177e4SLinus Torvalds if (STp->block_size == 0)
18651da177e4SLinus Torvalds STps->drv_block += (do_count > 0);
18661da177e4SLinus Torvalds else
18671da177e4SLinus Torvalds STps->drv_block += blks;
18681da177e4SLinus Torvalds }
18691da177e4SLinus Torvalds
18701da177e4SLinus Torvalds STbp->buffer_bytes = 0;
18711da177e4SLinus Torvalds STp->dirty = 0;
18721da177e4SLinus Torvalds
18731da177e4SLinus Torvalds if (retval || retry_eot) {
18741da177e4SLinus Torvalds if (count < total)
18751da177e4SLinus Torvalds retval = total - count;
18761da177e4SLinus Torvalds goto out;
18771da177e4SLinus Torvalds }
18781da177e4SLinus Torvalds }
18791da177e4SLinus Torvalds
18801da177e4SLinus Torvalds if (STps->eof == ST_EOD_1)
18811da177e4SLinus Torvalds STps->eof = ST_EOM_OK;
18821da177e4SLinus Torvalds else if (STps->eof != ST_EOM_OK)
18831da177e4SLinus Torvalds STps->eof = ST_NOEOF;
18841da177e4SLinus Torvalds retval = total - count;
18851da177e4SLinus Torvalds
18861da177e4SLinus Torvalds out:
18871da177e4SLinus Torvalds if (SRpnt != NULL)
18888b05b773SMike Christie st_release_request(SRpnt);
1889787926b1SKai Makisara release_buffering(STp, 0);
189028f85009SMatthias Kaehlcke mutex_unlock(&STp->lock);
18911da177e4SLinus Torvalds
18921da177e4SLinus Torvalds return retval;
18931da177e4SLinus Torvalds }
18941da177e4SLinus Torvalds
18951da177e4SLinus Torvalds /* Read data from the tape. Returns zero in the normal case, one if the
18961da177e4SLinus Torvalds eof status has changed, and the negative error code in case of a
18971da177e4SLinus Torvalds fatal error. Otherwise updates the buffer and the eof state.
18981da177e4SLinus Torvalds
18991da177e4SLinus Torvalds Does release user buffer mapping if it is set.
19001da177e4SLinus Torvalds */
read_tape(struct scsi_tape * STp,long count,struct st_request ** aSRpnt)19011da177e4SLinus Torvalds static long read_tape(struct scsi_tape *STp, long count,
19028b05b773SMike Christie struct st_request ** aSRpnt)
19031da177e4SLinus Torvalds {
19041da177e4SLinus Torvalds int transfer, blks, bytes;
19051da177e4SLinus Torvalds unsigned char cmd[MAX_COMMAND_SIZE];
19068b05b773SMike Christie struct st_request *SRpnt;
19071da177e4SLinus Torvalds struct st_modedef *STm;
19081da177e4SLinus Torvalds struct st_partstat *STps;
19091da177e4SLinus Torvalds struct st_buffer *STbp;
19101da177e4SLinus Torvalds int retval = 0;
19111da177e4SLinus Torvalds
19121da177e4SLinus Torvalds if (count == 0)
19131da177e4SLinus Torvalds return 0;
19141da177e4SLinus Torvalds
19151da177e4SLinus Torvalds STm = &(STp->modes[STp->current_mode]);
19161da177e4SLinus Torvalds STps = &(STp->ps[STp->partition]);
19171da177e4SLinus Torvalds if (STps->eof == ST_FM_HIT)
19181da177e4SLinus Torvalds return 1;
19191da177e4SLinus Torvalds STbp = STp->buffer;
19201da177e4SLinus Torvalds
19211da177e4SLinus Torvalds if (STp->block_size == 0)
19221da177e4SLinus Torvalds blks = bytes = count;
19231da177e4SLinus Torvalds else {
19249abe16c6SKai Makisara if (!(STp->try_dio_now && try_rdio) && STm->do_read_ahead) {
19251da177e4SLinus Torvalds blks = (STp->buffer)->buffer_blocks;
19261da177e4SLinus Torvalds bytes = blks * STp->block_size;
19271da177e4SLinus Torvalds } else {
19281da177e4SLinus Torvalds bytes = count;
19291da177e4SLinus Torvalds if (!STbp->do_dio && bytes > (STp->buffer)->buffer_size)
19301da177e4SLinus Torvalds bytes = (STp->buffer)->buffer_size;
19311da177e4SLinus Torvalds blks = bytes / STp->block_size;
19321da177e4SLinus Torvalds bytes = blks * STp->block_size;
19331da177e4SLinus Torvalds }
19341da177e4SLinus Torvalds }
19351da177e4SLinus Torvalds
19361da177e4SLinus Torvalds memset(cmd, 0, MAX_COMMAND_SIZE);
19371da177e4SLinus Torvalds cmd[0] = READ_6;
19381da177e4SLinus Torvalds cmd[1] = (STp->block_size != 0);
193940f6b36cSKai Makisara if (!cmd[1] && STp->sili)
194040f6b36cSKai Makisara cmd[1] |= 2;
19411da177e4SLinus Torvalds cmd[2] = blks >> 16;
19421da177e4SLinus Torvalds cmd[3] = blks >> 8;
19431da177e4SLinus Torvalds cmd[4] = blks;
19441da177e4SLinus Torvalds
19451da177e4SLinus Torvalds SRpnt = *aSRpnt;
19461da177e4SLinus Torvalds SRpnt = st_do_scsi(SRpnt, STp, cmd, bytes, DMA_FROM_DEVICE,
1947a02488edSJames Bottomley STp->device->request_queue->rq_timeout,
1948a02488edSJames Bottomley MAX_RETRIES, 1);
1949787926b1SKai Makisara release_buffering(STp, 1);
19501da177e4SLinus Torvalds *aSRpnt = SRpnt;
19511da177e4SLinus Torvalds if (!SRpnt)
19521da177e4SLinus Torvalds return STbp->syscall_result;
19531da177e4SLinus Torvalds
19541da177e4SLinus Torvalds STbp->read_pointer = 0;
19551da177e4SLinus Torvalds STps->at_sm = 0;
19561da177e4SLinus Torvalds
19571da177e4SLinus Torvalds /* Something to check */
19581da177e4SLinus Torvalds if (STbp->syscall_result) {
19591da177e4SLinus Torvalds struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat;
19601da177e4SLinus Torvalds
19611da177e4SLinus Torvalds retval = 1;
1962b30d8bcaSHannes Reinecke DEBC_printk(STp,
1963b30d8bcaSHannes Reinecke "Sense: %2x %2x %2x %2x %2x %2x %2x %2x\n",
19648b05b773SMike Christie SRpnt->sense[0], SRpnt->sense[1],
19658b05b773SMike Christie SRpnt->sense[2], SRpnt->sense[3],
19668b05b773SMike Christie SRpnt->sense[4], SRpnt->sense[5],
1967b30d8bcaSHannes Reinecke SRpnt->sense[6], SRpnt->sense[7]);
19681da177e4SLinus Torvalds if (cmdstatp->have_sense) {
19691da177e4SLinus Torvalds
19701da177e4SLinus Torvalds if (cmdstatp->sense_hdr.sense_key == BLANK_CHECK)
19711da177e4SLinus Torvalds cmdstatp->flags &= 0xcf; /* No need for EOM in this case */
19721da177e4SLinus Torvalds
19731da177e4SLinus Torvalds if (cmdstatp->flags != 0) { /* EOF, EOM, or ILI */
19741da177e4SLinus Torvalds /* Compute the residual count */
19751da177e4SLinus Torvalds if (cmdstatp->remainder_valid)
19761da177e4SLinus Torvalds transfer = (int)cmdstatp->uremainder64;
19771da177e4SLinus Torvalds else
19781da177e4SLinus Torvalds transfer = 0;
19795e4fabb6SKai Makisara if (cmdstatp->sense_hdr.sense_key == MEDIUM_ERROR) {
19805e4fabb6SKai Makisara if (STp->block_size == 0)
19811da177e4SLinus Torvalds transfer = bytes;
19825e4fabb6SKai Makisara /* Some drives set ILI with MEDIUM ERROR */
19835e4fabb6SKai Makisara cmdstatp->flags &= ~SENSE_ILI;
19845e4fabb6SKai Makisara }
19851da177e4SLinus Torvalds
19861da177e4SLinus Torvalds if (cmdstatp->flags & SENSE_ILI) { /* ILI */
1987b30d8bcaSHannes Reinecke if (STp->block_size == 0 &&
1988b30d8bcaSHannes Reinecke transfer < 0) {
1989b30d8bcaSHannes Reinecke st_printk(KERN_NOTICE, STp,
1990b30d8bcaSHannes Reinecke "Failed to read %d "
1991b30d8bcaSHannes Reinecke "byte block with %d "
1992b30d8bcaSHannes Reinecke "byte transfer.\n",
1993b30d8bcaSHannes Reinecke bytes - transfer,
1994b30d8bcaSHannes Reinecke bytes);
19951da177e4SLinus Torvalds if (STps->drv_block >= 0)
19961da177e4SLinus Torvalds STps->drv_block += 1;
19971da177e4SLinus Torvalds STbp->buffer_bytes = 0;
19981da177e4SLinus Torvalds return (-ENOMEM);
1999b30d8bcaSHannes Reinecke } else if (STp->block_size == 0) {
20001da177e4SLinus Torvalds STbp->buffer_bytes = bytes - transfer;
20011da177e4SLinus Torvalds } else {
20028b05b773SMike Christie st_release_request(SRpnt);
20031da177e4SLinus Torvalds SRpnt = *aSRpnt = NULL;
20041da177e4SLinus Torvalds if (transfer == blks) { /* We did not get anything, error */
2005b30d8bcaSHannes Reinecke st_printk(KERN_NOTICE, STp,
2006b30d8bcaSHannes Reinecke "Incorrect "
2007b30d8bcaSHannes Reinecke "block size.\n");
20081da177e4SLinus Torvalds if (STps->drv_block >= 0)
20091da177e4SLinus Torvalds STps->drv_block += blks - transfer + 1;
20101da177e4SLinus Torvalds st_int_ioctl(STp, MTBSR, 1);
20111da177e4SLinus Torvalds return (-EIO);
20121da177e4SLinus Torvalds }
20131da177e4SLinus Torvalds /* We have some data, deliver it */
20141da177e4SLinus Torvalds STbp->buffer_bytes = (blks - transfer) *
20151da177e4SLinus Torvalds STp->block_size;
2016b30d8bcaSHannes Reinecke DEBC_printk(STp, "ILI but "
2017b30d8bcaSHannes Reinecke "enough data "
2018b30d8bcaSHannes Reinecke "received %ld "
2019b30d8bcaSHannes Reinecke "%d.\n", count,
2020b30d8bcaSHannes Reinecke STbp->buffer_bytes);
20211da177e4SLinus Torvalds if (STps->drv_block >= 0)
20221da177e4SLinus Torvalds STps->drv_block += 1;
20231da177e4SLinus Torvalds if (st_int_ioctl(STp, MTBSR, 1))
20241da177e4SLinus Torvalds return (-EIO);
20251da177e4SLinus Torvalds }
20261da177e4SLinus Torvalds } else if (cmdstatp->flags & SENSE_FMK) { /* FM overrides EOM */
20271da177e4SLinus Torvalds if (STps->eof != ST_FM_HIT)
20281da177e4SLinus Torvalds STps->eof = ST_FM_HIT;
20291da177e4SLinus Torvalds else
20301da177e4SLinus Torvalds STps->eof = ST_EOD_2;
20311da177e4SLinus Torvalds if (STp->block_size == 0)
20321da177e4SLinus Torvalds STbp->buffer_bytes = 0;
20331da177e4SLinus Torvalds else
20341da177e4SLinus Torvalds STbp->buffer_bytes =
20351da177e4SLinus Torvalds bytes - transfer * STp->block_size;
2036b30d8bcaSHannes Reinecke DEBC_printk(STp, "EOF detected (%d "
2037b30d8bcaSHannes Reinecke "bytes read).\n",
2038b30d8bcaSHannes Reinecke STbp->buffer_bytes);
20391da177e4SLinus Torvalds } else if (cmdstatp->flags & SENSE_EOM) {
20401da177e4SLinus Torvalds if (STps->eof == ST_FM)
20411da177e4SLinus Torvalds STps->eof = ST_EOD_1;
20421da177e4SLinus Torvalds else
20431da177e4SLinus Torvalds STps->eof = ST_EOM_OK;
20441da177e4SLinus Torvalds if (STp->block_size == 0)
20451da177e4SLinus Torvalds STbp->buffer_bytes = bytes - transfer;
20461da177e4SLinus Torvalds else
20471da177e4SLinus Torvalds STbp->buffer_bytes =
20481da177e4SLinus Torvalds bytes - transfer * STp->block_size;
20491da177e4SLinus Torvalds
2050b30d8bcaSHannes Reinecke DEBC_printk(STp, "EOM detected (%d "
2051b30d8bcaSHannes Reinecke "bytes read).\n",
2052b30d8bcaSHannes Reinecke STbp->buffer_bytes);
20531da177e4SLinus Torvalds }
20541da177e4SLinus Torvalds }
20551da177e4SLinus Torvalds /* end of EOF, EOM, ILI test */
20561da177e4SLinus Torvalds else { /* nonzero sense key */
2057b30d8bcaSHannes Reinecke DEBC_printk(STp, "Tape error while reading.\n");
20581da177e4SLinus Torvalds STps->drv_block = (-1);
20591da177e4SLinus Torvalds if (STps->eof == ST_FM &&
20601da177e4SLinus Torvalds cmdstatp->sense_hdr.sense_key == BLANK_CHECK) {
2061b30d8bcaSHannes Reinecke DEBC_printk(STp, "Zero returned for "
2062b30d8bcaSHannes Reinecke "first BLANK CHECK "
2063b30d8bcaSHannes Reinecke "after EOF.\n");
20641da177e4SLinus Torvalds STps->eof = ST_EOD_2; /* First BLANK_CHECK after FM */
20651da177e4SLinus Torvalds } else /* Some other extended sense code */
20661da177e4SLinus Torvalds retval = (-EIO);
20671da177e4SLinus Torvalds }
20681da177e4SLinus Torvalds
20691da177e4SLinus Torvalds if (STbp->buffer_bytes < 0) /* Caused by bogus sense data */
20701da177e4SLinus Torvalds STbp->buffer_bytes = 0;
20711da177e4SLinus Torvalds }
20721da177e4SLinus Torvalds /* End of extended sense test */
20731da177e4SLinus Torvalds else { /* Non-extended sense */
20741da177e4SLinus Torvalds retval = STbp->syscall_result;
20751da177e4SLinus Torvalds }
20761da177e4SLinus Torvalds
20771da177e4SLinus Torvalds }
20781da177e4SLinus Torvalds /* End of error handling */
207940f6b36cSKai Makisara else { /* Read successful */
20801da177e4SLinus Torvalds STbp->buffer_bytes = bytes;
208140f6b36cSKai Makisara if (STp->sili) /* In fixed block mode residual is always zero here */
208240f6b36cSKai Makisara STbp->buffer_bytes -= STp->buffer->cmdstat.residual;
208340f6b36cSKai Makisara }
20841da177e4SLinus Torvalds
20851da177e4SLinus Torvalds if (STps->drv_block >= 0) {
20861da177e4SLinus Torvalds if (STp->block_size == 0)
20871da177e4SLinus Torvalds STps->drv_block++;
20881da177e4SLinus Torvalds else
20891da177e4SLinus Torvalds STps->drv_block += STbp->buffer_bytes / STp->block_size;
20901da177e4SLinus Torvalds }
20911da177e4SLinus Torvalds return retval;
20921da177e4SLinus Torvalds }
20931da177e4SLinus Torvalds
20941da177e4SLinus Torvalds
20951da177e4SLinus Torvalds /* Read command */
20961da177e4SLinus Torvalds static ssize_t
st_read(struct file * filp,char __user * buf,size_t count,loff_t * ppos)20971da177e4SLinus Torvalds st_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos)
20981da177e4SLinus Torvalds {
20991da177e4SLinus Torvalds ssize_t total;
21001da177e4SLinus Torvalds ssize_t retval = 0;
21011da177e4SLinus Torvalds ssize_t i, transfer;
21021da177e4SLinus Torvalds int special, do_dio = 0;
21038b05b773SMike Christie struct st_request *SRpnt = NULL;
21041da177e4SLinus Torvalds struct scsi_tape *STp = filp->private_data;
21051da177e4SLinus Torvalds struct st_modedef *STm;
21061da177e4SLinus Torvalds struct st_partstat *STps;
21071da177e4SLinus Torvalds struct st_buffer *STbp = STp->buffer;
21081da177e4SLinus Torvalds
210928f85009SMatthias Kaehlcke if (mutex_lock_interruptible(&STp->lock))
21101da177e4SLinus Torvalds return -ERESTARTSYS;
21111da177e4SLinus Torvalds
21121da177e4SLinus Torvalds retval = rw_checks(STp, filp, count);
21131da177e4SLinus Torvalds if (retval || count == 0)
21141da177e4SLinus Torvalds goto out;
21151da177e4SLinus Torvalds
21161da177e4SLinus Torvalds STm = &(STp->modes[STp->current_mode]);
21179abe16c6SKai Makisara if (STp->block_size != 0 && (count % STp->block_size) != 0) {
21189abe16c6SKai Makisara if (!STm->do_read_ahead) {
21191da177e4SLinus Torvalds retval = (-EINVAL); /* Read must be integral number of blocks */
21201da177e4SLinus Torvalds goto out;
21211da177e4SLinus Torvalds }
21229abe16c6SKai Makisara STp->try_dio_now = 0; /* Direct i/o can't handle split blocks */
21239abe16c6SKai Makisara }
21241da177e4SLinus Torvalds
21251da177e4SLinus Torvalds STps = &(STp->ps[STp->partition]);
21261da177e4SLinus Torvalds if (STps->rw == ST_WRITING) {
21271da177e4SLinus Torvalds retval = flush_buffer(STp, 0);
21281da177e4SLinus Torvalds if (retval)
21291da177e4SLinus Torvalds goto out;
21301da177e4SLinus Torvalds STps->rw = ST_READING;
21311da177e4SLinus Torvalds }
21321da177e4SLinus Torvalds DEB(
21331da177e4SLinus Torvalds if (debugging && STps->eof != ST_NOEOF)
2134b30d8bcaSHannes Reinecke st_printk(ST_DEB_MSG, STp,
2135b30d8bcaSHannes Reinecke "EOF/EOM flag up (%d). Bytes %d\n",
21361da177e4SLinus Torvalds STps->eof, STbp->buffer_bytes);
21371da177e4SLinus Torvalds ) /* end DEB */
21381da177e4SLinus Torvalds
21391da177e4SLinus Torvalds retval = setup_buffering(STp, buf, count, 1);
21401da177e4SLinus Torvalds if (retval)
21411da177e4SLinus Torvalds goto out;
21421da177e4SLinus Torvalds do_dio = STbp->do_dio;
21431da177e4SLinus Torvalds
21441da177e4SLinus Torvalds if (STbp->buffer_bytes == 0 &&
21451da177e4SLinus Torvalds STps->eof >= ST_EOD_1) {
21461da177e4SLinus Torvalds if (STps->eof < ST_EOD) {
21471da177e4SLinus Torvalds STps->eof += 1;
21481da177e4SLinus Torvalds retval = 0;
21491da177e4SLinus Torvalds goto out;
21501da177e4SLinus Torvalds }
21511da177e4SLinus Torvalds retval = (-EIO); /* EOM or Blank Check */
21521da177e4SLinus Torvalds goto out;
21531da177e4SLinus Torvalds }
21541da177e4SLinus Torvalds
21551da177e4SLinus Torvalds if (do_dio) {
21561da177e4SLinus Torvalds /* Check the buffer writability before any tape movement. Don't alter
21571da177e4SLinus Torvalds buffer data. */
21581da177e4SLinus Torvalds if (copy_from_user(&i, buf, 1) != 0 ||
21591da177e4SLinus Torvalds copy_to_user(buf, &i, 1) != 0 ||
21601da177e4SLinus Torvalds copy_from_user(&i, buf + count - 1, 1) != 0 ||
21611da177e4SLinus Torvalds copy_to_user(buf + count - 1, &i, 1) != 0) {
21621da177e4SLinus Torvalds retval = (-EFAULT);
21631da177e4SLinus Torvalds goto out;
21641da177e4SLinus Torvalds }
21651da177e4SLinus Torvalds }
21661da177e4SLinus Torvalds
21671da177e4SLinus Torvalds STps->rw = ST_READING;
21681da177e4SLinus Torvalds
21691da177e4SLinus Torvalds
21701da177e4SLinus Torvalds /* Loop until enough data in buffer or a special condition found */
21711da177e4SLinus Torvalds for (total = 0, special = 0; total < count && !special;) {
21721da177e4SLinus Torvalds
21731da177e4SLinus Torvalds /* Get new data if the buffer is empty */
21741da177e4SLinus Torvalds if (STbp->buffer_bytes == 0) {
21751da177e4SLinus Torvalds special = read_tape(STp, count - total, &SRpnt);
21761da177e4SLinus Torvalds if (special < 0) { /* No need to continue read */
21771da177e4SLinus Torvalds retval = special;
21781da177e4SLinus Torvalds goto out;
21791da177e4SLinus Torvalds }
21801da177e4SLinus Torvalds }
21811da177e4SLinus Torvalds
21821da177e4SLinus Torvalds /* Move the data from driver buffer to user buffer */
21831da177e4SLinus Torvalds if (STbp->buffer_bytes > 0) {
21841da177e4SLinus Torvalds DEB(
21851da177e4SLinus Torvalds if (debugging && STps->eof != ST_NOEOF)
2186b30d8bcaSHannes Reinecke st_printk(ST_DEB_MSG, STp,
2187b30d8bcaSHannes Reinecke "EOF up (%d). Left %d, needed %d.\n",
21881da177e4SLinus Torvalds STps->eof, STbp->buffer_bytes,
21891da177e4SLinus Torvalds (int)(count - total));
21901da177e4SLinus Torvalds ) /* end DEB */
21911da177e4SLinus Torvalds transfer = STbp->buffer_bytes < count - total ?
21921da177e4SLinus Torvalds STbp->buffer_bytes : count - total;
21931da177e4SLinus Torvalds if (!do_dio) {
21941da177e4SLinus Torvalds i = from_buffer(STbp, buf, transfer);
21951da177e4SLinus Torvalds if (i) {
21961da177e4SLinus Torvalds retval = i;
21971da177e4SLinus Torvalds goto out;
21981da177e4SLinus Torvalds }
21991da177e4SLinus Torvalds }
22001da177e4SLinus Torvalds buf += transfer;
22011da177e4SLinus Torvalds total += transfer;
22021da177e4SLinus Torvalds }
22031da177e4SLinus Torvalds
22041da177e4SLinus Torvalds if (STp->block_size == 0)
22051da177e4SLinus Torvalds break; /* Read only one variable length block */
22061da177e4SLinus Torvalds
22071da177e4SLinus Torvalds } /* for (total = 0, special = 0;
22081da177e4SLinus Torvalds total < count && !special; ) */
22091da177e4SLinus Torvalds
22101da177e4SLinus Torvalds /* Change the eof state if no data from tape or buffer */
22111da177e4SLinus Torvalds if (total == 0) {
22121da177e4SLinus Torvalds if (STps->eof == ST_FM_HIT) {
22131da177e4SLinus Torvalds STps->eof = ST_FM;
22141da177e4SLinus Torvalds STps->drv_block = 0;
22151da177e4SLinus Torvalds if (STps->drv_file >= 0)
22161da177e4SLinus Torvalds STps->drv_file++;
22171da177e4SLinus Torvalds } else if (STps->eof == ST_EOD_1) {
22181da177e4SLinus Torvalds STps->eof = ST_EOD_2;
22191da177e4SLinus Torvalds STps->drv_block = 0;
22201da177e4SLinus Torvalds if (STps->drv_file >= 0)
22211da177e4SLinus Torvalds STps->drv_file++;
22221da177e4SLinus Torvalds } else if (STps->eof == ST_EOD_2)
22231da177e4SLinus Torvalds STps->eof = ST_EOD;
22241da177e4SLinus Torvalds } else if (STps->eof == ST_FM)
22251da177e4SLinus Torvalds STps->eof = ST_NOEOF;
22261da177e4SLinus Torvalds retval = total;
22271da177e4SLinus Torvalds
22281da177e4SLinus Torvalds out:
22291da177e4SLinus Torvalds if (SRpnt != NULL) {
22308b05b773SMike Christie st_release_request(SRpnt);
22311da177e4SLinus Torvalds SRpnt = NULL;
22321da177e4SLinus Torvalds }
22331da177e4SLinus Torvalds if (do_dio) {
2234787926b1SKai Makisara release_buffering(STp, 1);
22351da177e4SLinus Torvalds STbp->buffer_bytes = 0;
22361da177e4SLinus Torvalds }
223728f85009SMatthias Kaehlcke mutex_unlock(&STp->lock);
22381da177e4SLinus Torvalds
22391da177e4SLinus Torvalds return retval;
22401da177e4SLinus Torvalds }
22411da177e4SLinus Torvalds
22421da177e4SLinus Torvalds
22431da177e4SLinus 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); } } )22441da177e4SLinus Torvalds DEB(
22451da177e4SLinus Torvalds /* Set the driver options */
2246b30d8bcaSHannes Reinecke static void st_log_options(struct scsi_tape * STp, struct st_modedef * STm)
22471da177e4SLinus Torvalds {
22481da177e4SLinus Torvalds if (debugging) {
2249b30d8bcaSHannes Reinecke st_printk(KERN_INFO, STp,
2250b30d8bcaSHannes Reinecke "Mode %d options: buffer writes: %d, "
2251b30d8bcaSHannes Reinecke "async writes: %d, read ahead: %d\n",
2252b30d8bcaSHannes Reinecke STp->current_mode, STm->do_buffer_writes,
2253b30d8bcaSHannes Reinecke STm->do_async_writes, STm->do_read_ahead);
2254b30d8bcaSHannes Reinecke st_printk(KERN_INFO, STp,
2255b30d8bcaSHannes Reinecke " can bsr: %d, two FMs: %d, "
2256b30d8bcaSHannes Reinecke "fast mteom: %d, auto lock: %d,\n",
2257b30d8bcaSHannes Reinecke STp->can_bsr, STp->two_fm, STp->fast_mteom,
2258b30d8bcaSHannes Reinecke STp->do_auto_lock);
2259b30d8bcaSHannes Reinecke st_printk(KERN_INFO, STp,
2260b30d8bcaSHannes Reinecke " defs for wr: %d, no block limits: %d, "
2261b30d8bcaSHannes Reinecke "partitions: %d, s2 log: %d\n",
2262b30d8bcaSHannes Reinecke STm->defaults_for_writes, STp->omit_blklims,
2263b30d8bcaSHannes Reinecke STp->can_partitions, STp->scsi2_logical);
2264b30d8bcaSHannes Reinecke st_printk(KERN_INFO, STp,
2265b30d8bcaSHannes Reinecke " sysv: %d nowait: %d sili: %d "
2266b30d8bcaSHannes Reinecke "nowait_filemark: %d\n",
2267b30d8bcaSHannes Reinecke STm->sysv, STp->immediate, STp->sili,
2268c743e44fSLee Duncan STp->immediate_filemark);
2269b30d8bcaSHannes Reinecke st_printk(KERN_INFO, STp, " debugging: %d\n", debugging);
22701da177e4SLinus Torvalds }
22711da177e4SLinus Torvalds }
22721da177e4SLinus Torvalds )
22731da177e4SLinus Torvalds
22741da177e4SLinus Torvalds
22751da177e4SLinus Torvalds static int st_set_options(struct scsi_tape *STp, long options)
22761da177e4SLinus Torvalds {
22771da177e4SLinus Torvalds int value;
22781da177e4SLinus Torvalds long code;
22791da177e4SLinus Torvalds struct st_modedef *STm;
22801da177e4SLinus Torvalds struct cdev *cd0, *cd1;
2281d6216c47SMaurizio Lombardi struct device *d0, *d1;
22821da177e4SLinus Torvalds
22831da177e4SLinus Torvalds STm = &(STp->modes[STp->current_mode]);
22841da177e4SLinus Torvalds if (!STm->defined) {
2285d6216c47SMaurizio Lombardi cd0 = STm->cdevs[0];
2286d6216c47SMaurizio Lombardi cd1 = STm->cdevs[1];
2287d6216c47SMaurizio Lombardi d0 = STm->devs[0];
2288d6216c47SMaurizio Lombardi d1 = STm->devs[1];
22891da177e4SLinus Torvalds memcpy(STm, &(STp->modes[0]), sizeof(struct st_modedef));
2290d6216c47SMaurizio Lombardi STm->cdevs[0] = cd0;
2291d6216c47SMaurizio Lombardi STm->cdevs[1] = cd1;
2292d6216c47SMaurizio Lombardi STm->devs[0] = d0;
2293d6216c47SMaurizio Lombardi STm->devs[1] = d1;
22941da177e4SLinus Torvalds modes_defined = 1;
2295b30d8bcaSHannes Reinecke DEBC_printk(STp, "Initialized mode %d definition from mode 0\n",
2296b30d8bcaSHannes Reinecke STp->current_mode);
22971da177e4SLinus Torvalds }
22981da177e4SLinus Torvalds
22991da177e4SLinus Torvalds code = options & MT_ST_OPTIONS;
23001da177e4SLinus Torvalds if (code == MT_ST_BOOLEANS) {
23011da177e4SLinus Torvalds STm->do_buffer_writes = (options & MT_ST_BUFFER_WRITES) != 0;
23021da177e4SLinus Torvalds STm->do_async_writes = (options & MT_ST_ASYNC_WRITES) != 0;
23031da177e4SLinus Torvalds STm->defaults_for_writes = (options & MT_ST_DEF_WRITES) != 0;
23041da177e4SLinus Torvalds STm->do_read_ahead = (options & MT_ST_READ_AHEAD) != 0;
23051da177e4SLinus Torvalds STp->two_fm = (options & MT_ST_TWO_FM) != 0;
23061da177e4SLinus Torvalds STp->fast_mteom = (options & MT_ST_FAST_MTEOM) != 0;
23071da177e4SLinus Torvalds STp->do_auto_lock = (options & MT_ST_AUTO_LOCK) != 0;
23081da177e4SLinus Torvalds STp->can_bsr = (options & MT_ST_CAN_BSR) != 0;
23091da177e4SLinus Torvalds STp->omit_blklims = (options & MT_ST_NO_BLKLIMS) != 0;
23101da177e4SLinus Torvalds if ((STp->device)->scsi_level >= SCSI_2)
23111da177e4SLinus Torvalds STp->can_partitions = (options & MT_ST_CAN_PARTITIONS) != 0;
23121da177e4SLinus Torvalds STp->scsi2_logical = (options & MT_ST_SCSI2LOGICAL) != 0;
23131da177e4SLinus Torvalds STp->immediate = (options & MT_ST_NOWAIT) != 0;
2314c743e44fSLee Duncan STp->immediate_filemark = (options & MT_ST_NOWAIT_EOF) != 0;
23151da177e4SLinus Torvalds STm->sysv = (options & MT_ST_SYSV) != 0;
231640f6b36cSKai Makisara STp->sili = (options & MT_ST_SILI) != 0;
23171da177e4SLinus Torvalds DEB( debugging = (options & MT_ST_DEBUGGING) != 0;
2318b30d8bcaSHannes Reinecke st_log_options(STp, STm); )
23191da177e4SLinus Torvalds } else if (code == MT_ST_SETBOOLEANS || code == MT_ST_CLEARBOOLEANS) {
23201da177e4SLinus Torvalds value = (code == MT_ST_SETBOOLEANS);
23211da177e4SLinus Torvalds if ((options & MT_ST_BUFFER_WRITES) != 0)
23221da177e4SLinus Torvalds STm->do_buffer_writes = value;
23231da177e4SLinus Torvalds if ((options & MT_ST_ASYNC_WRITES) != 0)
23241da177e4SLinus Torvalds STm->do_async_writes = value;
23251da177e4SLinus Torvalds if ((options & MT_ST_DEF_WRITES) != 0)
23261da177e4SLinus Torvalds STm->defaults_for_writes = value;
23271da177e4SLinus Torvalds if ((options & MT_ST_READ_AHEAD) != 0)
23281da177e4SLinus Torvalds STm->do_read_ahead = value;
23291da177e4SLinus Torvalds if ((options & MT_ST_TWO_FM) != 0)
23301da177e4SLinus Torvalds STp->two_fm = value;
23311da177e4SLinus Torvalds if ((options & MT_ST_FAST_MTEOM) != 0)
23321da177e4SLinus Torvalds STp->fast_mteom = value;
23331da177e4SLinus Torvalds if ((options & MT_ST_AUTO_LOCK) != 0)
23341da177e4SLinus Torvalds STp->do_auto_lock = value;
23351da177e4SLinus Torvalds if ((options & MT_ST_CAN_BSR) != 0)
23361da177e4SLinus Torvalds STp->can_bsr = value;
23371da177e4SLinus Torvalds if ((options & MT_ST_NO_BLKLIMS) != 0)
23381da177e4SLinus Torvalds STp->omit_blklims = value;
23391da177e4SLinus Torvalds if ((STp->device)->scsi_level >= SCSI_2 &&
23401da177e4SLinus Torvalds (options & MT_ST_CAN_PARTITIONS) != 0)
23411da177e4SLinus Torvalds STp->can_partitions = value;
23421da177e4SLinus Torvalds if ((options & MT_ST_SCSI2LOGICAL) != 0)
23431da177e4SLinus Torvalds STp->scsi2_logical = value;
23441da177e4SLinus Torvalds if ((options & MT_ST_NOWAIT) != 0)
23451da177e4SLinus Torvalds STp->immediate = value;
2346c743e44fSLee Duncan if ((options & MT_ST_NOWAIT_EOF) != 0)
2347c743e44fSLee Duncan STp->immediate_filemark = value;
23481da177e4SLinus Torvalds if ((options & MT_ST_SYSV) != 0)
23491da177e4SLinus Torvalds STm->sysv = value;
235040f6b36cSKai Makisara if ((options & MT_ST_SILI) != 0)
235140f6b36cSKai Makisara STp->sili = value;
23521da177e4SLinus Torvalds DEB(
23531da177e4SLinus Torvalds if ((options & MT_ST_DEBUGGING) != 0)
23541da177e4SLinus Torvalds debugging = value;
2355b30d8bcaSHannes Reinecke st_log_options(STp, STm); )
23561da177e4SLinus Torvalds } else if (code == MT_ST_WRITE_THRESHOLD) {
23571da177e4SLinus Torvalds /* Retained for compatibility */
23581da177e4SLinus Torvalds } else if (code == MT_ST_DEF_BLKSIZE) {
23591da177e4SLinus Torvalds value = (options & ~MT_ST_OPTIONS);
23601da177e4SLinus Torvalds if (value == ~MT_ST_OPTIONS) {
23611da177e4SLinus Torvalds STm->default_blksize = (-1);
2362b30d8bcaSHannes Reinecke DEBC_printk(STp, "Default block size disabled.\n");
23631da177e4SLinus Torvalds } else {
23641da177e4SLinus Torvalds STm->default_blksize = value;
2365b30d8bcaSHannes Reinecke DEBC_printk(STp,"Default block size set to "
2366b30d8bcaSHannes Reinecke "%d bytes.\n", STm->default_blksize);
23671da177e4SLinus Torvalds if (STp->ready == ST_READY) {
23681da177e4SLinus Torvalds STp->blksize_changed = 0;
23691da177e4SLinus Torvalds set_mode_densblk(STp, STm);
23701da177e4SLinus Torvalds }
23711da177e4SLinus Torvalds }
23721da177e4SLinus Torvalds } else if (code == MT_ST_TIMEOUTS) {
23731da177e4SLinus Torvalds value = (options & ~MT_ST_OPTIONS);
23741da177e4SLinus Torvalds if ((value & MT_ST_SET_LONG_TIMEOUT) != 0) {
23751da177e4SLinus Torvalds STp->long_timeout = (value & ~MT_ST_SET_LONG_TIMEOUT) * HZ;
2376b30d8bcaSHannes Reinecke DEBC_printk(STp, "Long timeout set to %d seconds.\n",
2377b30d8bcaSHannes Reinecke (value & ~MT_ST_SET_LONG_TIMEOUT));
23781da177e4SLinus Torvalds } else {
2379a02488edSJames Bottomley blk_queue_rq_timeout(STp->device->request_queue,
2380a02488edSJames Bottomley value * HZ);
2381b30d8bcaSHannes Reinecke DEBC_printk(STp, "Normal timeout set to %d seconds.\n",
2382b30d8bcaSHannes Reinecke value);
23831da177e4SLinus Torvalds }
23841da177e4SLinus Torvalds } else if (code == MT_ST_SET_CLN) {
23851da177e4SLinus Torvalds value = (options & ~MT_ST_OPTIONS) & 0xff;
23861da177e4SLinus Torvalds if (value != 0 &&
2387832151f4SRoel Kluin (value < EXTENDED_SENSE_START ||
2388832151f4SRoel Kluin value >= SCSI_SENSE_BUFFERSIZE))
23891da177e4SLinus Torvalds return (-EINVAL);
23901da177e4SLinus Torvalds STp->cln_mode = value;
23911da177e4SLinus Torvalds STp->cln_sense_mask = (options >> 8) & 0xff;
23921da177e4SLinus Torvalds STp->cln_sense_value = (options >> 16) & 0xff;
2393b30d8bcaSHannes Reinecke st_printk(KERN_INFO, STp,
2394b30d8bcaSHannes Reinecke "Cleaning request mode %d, mask %02x, value %02x\n",
2395b30d8bcaSHannes Reinecke value, STp->cln_sense_mask, STp->cln_sense_value);
23961da177e4SLinus Torvalds } else if (code == MT_ST_DEF_OPTIONS) {
23971da177e4SLinus Torvalds code = (options & ~MT_ST_CLEAR_DEFAULT);
23981da177e4SLinus Torvalds value = (options & MT_ST_CLEAR_DEFAULT);
23991da177e4SLinus Torvalds if (code == MT_ST_DEF_DENSITY) {
24001da177e4SLinus Torvalds if (value == MT_ST_CLEAR_DEFAULT) {
24011da177e4SLinus Torvalds STm->default_density = (-1);
2402b30d8bcaSHannes Reinecke DEBC_printk(STp,
2403b30d8bcaSHannes Reinecke "Density default disabled.\n");
24041da177e4SLinus Torvalds } else {
24051da177e4SLinus Torvalds STm->default_density = value & 0xff;
2406b30d8bcaSHannes Reinecke DEBC_printk(STp, "Density default set to %x\n",
2407b30d8bcaSHannes Reinecke STm->default_density);
24081da177e4SLinus Torvalds if (STp->ready == ST_READY) {
24091da177e4SLinus Torvalds STp->density_changed = 0;
24101da177e4SLinus Torvalds set_mode_densblk(STp, STm);
24111da177e4SLinus Torvalds }
24121da177e4SLinus Torvalds }
24131da177e4SLinus Torvalds } else if (code == MT_ST_DEF_DRVBUFFER) {
24141da177e4SLinus Torvalds if (value == MT_ST_CLEAR_DEFAULT) {
24151da177e4SLinus Torvalds STp->default_drvbuffer = 0xff;
2416b30d8bcaSHannes Reinecke DEBC_printk(STp,
2417b30d8bcaSHannes Reinecke "Drive buffer default disabled.\n");
24181da177e4SLinus Torvalds } else {
24191da177e4SLinus Torvalds STp->default_drvbuffer = value & 7;
2420b30d8bcaSHannes Reinecke DEBC_printk(STp,
2421b30d8bcaSHannes Reinecke "Drive buffer default set to %x\n",
2422b30d8bcaSHannes Reinecke STp->default_drvbuffer);
24231da177e4SLinus Torvalds if (STp->ready == ST_READY)
24241da177e4SLinus Torvalds st_int_ioctl(STp, MTSETDRVBUFFER, STp->default_drvbuffer);
24251da177e4SLinus Torvalds }
24261da177e4SLinus Torvalds } else if (code == MT_ST_DEF_COMPRESSION) {
24271da177e4SLinus Torvalds if (value == MT_ST_CLEAR_DEFAULT) {
24281da177e4SLinus Torvalds STm->default_compression = ST_DONT_TOUCH;
2429b30d8bcaSHannes Reinecke DEBC_printk(STp,
2430b30d8bcaSHannes Reinecke "Compression default disabled.\n");
24311da177e4SLinus Torvalds } else {
24321da177e4SLinus Torvalds if ((value & 0xff00) != 0) {
24331da177e4SLinus Torvalds STp->c_algo = (value & 0xff00) >> 8;
2434b30d8bcaSHannes Reinecke DEBC_printk(STp, "Compression "
2435b30d8bcaSHannes Reinecke "algorithm set to 0x%x.\n",
2436b30d8bcaSHannes Reinecke STp->c_algo);
24371da177e4SLinus Torvalds }
24381da177e4SLinus Torvalds if ((value & 0xff) != 0xff) {
24391da177e4SLinus Torvalds STm->default_compression = (value & 1 ? ST_YES : ST_NO);
2440b30d8bcaSHannes Reinecke DEBC_printk(STp, "Compression default "
2441b30d8bcaSHannes Reinecke "set to %x\n",
2442b30d8bcaSHannes Reinecke (value & 1));
24431da177e4SLinus Torvalds if (STp->ready == ST_READY) {
24441da177e4SLinus Torvalds STp->compression_changed = 0;
24451da177e4SLinus Torvalds st_compression(STp, (STm->default_compression == ST_YES));
24461da177e4SLinus Torvalds }
24471da177e4SLinus Torvalds }
24481da177e4SLinus Torvalds }
24491da177e4SLinus Torvalds }
24501da177e4SLinus Torvalds } else
24511da177e4SLinus Torvalds return (-EIO);
24521da177e4SLinus Torvalds
24531da177e4SLinus Torvalds return 0;
24541da177e4SLinus Torvalds }
24551da177e4SLinus Torvalds
24561da177e4SLinus Torvalds #define MODE_HEADER_LENGTH 4
24571da177e4SLinus Torvalds
24581da177e4SLinus Torvalds /* Mode header and page byte offsets */
24591da177e4SLinus Torvalds #define MH_OFF_DATA_LENGTH 0
24601da177e4SLinus Torvalds #define MH_OFF_MEDIUM_TYPE 1
24611da177e4SLinus Torvalds #define MH_OFF_DEV_SPECIFIC 2
24621da177e4SLinus Torvalds #define MH_OFF_BDESCS_LENGTH 3
24631da177e4SLinus Torvalds #define MP_OFF_PAGE_NBR 0
24641da177e4SLinus Torvalds #define MP_OFF_PAGE_LENGTH 1
24651da177e4SLinus Torvalds
24661da177e4SLinus Torvalds /* Mode header and page bit masks */
24671da177e4SLinus Torvalds #define MH_BIT_WP 0x80
24681da177e4SLinus Torvalds #define MP_MSK_PAGE_NBR 0x3f
24691da177e4SLinus Torvalds
24701da177e4SLinus Torvalds /* Don't return block descriptors */
24711da177e4SLinus Torvalds #define MODE_SENSE_OMIT_BDESCS 0x08
24721da177e4SLinus Torvalds
24731da177e4SLinus Torvalds #define MODE_SELECT_PAGE_FORMAT 0x10
24741da177e4SLinus Torvalds
24751da177e4SLinus Torvalds /* Read a mode page into the tape buffer. The block descriptors are included
24761da177e4SLinus Torvalds if incl_block_descs is true. The page control is ored to the page number
24771da177e4SLinus Torvalds parameter, if necessary. */
read_mode_page(struct scsi_tape * STp,int page,int omit_block_descs)24781da177e4SLinus Torvalds static int read_mode_page(struct scsi_tape *STp, int page, int omit_block_descs)
24791da177e4SLinus Torvalds {
24801da177e4SLinus Torvalds unsigned char cmd[MAX_COMMAND_SIZE];
24818ecf0d99SFUJITA Tomonori struct st_request *SRpnt;
24821da177e4SLinus Torvalds
24831da177e4SLinus Torvalds memset(cmd, 0, MAX_COMMAND_SIZE);
24841da177e4SLinus Torvalds cmd[0] = MODE_SENSE;
24851da177e4SLinus Torvalds if (omit_block_descs)
24861da177e4SLinus Torvalds cmd[1] = MODE_SENSE_OMIT_BDESCS;
24871da177e4SLinus Torvalds cmd[2] = page;
24881da177e4SLinus Torvalds cmd[4] = 255;
24891da177e4SLinus Torvalds
249002ae2c0eSKai Makisara SRpnt = st_do_scsi(NULL, STp, cmd, cmd[4], DMA_FROM_DEVICE,
249102ae2c0eSKai Makisara STp->device->request_queue->rq_timeout, 0, 1);
249202ae2c0eSKai Makisara if (SRpnt == NULL)
249302ae2c0eSKai Makisara return (STp->buffer)->syscall_result;
24941da177e4SLinus Torvalds
24958b05b773SMike Christie st_release_request(SRpnt);
24961da177e4SLinus Torvalds
249702ae2c0eSKai Makisara return STp->buffer->syscall_result;
24981da177e4SLinus Torvalds }
24991da177e4SLinus Torvalds
25001da177e4SLinus Torvalds
25011da177e4SLinus Torvalds /* Send the mode page in the tape buffer to the drive. Assumes that the mode data
25021da177e4SLinus 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)25031da177e4SLinus Torvalds static int write_mode_page(struct scsi_tape *STp, int page, int slow)
25041da177e4SLinus Torvalds {
250502ae2c0eSKai Makisara int pgo;
25061da177e4SLinus Torvalds unsigned char cmd[MAX_COMMAND_SIZE];
250718c87015SFUJITA Tomonori struct st_request *SRpnt;
250802ae2c0eSKai Makisara int timeout;
25091da177e4SLinus Torvalds
25101da177e4SLinus Torvalds memset(cmd, 0, MAX_COMMAND_SIZE);
25111da177e4SLinus Torvalds cmd[0] = MODE_SELECT;
25121da177e4SLinus Torvalds cmd[1] = MODE_SELECT_PAGE_FORMAT;
25131da177e4SLinus Torvalds pgo = MODE_HEADER_LENGTH + (STp->buffer)->b_data[MH_OFF_BDESCS_LENGTH];
25141da177e4SLinus Torvalds cmd[4] = pgo + (STp->buffer)->b_data[pgo + MP_OFF_PAGE_LENGTH] + 2;
25151da177e4SLinus Torvalds
25161da177e4SLinus Torvalds /* Clear reserved fields */
25171da177e4SLinus Torvalds (STp->buffer)->b_data[MH_OFF_DATA_LENGTH] = 0;
25181da177e4SLinus Torvalds (STp->buffer)->b_data[MH_OFF_MEDIUM_TYPE] = 0;
25191da177e4SLinus Torvalds (STp->buffer)->b_data[MH_OFF_DEV_SPECIFIC] &= ~MH_BIT_WP;
25201da177e4SLinus Torvalds (STp->buffer)->b_data[pgo + MP_OFF_PAGE_NBR] &= MP_MSK_PAGE_NBR;
25211da177e4SLinus Torvalds
252202ae2c0eSKai Makisara timeout = slow ?
252302ae2c0eSKai Makisara STp->long_timeout : STp->device->request_queue->rq_timeout;
252402ae2c0eSKai Makisara SRpnt = st_do_scsi(NULL, STp, cmd, cmd[4], DMA_TO_DEVICE,
252502ae2c0eSKai Makisara timeout, 0, 1);
252602ae2c0eSKai Makisara if (SRpnt == NULL)
252702ae2c0eSKai Makisara return (STp->buffer)->syscall_result;
25281da177e4SLinus Torvalds
25298b05b773SMike Christie st_release_request(SRpnt);
25301da177e4SLinus Torvalds
253102ae2c0eSKai Makisara return STp->buffer->syscall_result;
25321da177e4SLinus Torvalds }
25331da177e4SLinus Torvalds
25341da177e4SLinus Torvalds
25351da177e4SLinus Torvalds #define COMPRESSION_PAGE 0x0f
25361da177e4SLinus Torvalds #define COMPRESSION_PAGE_LENGTH 16
25371da177e4SLinus Torvalds
25381da177e4SLinus Torvalds #define CP_OFF_DCE_DCC 2
25391da177e4SLinus Torvalds #define CP_OFF_C_ALGO 7
25401da177e4SLinus Torvalds
25411da177e4SLinus Torvalds #define DCE_MASK 0x80
25421da177e4SLinus Torvalds #define DCC_MASK 0x40
25431da177e4SLinus Torvalds #define RED_MASK 0x60
25441da177e4SLinus Torvalds
25451da177e4SLinus Torvalds
25461da177e4SLinus Torvalds /* Control the compression with mode page 15. Algorithm not changed if zero.
25471da177e4SLinus Torvalds
25481da177e4SLinus Torvalds The block descriptors are read and written because Sony SDT-7000 does not
25491da177e4SLinus Torvalds work without this (suggestion from Michael Schaefer <Michael.Schaefer@dlr.de>).
25501da177e4SLinus Torvalds Including block descriptors should not cause any harm to other drives. */
25511da177e4SLinus Torvalds
st_compression(struct scsi_tape * STp,int state)25521da177e4SLinus Torvalds static int st_compression(struct scsi_tape * STp, int state)
25531da177e4SLinus Torvalds {
25541da177e4SLinus Torvalds int retval;
25551da177e4SLinus Torvalds int mpoffs; /* Offset to mode page start */
25561da177e4SLinus Torvalds unsigned char *b_data = (STp->buffer)->b_data;
25571da177e4SLinus Torvalds
25581da177e4SLinus Torvalds if (STp->ready != ST_READY)
25591da177e4SLinus Torvalds return (-EIO);
25601da177e4SLinus Torvalds
25611da177e4SLinus Torvalds /* Read the current page contents */
25621da177e4SLinus Torvalds retval = read_mode_page(STp, COMPRESSION_PAGE, 0);
25631da177e4SLinus Torvalds if (retval) {
2564b30d8bcaSHannes Reinecke DEBC_printk(STp, "Compression mode page not supported.\n");
25651da177e4SLinus Torvalds return (-EIO);
25661da177e4SLinus Torvalds }
25671da177e4SLinus Torvalds
25681da177e4SLinus Torvalds mpoffs = MODE_HEADER_LENGTH + b_data[MH_OFF_BDESCS_LENGTH];
2569b30d8bcaSHannes Reinecke DEBC_printk(STp, "Compression state is %d.\n",
2570b30d8bcaSHannes Reinecke (b_data[mpoffs + CP_OFF_DCE_DCC] & DCE_MASK ? 1 : 0));
25711da177e4SLinus Torvalds
25721da177e4SLinus Torvalds /* Check if compression can be changed */
25731da177e4SLinus Torvalds if ((b_data[mpoffs + CP_OFF_DCE_DCC] & DCC_MASK) == 0) {
2574b30d8bcaSHannes Reinecke DEBC_printk(STp, "Compression not supported.\n");
25751da177e4SLinus Torvalds return (-EIO);
25761da177e4SLinus Torvalds }
25771da177e4SLinus Torvalds
25781da177e4SLinus Torvalds /* Do the change */
25791da177e4SLinus Torvalds if (state) {
25801da177e4SLinus Torvalds b_data[mpoffs + CP_OFF_DCE_DCC] |= DCE_MASK;
25811da177e4SLinus Torvalds if (STp->c_algo != 0)
25821da177e4SLinus Torvalds b_data[mpoffs + CP_OFF_C_ALGO] = STp->c_algo;
25831da177e4SLinus Torvalds }
25841da177e4SLinus Torvalds else {
25851da177e4SLinus Torvalds b_data[mpoffs + CP_OFF_DCE_DCC] &= ~DCE_MASK;
25861da177e4SLinus Torvalds if (STp->c_algo != 0)
25871da177e4SLinus Torvalds b_data[mpoffs + CP_OFF_C_ALGO] = 0; /* no compression */
25881da177e4SLinus Torvalds }
25891da177e4SLinus Torvalds
25901da177e4SLinus Torvalds retval = write_mode_page(STp, COMPRESSION_PAGE, 0);
25911da177e4SLinus Torvalds if (retval) {
2592b30d8bcaSHannes Reinecke DEBC_printk(STp, "Compression change failed.\n");
25931da177e4SLinus Torvalds return (-EIO);
25941da177e4SLinus Torvalds }
2595b30d8bcaSHannes Reinecke DEBC_printk(STp, "Compression state changed to %d.\n", state);
25961da177e4SLinus Torvalds
25971da177e4SLinus Torvalds STp->compression_changed = 1;
25981da177e4SLinus Torvalds return 0;
25991da177e4SLinus Torvalds }
26001da177e4SLinus Torvalds
26011da177e4SLinus Torvalds
26021da177e4SLinus 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)26031da177e4SLinus Torvalds static int do_load_unload(struct scsi_tape *STp, struct file *filp, int load_code)
26041da177e4SLinus Torvalds {
26051da177e4SLinus Torvalds int retval = (-EIO), timeout;
26061da177e4SLinus Torvalds unsigned char cmd[MAX_COMMAND_SIZE];
26071da177e4SLinus Torvalds struct st_partstat *STps;
26088b05b773SMike Christie struct st_request *SRpnt;
26091da177e4SLinus Torvalds
26101da177e4SLinus Torvalds if (STp->ready != ST_READY && !load_code) {
26111da177e4SLinus Torvalds if (STp->ready == ST_NO_TAPE)
26121da177e4SLinus Torvalds return (-ENOMEDIUM);
26131da177e4SLinus Torvalds else
26141da177e4SLinus Torvalds return (-EIO);
26151da177e4SLinus Torvalds }
26161da177e4SLinus Torvalds
26171da177e4SLinus Torvalds memset(cmd, 0, MAX_COMMAND_SIZE);
26181da177e4SLinus Torvalds cmd[0] = START_STOP;
26191da177e4SLinus Torvalds if (load_code)
26201da177e4SLinus Torvalds cmd[4] |= 1;
26211da177e4SLinus Torvalds /*
26221da177e4SLinus Torvalds * If arg >= 1 && arg <= 6 Enhanced load/unload in HP C1553A
26231da177e4SLinus Torvalds */
26241da177e4SLinus Torvalds if (load_code >= 1 + MT_ST_HPLOADER_OFFSET
26251da177e4SLinus Torvalds && load_code <= 6 + MT_ST_HPLOADER_OFFSET) {
2626b30d8bcaSHannes Reinecke DEBC_printk(STp, " Enhanced %sload slot %2d.\n",
2627b30d8bcaSHannes Reinecke (cmd[4]) ? "" : "un",
2628b30d8bcaSHannes Reinecke load_code - MT_ST_HPLOADER_OFFSET);
26291da177e4SLinus Torvalds cmd[3] = load_code - MT_ST_HPLOADER_OFFSET; /* MediaID field of C1553A */
26301da177e4SLinus Torvalds }
26311da177e4SLinus Torvalds if (STp->immediate) {
26321da177e4SLinus Torvalds cmd[1] = 1; /* Don't wait for completion */
2633a02488edSJames Bottomley timeout = STp->device->request_queue->rq_timeout;
26341da177e4SLinus Torvalds }
26351da177e4SLinus Torvalds else
26361da177e4SLinus Torvalds timeout = STp->long_timeout;
26371da177e4SLinus Torvalds
26381da177e4SLinus Torvalds DEBC(
26391da177e4SLinus Torvalds if (!load_code)
2640b30d8bcaSHannes Reinecke st_printk(ST_DEB_MSG, STp, "Unloading tape.\n");
26411da177e4SLinus Torvalds else
2642b30d8bcaSHannes Reinecke st_printk(ST_DEB_MSG, STp, "Loading tape.\n");
26431da177e4SLinus Torvalds );
26441da177e4SLinus Torvalds
264502ae2c0eSKai Makisara SRpnt = st_do_scsi(NULL, STp, cmd, 0, DMA_NONE,
264602ae2c0eSKai Makisara timeout, MAX_RETRIES, 1);
26471da177e4SLinus Torvalds if (!SRpnt)
264802ae2c0eSKai Makisara return (STp->buffer)->syscall_result;
26491da177e4SLinus Torvalds
26501da177e4SLinus Torvalds retval = (STp->buffer)->syscall_result;
265102ae2c0eSKai Makisara st_release_request(SRpnt);
26521da177e4SLinus Torvalds
26531da177e4SLinus Torvalds if (!retval) { /* SCSI command successful */
26541da177e4SLinus Torvalds
26551da177e4SLinus Torvalds if (!load_code) {
26561da177e4SLinus Torvalds STp->rew_at_close = 0;
26571da177e4SLinus Torvalds STp->ready = ST_NO_TAPE;
26581da177e4SLinus Torvalds }
26591da177e4SLinus Torvalds else {
26601da177e4SLinus Torvalds STp->rew_at_close = STp->autorew_dev;
26611da177e4SLinus Torvalds retval = check_tape(STp, filp);
26621da177e4SLinus Torvalds if (retval > 0)
26631da177e4SLinus Torvalds retval = 0;
26641da177e4SLinus Torvalds }
26651da177e4SLinus Torvalds }
26661da177e4SLinus Torvalds else {
26671da177e4SLinus Torvalds STps = &(STp->ps[STp->partition]);
26681da177e4SLinus Torvalds STps->drv_file = STps->drv_block = (-1);
26691da177e4SLinus Torvalds }
26701da177e4SLinus Torvalds
26711da177e4SLinus Torvalds return retval;
26721da177e4SLinus Torvalds }
26731da177e4SLinus Torvalds
26741da177e4SLinus Torvalds #if DEBUG
26751da177e4SLinus Torvalds #define ST_DEB_FORWARD 0
26761da177e4SLinus Torvalds #define ST_DEB_BACKWARD 1
deb_space_print(struct scsi_tape * STp,int direction,char * units,unsigned char * cmd)2677b30d8bcaSHannes Reinecke static void deb_space_print(struct scsi_tape *STp, int direction, char *units, unsigned char *cmd)
26781da177e4SLinus Torvalds {
26791da177e4SLinus Torvalds s32 sc;
26801da177e4SLinus Torvalds
2681b30d8bcaSHannes Reinecke if (!debugging)
2682b30d8bcaSHannes Reinecke return;
2683b30d8bcaSHannes Reinecke
268435b703dbSBart Van Assche sc = sign_extend32(get_unaligned_be24(&cmd[2]), 23);
26851da177e4SLinus Torvalds if (direction)
26861da177e4SLinus Torvalds sc = -sc;
2687b30d8bcaSHannes Reinecke st_printk(ST_DEB_MSG, STp, "Spacing tape %s over %d %s.\n",
26881da177e4SLinus Torvalds direction ? "backward" : "forward", sc, units);
26891da177e4SLinus Torvalds }
2690b30d8bcaSHannes Reinecke #else
2691b30d8bcaSHannes Reinecke #define ST_DEB_FORWARD 0
2692b30d8bcaSHannes Reinecke #define ST_DEB_BACKWARD 1
deb_space_print(struct scsi_tape * STp,int direction,char * units,unsigned char * cmd)2693b30d8bcaSHannes Reinecke static void deb_space_print(struct scsi_tape *STp, int direction, char *units, unsigned char *cmd) {}
26941da177e4SLinus Torvalds #endif
26951da177e4SLinus Torvalds
26961da177e4SLinus Torvalds
26971da177e4SLinus Torvalds /* Internal ioctl function */
st_int_ioctl(struct scsi_tape * STp,unsigned int cmd_in,unsigned long arg)26981da177e4SLinus Torvalds static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned long arg)
26991da177e4SLinus Torvalds {
27001da177e4SLinus Torvalds int timeout;
27011da177e4SLinus Torvalds long ltmp;
27021da177e4SLinus Torvalds int ioctl_result;
27031da177e4SLinus Torvalds int chg_eof = 1;
27041da177e4SLinus Torvalds unsigned char cmd[MAX_COMMAND_SIZE];
27058b05b773SMike Christie struct st_request *SRpnt;
27061da177e4SLinus Torvalds struct st_partstat *STps;
27071da177e4SLinus Torvalds int fileno, blkno, at_sm, undone;
27081da177e4SLinus Torvalds int datalen = 0, direction = DMA_NONE;
27091da177e4SLinus Torvalds
27101da177e4SLinus Torvalds WARN_ON(STp->buffer->do_dio != 0);
27111da177e4SLinus Torvalds if (STp->ready != ST_READY) {
27121da177e4SLinus Torvalds if (STp->ready == ST_NO_TAPE)
27131da177e4SLinus Torvalds return (-ENOMEDIUM);
27141da177e4SLinus Torvalds else
27151da177e4SLinus Torvalds return (-EIO);
27161da177e4SLinus Torvalds }
27171da177e4SLinus Torvalds timeout = STp->long_timeout;
27181da177e4SLinus Torvalds STps = &(STp->ps[STp->partition]);
27191da177e4SLinus Torvalds fileno = STps->drv_file;
27201da177e4SLinus Torvalds blkno = STps->drv_block;
27211da177e4SLinus Torvalds at_sm = STps->at_sm;
27221da177e4SLinus Torvalds
27231da177e4SLinus Torvalds memset(cmd, 0, MAX_COMMAND_SIZE);
27241da177e4SLinus Torvalds switch (cmd_in) {
27251da177e4SLinus Torvalds case MTFSFM:
27261da177e4SLinus Torvalds chg_eof = 0; /* Changed from the FSF after this */
2727df561f66SGustavo A. R. Silva fallthrough;
27281da177e4SLinus Torvalds case MTFSF:
27291da177e4SLinus Torvalds cmd[0] = SPACE;
27301da177e4SLinus Torvalds cmd[1] = 0x01; /* Space FileMarks */
27311da177e4SLinus Torvalds cmd[2] = (arg >> 16);
27321da177e4SLinus Torvalds cmd[3] = (arg >> 8);
27331da177e4SLinus Torvalds cmd[4] = arg;
2734b30d8bcaSHannes Reinecke deb_space_print(STp, ST_DEB_FORWARD, "filemarks", cmd);
27351da177e4SLinus Torvalds if (fileno >= 0)
27361da177e4SLinus Torvalds fileno += arg;
27371da177e4SLinus Torvalds blkno = 0;
27381da177e4SLinus Torvalds at_sm &= (arg == 0);
27391da177e4SLinus Torvalds break;
27401da177e4SLinus Torvalds case MTBSFM:
27411da177e4SLinus Torvalds chg_eof = 0; /* Changed from the FSF after this */
2742df561f66SGustavo A. R. Silva fallthrough;
27431da177e4SLinus Torvalds case MTBSF:
27441da177e4SLinus Torvalds cmd[0] = SPACE;
27451da177e4SLinus Torvalds cmd[1] = 0x01; /* Space FileMarks */
27461da177e4SLinus Torvalds ltmp = (-arg);
27471da177e4SLinus Torvalds cmd[2] = (ltmp >> 16);
27481da177e4SLinus Torvalds cmd[3] = (ltmp >> 8);
27491da177e4SLinus Torvalds cmd[4] = ltmp;
2750b30d8bcaSHannes Reinecke deb_space_print(STp, ST_DEB_BACKWARD, "filemarks", cmd);
27511da177e4SLinus Torvalds if (fileno >= 0)
27521da177e4SLinus Torvalds fileno -= arg;
27531da177e4SLinus Torvalds blkno = (-1); /* We can't know the block number */
27541da177e4SLinus Torvalds at_sm &= (arg == 0);
27551da177e4SLinus Torvalds break;
27561da177e4SLinus Torvalds case MTFSR:
27571da177e4SLinus Torvalds cmd[0] = SPACE;
27581da177e4SLinus Torvalds cmd[1] = 0x00; /* Space Blocks */
27591da177e4SLinus Torvalds cmd[2] = (arg >> 16);
27601da177e4SLinus Torvalds cmd[3] = (arg >> 8);
27611da177e4SLinus Torvalds cmd[4] = arg;
2762b30d8bcaSHannes Reinecke deb_space_print(STp, ST_DEB_FORWARD, "blocks", cmd);
27631da177e4SLinus Torvalds if (blkno >= 0)
27641da177e4SLinus Torvalds blkno += arg;
27651da177e4SLinus Torvalds at_sm &= (arg == 0);
27661da177e4SLinus Torvalds break;
27671da177e4SLinus Torvalds case MTBSR:
27681da177e4SLinus Torvalds cmd[0] = SPACE;
27691da177e4SLinus Torvalds cmd[1] = 0x00; /* Space Blocks */
27701da177e4SLinus Torvalds ltmp = (-arg);
27711da177e4SLinus Torvalds cmd[2] = (ltmp >> 16);
27721da177e4SLinus Torvalds cmd[3] = (ltmp >> 8);
27731da177e4SLinus Torvalds cmd[4] = ltmp;
2774b30d8bcaSHannes Reinecke deb_space_print(STp, ST_DEB_BACKWARD, "blocks", cmd);
27751da177e4SLinus Torvalds if (blkno >= 0)
27761da177e4SLinus Torvalds blkno -= arg;
27771da177e4SLinus Torvalds at_sm &= (arg == 0);
27781da177e4SLinus Torvalds break;
27791da177e4SLinus Torvalds case MTFSS:
27801da177e4SLinus Torvalds cmd[0] = SPACE;
27811da177e4SLinus Torvalds cmd[1] = 0x04; /* Space Setmarks */
27821da177e4SLinus Torvalds cmd[2] = (arg >> 16);
27831da177e4SLinus Torvalds cmd[3] = (arg >> 8);
27841da177e4SLinus Torvalds cmd[4] = arg;
2785b30d8bcaSHannes Reinecke deb_space_print(STp, ST_DEB_FORWARD, "setmarks", cmd);
27861da177e4SLinus Torvalds if (arg != 0) {
27871da177e4SLinus Torvalds blkno = fileno = (-1);
27881da177e4SLinus Torvalds at_sm = 1;
27891da177e4SLinus Torvalds }
27901da177e4SLinus Torvalds break;
27911da177e4SLinus Torvalds case MTBSS:
27921da177e4SLinus Torvalds cmd[0] = SPACE;
27931da177e4SLinus Torvalds cmd[1] = 0x04; /* Space Setmarks */
27941da177e4SLinus Torvalds ltmp = (-arg);
27951da177e4SLinus Torvalds cmd[2] = (ltmp >> 16);
27961da177e4SLinus Torvalds cmd[3] = (ltmp >> 8);
27971da177e4SLinus Torvalds cmd[4] = ltmp;
2798b30d8bcaSHannes Reinecke deb_space_print(STp, ST_DEB_BACKWARD, "setmarks", cmd);
27991da177e4SLinus Torvalds if (arg != 0) {
28001da177e4SLinus Torvalds blkno = fileno = (-1);
28011da177e4SLinus Torvalds at_sm = 1;
28021da177e4SLinus Torvalds }
28031da177e4SLinus Torvalds break;
28041da177e4SLinus Torvalds case MTWEOF:
28053e51d3c9SKai Makisara case MTWEOFI:
28061da177e4SLinus Torvalds case MTWSM:
28071da177e4SLinus Torvalds if (STp->write_prot)
28081da177e4SLinus Torvalds return (-EACCES);
28091da177e4SLinus Torvalds cmd[0] = WRITE_FILEMARKS;
28101da177e4SLinus Torvalds if (cmd_in == MTWSM)
28111da177e4SLinus Torvalds cmd[1] = 2;
2812c743e44fSLee Duncan if (cmd_in == MTWEOFI ||
2813c743e44fSLee Duncan (cmd_in == MTWEOF && STp->immediate_filemark))
28143e51d3c9SKai Makisara cmd[1] |= 1;
28151da177e4SLinus Torvalds cmd[2] = (arg >> 16);
28161da177e4SLinus Torvalds cmd[3] = (arg >> 8);
28171da177e4SLinus Torvalds cmd[4] = arg;
2818a02488edSJames Bottomley timeout = STp->device->request_queue->rq_timeout;
28191da177e4SLinus Torvalds DEBC(
28203e51d3c9SKai Makisara if (cmd_in != MTWSM)
2821b30d8bcaSHannes Reinecke st_printk(ST_DEB_MSG, STp,
2822b30d8bcaSHannes Reinecke "Writing %d filemarks.\n",
2823b30d8bcaSHannes Reinecke cmd[2] * 65536 +
2824b30d8bcaSHannes Reinecke cmd[3] * 256 +
2825b30d8bcaSHannes Reinecke cmd[4]);
28261da177e4SLinus Torvalds else
2827b30d8bcaSHannes Reinecke st_printk(ST_DEB_MSG, STp,
2828b30d8bcaSHannes Reinecke "Writing %d setmarks.\n",
2829b30d8bcaSHannes Reinecke cmd[2] * 65536 +
2830b30d8bcaSHannes Reinecke cmd[3] * 256 +
2831b30d8bcaSHannes Reinecke cmd[4]);
28321da177e4SLinus Torvalds )
28331da177e4SLinus Torvalds if (fileno >= 0)
28341da177e4SLinus Torvalds fileno += arg;
28351da177e4SLinus Torvalds blkno = 0;
28361da177e4SLinus Torvalds at_sm = (cmd_in == MTWSM);
28371da177e4SLinus Torvalds break;
28381da177e4SLinus Torvalds case MTREW:
28391da177e4SLinus Torvalds cmd[0] = REZERO_UNIT;
28401da177e4SLinus Torvalds if (STp->immediate) {
28411da177e4SLinus Torvalds cmd[1] = 1; /* Don't wait for completion */
2842a02488edSJames Bottomley timeout = STp->device->request_queue->rq_timeout;
28431da177e4SLinus Torvalds }
2844b30d8bcaSHannes Reinecke DEBC_printk(STp, "Rewinding tape.\n");
28451da177e4SLinus Torvalds fileno = blkno = at_sm = 0;
28461da177e4SLinus Torvalds break;
28471da177e4SLinus Torvalds case MTNOP:
2848b30d8bcaSHannes Reinecke DEBC_printk(STp, "No op on tape.\n");
28491da177e4SLinus Torvalds return 0; /* Should do something ? */
28501da177e4SLinus Torvalds case MTRETEN:
28511da177e4SLinus Torvalds cmd[0] = START_STOP;
28521da177e4SLinus Torvalds if (STp->immediate) {
28531da177e4SLinus Torvalds cmd[1] = 1; /* Don't wait for completion */
2854a02488edSJames Bottomley timeout = STp->device->request_queue->rq_timeout;
28551da177e4SLinus Torvalds }
28561da177e4SLinus Torvalds cmd[4] = 3;
2857b30d8bcaSHannes Reinecke DEBC_printk(STp, "Retensioning tape.\n");
28581da177e4SLinus Torvalds fileno = blkno = at_sm = 0;
28591da177e4SLinus Torvalds break;
28601da177e4SLinus Torvalds case MTEOM:
28611da177e4SLinus Torvalds if (!STp->fast_mteom) {
28621da177e4SLinus Torvalds /* space to the end of tape */
28631da177e4SLinus Torvalds ioctl_result = st_int_ioctl(STp, MTFSF, 0x7fffff);
28641da177e4SLinus Torvalds fileno = STps->drv_file;
28651da177e4SLinus Torvalds if (STps->eof >= ST_EOD_1)
28661da177e4SLinus Torvalds return 0;
28671da177e4SLinus Torvalds /* The next lines would hide the number of spaced FileMarks
28681da177e4SLinus Torvalds That's why I inserted the previous lines. I had no luck
28691da177e4SLinus Torvalds with detecting EOM with FSF, so we go now to EOM.
28701da177e4SLinus Torvalds Joerg Weule */
28711da177e4SLinus Torvalds } else
28721da177e4SLinus Torvalds fileno = (-1);
28731da177e4SLinus Torvalds cmd[0] = SPACE;
28741da177e4SLinus Torvalds cmd[1] = 3;
2875b30d8bcaSHannes Reinecke DEBC_printk(STp, "Spacing to end of recorded medium.\n");
28761da177e4SLinus Torvalds blkno = -1;
28771da177e4SLinus Torvalds at_sm = 0;
28781da177e4SLinus Torvalds break;
28791da177e4SLinus Torvalds case MTERASE:
28801da177e4SLinus Torvalds if (STp->write_prot)
28811da177e4SLinus Torvalds return (-EACCES);
28821da177e4SLinus Torvalds cmd[0] = ERASE;
28831da177e4SLinus Torvalds cmd[1] = (arg ? 1 : 0); /* Long erase with non-zero argument */
28841da177e4SLinus Torvalds if (STp->immediate) {
28851da177e4SLinus Torvalds cmd[1] |= 2; /* Don't wait for completion */
2886a02488edSJames Bottomley timeout = STp->device->request_queue->rq_timeout;
28871da177e4SLinus Torvalds }
28881da177e4SLinus Torvalds else
28891da177e4SLinus Torvalds timeout = STp->long_timeout * 8;
28901da177e4SLinus Torvalds
2891b30d8bcaSHannes Reinecke DEBC_printk(STp, "Erasing tape.\n");
28921da177e4SLinus Torvalds fileno = blkno = at_sm = 0;
28931da177e4SLinus Torvalds break;
28941da177e4SLinus Torvalds case MTSETBLK: /* Set block length */
28951da177e4SLinus Torvalds case MTSETDENSITY: /* Set tape density */
28961da177e4SLinus Torvalds case MTSETDRVBUFFER: /* Set drive buffering */
28971da177e4SLinus Torvalds case SET_DENS_AND_BLK: /* Set density and block size */
28981da177e4SLinus Torvalds chg_eof = 0;
28991da177e4SLinus Torvalds if (STp->dirty || (STp->buffer)->buffer_bytes != 0)
29001da177e4SLinus Torvalds return (-EIO); /* Not allowed if data in buffer */
29011da177e4SLinus Torvalds if ((cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) &&
29021da177e4SLinus Torvalds (arg & MT_ST_BLKSIZE_MASK) != 0 &&
29031da177e4SLinus Torvalds STp->max_block > 0 &&
29041da177e4SLinus Torvalds ((arg & MT_ST_BLKSIZE_MASK) < STp->min_block ||
29051da177e4SLinus Torvalds (arg & MT_ST_BLKSIZE_MASK) > STp->max_block)) {
2906b30d8bcaSHannes Reinecke st_printk(KERN_WARNING, STp, "Illegal block size.\n");
29071da177e4SLinus Torvalds return (-EINVAL);
29081da177e4SLinus Torvalds }
29091da177e4SLinus Torvalds cmd[0] = MODE_SELECT;
29101da177e4SLinus Torvalds if ((STp->use_pf & USE_PF))
29111da177e4SLinus Torvalds cmd[1] = MODE_SELECT_PAGE_FORMAT;
29121da177e4SLinus Torvalds cmd[4] = datalen = 12;
29131da177e4SLinus Torvalds direction = DMA_TO_DEVICE;
29141da177e4SLinus Torvalds
29151da177e4SLinus Torvalds memset((STp->buffer)->b_data, 0, 12);
29161da177e4SLinus Torvalds if (cmd_in == MTSETDRVBUFFER)
29171da177e4SLinus Torvalds (STp->buffer)->b_data[2] = (arg & 7) << 4;
29181da177e4SLinus Torvalds else
29191da177e4SLinus Torvalds (STp->buffer)->b_data[2] =
29201da177e4SLinus Torvalds STp->drv_buffer << 4;
29211da177e4SLinus Torvalds (STp->buffer)->b_data[3] = 8; /* block descriptor length */
29221da177e4SLinus Torvalds if (cmd_in == MTSETDENSITY) {
29231da177e4SLinus Torvalds (STp->buffer)->b_data[4] = arg;
29241da177e4SLinus Torvalds STp->density_changed = 1; /* At least we tried ;-) */
29251da177e4SLinus Torvalds } else if (cmd_in == SET_DENS_AND_BLK)
29261da177e4SLinus Torvalds (STp->buffer)->b_data[4] = arg >> 24;
29271da177e4SLinus Torvalds else
29281da177e4SLinus Torvalds (STp->buffer)->b_data[4] = STp->density;
29291da177e4SLinus Torvalds if (cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) {
29301da177e4SLinus Torvalds ltmp = arg & MT_ST_BLKSIZE_MASK;
29311da177e4SLinus Torvalds if (cmd_in == MTSETBLK)
29321da177e4SLinus Torvalds STp->blksize_changed = 1; /* At least we tried ;-) */
29331da177e4SLinus Torvalds } else
29341da177e4SLinus Torvalds ltmp = STp->block_size;
29351da177e4SLinus Torvalds (STp->buffer)->b_data[9] = (ltmp >> 16);
29361da177e4SLinus Torvalds (STp->buffer)->b_data[10] = (ltmp >> 8);
29371da177e4SLinus Torvalds (STp->buffer)->b_data[11] = ltmp;
2938a02488edSJames Bottomley timeout = STp->device->request_queue->rq_timeout;
29391da177e4SLinus Torvalds DEBC(
29401da177e4SLinus Torvalds if (cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK)
2941b30d8bcaSHannes Reinecke st_printk(ST_DEB_MSG, STp,
2942b30d8bcaSHannes Reinecke "Setting block size to %d bytes.\n",
29431da177e4SLinus Torvalds (STp->buffer)->b_data[9] * 65536 +
29441da177e4SLinus Torvalds (STp->buffer)->b_data[10] * 256 +
29451da177e4SLinus Torvalds (STp->buffer)->b_data[11]);
29461da177e4SLinus Torvalds if (cmd_in == MTSETDENSITY || cmd_in == SET_DENS_AND_BLK)
2947b30d8bcaSHannes Reinecke st_printk(ST_DEB_MSG, STp,
2948b30d8bcaSHannes Reinecke "Setting density code to %x.\n",
29491da177e4SLinus Torvalds (STp->buffer)->b_data[4]);
29501da177e4SLinus Torvalds if (cmd_in == MTSETDRVBUFFER)
2951b30d8bcaSHannes Reinecke st_printk(ST_DEB_MSG, STp,
2952b30d8bcaSHannes Reinecke "Setting drive buffer code to %d.\n",
29531da177e4SLinus Torvalds ((STp->buffer)->b_data[2] >> 4) & 7);
29541da177e4SLinus Torvalds )
29551da177e4SLinus Torvalds break;
29561da177e4SLinus Torvalds default:
29571da177e4SLinus Torvalds return (-ENOSYS);
29581da177e4SLinus Torvalds }
29591da177e4SLinus Torvalds
296002ae2c0eSKai Makisara SRpnt = st_do_scsi(NULL, STp, cmd, datalen, direction,
296102ae2c0eSKai Makisara timeout, MAX_RETRIES, 1);
29621da177e4SLinus Torvalds if (!SRpnt)
29631da177e4SLinus Torvalds return (STp->buffer)->syscall_result;
29641da177e4SLinus Torvalds
29651da177e4SLinus Torvalds ioctl_result = (STp->buffer)->syscall_result;
29661da177e4SLinus Torvalds
29671da177e4SLinus Torvalds if (!ioctl_result) { /* SCSI command successful */
29688b05b773SMike Christie st_release_request(SRpnt);
29691da177e4SLinus Torvalds SRpnt = NULL;
29701da177e4SLinus Torvalds STps->drv_block = blkno;
29711da177e4SLinus Torvalds STps->drv_file = fileno;
29721da177e4SLinus Torvalds STps->at_sm = at_sm;
29731da177e4SLinus Torvalds
29741da177e4SLinus Torvalds if (cmd_in == MTBSFM)
29751da177e4SLinus Torvalds ioctl_result = st_int_ioctl(STp, MTFSF, 1);
29761da177e4SLinus Torvalds else if (cmd_in == MTFSFM)
29771da177e4SLinus Torvalds ioctl_result = st_int_ioctl(STp, MTBSF, 1);
29781da177e4SLinus Torvalds
29791da177e4SLinus Torvalds if (cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) {
29801da177e4SLinus Torvalds STp->block_size = arg & MT_ST_BLKSIZE_MASK;
29811da177e4SLinus Torvalds if (STp->block_size != 0) {
29821da177e4SLinus Torvalds (STp->buffer)->buffer_blocks =
29831da177e4SLinus Torvalds (STp->buffer)->buffer_size / STp->block_size;
29841da177e4SLinus Torvalds }
29851da177e4SLinus Torvalds (STp->buffer)->buffer_bytes = (STp->buffer)->read_pointer = 0;
29861da177e4SLinus Torvalds if (cmd_in == SET_DENS_AND_BLK)
29871da177e4SLinus Torvalds STp->density = arg >> MT_ST_DENSITY_SHIFT;
29881da177e4SLinus Torvalds } else if (cmd_in == MTSETDRVBUFFER)
29891da177e4SLinus Torvalds STp->drv_buffer = (arg & 7);
29901da177e4SLinus Torvalds else if (cmd_in == MTSETDENSITY)
29911da177e4SLinus Torvalds STp->density = arg;
29921da177e4SLinus Torvalds
29931da177e4SLinus Torvalds if (cmd_in == MTEOM)
29941da177e4SLinus Torvalds STps->eof = ST_EOD;
29951da177e4SLinus Torvalds else if (cmd_in == MTFSF)
29961da177e4SLinus Torvalds STps->eof = ST_FM;
29971da177e4SLinus Torvalds else if (chg_eof)
29981da177e4SLinus Torvalds STps->eof = ST_NOEOF;
29991da177e4SLinus Torvalds
30003e51d3c9SKai Makisara if (cmd_in == MTWEOF || cmd_in == MTWEOFI)
30013e51d3c9SKai Makisara STps->rw = ST_IDLE; /* prevent automatic WEOF at close */
30021da177e4SLinus Torvalds } else { /* SCSI command was not completely successful. Don't return
30031da177e4SLinus Torvalds from this block without releasing the SCSI command block! */
30041da177e4SLinus Torvalds struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat;
30051da177e4SLinus Torvalds
30061da177e4SLinus Torvalds if (cmdstatp->flags & SENSE_EOM) {
30071da177e4SLinus Torvalds if (cmd_in != MTBSF && cmd_in != MTBSFM &&
30081da177e4SLinus Torvalds cmd_in != MTBSR && cmd_in != MTBSS)
30091da177e4SLinus Torvalds STps->eof = ST_EOM_OK;
30101da177e4SLinus Torvalds STps->drv_block = 0;
30111da177e4SLinus Torvalds }
30121da177e4SLinus Torvalds
30131da177e4SLinus Torvalds if (cmdstatp->remainder_valid)
30141da177e4SLinus Torvalds undone = (int)cmdstatp->uremainder64;
30151da177e4SLinus Torvalds else
30161da177e4SLinus Torvalds undone = 0;
30171da177e4SLinus Torvalds
30183e51d3c9SKai Makisara if ((cmd_in == MTWEOF || cmd_in == MTWEOFI) &&
30191da177e4SLinus Torvalds cmdstatp->have_sense &&
302091614c05SKai Makisara (cmdstatp->flags & SENSE_EOM)) {
302191614c05SKai Makisara if (cmdstatp->sense_hdr.sense_key == NO_SENSE ||
302291614c05SKai Makisara cmdstatp->sense_hdr.sense_key == RECOVERED_ERROR) {
302391614c05SKai Makisara ioctl_result = 0; /* EOF(s) written successfully at EOM */
30241da177e4SLinus Torvalds STps->eof = ST_NOEOF;
302591614c05SKai Makisara } else { /* Writing EOF(s) failed */
302691614c05SKai Makisara if (fileno >= 0)
302791614c05SKai Makisara fileno -= undone;
302891614c05SKai Makisara if (undone < arg)
302991614c05SKai Makisara STps->eof = ST_NOEOF;
303091614c05SKai Makisara }
303191614c05SKai Makisara STps->drv_file = fileno;
30321da177e4SLinus Torvalds } else if ((cmd_in == MTFSF) || (cmd_in == MTFSFM)) {
30331da177e4SLinus Torvalds if (fileno >= 0)
30341da177e4SLinus Torvalds STps->drv_file = fileno - undone;
30351da177e4SLinus Torvalds else
30361da177e4SLinus Torvalds STps->drv_file = fileno;
30371da177e4SLinus Torvalds STps->drv_block = -1;
30381da177e4SLinus Torvalds STps->eof = ST_NOEOF;
30391da177e4SLinus Torvalds } else if ((cmd_in == MTBSF) || (cmd_in == MTBSFM)) {
30401da177e4SLinus Torvalds if (arg > 0 && undone < 0) /* Some drives get this wrong */
30411da177e4SLinus Torvalds undone = (-undone);
30421da177e4SLinus Torvalds if (STps->drv_file >= 0)
30431da177e4SLinus Torvalds STps->drv_file = fileno + undone;
30441da177e4SLinus Torvalds STps->drv_block = 0;
30451da177e4SLinus Torvalds STps->eof = ST_NOEOF;
30461da177e4SLinus Torvalds } else if (cmd_in == MTFSR) {
30471da177e4SLinus Torvalds if (cmdstatp->flags & SENSE_FMK) { /* Hit filemark */
30481da177e4SLinus Torvalds if (STps->drv_file >= 0)
30491da177e4SLinus Torvalds STps->drv_file++;
30501da177e4SLinus Torvalds STps->drv_block = 0;
30511da177e4SLinus Torvalds STps->eof = ST_FM;
30521da177e4SLinus Torvalds } else {
30531da177e4SLinus Torvalds if (blkno >= undone)
30541da177e4SLinus Torvalds STps->drv_block = blkno - undone;
30551da177e4SLinus Torvalds else
30561da177e4SLinus Torvalds STps->drv_block = (-1);
30571da177e4SLinus Torvalds STps->eof = ST_NOEOF;
30581da177e4SLinus Torvalds }
30591da177e4SLinus Torvalds } else if (cmd_in == MTBSR) {
30601da177e4SLinus Torvalds if (cmdstatp->flags & SENSE_FMK) { /* Hit filemark */
30611da177e4SLinus Torvalds STps->drv_file--;
30621da177e4SLinus Torvalds STps->drv_block = (-1);
30631da177e4SLinus Torvalds } else {
30641da177e4SLinus Torvalds if (arg > 0 && undone < 0) /* Some drives get this wrong */
30651da177e4SLinus Torvalds undone = (-undone);
30661da177e4SLinus Torvalds if (STps->drv_block >= 0)
30671da177e4SLinus Torvalds STps->drv_block = blkno + undone;
30681da177e4SLinus Torvalds }
30691da177e4SLinus Torvalds STps->eof = ST_NOEOF;
30701da177e4SLinus Torvalds } else if (cmd_in == MTEOM) {
30711da177e4SLinus Torvalds STps->drv_file = (-1);
30721da177e4SLinus Torvalds STps->drv_block = (-1);
30731da177e4SLinus Torvalds STps->eof = ST_EOD;
30741da177e4SLinus Torvalds } else if (cmd_in == MTSETBLK ||
30751da177e4SLinus Torvalds cmd_in == MTSETDENSITY ||
30761da177e4SLinus Torvalds cmd_in == MTSETDRVBUFFER ||
30771da177e4SLinus Torvalds cmd_in == SET_DENS_AND_BLK) {
30781da177e4SLinus Torvalds if (cmdstatp->sense_hdr.sense_key == ILLEGAL_REQUEST &&
30791da177e4SLinus Torvalds !(STp->use_pf & PF_TESTED)) {
30801da177e4SLinus Torvalds /* Try the other possible state of Page Format if not
30811da177e4SLinus Torvalds already tried */
30821da2019fSKai Makisara STp->use_pf = (STp->use_pf ^ USE_PF) | PF_TESTED;
30838b05b773SMike Christie st_release_request(SRpnt);
30841da177e4SLinus Torvalds SRpnt = NULL;
30851da177e4SLinus Torvalds return st_int_ioctl(STp, cmd_in, arg);
30861da177e4SLinus Torvalds }
30871da177e4SLinus Torvalds } else if (chg_eof)
30881da177e4SLinus Torvalds STps->eof = ST_NOEOF;
30891da177e4SLinus Torvalds
30901da177e4SLinus Torvalds if (cmdstatp->sense_hdr.sense_key == BLANK_CHECK)
30911da177e4SLinus Torvalds STps->eof = ST_EOD;
30921da177e4SLinus Torvalds
30938b05b773SMike Christie st_release_request(SRpnt);
30941da177e4SLinus Torvalds SRpnt = NULL;
30951da177e4SLinus Torvalds }
30961da177e4SLinus Torvalds
30971da177e4SLinus Torvalds return ioctl_result;
30981da177e4SLinus Torvalds }
30991da177e4SLinus Torvalds
31001da177e4SLinus Torvalds
31011da177e4SLinus Torvalds /* Get the tape position. If bt == 2, arg points into a kernel space mt_loc
31021da177e4SLinus Torvalds structure. */
31031da177e4SLinus Torvalds
get_location(struct scsi_tape * STp,unsigned int * block,int * partition,int logical)31041da177e4SLinus Torvalds static int get_location(struct scsi_tape *STp, unsigned int *block, int *partition,
31051da177e4SLinus Torvalds int logical)
31061da177e4SLinus Torvalds {
31071da177e4SLinus Torvalds int result;
31081da177e4SLinus Torvalds unsigned char scmd[MAX_COMMAND_SIZE];
31098b05b773SMike Christie struct st_request *SRpnt;
31101da177e4SLinus Torvalds
31111da177e4SLinus Torvalds if (STp->ready != ST_READY)
31121da177e4SLinus Torvalds return (-EIO);
31131da177e4SLinus Torvalds
31141da177e4SLinus Torvalds memset(scmd, 0, MAX_COMMAND_SIZE);
31151da177e4SLinus Torvalds if ((STp->device)->scsi_level < SCSI_2) {
31161da177e4SLinus Torvalds scmd[0] = QFA_REQUEST_BLOCK;
31171da177e4SLinus Torvalds scmd[4] = 3;
31181da177e4SLinus Torvalds } else {
31191da177e4SLinus Torvalds scmd[0] = READ_POSITION;
31201da177e4SLinus Torvalds if (!logical && !STp->scsi2_logical)
31211da177e4SLinus Torvalds scmd[1] = 1;
31221da177e4SLinus Torvalds }
312302ae2c0eSKai Makisara SRpnt = st_do_scsi(NULL, STp, scmd, 20, DMA_FROM_DEVICE,
31247a31ec3cSFUJITA Tomonori STp->device->request_queue->rq_timeout,
312502ae2c0eSKai Makisara MAX_READY_RETRIES, 1);
312602ae2c0eSKai Makisara if (!SRpnt)
312702ae2c0eSKai Makisara return (STp->buffer)->syscall_result;
31281da177e4SLinus Torvalds
31291da177e4SLinus Torvalds if ((STp->buffer)->syscall_result != 0 ||
31301da177e4SLinus Torvalds (STp->device->scsi_level >= SCSI_2 &&
31311da177e4SLinus Torvalds ((STp->buffer)->b_data[0] & 4) != 0)) {
31321da177e4SLinus Torvalds *block = *partition = 0;
3133b30d8bcaSHannes Reinecke DEBC_printk(STp, " Can't read tape position.\n");
31341da177e4SLinus Torvalds result = (-EIO);
31351da177e4SLinus Torvalds } else {
31361da177e4SLinus Torvalds result = 0;
31371da177e4SLinus Torvalds if ((STp->device)->scsi_level < SCSI_2) {
31381da177e4SLinus Torvalds *block = ((STp->buffer)->b_data[0] << 16)
31391da177e4SLinus Torvalds + ((STp->buffer)->b_data[1] << 8)
31401da177e4SLinus Torvalds + (STp->buffer)->b_data[2];
31411da177e4SLinus Torvalds *partition = 0;
31421da177e4SLinus Torvalds } else {
31431da177e4SLinus Torvalds *block = ((STp->buffer)->b_data[4] << 24)
31441da177e4SLinus Torvalds + ((STp->buffer)->b_data[5] << 16)
31451da177e4SLinus Torvalds + ((STp->buffer)->b_data[6] << 8)
31461da177e4SLinus Torvalds + (STp->buffer)->b_data[7];
31471da177e4SLinus Torvalds *partition = (STp->buffer)->b_data[1];
31481da177e4SLinus Torvalds if (((STp->buffer)->b_data[0] & 0x80) &&
31491da177e4SLinus Torvalds (STp->buffer)->b_data[1] == 0) /* BOP of partition 0 */
31501da177e4SLinus Torvalds STp->ps[0].drv_block = STp->ps[0].drv_file = 0;
31511da177e4SLinus Torvalds }
3152b30d8bcaSHannes Reinecke DEBC_printk(STp, "Got tape pos. blk %d part %d.\n",
3153b30d8bcaSHannes Reinecke *block, *partition);
31541da177e4SLinus Torvalds }
31558b05b773SMike Christie st_release_request(SRpnt);
31561da177e4SLinus Torvalds SRpnt = NULL;
31571da177e4SLinus Torvalds
31581da177e4SLinus Torvalds return result;
31591da177e4SLinus Torvalds }
31601da177e4SLinus Torvalds
31611da177e4SLinus Torvalds
31621da177e4SLinus Torvalds /* Set the tape block and partition. Negative partition means that only the
31631da177e4SLinus Torvalds block should be set in vendor specific way. */
set_location(struct scsi_tape * STp,unsigned int block,int partition,int logical)31641da177e4SLinus Torvalds static int set_location(struct scsi_tape *STp, unsigned int block, int partition,
31651da177e4SLinus Torvalds int logical)
31661da177e4SLinus Torvalds {
31671da177e4SLinus Torvalds struct st_partstat *STps;
31681da177e4SLinus Torvalds int result, p;
31691da177e4SLinus Torvalds unsigned int blk;
31701da177e4SLinus Torvalds int timeout;
31711da177e4SLinus Torvalds unsigned char scmd[MAX_COMMAND_SIZE];
31728b05b773SMike Christie struct st_request *SRpnt;
31731da177e4SLinus Torvalds
31741da177e4SLinus Torvalds if (STp->ready != ST_READY)
31751da177e4SLinus Torvalds return (-EIO);
31761da177e4SLinus Torvalds timeout = STp->long_timeout;
31771da177e4SLinus Torvalds STps = &(STp->ps[STp->partition]);
31781da177e4SLinus Torvalds
3179b30d8bcaSHannes Reinecke DEBC_printk(STp, "Setting block to %d and partition to %d.\n",
3180b30d8bcaSHannes Reinecke block, partition);
31811da177e4SLinus Torvalds DEB(if (partition < 0)
31821da177e4SLinus Torvalds return (-EIO); )
31831da177e4SLinus Torvalds
31841da177e4SLinus Torvalds /* Update the location at the partition we are leaving */
31851da177e4SLinus Torvalds if ((!STp->can_partitions && partition != 0) ||
31861da177e4SLinus Torvalds partition >= ST_NBR_PARTITIONS)
31871da177e4SLinus Torvalds return (-EINVAL);
31881da177e4SLinus Torvalds if (partition != STp->partition) {
31891da177e4SLinus Torvalds if (get_location(STp, &blk, &p, 1))
31901da177e4SLinus Torvalds STps->last_block_valid = 0;
31911da177e4SLinus Torvalds else {
31921da177e4SLinus Torvalds STps->last_block_valid = 1;
31931da177e4SLinus Torvalds STps->last_block_visited = blk;
3194b30d8bcaSHannes Reinecke DEBC_printk(STp, "Visited block %d for "
3195b30d8bcaSHannes Reinecke "partition %d saved.\n",
3196b30d8bcaSHannes Reinecke blk, STp->partition);
31971da177e4SLinus Torvalds }
31981da177e4SLinus Torvalds }
31991da177e4SLinus Torvalds
32001da177e4SLinus Torvalds memset(scmd, 0, MAX_COMMAND_SIZE);
32011da177e4SLinus Torvalds if ((STp->device)->scsi_level < SCSI_2) {
32021da177e4SLinus Torvalds scmd[0] = QFA_SEEK_BLOCK;
32031da177e4SLinus Torvalds scmd[2] = (block >> 16);
32041da177e4SLinus Torvalds scmd[3] = (block >> 8);
32051da177e4SLinus Torvalds scmd[4] = block;
32061da177e4SLinus Torvalds scmd[5] = 0;
32071da177e4SLinus Torvalds } else {
32081da177e4SLinus Torvalds scmd[0] = SEEK_10;
32091da177e4SLinus Torvalds scmd[3] = (block >> 24);
32101da177e4SLinus Torvalds scmd[4] = (block >> 16);
32111da177e4SLinus Torvalds scmd[5] = (block >> 8);
32121da177e4SLinus Torvalds scmd[6] = block;
32131da177e4SLinus Torvalds if (!logical && !STp->scsi2_logical)
32141da177e4SLinus Torvalds scmd[1] = 4;
32151da177e4SLinus Torvalds if (STp->partition != partition) {
32161da177e4SLinus Torvalds scmd[1] |= 2;
32171da177e4SLinus Torvalds scmd[8] = partition;
3218b30d8bcaSHannes Reinecke DEBC_printk(STp, "Trying to change partition "
3219b30d8bcaSHannes Reinecke "from %d to %d\n", STp->partition,
3220b30d8bcaSHannes Reinecke partition);
32211da177e4SLinus Torvalds }
32221da177e4SLinus Torvalds }
32231da177e4SLinus Torvalds if (STp->immediate) {
32241da177e4SLinus Torvalds scmd[1] |= 1; /* Don't wait for completion */
3225a02488edSJames Bottomley timeout = STp->device->request_queue->rq_timeout;
32261da177e4SLinus Torvalds }
32271da177e4SLinus Torvalds
322802ae2c0eSKai Makisara SRpnt = st_do_scsi(NULL, STp, scmd, 0, DMA_NONE,
322902ae2c0eSKai Makisara timeout, MAX_READY_RETRIES, 1);
32301da177e4SLinus Torvalds if (!SRpnt)
323102ae2c0eSKai Makisara return (STp->buffer)->syscall_result;
32321da177e4SLinus Torvalds
32331da177e4SLinus Torvalds STps->drv_block = STps->drv_file = (-1);
32341da177e4SLinus Torvalds STps->eof = ST_NOEOF;
32351da177e4SLinus Torvalds if ((STp->buffer)->syscall_result != 0) {
32361da177e4SLinus Torvalds result = (-EIO);
32371da177e4SLinus Torvalds if (STp->can_partitions &&
32381da177e4SLinus Torvalds (STp->device)->scsi_level >= SCSI_2 &&
32391da177e4SLinus Torvalds (p = find_partition(STp)) >= 0)
32401da177e4SLinus Torvalds STp->partition = p;
32411da177e4SLinus Torvalds } else {
32421da177e4SLinus Torvalds if (STp->can_partitions) {
32431da177e4SLinus Torvalds STp->partition = partition;
32441da177e4SLinus Torvalds STps = &(STp->ps[partition]);
32451da177e4SLinus Torvalds if (!STps->last_block_valid ||
32461da177e4SLinus Torvalds STps->last_block_visited != block) {
32471da177e4SLinus Torvalds STps->at_sm = 0;
32481da177e4SLinus Torvalds STps->rw = ST_IDLE;
32491da177e4SLinus Torvalds }
32501da177e4SLinus Torvalds } else
32511da177e4SLinus Torvalds STps->at_sm = 0;
32521da177e4SLinus Torvalds if (block == 0)
32531da177e4SLinus Torvalds STps->drv_block = STps->drv_file = 0;
32541da177e4SLinus Torvalds result = 0;
32551da177e4SLinus Torvalds }
325602ae2c0eSKai Makisara
32578b05b773SMike Christie st_release_request(SRpnt);
32581da177e4SLinus Torvalds SRpnt = NULL;
32591da177e4SLinus Torvalds
32601da177e4SLinus Torvalds return result;
32611da177e4SLinus Torvalds }
32621da177e4SLinus Torvalds
32631da177e4SLinus Torvalds
32641da177e4SLinus Torvalds /* Find the current partition number for the drive status. Called from open and
32651da177e4SLinus Torvalds returns either partition number of negative error code. */
find_partition(struct scsi_tape * STp)32661da177e4SLinus Torvalds static int find_partition(struct scsi_tape *STp)
32671da177e4SLinus Torvalds {
32681da177e4SLinus Torvalds int i, partition;
32691da177e4SLinus Torvalds unsigned int block;
32701da177e4SLinus Torvalds
32711da177e4SLinus Torvalds if ((i = get_location(STp, &block, &partition, 1)) < 0)
32721da177e4SLinus Torvalds return i;
32731da177e4SLinus Torvalds if (partition >= ST_NBR_PARTITIONS)
32741da177e4SLinus Torvalds return (-EIO);
32751da177e4SLinus Torvalds return partition;
32761da177e4SLinus Torvalds }
32771da177e4SLinus Torvalds
32781da177e4SLinus Torvalds
32791da177e4SLinus Torvalds /* Change the partition if necessary */
switch_partition(struct scsi_tape * STp)32801da177e4SLinus Torvalds static int switch_partition(struct scsi_tape *STp)
32811da177e4SLinus Torvalds {
32821da177e4SLinus Torvalds struct st_partstat *STps;
32831da177e4SLinus Torvalds
32841da177e4SLinus Torvalds if (STp->partition == STp->new_partition)
32851da177e4SLinus Torvalds return 0;
32861da177e4SLinus Torvalds STps = &(STp->ps[STp->new_partition]);
32871da177e4SLinus Torvalds if (!STps->last_block_valid)
32881da177e4SLinus Torvalds STps->last_block_visited = 0;
32891da177e4SLinus Torvalds return set_location(STp, STps->last_block_visited, STp->new_partition, 1);
32901da177e4SLinus Torvalds }
32911da177e4SLinus Torvalds
32921da177e4SLinus Torvalds /* Functions for reading and writing the medium partition mode page. */
32931da177e4SLinus Torvalds
32941da177e4SLinus Torvalds #define PART_PAGE 0x11
32951da177e4SLinus Torvalds #define PART_PAGE_FIXED_LENGTH 8
32961da177e4SLinus Torvalds
32971da177e4SLinus Torvalds #define PP_OFF_MAX_ADD_PARTS 2
32981da177e4SLinus Torvalds #define PP_OFF_NBR_ADD_PARTS 3
32991da177e4SLinus Torvalds #define PP_OFF_FLAGS 4
33001da177e4SLinus Torvalds #define PP_OFF_PART_UNITS 6
33011da177e4SLinus Torvalds #define PP_OFF_RESERVED 7
33021da177e4SLinus Torvalds
33031da177e4SLinus Torvalds #define PP_BIT_IDP 0x20
33048038e645SKai Makisara #define PP_BIT_FDP 0x80
33051da177e4SLinus Torvalds #define PP_MSK_PSUM_MB 0x10
33068038e645SKai Makisara #define PP_MSK_PSUM_UNITS 0x18
33078038e645SKai Makisara #define PP_MSK_POFM 0x04
33081da177e4SLinus Torvalds
33091da177e4SLinus Torvalds /* Get the number of partitions on the tape. As a side effect reads the
33101da177e4SLinus Torvalds mode page into the tape buffer. */
nbr_partitions(struct scsi_tape * STp)33111da177e4SLinus Torvalds static int nbr_partitions(struct scsi_tape *STp)
33121da177e4SLinus Torvalds {
33131da177e4SLinus Torvalds int result;
33141da177e4SLinus Torvalds
33151da177e4SLinus Torvalds if (STp->ready != ST_READY)
33161da177e4SLinus Torvalds return (-EIO);
33171da177e4SLinus Torvalds
33181da177e4SLinus Torvalds result = read_mode_page(STp, PART_PAGE, 1);
33191da177e4SLinus Torvalds
33201da177e4SLinus Torvalds if (result) {
3321b30d8bcaSHannes Reinecke DEBC_printk(STp, "Can't read medium partition page.\n");
33221da177e4SLinus Torvalds result = (-EIO);
33231da177e4SLinus Torvalds } else {
33241da177e4SLinus Torvalds result = (STp->buffer)->b_data[MODE_HEADER_LENGTH +
33251da177e4SLinus Torvalds PP_OFF_NBR_ADD_PARTS] + 1;
3326b30d8bcaSHannes Reinecke DEBC_printk(STp, "Number of partitions %d.\n", result);
33271da177e4SLinus Torvalds }
33281da177e4SLinus Torvalds
33291da177e4SLinus Torvalds return result;
33301da177e4SLinus Torvalds }
33311da177e4SLinus Torvalds
33321da177e4SLinus Torvalds
format_medium(struct scsi_tape * STp,int format)33338038e645SKai Makisara static int format_medium(struct scsi_tape *STp, int format)
33348038e645SKai Makisara {
33358038e645SKai Makisara int result = 0;
33368038e645SKai Makisara int timeout = STp->long_timeout;
33378038e645SKai Makisara unsigned char scmd[MAX_COMMAND_SIZE];
33388038e645SKai Makisara struct st_request *SRpnt;
33398038e645SKai Makisara
33408038e645SKai Makisara memset(scmd, 0, MAX_COMMAND_SIZE);
33418038e645SKai Makisara scmd[0] = FORMAT_UNIT;
33428038e645SKai Makisara scmd[2] = format;
33438038e645SKai Makisara if (STp->immediate) {
33448038e645SKai Makisara scmd[1] |= 1; /* Don't wait for completion */
33458038e645SKai Makisara timeout = STp->device->request_queue->rq_timeout;
33468038e645SKai Makisara }
33478038e645SKai Makisara DEBC_printk(STp, "Sending FORMAT MEDIUM\n");
33488038e645SKai Makisara SRpnt = st_do_scsi(NULL, STp, scmd, 0, DMA_NONE,
33498038e645SKai Makisara timeout, MAX_RETRIES, 1);
33508038e645SKai Makisara if (!SRpnt)
33518038e645SKai Makisara result = STp->buffer->syscall_result;
33528038e645SKai Makisara return result;
33538038e645SKai Makisara }
33548038e645SKai Makisara
33558038e645SKai Makisara
33561da177e4SLinus Torvalds /* Partition the tape into two partitions if size > 0 or one partition if
33571da177e4SLinus Torvalds size == 0.
33581da177e4SLinus Torvalds
33591da177e4SLinus Torvalds The block descriptors are read and written because Sony SDT-7000 does not
33601da177e4SLinus Torvalds work without this (suggestion from Michael Schaefer <Michael.Schaefer@dlr.de>).
33611da177e4SLinus Torvalds
33621da177e4SLinus Torvalds My HP C1533A drive returns only one partition size field. This is used to
33631da177e4SLinus Torvalds set the size of partition 1. There is no size field for the default partition.
33641da177e4SLinus Torvalds Michael Schaefer's Sony SDT-7000 returns two descriptors and the second is
33651da177e4SLinus Torvalds used to set the size of partition 1 (this is what the SCSI-3 standard specifies).
33661da177e4SLinus Torvalds The following algorithm is used to accommodate both drives: if the number of
33671da177e4SLinus Torvalds partition size fields is greater than the maximum number of additional partitions
33681da177e4SLinus Torvalds in the mode page, the second field is used. Otherwise the first field is used.
33691da177e4SLinus Torvalds
33701da177e4SLinus Torvalds For Seagate DDS drives the page length must be 8 when no partitions is defined
33711da177e4SLinus Torvalds and 10 when 1 partition is defined (information from Eric Lee Green). This is
33721da177e4SLinus Torvalds is acceptable also to some other old drives and enforced if the first partition
33731da177e4SLinus Torvalds size field is used for the first additional partition size.
33748038e645SKai Makisara
33758038e645SKai Makisara For drives that advertize SCSI-3 or newer, use the SSC-3 methods.
33761da177e4SLinus Torvalds */
partition_tape(struct scsi_tape * STp,int size)33771da177e4SLinus Torvalds static int partition_tape(struct scsi_tape *STp, int size)
33781da177e4SLinus Torvalds {
33791da177e4SLinus Torvalds int result;
33808038e645SKai Makisara int target_partition;
33818038e645SKai Makisara bool scsi3 = STp->device->scsi_level >= SCSI_3, needs_format = false;
33821da177e4SLinus Torvalds int pgo, psd_cnt, psdo;
33838038e645SKai Makisara int psum = PP_MSK_PSUM_MB, units = 0;
33841da177e4SLinus Torvalds unsigned char *bp;
33851da177e4SLinus Torvalds
33861da177e4SLinus Torvalds result = read_mode_page(STp, PART_PAGE, 0);
33871da177e4SLinus Torvalds if (result) {
3388b30d8bcaSHannes Reinecke DEBC_printk(STp, "Can't read partition mode page.\n");
33891da177e4SLinus Torvalds return result;
33901da177e4SLinus Torvalds }
33918038e645SKai Makisara target_partition = 1;
33928038e645SKai Makisara if (size < 0) {
33938038e645SKai Makisara target_partition = 0;
33948038e645SKai Makisara size = -size;
33958038e645SKai Makisara }
33968038e645SKai Makisara
33971da177e4SLinus Torvalds /* The mode page is in the buffer. Let's modify it and write it. */
33981da177e4SLinus Torvalds bp = (STp->buffer)->b_data;
33991da177e4SLinus Torvalds pgo = MODE_HEADER_LENGTH + bp[MH_OFF_BDESCS_LENGTH];
3400b30d8bcaSHannes Reinecke DEBC_printk(STp, "Partition page length is %d bytes.\n",
3401b30d8bcaSHannes Reinecke bp[pgo + MP_OFF_PAGE_LENGTH] + 2);
34021da177e4SLinus Torvalds
34031da177e4SLinus Torvalds psd_cnt = (bp[pgo + MP_OFF_PAGE_LENGTH] + 2 - PART_PAGE_FIXED_LENGTH) / 2;
34048038e645SKai Makisara
34058038e645SKai Makisara if (scsi3) {
34068038e645SKai Makisara needs_format = (bp[pgo + PP_OFF_FLAGS] & PP_MSK_POFM) != 0;
34078038e645SKai Makisara if (needs_format && size == 0) {
34088038e645SKai Makisara /* No need to write the mode page when clearing
34098038e645SKai Makisara * partitioning
34108038e645SKai Makisara */
34118038e645SKai Makisara DEBC_printk(STp, "Formatting tape with one partition.\n");
34128038e645SKai Makisara result = format_medium(STp, 0);
34138038e645SKai Makisara goto out;
34148038e645SKai Makisara }
34158038e645SKai Makisara if (needs_format) /* Leave the old value for HP DATs claiming SCSI_3 */
34168038e645SKai Makisara psd_cnt = 2;
34178038e645SKai Makisara if ((bp[pgo + PP_OFF_FLAGS] & PP_MSK_PSUM_UNITS) == PP_MSK_PSUM_UNITS) {
34188038e645SKai Makisara /* Use units scaling for large partitions if the device
34198038e645SKai Makisara * suggests it and no precision lost. Required for IBM
34208038e645SKai Makisara * TS1140/50 drives that don't support MB units.
34218038e645SKai Makisara */
34228038e645SKai Makisara if (size >= 1000 && (size % 1000) == 0) {
34238038e645SKai Makisara size /= 1000;
34248038e645SKai Makisara psum = PP_MSK_PSUM_UNITS;
34258038e645SKai Makisara units = 9; /* GB */
34268038e645SKai Makisara }
34278038e645SKai Makisara }
34288038e645SKai Makisara /* Try it anyway if too large to specify in MB */
34298038e645SKai Makisara if (psum == PP_MSK_PSUM_MB && size >= 65534) {
34308038e645SKai Makisara size /= 1000;
34318038e645SKai Makisara psum = PP_MSK_PSUM_UNITS;
34328038e645SKai Makisara units = 9; /* GB */
34338038e645SKai Makisara }
34348038e645SKai Makisara }
34358038e645SKai Makisara
34368038e645SKai Makisara if (size >= 65535 || /* Does not fit into two bytes */
34378038e645SKai Makisara (target_partition == 0 && psd_cnt < 2)) {
34388038e645SKai Makisara result = -EINVAL;
34398038e645SKai Makisara goto out;
34408038e645SKai Makisara }
34418038e645SKai Makisara
34421da177e4SLinus Torvalds psdo = pgo + PART_PAGE_FIXED_LENGTH;
34438038e645SKai Makisara /* The second condition is for HP DDS which use only one partition size
34448038e645SKai Makisara * descriptor
34458038e645SKai Makisara */
34468038e645SKai Makisara if (target_partition > 0 &&
34478038e645SKai Makisara (psd_cnt > bp[pgo + PP_OFF_MAX_ADD_PARTS] ||
34488038e645SKai Makisara bp[pgo + PP_OFF_MAX_ADD_PARTS] != 1)) {
34498038e645SKai Makisara bp[psdo] = bp[psdo + 1] = 0xff; /* Rest to partition 0 */
34501da177e4SLinus Torvalds psdo += 2;
34511da177e4SLinus Torvalds }
34521da177e4SLinus Torvalds memset(bp + psdo, 0, bp[pgo + PP_OFF_NBR_ADD_PARTS] * 2);
34531da177e4SLinus Torvalds
3454b30d8bcaSHannes Reinecke DEBC_printk(STp, "psd_cnt %d, max.parts %d, nbr_parts %d\n",
34551da177e4SLinus Torvalds psd_cnt, bp[pgo + PP_OFF_MAX_ADD_PARTS],
3456b30d8bcaSHannes Reinecke bp[pgo + PP_OFF_NBR_ADD_PARTS]);
34571da177e4SLinus Torvalds
34588038e645SKai Makisara if (size == 0) {
34591da177e4SLinus Torvalds bp[pgo + PP_OFF_NBR_ADD_PARTS] = 0;
34601da177e4SLinus Torvalds if (psd_cnt <= bp[pgo + PP_OFF_MAX_ADD_PARTS])
34611da177e4SLinus Torvalds bp[pgo + MP_OFF_PAGE_LENGTH] = 6;
3462b30d8bcaSHannes Reinecke DEBC_printk(STp, "Formatting tape with one partition.\n");
34631da177e4SLinus Torvalds } else {
34641da177e4SLinus Torvalds bp[psdo] = (size >> 8) & 0xff;
34651da177e4SLinus Torvalds bp[psdo + 1] = size & 0xff;
34668038e645SKai Makisara if (target_partition == 0)
34678038e645SKai Makisara bp[psdo + 2] = bp[psdo + 3] = 0xff;
34681da177e4SLinus Torvalds bp[pgo + 3] = 1;
34691da177e4SLinus Torvalds if (bp[pgo + MP_OFF_PAGE_LENGTH] < 8)
34701da177e4SLinus Torvalds bp[pgo + MP_OFF_PAGE_LENGTH] = 8;
34718038e645SKai Makisara DEBC_printk(STp,
34728038e645SKai Makisara "Formatting tape with two partitions (%i = %d MB).\n",
34738038e645SKai Makisara target_partition, units > 0 ? size * 1000 : size);
34741da177e4SLinus Torvalds }
34751da177e4SLinus Torvalds bp[pgo + PP_OFF_PART_UNITS] = 0;
34761da177e4SLinus Torvalds bp[pgo + PP_OFF_RESERVED] = 0;
34778038e645SKai Makisara if (size != 1 || units != 0) {
34788038e645SKai Makisara bp[pgo + PP_OFF_FLAGS] = PP_BIT_IDP | psum |
34798038e645SKai Makisara (bp[pgo + PP_OFF_FLAGS] & 0x07);
34808038e645SKai Makisara bp[pgo + PP_OFF_PART_UNITS] = units;
34818038e645SKai Makisara } else
34828038e645SKai Makisara bp[pgo + PP_OFF_FLAGS] = PP_BIT_FDP |
34838038e645SKai Makisara (bp[pgo + PP_OFF_FLAGS] & 0x1f);
34848038e645SKai Makisara bp[pgo + MP_OFF_PAGE_LENGTH] = 6 + psd_cnt * 2;
34851da177e4SLinus Torvalds
34861da177e4SLinus Torvalds result = write_mode_page(STp, PART_PAGE, 1);
34878038e645SKai Makisara
34888038e645SKai Makisara if (!result && needs_format)
34898038e645SKai Makisara result = format_medium(STp, 1);
34908038e645SKai Makisara
34911da177e4SLinus Torvalds if (result) {
3492b30d8bcaSHannes Reinecke st_printk(KERN_INFO, STp, "Partitioning of tape failed.\n");
34931da177e4SLinus Torvalds result = (-EIO);
34941da177e4SLinus Torvalds }
34951da177e4SLinus Torvalds
34968038e645SKai Makisara out:
34971da177e4SLinus Torvalds return result;
34981da177e4SLinus Torvalds }
34991da177e4SLinus Torvalds
35001da177e4SLinus Torvalds
35011da177e4SLinus Torvalds
35021da177e4SLinus Torvalds /* The ioctl command */
st_ioctl(struct file * file,unsigned int cmd_in,unsigned long arg)3503dba7688fSChristoph Hellwig static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
35041da177e4SLinus Torvalds {
3505dba7688fSChristoph Hellwig void __user *p = (void __user *)arg;
35061da177e4SLinus Torvalds int i, cmd_nr, cmd_type, bt;
35071da177e4SLinus Torvalds int retval = 0;
35081da177e4SLinus Torvalds unsigned int blk;
35091da177e4SLinus Torvalds struct scsi_tape *STp = file->private_data;
35101da177e4SLinus Torvalds struct st_modedef *STm;
35111da177e4SLinus Torvalds struct st_partstat *STps;
35121da177e4SLinus Torvalds
351328f85009SMatthias Kaehlcke if (mutex_lock_interruptible(&STp->lock))
35141da177e4SLinus Torvalds return -ERESTARTSYS;
35151da177e4SLinus Torvalds
35161da177e4SLinus Torvalds DEB(
35171da177e4SLinus Torvalds if (debugging && !STp->in_use) {
3518b30d8bcaSHannes Reinecke st_printk(ST_DEB_MSG, STp, "Incorrect device.\n");
35191da177e4SLinus Torvalds retval = (-EIO);
35201da177e4SLinus Torvalds goto out;
35211da177e4SLinus Torvalds } ) /* end DEB */
35221da177e4SLinus Torvalds
35231da177e4SLinus Torvalds STm = &(STp->modes[STp->current_mode]);
35241da177e4SLinus Torvalds STps = &(STp->ps[STp->partition]);
35251da177e4SLinus Torvalds
35261da177e4SLinus Torvalds /*
35271da177e4SLinus Torvalds * If we are in the middle of error recovery, don't let anyone
35281da177e4SLinus Torvalds * else try and use this device. Also, if error recovery fails, it
35291da177e4SLinus Torvalds * may try and take the device offline, in which case all further
35301da177e4SLinus Torvalds * access to the device is prohibited.
35311da177e4SLinus Torvalds */
3532906d15fbSChristoph Hellwig retval = scsi_ioctl_block_when_processing_errors(STp->device, cmd_in,
353383ff6fe8SAl Viro file->f_flags & O_NDELAY);
3534906d15fbSChristoph Hellwig if (retval)
35351da177e4SLinus Torvalds goto out;
35361da177e4SLinus Torvalds
35371da177e4SLinus Torvalds cmd_type = _IOC_TYPE(cmd_in);
35381da177e4SLinus Torvalds cmd_nr = _IOC_NR(cmd_in);
35391da177e4SLinus Torvalds
35401da177e4SLinus Torvalds if (cmd_type == _IOC_TYPE(MTIOCTOP) && cmd_nr == _IOC_NR(MTIOCTOP)) {
35411da177e4SLinus Torvalds struct mtop mtc;
35421da177e4SLinus Torvalds
35431da177e4SLinus Torvalds if (_IOC_SIZE(cmd_in) != sizeof(mtc)) {
35441da177e4SLinus Torvalds retval = (-EINVAL);
35451da177e4SLinus Torvalds goto out;
35461da177e4SLinus Torvalds }
35471da177e4SLinus Torvalds
35481da177e4SLinus Torvalds i = copy_from_user(&mtc, p, sizeof(struct mtop));
35491da177e4SLinus Torvalds if (i) {
35501da177e4SLinus Torvalds retval = (-EFAULT);
35511da177e4SLinus Torvalds goto out;
35521da177e4SLinus Torvalds }
35531da177e4SLinus Torvalds
35541da177e4SLinus Torvalds if (mtc.mt_op == MTSETDRVBUFFER && !capable(CAP_SYS_ADMIN)) {
3555b30d8bcaSHannes Reinecke st_printk(KERN_WARNING, STp,
3556b30d8bcaSHannes Reinecke "MTSETDRVBUFFER only allowed for root.\n");
35571da177e4SLinus Torvalds retval = (-EPERM);
35581da177e4SLinus Torvalds goto out;
35591da177e4SLinus Torvalds }
35601da177e4SLinus Torvalds if (!STm->defined &&
35611da177e4SLinus Torvalds (mtc.mt_op != MTSETDRVBUFFER &&
35621da177e4SLinus Torvalds (mtc.mt_count & MT_ST_OPTIONS) == 0)) {
35631da177e4SLinus Torvalds retval = (-ENXIO);
35641da177e4SLinus Torvalds goto out;
35651da177e4SLinus Torvalds }
35661da177e4SLinus Torvalds
35671da177e4SLinus Torvalds if (!STp->pos_unknown) {
35681da177e4SLinus Torvalds
35691da177e4SLinus Torvalds if (STps->eof == ST_FM_HIT) {
35701da177e4SLinus Torvalds if (mtc.mt_op == MTFSF || mtc.mt_op == MTFSFM ||
35711da177e4SLinus Torvalds mtc.mt_op == MTEOM) {
35721da177e4SLinus Torvalds mtc.mt_count -= 1;
35731da177e4SLinus Torvalds if (STps->drv_file >= 0)
35741da177e4SLinus Torvalds STps->drv_file += 1;
35751da177e4SLinus Torvalds } else if (mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM) {
35761da177e4SLinus Torvalds mtc.mt_count += 1;
35771da177e4SLinus Torvalds if (STps->drv_file >= 0)
35781da177e4SLinus Torvalds STps->drv_file += 1;
35791da177e4SLinus Torvalds }
35801da177e4SLinus Torvalds }
35811da177e4SLinus Torvalds
35821da177e4SLinus Torvalds if (mtc.mt_op == MTSEEK) {
35831da177e4SLinus Torvalds /* Old position must be restored if partition will be
35841da177e4SLinus Torvalds changed */
35851da177e4SLinus Torvalds i = !STp->can_partitions ||
35861da177e4SLinus Torvalds (STp->new_partition != STp->partition);
35871da177e4SLinus Torvalds } else {
35881da177e4SLinus Torvalds i = mtc.mt_op == MTREW || mtc.mt_op == MTOFFL ||
35891da177e4SLinus Torvalds mtc.mt_op == MTRETEN || mtc.mt_op == MTEOM ||
35901da177e4SLinus Torvalds mtc.mt_op == MTLOCK || mtc.mt_op == MTLOAD ||
35911da177e4SLinus Torvalds mtc.mt_op == MTFSF || mtc.mt_op == MTFSFM ||
35921da177e4SLinus Torvalds mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM ||
35931da177e4SLinus Torvalds mtc.mt_op == MTCOMPRESSION;
35941da177e4SLinus Torvalds }
35951da177e4SLinus Torvalds i = flush_buffer(STp, i);
35961da177e4SLinus Torvalds if (i < 0) {
35971da177e4SLinus Torvalds retval = i;
35981da177e4SLinus Torvalds goto out;
35991da177e4SLinus Torvalds }
36001da177e4SLinus Torvalds if (STps->rw == ST_WRITING &&
36011da177e4SLinus Torvalds (mtc.mt_op == MTREW || mtc.mt_op == MTOFFL ||
36021da177e4SLinus Torvalds mtc.mt_op == MTSEEK ||
36031da177e4SLinus Torvalds mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM)) {
36041da177e4SLinus Torvalds i = st_int_ioctl(STp, MTWEOF, 1);
36051da177e4SLinus Torvalds if (i < 0) {
36061da177e4SLinus Torvalds retval = i;
36071da177e4SLinus Torvalds goto out;
36081da177e4SLinus Torvalds }
36091da177e4SLinus Torvalds if (mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM)
36101da177e4SLinus Torvalds mtc.mt_count++;
36111da177e4SLinus Torvalds STps->rw = ST_IDLE;
36121da177e4SLinus Torvalds }
36131da177e4SLinus Torvalds
36141da177e4SLinus Torvalds } else {
36151da177e4SLinus Torvalds /*
36161da177e4SLinus Torvalds * If there was a bus reset, block further access
36171da177e4SLinus Torvalds * to this device. If the user wants to rewind the tape,
36181da177e4SLinus Torvalds * then reset the flag and allow access again.
36191da177e4SLinus Torvalds */
36201da177e4SLinus Torvalds if (mtc.mt_op != MTREW &&
36211da177e4SLinus Torvalds mtc.mt_op != MTOFFL &&
36221da177e4SLinus Torvalds mtc.mt_op != MTRETEN &&
36231da177e4SLinus Torvalds mtc.mt_op != MTERASE &&
36241da177e4SLinus Torvalds mtc.mt_op != MTSEEK &&
36251da177e4SLinus Torvalds mtc.mt_op != MTEOM) {
36261da177e4SLinus Torvalds retval = (-EIO);
36271da177e4SLinus Torvalds goto out;
36281da177e4SLinus Torvalds }
36291da177e4SLinus Torvalds reset_state(STp);
36301da177e4SLinus Torvalds /* remove this when the midlevel properly clears was_reset */
36311da177e4SLinus Torvalds STp->device->was_reset = 0;
36321da177e4SLinus Torvalds }
36331da177e4SLinus Torvalds
36341da177e4SLinus Torvalds if (mtc.mt_op != MTNOP && mtc.mt_op != MTSETBLK &&
36351da177e4SLinus Torvalds mtc.mt_op != MTSETDENSITY && mtc.mt_op != MTWSM &&
36361da177e4SLinus Torvalds mtc.mt_op != MTSETDRVBUFFER && mtc.mt_op != MTSETPART)
36371da177e4SLinus Torvalds STps->rw = ST_IDLE; /* Prevent automatic WEOF and fsf */
36381da177e4SLinus Torvalds
36391da177e4SLinus Torvalds if (mtc.mt_op == MTOFFL && STp->door_locked != ST_UNLOCKED)
36401da177e4SLinus Torvalds do_door_lock(STp, 0); /* Ignore result! */
36411da177e4SLinus Torvalds
36421da177e4SLinus Torvalds if (mtc.mt_op == MTSETDRVBUFFER &&
36431da177e4SLinus Torvalds (mtc.mt_count & MT_ST_OPTIONS) != 0) {
36441da177e4SLinus Torvalds retval = st_set_options(STp, mtc.mt_count);
36451da177e4SLinus Torvalds goto out;
36461da177e4SLinus Torvalds }
36471da177e4SLinus Torvalds
36481da177e4SLinus Torvalds if (mtc.mt_op == MTSETPART) {
36491da177e4SLinus Torvalds if (!STp->can_partitions ||
36501da177e4SLinus Torvalds mtc.mt_count < 0 || mtc.mt_count >= ST_NBR_PARTITIONS) {
36511da177e4SLinus Torvalds retval = (-EINVAL);
36521da177e4SLinus Torvalds goto out;
36531da177e4SLinus Torvalds }
36541da177e4SLinus Torvalds if (mtc.mt_count >= STp->nbr_partitions &&
36551da177e4SLinus Torvalds (STp->nbr_partitions = nbr_partitions(STp)) < 0) {
36561da177e4SLinus Torvalds retval = (-EIO);
36571da177e4SLinus Torvalds goto out;
36581da177e4SLinus Torvalds }
36591da177e4SLinus Torvalds if (mtc.mt_count >= STp->nbr_partitions) {
36601da177e4SLinus Torvalds retval = (-EINVAL);
36611da177e4SLinus Torvalds goto out;
36621da177e4SLinus Torvalds }
36631da177e4SLinus Torvalds STp->new_partition = mtc.mt_count;
36641da177e4SLinus Torvalds retval = 0;
36651da177e4SLinus Torvalds goto out;
36661da177e4SLinus Torvalds }
36671da177e4SLinus Torvalds
36681da177e4SLinus Torvalds if (mtc.mt_op == MTMKPART) {
36691da177e4SLinus Torvalds if (!STp->can_partitions) {
36701da177e4SLinus Torvalds retval = (-EINVAL);
36711da177e4SLinus Torvalds goto out;
36721da177e4SLinus Torvalds }
36738038e645SKai Makisara i = do_load_unload(STp, file, 1);
36748038e645SKai Makisara if (i < 0) {
36758038e645SKai Makisara retval = i;
36768038e645SKai Makisara goto out;
36778038e645SKai Makisara }
36788038e645SKai Makisara i = partition_tape(STp, mtc.mt_count);
36798038e645SKai Makisara if (i < 0) {
36801da177e4SLinus Torvalds retval = i;
36811da177e4SLinus Torvalds goto out;
36821da177e4SLinus Torvalds }
36831da177e4SLinus Torvalds for (i = 0; i < ST_NBR_PARTITIONS; i++) {
36841da177e4SLinus Torvalds STp->ps[i].rw = ST_IDLE;
36851da177e4SLinus Torvalds STp->ps[i].at_sm = 0;
36861da177e4SLinus Torvalds STp->ps[i].last_block_valid = 0;
36871da177e4SLinus Torvalds }
36881da177e4SLinus Torvalds STp->partition = STp->new_partition = 0;
36898038e645SKai Makisara STp->nbr_partitions = mtc.mt_count != 0 ? 2 : 1;
36901da177e4SLinus Torvalds STps->drv_block = STps->drv_file = 0;
36911da177e4SLinus Torvalds retval = 0;
36921da177e4SLinus Torvalds goto out;
36931da177e4SLinus Torvalds }
36941da177e4SLinus Torvalds
36951da177e4SLinus Torvalds if (mtc.mt_op == MTSEEK) {
36961da177e4SLinus Torvalds i = set_location(STp, mtc.mt_count, STp->new_partition, 0);
36971da177e4SLinus Torvalds if (!STp->can_partitions)
36981da177e4SLinus Torvalds STp->ps[0].rw = ST_IDLE;
36991da177e4SLinus Torvalds retval = i;
37001da177e4SLinus Torvalds goto out;
37011da177e4SLinus Torvalds }
37021da177e4SLinus Torvalds
37031da177e4SLinus Torvalds if (mtc.mt_op == MTUNLOAD || mtc.mt_op == MTOFFL) {
37041da177e4SLinus Torvalds retval = do_load_unload(STp, file, 0);
37051da177e4SLinus Torvalds goto out;
37061da177e4SLinus Torvalds }
37071da177e4SLinus Torvalds
37081da177e4SLinus Torvalds if (mtc.mt_op == MTLOAD) {
37091da177e4SLinus Torvalds retval = do_load_unload(STp, file, max(1, mtc.mt_count));
37101da177e4SLinus Torvalds goto out;
37111da177e4SLinus Torvalds }
37121da177e4SLinus Torvalds
37131da177e4SLinus Torvalds if (mtc.mt_op == MTLOCK || mtc.mt_op == MTUNLOCK) {
37141da177e4SLinus Torvalds retval = do_door_lock(STp, (mtc.mt_op == MTLOCK));
37151da177e4SLinus Torvalds goto out;
37161da177e4SLinus Torvalds }
37171da177e4SLinus Torvalds
37181da177e4SLinus Torvalds if (STp->can_partitions && STp->ready == ST_READY &&
37191da177e4SLinus Torvalds (i = switch_partition(STp)) < 0) {
37201da177e4SLinus Torvalds retval = i;
37211da177e4SLinus Torvalds goto out;
37221da177e4SLinus Torvalds }
37231da177e4SLinus Torvalds
37241da177e4SLinus Torvalds if (mtc.mt_op == MTCOMPRESSION)
37251da177e4SLinus Torvalds retval = st_compression(STp, (mtc.mt_count & 1));
37261da177e4SLinus Torvalds else
37271da177e4SLinus Torvalds retval = st_int_ioctl(STp, mtc.mt_op, mtc.mt_count);
37281da177e4SLinus Torvalds goto out;
37291da177e4SLinus Torvalds }
37301da177e4SLinus Torvalds if (!STm->defined) {
37311da177e4SLinus Torvalds retval = (-ENXIO);
37321da177e4SLinus Torvalds goto out;
37331da177e4SLinus Torvalds }
37341da177e4SLinus Torvalds
37351da177e4SLinus Torvalds if ((i = flush_buffer(STp, 0)) < 0) {
37361da177e4SLinus Torvalds retval = i;
37371da177e4SLinus Torvalds goto out;
37381da177e4SLinus Torvalds }
37391da177e4SLinus Torvalds if (STp->can_partitions &&
37401da177e4SLinus Torvalds (i = switch_partition(STp)) < 0) {
37411da177e4SLinus Torvalds retval = i;
37421da177e4SLinus Torvalds goto out;
37431da177e4SLinus Torvalds }
37441da177e4SLinus Torvalds
37451da177e4SLinus Torvalds if (cmd_type == _IOC_TYPE(MTIOCGET) && cmd_nr == _IOC_NR(MTIOCGET)) {
37461da177e4SLinus Torvalds struct mtget mt_status;
37471da177e4SLinus Torvalds
37481da177e4SLinus Torvalds if (_IOC_SIZE(cmd_in) != sizeof(struct mtget)) {
37491da177e4SLinus Torvalds retval = (-EINVAL);
37501da177e4SLinus Torvalds goto out;
37511da177e4SLinus Torvalds }
37521da177e4SLinus Torvalds
37531da177e4SLinus Torvalds mt_status.mt_type = STp->tape_type;
37541da177e4SLinus Torvalds mt_status.mt_dsreg =
37551da177e4SLinus Torvalds ((STp->block_size << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK) |
37561da177e4SLinus Torvalds ((STp->density << MT_ST_DENSITY_SHIFT) & MT_ST_DENSITY_MASK);
37571da177e4SLinus Torvalds mt_status.mt_blkno = STps->drv_block;
37581da177e4SLinus Torvalds mt_status.mt_fileno = STps->drv_file;
37591da177e4SLinus Torvalds if (STp->block_size != 0) {
37601da177e4SLinus Torvalds if (STps->rw == ST_WRITING)
37611da177e4SLinus Torvalds mt_status.mt_blkno +=
37621da177e4SLinus Torvalds (STp->buffer)->buffer_bytes / STp->block_size;
37631da177e4SLinus Torvalds else if (STps->rw == ST_READING)
37641da177e4SLinus Torvalds mt_status.mt_blkno -=
37651da177e4SLinus Torvalds ((STp->buffer)->buffer_bytes +
37661da177e4SLinus Torvalds STp->block_size - 1) / STp->block_size;
37671da177e4SLinus Torvalds }
37681da177e4SLinus Torvalds
37691da177e4SLinus Torvalds mt_status.mt_gstat = 0;
37701da177e4SLinus Torvalds if (STp->drv_write_prot)
37711da177e4SLinus Torvalds mt_status.mt_gstat |= GMT_WR_PROT(0xffffffff);
37721da177e4SLinus Torvalds if (mt_status.mt_blkno == 0) {
37731da177e4SLinus Torvalds if (mt_status.mt_fileno == 0)
37741da177e4SLinus Torvalds mt_status.mt_gstat |= GMT_BOT(0xffffffff);
37751da177e4SLinus Torvalds else
37761da177e4SLinus Torvalds mt_status.mt_gstat |= GMT_EOF(0xffffffff);
37771da177e4SLinus Torvalds }
37781da177e4SLinus Torvalds mt_status.mt_erreg = (STp->recover_reg << MT_ST_SOFTERR_SHIFT);
37791da177e4SLinus Torvalds mt_status.mt_resid = STp->partition;
37801da177e4SLinus Torvalds if (STps->eof == ST_EOM_OK || STps->eof == ST_EOM_ERROR)
37811da177e4SLinus Torvalds mt_status.mt_gstat |= GMT_EOT(0xffffffff);
37821da177e4SLinus Torvalds else if (STps->eof >= ST_EOM_OK)
37831da177e4SLinus Torvalds mt_status.mt_gstat |= GMT_EOD(0xffffffff);
37841da177e4SLinus Torvalds if (STp->density == 1)
37851da177e4SLinus Torvalds mt_status.mt_gstat |= GMT_D_800(0xffffffff);
37861da177e4SLinus Torvalds else if (STp->density == 2)
37871da177e4SLinus Torvalds mt_status.mt_gstat |= GMT_D_1600(0xffffffff);
37881da177e4SLinus Torvalds else if (STp->density == 3)
37891da177e4SLinus Torvalds mt_status.mt_gstat |= GMT_D_6250(0xffffffff);
37901da177e4SLinus Torvalds if (STp->ready == ST_READY)
37911da177e4SLinus Torvalds mt_status.mt_gstat |= GMT_ONLINE(0xffffffff);
37921da177e4SLinus Torvalds if (STp->ready == ST_NO_TAPE)
37931da177e4SLinus Torvalds mt_status.mt_gstat |= GMT_DR_OPEN(0xffffffff);
37941da177e4SLinus Torvalds if (STps->at_sm)
37951da177e4SLinus Torvalds mt_status.mt_gstat |= GMT_SM(0xffffffff);
37961da177e4SLinus Torvalds if (STm->do_async_writes ||
37971da177e4SLinus Torvalds (STm->do_buffer_writes && STp->block_size != 0) ||
37981da177e4SLinus Torvalds STp->drv_buffer != 0)
37991da177e4SLinus Torvalds mt_status.mt_gstat |= GMT_IM_REP_EN(0xffffffff);
38001da177e4SLinus Torvalds if (STp->cleaning_req)
38011da177e4SLinus Torvalds mt_status.mt_gstat |= GMT_CLN(0xffffffff);
38021da177e4SLinus Torvalds
38031207045dSArnd Bergmann retval = put_user_mtget(p, &mt_status);
38041207045dSArnd Bergmann if (retval)
38051da177e4SLinus Torvalds goto out;
38061da177e4SLinus Torvalds
38071da177e4SLinus Torvalds STp->recover_reg = 0; /* Clear after read */
38081da177e4SLinus Torvalds goto out;
38091da177e4SLinus Torvalds } /* End of MTIOCGET */
38101da177e4SLinus Torvalds if (cmd_type == _IOC_TYPE(MTIOCPOS) && cmd_nr == _IOC_NR(MTIOCPOS)) {
38111da177e4SLinus Torvalds struct mtpos mt_pos;
38121da177e4SLinus Torvalds if (_IOC_SIZE(cmd_in) != sizeof(struct mtpos)) {
38131da177e4SLinus Torvalds retval = (-EINVAL);
38141da177e4SLinus Torvalds goto out;
38151da177e4SLinus Torvalds }
38161da177e4SLinus Torvalds if ((i = get_location(STp, &blk, &bt, 0)) < 0) {
38171da177e4SLinus Torvalds retval = i;
38181da177e4SLinus Torvalds goto out;
38191da177e4SLinus Torvalds }
38201da177e4SLinus Torvalds mt_pos.mt_blkno = blk;
38211207045dSArnd Bergmann retval = put_user_mtpos(p, &mt_pos);
38221da177e4SLinus Torvalds goto out;
38231da177e4SLinus Torvalds }
382428f85009SMatthias Kaehlcke mutex_unlock(&STp->lock);
3825dba7688fSChristoph Hellwig
38261da177e4SLinus Torvalds switch (cmd_in) {
3827dba7688fSChristoph Hellwig case SG_IO:
3828dba7688fSChristoph Hellwig case SCSI_IOCTL_SEND_COMMAND:
3829dba7688fSChristoph Hellwig case CDROM_SEND_PACKET:
3830dba7688fSChristoph Hellwig if (!capable(CAP_SYS_RAWIO))
3831dba7688fSChristoph Hellwig return -EPERM;
38326a2ea0d3SNathan Chancellor break;
3833dba7688fSChristoph Hellwig default:
3834dba7688fSChristoph Hellwig break;
3835dba7688fSChristoph Hellwig }
3836dba7688fSChristoph Hellwig
38372e80089cSChristoph Hellwig retval = scsi_ioctl(STp->device, file->f_mode & FMODE_WRITE, cmd_in, p);
3838dba7688fSChristoph Hellwig if (!retval && cmd_in == SCSI_IOCTL_STOP_UNIT) {
3839d320a955SArnd Bergmann /* unload */
3840d320a955SArnd Bergmann STp->rew_at_close = 0;
3841d320a955SArnd Bergmann STp->ready = ST_NO_TAPE;
3842d320a955SArnd Bergmann }
3843d320a955SArnd Bergmann return retval;
3844d320a955SArnd Bergmann
38451da177e4SLinus Torvalds out:
384628f85009SMatthias Kaehlcke mutex_unlock(&STp->lock);
38471da177e4SLinus Torvalds return retval;
38481da177e4SLinus Torvalds }
38491da177e4SLinus Torvalds
38501da177e4SLinus Torvalds #ifdef CONFIG_COMPAT
st_compat_ioctl(struct file * file,unsigned int cmd_in,unsigned long arg)38511207045dSArnd Bergmann static long st_compat_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
38521da177e4SLinus Torvalds {
38531207045dSArnd Bergmann /* argument conversion is handled using put_user_mtpos/put_user_mtget */
38541207045dSArnd Bergmann switch (cmd_in) {
38551207045dSArnd Bergmann case MTIOCPOS32:
3856dba7688fSChristoph Hellwig cmd_in = MTIOCPOS;
3857dba7688fSChristoph Hellwig break;
38581207045dSArnd Bergmann case MTIOCGET32:
3859dba7688fSChristoph Hellwig cmd_in = MTIOCGET;
3860dba7688fSChristoph Hellwig break;
38611207045dSArnd Bergmann }
38621207045dSArnd Bergmann
3863dba7688fSChristoph Hellwig return st_ioctl(file, cmd_in, arg);
38641da177e4SLinus Torvalds }
38651da177e4SLinus Torvalds #endif
38661da177e4SLinus Torvalds
38671da177e4SLinus Torvalds
38681da177e4SLinus Torvalds
38691da177e4SLinus Torvalds /* Try to allocate a new tape buffer. Calling function must not hold
38701da177e4SLinus Torvalds dev_arr_lock. */
new_tape_buffer(int max_sg)3871aaff5ebaSChristoph Hellwig static struct st_buffer *new_tape_buffer(int max_sg)
38721da177e4SLinus Torvalds {
38731da177e4SLinus Torvalds struct st_buffer *tb;
38741da177e4SLinus Torvalds
38754011f076SJia-Ju Bai tb = kzalloc(sizeof(struct st_buffer), GFP_KERNEL);
38761da177e4SLinus Torvalds if (!tb) {
38771da177e4SLinus Torvalds printk(KERN_NOTICE "st: Can't allocate new tape buffer.\n");
38781da177e4SLinus Torvalds return NULL;
38791da177e4SLinus Torvalds }
38801ac63cf5SFUJITA Tomonori tb->frp_segs = 0;
38811da177e4SLinus Torvalds tb->use_sg = max_sg;
3882f409d6ccSFUJITA Tomonori tb->buffer_size = 0;
38831da177e4SLinus Torvalds
38846396bb22SKees Cook tb->reserved_pages = kcalloc(max_sg, sizeof(struct page *),
38854011f076SJia-Ju Bai GFP_KERNEL);
3886d0e1ae31SFUJITA Tomonori if (!tb->reserved_pages) {
3887d0e1ae31SFUJITA Tomonori kfree(tb);
3888d0e1ae31SFUJITA Tomonori return NULL;
3889d0e1ae31SFUJITA Tomonori }
3890d0e1ae31SFUJITA Tomonori
38911da177e4SLinus Torvalds return tb;
38921da177e4SLinus Torvalds }
38931da177e4SLinus Torvalds
38941da177e4SLinus Torvalds
38951da177e4SLinus Torvalds /* Try to allocate enough space in the tape buffer */
38968f78fc5eSKai Makisara #define ST_MAX_ORDER 6
38978f78fc5eSKai Makisara
enlarge_buffer(struct st_buffer * STbuffer,int new_size)3898aaff5ebaSChristoph Hellwig static int enlarge_buffer(struct st_buffer * STbuffer, int new_size)
38991da177e4SLinus Torvalds {
3900769989a4SBodo Stroesser int segs, max_segs, b_size, order, got;
3901c53033f6SAl Viro gfp_t priority;
39021da177e4SLinus Torvalds
39031da177e4SLinus Torvalds if (new_size <= STbuffer->buffer_size)
39041da177e4SLinus Torvalds return 1;
39051da177e4SLinus Torvalds
39061da177e4SLinus Torvalds if (STbuffer->buffer_size <= PAGE_SIZE)
39071da177e4SLinus Torvalds normalize_buffer(STbuffer); /* Avoid extra segment */
39081da177e4SLinus Torvalds
39091da177e4SLinus Torvalds max_segs = STbuffer->use_sg;
39101da177e4SLinus Torvalds
39111da177e4SLinus Torvalds priority = GFP_KERNEL | __GFP_NOWARN;
39129c905966SFUJITA Tomonori
391308c95832SFUJITA Tomonori if (STbuffer->cleared)
391408c95832SFUJITA Tomonori priority |= __GFP_ZERO;
391508c95832SFUJITA Tomonori
39169c905966SFUJITA Tomonori if (STbuffer->frp_segs) {
3917c982c368SFUJITA Tomonori order = STbuffer->reserved_page_order;
391808c95832SFUJITA Tomonori b_size = PAGE_SIZE << order;
39199c905966SFUJITA Tomonori } else {
39209c905966SFUJITA Tomonori for (b_size = PAGE_SIZE, order = 0;
392146081b16SFUJITA Tomonori order < ST_MAX_ORDER &&
392246081b16SFUJITA Tomonori max_segs * (PAGE_SIZE << order) < new_size;
39238f78fc5eSKai Makisara order++, b_size *= 2)
39241da177e4SLinus Torvalds ; /* empty */
3925373daacfSKai Makisara STbuffer->reserved_page_order = order;
39269c905966SFUJITA Tomonori }
39278f78fc5eSKai Makisara if (max_segs * (PAGE_SIZE << order) < new_size) {
39288f78fc5eSKai Makisara if (order == ST_MAX_ORDER)
39298f78fc5eSKai Makisara return 0;
39308f78fc5eSKai Makisara normalize_buffer(STbuffer);
3931aaff5ebaSChristoph Hellwig return enlarge_buffer(STbuffer, new_size);
39328f78fc5eSKai Makisara }
39331da177e4SLinus Torvalds
39341da177e4SLinus Torvalds for (segs = STbuffer->frp_segs, got = STbuffer->buffer_size;
39351da177e4SLinus Torvalds segs < max_segs && got < new_size;) {
393608c95832SFUJITA Tomonori struct page *page;
393708c95832SFUJITA Tomonori
393808c95832SFUJITA Tomonori page = alloc_pages(priority, order);
393908c95832SFUJITA Tomonori if (!page) {
39401da177e4SLinus Torvalds DEB(STbuffer->buffer_size = got);
39411da177e4SLinus Torvalds normalize_buffer(STbuffer);
39421da177e4SLinus Torvalds return 0;
39431da177e4SLinus Torvalds }
394408c95832SFUJITA Tomonori
39451da177e4SLinus Torvalds STbuffer->frp_segs += 1;
39461da177e4SLinus Torvalds got += b_size;
39471da177e4SLinus Torvalds STbuffer->buffer_size = got;
394808c95832SFUJITA Tomonori STbuffer->reserved_pages[segs] = page;
39491da177e4SLinus Torvalds segs++;
39501da177e4SLinus Torvalds }
395108c95832SFUJITA Tomonori STbuffer->b_data = page_address(STbuffer->reserved_pages[0]);
39521da177e4SLinus Torvalds
39531da177e4SLinus Torvalds return 1;
39541da177e4SLinus Torvalds }
39551da177e4SLinus Torvalds
39561da177e4SLinus Torvalds
395740f6b36cSKai Makisara /* Make sure that no data from previous user is in the internal buffer */
clear_buffer(struct st_buffer * st_bp)395840f6b36cSKai Makisara static void clear_buffer(struct st_buffer * st_bp)
395940f6b36cSKai Makisara {
396040f6b36cSKai Makisara int i;
396140f6b36cSKai Makisara
396240f6b36cSKai Makisara for (i=0; i < st_bp->frp_segs; i++)
396308c95832SFUJITA Tomonori memset(page_address(st_bp->reserved_pages[i]), 0,
3964c982c368SFUJITA Tomonori PAGE_SIZE << st_bp->reserved_page_order);
396540f6b36cSKai Makisara st_bp->cleared = 1;
396640f6b36cSKai Makisara }
396740f6b36cSKai Makisara
396840f6b36cSKai Makisara
39691da177e4SLinus Torvalds /* Release the extra buffer */
normalize_buffer(struct st_buffer * STbuffer)39701da177e4SLinus Torvalds static void normalize_buffer(struct st_buffer * STbuffer)
39711da177e4SLinus Torvalds {
3972c982c368SFUJITA Tomonori int i, order = STbuffer->reserved_page_order;
39731da177e4SLinus Torvalds
39741ac63cf5SFUJITA Tomonori for (i = 0; i < STbuffer->frp_segs; i++) {
397508c95832SFUJITA Tomonori __free_pages(STbuffer->reserved_pages[i], order);
397608c95832SFUJITA Tomonori STbuffer->buffer_size -= (PAGE_SIZE << order);
39771da177e4SLinus Torvalds }
39781ac63cf5SFUJITA Tomonori STbuffer->frp_segs = 0;
39798b05b773SMike Christie STbuffer->sg_segs = 0;
3980c982c368SFUJITA Tomonori STbuffer->reserved_page_order = 0;
3981d0e1ae31SFUJITA Tomonori STbuffer->map_data.offset = 0;
39821da177e4SLinus Torvalds }
39831da177e4SLinus Torvalds
39841da177e4SLinus Torvalds
39851da177e4SLinus Torvalds /* Move data from the user buffer to the tape buffer. Returns zero (success) or
39861da177e4SLinus Torvalds negative error code. */
append_to_buffer(const char __user * ubp,struct st_buffer * st_bp,int do_count)39871da177e4SLinus Torvalds static int append_to_buffer(const char __user *ubp, struct st_buffer * st_bp, int do_count)
39881da177e4SLinus Torvalds {
39891da177e4SLinus Torvalds int i, cnt, res, offset;
3990c982c368SFUJITA Tomonori int length = PAGE_SIZE << st_bp->reserved_page_order;
39911da177e4SLinus Torvalds
39921da177e4SLinus Torvalds for (i = 0, offset = st_bp->buffer_bytes;
399308c95832SFUJITA Tomonori i < st_bp->frp_segs && offset >= length; i++)
399408c95832SFUJITA Tomonori offset -= length;
39951da177e4SLinus Torvalds if (i == st_bp->frp_segs) { /* Should never happen */
39961da177e4SLinus Torvalds printk(KERN_WARNING "st: append_to_buffer offset overflow.\n");
39971da177e4SLinus Torvalds return (-EIO);
39981da177e4SLinus Torvalds }
39991da177e4SLinus Torvalds for (; i < st_bp->frp_segs && do_count > 0; i++) {
400008c95832SFUJITA Tomonori struct page *page = st_bp->reserved_pages[i];
400108c95832SFUJITA Tomonori cnt = length - offset < do_count ? length - offset : do_count;
400208c95832SFUJITA Tomonori res = copy_from_user(page_address(page) + offset, ubp, cnt);
40031da177e4SLinus Torvalds if (res)
40041da177e4SLinus Torvalds return (-EFAULT);
40051da177e4SLinus Torvalds do_count -= cnt;
40061da177e4SLinus Torvalds st_bp->buffer_bytes += cnt;
40071da177e4SLinus Torvalds ubp += cnt;
40081da177e4SLinus Torvalds offset = 0;
40091da177e4SLinus Torvalds }
40101da177e4SLinus Torvalds if (do_count) /* Should never happen */
40111da177e4SLinus Torvalds return (-EIO);
40121da177e4SLinus Torvalds
40131da177e4SLinus Torvalds return 0;
40141da177e4SLinus Torvalds }
40151da177e4SLinus Torvalds
40161da177e4SLinus Torvalds
40171da177e4SLinus Torvalds /* Move data from the tape buffer to the user buffer. Returns zero (success) or
40181da177e4SLinus Torvalds negative error code. */
from_buffer(struct st_buffer * st_bp,char __user * ubp,int do_count)40191da177e4SLinus Torvalds static int from_buffer(struct st_buffer * st_bp, char __user *ubp, int do_count)
40201da177e4SLinus Torvalds {
40211da177e4SLinus Torvalds int i, cnt, res, offset;
4022c982c368SFUJITA Tomonori int length = PAGE_SIZE << st_bp->reserved_page_order;
40231da177e4SLinus Torvalds
40241da177e4SLinus Torvalds for (i = 0, offset = st_bp->read_pointer;
402508c95832SFUJITA Tomonori i < st_bp->frp_segs && offset >= length; i++)
402608c95832SFUJITA Tomonori offset -= length;
40271da177e4SLinus Torvalds if (i == st_bp->frp_segs) { /* Should never happen */
40281da177e4SLinus Torvalds printk(KERN_WARNING "st: from_buffer offset overflow.\n");
40291da177e4SLinus Torvalds return (-EIO);
40301da177e4SLinus Torvalds }
40311da177e4SLinus Torvalds for (; i < st_bp->frp_segs && do_count > 0; i++) {
403208c95832SFUJITA Tomonori struct page *page = st_bp->reserved_pages[i];
403308c95832SFUJITA Tomonori cnt = length - offset < do_count ? length - offset : do_count;
403408c95832SFUJITA Tomonori res = copy_to_user(ubp, page_address(page) + offset, cnt);
40351da177e4SLinus Torvalds if (res)
40361da177e4SLinus Torvalds return (-EFAULT);
40371da177e4SLinus Torvalds do_count -= cnt;
40381da177e4SLinus Torvalds st_bp->buffer_bytes -= cnt;
40391da177e4SLinus Torvalds st_bp->read_pointer += cnt;
40401da177e4SLinus Torvalds ubp += cnt;
40411da177e4SLinus Torvalds offset = 0;
40421da177e4SLinus Torvalds }
40431da177e4SLinus Torvalds if (do_count) /* Should never happen */
40441da177e4SLinus Torvalds return (-EIO);
40451da177e4SLinus Torvalds
40461da177e4SLinus Torvalds return 0;
40471da177e4SLinus Torvalds }
40481da177e4SLinus Torvalds
40491da177e4SLinus Torvalds
40501da177e4SLinus Torvalds /* Move data towards start of buffer */
move_buffer_data(struct st_buffer * st_bp,int offset)40511da177e4SLinus Torvalds static void move_buffer_data(struct st_buffer * st_bp, int offset)
40521da177e4SLinus Torvalds {
40531da177e4SLinus Torvalds int src_seg, dst_seg, src_offset = 0, dst_offset;
40541da177e4SLinus Torvalds int count, total;
4055c982c368SFUJITA Tomonori int length = PAGE_SIZE << st_bp->reserved_page_order;
40561da177e4SLinus Torvalds
40571da177e4SLinus Torvalds if (offset == 0)
40581da177e4SLinus Torvalds return;
40591da177e4SLinus Torvalds
40601da177e4SLinus Torvalds total=st_bp->buffer_bytes - offset;
40611da177e4SLinus Torvalds for (src_seg=0; src_seg < st_bp->frp_segs; src_seg++) {
40621da177e4SLinus Torvalds src_offset = offset;
406308c95832SFUJITA Tomonori if (src_offset < length)
40641da177e4SLinus Torvalds break;
406508c95832SFUJITA Tomonori offset -= length;
40661da177e4SLinus Torvalds }
40671da177e4SLinus Torvalds
40681da177e4SLinus Torvalds st_bp->buffer_bytes = st_bp->read_pointer = total;
40691da177e4SLinus Torvalds for (dst_seg=dst_offset=0; total > 0; ) {
407008c95832SFUJITA Tomonori struct page *dpage = st_bp->reserved_pages[dst_seg];
407108c95832SFUJITA Tomonori struct page *spage = st_bp->reserved_pages[src_seg];
407208c95832SFUJITA Tomonori
407308c95832SFUJITA Tomonori count = min(length - dst_offset, length - src_offset);
407408c95832SFUJITA Tomonori memmove(page_address(dpage) + dst_offset,
407508c95832SFUJITA Tomonori page_address(spage) + src_offset, count);
40761da177e4SLinus Torvalds src_offset += count;
407708c95832SFUJITA Tomonori if (src_offset >= length) {
40781da177e4SLinus Torvalds src_seg++;
40791da177e4SLinus Torvalds src_offset = 0;
40801da177e4SLinus Torvalds }
40811da177e4SLinus Torvalds dst_offset += count;
408208c95832SFUJITA Tomonori if (dst_offset >= length) {
40831da177e4SLinus Torvalds dst_seg++;
40841da177e4SLinus Torvalds dst_offset = 0;
40851da177e4SLinus Torvalds }
40861da177e4SLinus Torvalds total -= count;
40871da177e4SLinus Torvalds }
40881da177e4SLinus Torvalds }
40891da177e4SLinus Torvalds
40901da177e4SLinus Torvalds /* Validate the options from command line or module parameters */
validate_options(void)40911da177e4SLinus Torvalds static void validate_options(void)
40921da177e4SLinus Torvalds {
40931da177e4SLinus Torvalds if (buffer_kbs > 0)
40941da177e4SLinus Torvalds st_fixed_buffer_size = buffer_kbs * ST_KILOBYTE;
40951da177e4SLinus Torvalds if (max_sg_segs >= ST_FIRST_SG)
40961da177e4SLinus Torvalds st_max_sg_segs = max_sg_segs;
40971da177e4SLinus Torvalds }
40981da177e4SLinus Torvalds
40991da177e4SLinus Torvalds #ifndef MODULE
41001da177e4SLinus Torvalds /* Set the boot options. Syntax is defined in Documenation/scsi/st.txt.
41011da177e4SLinus Torvalds */
st_setup(char * str)41021da177e4SLinus Torvalds static int __init st_setup(char *str)
41031da177e4SLinus Torvalds {
41041da177e4SLinus Torvalds int i, len, ints[5];
41051da177e4SLinus Torvalds char *stp;
41061da177e4SLinus Torvalds
41071da177e4SLinus Torvalds stp = get_options(str, ARRAY_SIZE(ints), ints);
41081da177e4SLinus Torvalds
41091da177e4SLinus Torvalds if (ints[0] > 0) {
41101da177e4SLinus Torvalds for (i = 0; i < ints[0] && i < ARRAY_SIZE(parms); i++)
41111da177e4SLinus Torvalds if (parms[i].val)
41121da177e4SLinus Torvalds *parms[i].val = ints[i + 1];
41131da177e4SLinus Torvalds } else {
41141da177e4SLinus Torvalds while (stp != NULL) {
41151da177e4SLinus Torvalds for (i = 0; i < ARRAY_SIZE(parms); i++) {
41161da177e4SLinus Torvalds len = strlen(parms[i].name);
41171da177e4SLinus Torvalds if (!strncmp(stp, parms[i].name, len) &&
41181da177e4SLinus Torvalds (*(stp + len) == ':' || *(stp + len) == '=')) {
41191da177e4SLinus Torvalds if (parms[i].val)
41201da177e4SLinus Torvalds *parms[i].val =
41211da177e4SLinus Torvalds simple_strtoul(stp + len + 1, NULL, 0);
41221da177e4SLinus Torvalds else
41231da177e4SLinus Torvalds printk(KERN_WARNING "st: Obsolete parameter %s\n",
41241da177e4SLinus Torvalds parms[i].name);
41251da177e4SLinus Torvalds break;
41261da177e4SLinus Torvalds }
41271da177e4SLinus Torvalds }
41286391a113STobias Klauser if (i >= ARRAY_SIZE(parms))
41291da177e4SLinus Torvalds printk(KERN_WARNING "st: invalid parameter in '%s'\n",
41301da177e4SLinus Torvalds stp);
41311da177e4SLinus Torvalds stp = strchr(stp, ',');
41321da177e4SLinus Torvalds if (stp)
41331da177e4SLinus Torvalds stp++;
41341da177e4SLinus Torvalds }
41351da177e4SLinus Torvalds }
41361da177e4SLinus Torvalds
41371da177e4SLinus Torvalds validate_options();
41381da177e4SLinus Torvalds
41391da177e4SLinus Torvalds return 1;
41401da177e4SLinus Torvalds }
41411da177e4SLinus Torvalds
41421da177e4SLinus Torvalds __setup("st=", st_setup);
41431da177e4SLinus Torvalds
41441da177e4SLinus Torvalds #endif
41451da177e4SLinus Torvalds
414600977a59SArjan van de Ven static const struct file_operations st_fops =
41471da177e4SLinus Torvalds {
41481da177e4SLinus Torvalds .owner = THIS_MODULE,
41491da177e4SLinus Torvalds .read = st_read,
41501da177e4SLinus Torvalds .write = st_write,
4151fd66c1b4SKai Makisara .unlocked_ioctl = st_ioctl,
41521da177e4SLinus Torvalds #ifdef CONFIG_COMPAT
41531da177e4SLinus Torvalds .compat_ioctl = st_compat_ioctl,
41541da177e4SLinus Torvalds #endif
41551da177e4SLinus Torvalds .open = st_open,
41561da177e4SLinus Torvalds .flush = st_flush,
41571da177e4SLinus Torvalds .release = st_release,
4158b4d878e2SJan Blunck .llseek = noop_llseek,
41591da177e4SLinus Torvalds };
41601da177e4SLinus Torvalds
create_one_cdev(struct scsi_tape * tape,int mode,int rew)416126898afdSJeff Mahoney static int create_one_cdev(struct scsi_tape *tape, int mode, int rew)
416226898afdSJeff Mahoney {
416326898afdSJeff Mahoney int i, error;
416426898afdSJeff Mahoney dev_t cdev_devno;
416526898afdSJeff Mahoney struct cdev *cdev;
416626898afdSJeff Mahoney struct device *dev;
416726898afdSJeff Mahoney struct st_modedef *STm = &(tape->modes[mode]);
416826898afdSJeff Mahoney char name[10];
416926898afdSJeff Mahoney int dev_num = tape->index;
417026898afdSJeff Mahoney
417126898afdSJeff Mahoney cdev_devno = MKDEV(SCSI_TAPE_MAJOR, TAPE_MINOR(dev_num, mode, rew));
417226898afdSJeff Mahoney
417326898afdSJeff Mahoney cdev = cdev_alloc();
417426898afdSJeff Mahoney if (!cdev) {
417526898afdSJeff Mahoney pr_err("st%d: out of memory. Device not attached.\n", dev_num);
417626898afdSJeff Mahoney error = -ENOMEM;
417726898afdSJeff Mahoney goto out;
417826898afdSJeff Mahoney }
417926898afdSJeff Mahoney cdev->owner = THIS_MODULE;
418026898afdSJeff Mahoney cdev->ops = &st_fops;
4181ab08ee14SMaurizio Lombardi STm->cdevs[rew] = cdev;
418226898afdSJeff Mahoney
418326898afdSJeff Mahoney error = cdev_add(cdev, cdev_devno, 1);
418426898afdSJeff Mahoney if (error) {
418526898afdSJeff Mahoney pr_err("st%d: Can't add %s-rewind mode %d\n", dev_num,
418626898afdSJeff Mahoney rew ? "non" : "auto", mode);
418726898afdSJeff Mahoney pr_err("st%d: Device not attached.\n", dev_num);
418826898afdSJeff Mahoney goto out_free;
418926898afdSJeff Mahoney }
419026898afdSJeff Mahoney
419126898afdSJeff Mahoney i = mode << (4 - ST_NBR_MODE_BITS);
419226898afdSJeff Mahoney snprintf(name, 10, "%s%s%s", rew ? "n" : "",
419345938335SChristoph Hellwig tape->name, st_formats[i]);
419426898afdSJeff Mahoney
419526898afdSJeff Mahoney dev = device_create(&st_sysfs_class, &tape->device->sdev_gendev,
419626898afdSJeff Mahoney cdev_devno, &tape->modes[mode], "%s", name);
419726898afdSJeff Mahoney if (IS_ERR(dev)) {
419826898afdSJeff Mahoney pr_err("st%d: device_create failed\n", dev_num);
419926898afdSJeff Mahoney error = PTR_ERR(dev);
420026898afdSJeff Mahoney goto out_free;
420126898afdSJeff Mahoney }
420226898afdSJeff Mahoney
420326898afdSJeff Mahoney STm->devs[rew] = dev;
420426898afdSJeff Mahoney
420526898afdSJeff Mahoney return 0;
420626898afdSJeff Mahoney out_free:
420726898afdSJeff Mahoney cdev_del(STm->cdevs[rew]);
420826898afdSJeff Mahoney out:
4209ab08ee14SMaurizio Lombardi STm->cdevs[rew] = NULL;
4210ab08ee14SMaurizio Lombardi STm->devs[rew] = NULL;
421126898afdSJeff Mahoney return error;
421226898afdSJeff Mahoney }
421326898afdSJeff Mahoney
create_cdevs(struct scsi_tape * tape)421426898afdSJeff Mahoney static int create_cdevs(struct scsi_tape *tape)
421526898afdSJeff Mahoney {
421626898afdSJeff Mahoney int mode, error;
421726898afdSJeff Mahoney for (mode = 0; mode < ST_NBR_MODES; ++mode) {
421826898afdSJeff Mahoney error = create_one_cdev(tape, mode, 0);
421926898afdSJeff Mahoney if (error)
422026898afdSJeff Mahoney return error;
422126898afdSJeff Mahoney error = create_one_cdev(tape, mode, 1);
422226898afdSJeff Mahoney if (error)
422326898afdSJeff Mahoney return error;
422426898afdSJeff Mahoney }
422526898afdSJeff Mahoney
422626898afdSJeff Mahoney return sysfs_create_link(&tape->device->sdev_gendev.kobj,
422726898afdSJeff Mahoney &tape->modes[0].devs[0]->kobj, "tape");
422826898afdSJeff Mahoney }
422926898afdSJeff Mahoney
remove_cdevs(struct scsi_tape * tape)423026898afdSJeff Mahoney static void remove_cdevs(struct scsi_tape *tape)
423126898afdSJeff Mahoney {
423226898afdSJeff Mahoney int mode, rew;
423326898afdSJeff Mahoney sysfs_remove_link(&tape->device->sdev_gendev.kobj, "tape");
423426898afdSJeff Mahoney for (mode = 0; mode < ST_NBR_MODES; mode++) {
423526898afdSJeff Mahoney struct st_modedef *STm = &(tape->modes[mode]);
423626898afdSJeff Mahoney for (rew = 0; rew < 2; rew++) {
423726898afdSJeff Mahoney if (STm->cdevs[rew])
423826898afdSJeff Mahoney cdev_del(STm->cdevs[rew]);
423926898afdSJeff Mahoney if (STm->devs[rew])
424026898afdSJeff Mahoney device_unregister(STm->devs[rew]);
424126898afdSJeff Mahoney }
424226898afdSJeff Mahoney }
424326898afdSJeff Mahoney }
424426898afdSJeff Mahoney
st_probe(struct device * dev)42451da177e4SLinus Torvalds static int st_probe(struct device *dev)
42461da177e4SLinus Torvalds {
42471da177e4SLinus Torvalds struct scsi_device *SDp = to_scsi_device(dev);
42481da177e4SLinus Torvalds struct scsi_tape *tpnt = NULL;
42491da177e4SLinus Torvalds struct st_modedef *STm;
42501da177e4SLinus Torvalds struct st_partstat *STps;
42511da177e4SLinus Torvalds struct st_buffer *buffer;
4252b98c52b5STejun Heo int i, error;
42531da177e4SLinus Torvalds
42541da177e4SLinus Torvalds if (SDp->type != TYPE_TAPE)
42551da177e4SLinus Torvalds return -ENODEV;
4256f0ee639aSColin Ian King if (st_incompatible(SDp)) {
4257b30d8bcaSHannes Reinecke sdev_printk(KERN_INFO, SDp,
42584e3ea141SHannes Reinecke "OnStream tapes are no longer supported;\n");
42594e3ea141SHannes Reinecke sdev_printk(KERN_INFO, SDp,
42604e3ea141SHannes Reinecke "please mail to linux-scsi@vger.kernel.org.\n");
42611da177e4SLinus Torvalds return -ENODEV;
42621da177e4SLinus Torvalds }
42631da177e4SLinus Torvalds
42646fe8c1dbSSubhash Jadavani scsi_autopm_get_device(SDp);
42658a78362cSMartin K. Petersen i = queue_max_segments(SDp->request_queue);
42661da177e4SLinus Torvalds if (st_max_sg_segs < i)
42671da177e4SLinus Torvalds i = st_max_sg_segs;
4268aaff5ebaSChristoph Hellwig buffer = new_tape_buffer(i);
42691da177e4SLinus Torvalds if (buffer == NULL) {
4270b30d8bcaSHannes Reinecke sdev_printk(KERN_ERR, SDp,
4271b30d8bcaSHannes Reinecke "st: Can't allocate new tape buffer. "
4272b30d8bcaSHannes Reinecke "Device not attached.\n");
42731da177e4SLinus Torvalds goto out;
42741da177e4SLinus Torvalds }
42751da177e4SLinus Torvalds
42761f618aacSJia-Ju Bai tpnt = kzalloc(sizeof(struct scsi_tape), GFP_KERNEL);
42771da177e4SLinus Torvalds if (tpnt == NULL) {
4278b30d8bcaSHannes Reinecke sdev_printk(KERN_ERR, SDp,
4279b30d8bcaSHannes Reinecke "st: Can't allocate device descriptor.\n");
428045938335SChristoph Hellwig goto out_buffer_free;
42811da177e4SLinus Torvalds }
4282f03a5670SKai Makisara kref_init(&tpnt->kref);
42831da177e4SLinus Torvalds
42841da177e4SLinus Torvalds tpnt->device = SDp;
42851da177e4SLinus Torvalds if (SDp->scsi_level <= 2)
42861da177e4SLinus Torvalds tpnt->tape_type = MT_ISSCSI1;
42871da177e4SLinus Torvalds else
42881da177e4SLinus Torvalds tpnt->tape_type = MT_ISSCSI2;
42891da177e4SLinus Torvalds
42901da177e4SLinus Torvalds tpnt->buffer = buffer;
4291f03a5670SKai Makisara tpnt->buffer->last_SRpnt = NULL;
42921da177e4SLinus Torvalds
42931da177e4SLinus Torvalds tpnt->inited = 0;
42941da177e4SLinus Torvalds tpnt->dirty = 0;
42951da177e4SLinus Torvalds tpnt->in_use = 0;
42961da177e4SLinus Torvalds tpnt->drv_buffer = 1; /* Try buffering if no mode sense */
42971da177e4SLinus Torvalds tpnt->use_pf = (SDp->scsi_level >= SCSI_2);
42981da177e4SLinus Torvalds tpnt->density = 0;
42991da177e4SLinus Torvalds tpnt->do_auto_lock = ST_AUTO_LOCK;
43001da177e4SLinus Torvalds tpnt->can_bsr = (SDp->scsi_level > 2 ? 1 : ST_IN_FILE_POS); /* BSR mandatory in SCSI3 */
43011da177e4SLinus Torvalds tpnt->can_partitions = 0;
43021da177e4SLinus Torvalds tpnt->two_fm = ST_TWO_FM;
43031da177e4SLinus Torvalds tpnt->fast_mteom = ST_FAST_MTEOM;
43041da177e4SLinus Torvalds tpnt->scsi2_logical = ST_SCSI2LOGICAL;
430540f6b36cSKai Makisara tpnt->sili = ST_SILI;
43061da177e4SLinus Torvalds tpnt->immediate = ST_NOWAIT;
4307c743e44fSLee Duncan tpnt->immediate_filemark = 0;
43081da177e4SLinus Torvalds tpnt->default_drvbuffer = 0xff; /* No forced buffering */
43091da177e4SLinus Torvalds tpnt->partition = 0;
43101da177e4SLinus Torvalds tpnt->new_partition = 0;
43111da177e4SLinus Torvalds tpnt->nbr_partitions = 0;
4312a02488edSJames Bottomley blk_queue_rq_timeout(tpnt->device->request_queue, ST_TIMEOUT);
43131da177e4SLinus Torvalds tpnt->long_timeout = ST_LONG_TIMEOUT;
4314aaff5ebaSChristoph Hellwig tpnt->try_dio = try_direct_io;
43151da177e4SLinus Torvalds
43161da177e4SLinus Torvalds for (i = 0; i < ST_NBR_MODES; i++) {
43171da177e4SLinus Torvalds STm = &(tpnt->modes[i]);
43181da177e4SLinus Torvalds STm->defined = 0;
43191da177e4SLinus Torvalds STm->sysv = ST_SYSV;
43201da177e4SLinus Torvalds STm->defaults_for_writes = 0;
43211da177e4SLinus Torvalds STm->do_async_writes = ST_ASYNC_WRITES;
43221da177e4SLinus Torvalds STm->do_buffer_writes = ST_BUFFER_WRITES;
43231da177e4SLinus Torvalds STm->do_read_ahead = ST_READ_AHEAD;
43241da177e4SLinus Torvalds STm->default_compression = ST_DONT_TOUCH;
43251da177e4SLinus Torvalds STm->default_blksize = (-1); /* No forced size */
43261da177e4SLinus Torvalds STm->default_density = (-1); /* No forced density */
43276c648d95SJeff Mahoney STm->tape = tpnt;
43281da177e4SLinus Torvalds }
43291da177e4SLinus Torvalds
43301da177e4SLinus Torvalds for (i = 0; i < ST_NBR_PARTITIONS; i++) {
43311da177e4SLinus Torvalds STps = &(tpnt->ps[i]);
43321da177e4SLinus Torvalds STps->rw = ST_IDLE;
43331da177e4SLinus Torvalds STps->eof = ST_NOEOF;
43341da177e4SLinus Torvalds STps->at_sm = 0;
43351da177e4SLinus Torvalds STps->last_block_valid = 0;
43361da177e4SLinus Torvalds STps->drv_block = (-1);
43371da177e4SLinus Torvalds STps->drv_file = (-1);
43381da177e4SLinus Torvalds }
43391da177e4SLinus Torvalds
43401da177e4SLinus Torvalds tpnt->current_mode = 0;
43411da177e4SLinus Torvalds tpnt->modes[0].defined = 1;
43421da177e4SLinus Torvalds
43431da177e4SLinus Torvalds tpnt->density_changed = tpnt->compression_changed =
43441da177e4SLinus Torvalds tpnt->blksize_changed = 0;
434528f85009SMatthias Kaehlcke mutex_init(&tpnt->lock);
43461da177e4SLinus Torvalds
4347b98c52b5STejun Heo idr_preload(GFP_KERNEL);
43486c648d95SJeff Mahoney spin_lock(&st_index_lock);
4349b98c52b5STejun Heo error = idr_alloc(&st_index_idr, tpnt, 0, ST_MAX_TAPES + 1, GFP_NOWAIT);
43506c648d95SJeff Mahoney spin_unlock(&st_index_lock);
4351b98c52b5STejun Heo idr_preload_end();
4352b98c52b5STejun Heo if (error < 0) {
43536c648d95SJeff Mahoney pr_warn("st: idr allocation failed: %d\n", error);
435445938335SChristoph Hellwig goto out_free_tape;
43556c648d95SJeff Mahoney }
4356b98c52b5STejun Heo tpnt->index = error;
435745938335SChristoph Hellwig sprintf(tpnt->name, "st%d", tpnt->index);
435805545c92SSeymour, Shane M tpnt->stats = kzalloc(sizeof(struct scsi_tape_stats), GFP_KERNEL);
435905545c92SSeymour, Shane M if (tpnt->stats == NULL) {
436005545c92SSeymour, Shane M sdev_printk(KERN_ERR, SDp,
436105545c92SSeymour, Shane M "st: Can't allocate statistics.\n");
436205545c92SSeymour, Shane M goto out_idr_remove;
436305545c92SSeymour, Shane M }
43646c648d95SJeff Mahoney
43656c648d95SJeff Mahoney dev_set_drvdata(dev, tpnt);
43661da177e4SLinus Torvalds
43671da177e4SLinus Torvalds
436826898afdSJeff Mahoney error = create_cdevs(tpnt);
436913026a6bSJeff Garzik if (error)
437026898afdSJeff Mahoney goto out_remove_devs;
437146a243f7SOliver Neukum scsi_autopm_put_device(SDp);
43721da177e4SLinus Torvalds
437342252854SKai Makisara sdev_printk(KERN_NOTICE, SDp,
437445938335SChristoph Hellwig "Attached scsi tape %s\n", tpnt->name);
437542252854SKai Makisara sdev_printk(KERN_INFO, SDp, "%s: try direct i/o: %s (alignment %d B)\n",
437645938335SChristoph Hellwig tpnt->name, tpnt->try_dio ? "yes" : "no",
43778b05b773SMike Christie queue_dma_alignment(SDp->request_queue) + 1);
43781da177e4SLinus Torvalds
43791da177e4SLinus Torvalds return 0;
43801da177e4SLinus Torvalds
438126898afdSJeff Mahoney out_remove_devs:
438226898afdSJeff Mahoney remove_cdevs(tpnt);
438305545c92SSeymour, Shane M kfree(tpnt->stats);
438405545c92SSeymour, Shane M out_idr_remove:
43856c648d95SJeff Mahoney spin_lock(&st_index_lock);
4386b98c52b5STejun Heo idr_remove(&st_index_idr, tpnt->index);
43876c648d95SJeff Mahoney spin_unlock(&st_index_lock);
438845938335SChristoph Hellwig out_free_tape:
43891da177e4SLinus Torvalds kfree(tpnt);
43901da177e4SLinus Torvalds out_buffer_free:
43911da177e4SLinus Torvalds kfree(buffer);
43921da177e4SLinus Torvalds out:
43936fe8c1dbSSubhash Jadavani scsi_autopm_put_device(SDp);
43941da177e4SLinus Torvalds return -ENODEV;
43951da177e4SLinus Torvalds };
43961da177e4SLinus Torvalds
43971da177e4SLinus Torvalds
st_remove(struct device * dev)43981da177e4SLinus Torvalds static int st_remove(struct device *dev)
43991da177e4SLinus Torvalds {
44006c648d95SJeff Mahoney struct scsi_tape *tpnt = dev_get_drvdata(dev);
44016c648d95SJeff Mahoney int index = tpnt->index;
44021da177e4SLinus Torvalds
44036c648d95SJeff Mahoney scsi_autopm_get_device(to_scsi_device(dev));
440426898afdSJeff Mahoney remove_cdevs(tpnt);
4405f03a5670SKai Makisara
44060b950672SArjan van de Ven mutex_lock(&st_ref_mutex);
4407f03a5670SKai Makisara kref_put(&tpnt->kref, scsi_tape_release);
44080b950672SArjan van de Ven mutex_unlock(&st_ref_mutex);
44096c648d95SJeff Mahoney spin_lock(&st_index_lock);
44106c648d95SJeff Mahoney idr_remove(&st_index_idr, index);
44116c648d95SJeff Mahoney spin_unlock(&st_index_lock);
4412f03a5670SKai Makisara return 0;
4413f03a5670SKai Makisara }
4414f03a5670SKai Makisara
4415f03a5670SKai Makisara /**
4416f03a5670SKai Makisara * scsi_tape_release - Called to free the Scsi_Tape structure
4417f03a5670SKai Makisara * @kref: pointer to embedded kref
4418f03a5670SKai Makisara *
44190b950672SArjan van de Ven * st_ref_mutex must be held entering this routine. Because it is
4420f03a5670SKai Makisara * called on last put, you should always use the scsi_tape_get()
4421f03a5670SKai Makisara * scsi_tape_put() helpers which manipulate the semaphore directly
4422f03a5670SKai Makisara * and never do a direct kref_put().
4423f03a5670SKai Makisara **/
scsi_tape_release(struct kref * kref)4424f03a5670SKai Makisara static void scsi_tape_release(struct kref *kref)
4425f03a5670SKai Makisara {
4426f03a5670SKai Makisara struct scsi_tape *tpnt = to_scsi_tape(kref);
4427f03a5670SKai Makisara
44281da177e4SLinus Torvalds tpnt->device = NULL;
44291da177e4SLinus Torvalds
44301da177e4SLinus Torvalds if (tpnt->buffer) {
44311da177e4SLinus Torvalds normalize_buffer(tpnt->buffer);
4432d0e1ae31SFUJITA Tomonori kfree(tpnt->buffer->reserved_pages);
44331da177e4SLinus Torvalds kfree(tpnt->buffer);
44341da177e4SLinus Torvalds }
44351da177e4SLinus Torvalds
443605545c92SSeymour, Shane M kfree(tpnt->stats);
4437f03a5670SKai Makisara kfree(tpnt);
4438f03a5670SKai Makisara return;
44391da177e4SLinus Torvalds }
44401da177e4SLinus Torvalds
4441af23782bSJeff Mahoney static struct class st_sysfs_class = {
4442af23782bSJeff Mahoney .name = "scsi_tape",
4443c69c6be5SGreg Kroah-Hartman .dev_groups = st_dev_groups,
4444af23782bSJeff Mahoney };
4445af23782bSJeff Mahoney
init_st(void)44461da177e4SLinus Torvalds static int __init init_st(void)
44471da177e4SLinus Torvalds {
444813026a6bSJeff Garzik int err;
444913026a6bSJeff Garzik
44501da177e4SLinus Torvalds validate_options();
44511da177e4SLinus Torvalds
445213026a6bSJeff Garzik printk(KERN_INFO "st: Version %s, fixed bufsize %d, s/g segs %d\n",
44531da177e4SLinus Torvalds verstr, st_fixed_buffer_size, st_max_sg_segs);
44541da177e4SLinus Torvalds
44552bec708aSLaurence Oberman debugging = (debug_flag > 0) ? debug_flag : NO_DEBUG;
44562bec708aSLaurence Oberman if (debugging) {
44572bec708aSLaurence Oberman printk(KERN_INFO "st: Debugging enabled debug_flag = %d\n",
44582bec708aSLaurence Oberman debugging);
44592bec708aSLaurence Oberman }
44602bec708aSLaurence Oberman
4461af23782bSJeff Mahoney err = class_register(&st_sysfs_class);
4462af23782bSJeff Mahoney if (err) {
4463af23782bSJeff Mahoney pr_err("Unable register sysfs class for SCSI tapes\n");
4464af23782bSJeff Mahoney return err;
44651da177e4SLinus Torvalds }
44661da177e4SLinus Torvalds
446713026a6bSJeff Garzik err = register_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0),
446813026a6bSJeff Garzik ST_MAX_TAPE_ENTRIES, "st");
446913026a6bSJeff Garzik if (err) {
447013026a6bSJeff Garzik printk(KERN_ERR "Unable to get major %d for SCSI tapes\n",
447113026a6bSJeff Garzik SCSI_TAPE_MAJOR);
447213026a6bSJeff Garzik goto err_class;
44731da177e4SLinus Torvalds }
447413026a6bSJeff Garzik
447513026a6bSJeff Garzik err = scsi_register_driver(&st_template.gendrv);
447613026a6bSJeff Garzik if (err)
447713026a6bSJeff Garzik goto err_chrdev;
447813026a6bSJeff Garzik
447913026a6bSJeff Garzik return 0;
448013026a6bSJeff Garzik
448113026a6bSJeff Garzik err_chrdev:
44821da177e4SLinus Torvalds unregister_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0),
44831da177e4SLinus Torvalds ST_MAX_TAPE_ENTRIES);
448413026a6bSJeff Garzik err_class:
4485af23782bSJeff Mahoney class_unregister(&st_sysfs_class);
448613026a6bSJeff Garzik return err;
44871da177e4SLinus Torvalds }
44881da177e4SLinus Torvalds
exit_st(void)44891da177e4SLinus Torvalds static void __exit exit_st(void)
44901da177e4SLinus Torvalds {
44911da177e4SLinus Torvalds scsi_unregister_driver(&st_template.gendrv);
44921da177e4SLinus Torvalds unregister_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0),
44931da177e4SLinus Torvalds ST_MAX_TAPE_ENTRIES);
4494af23782bSJeff Mahoney class_unregister(&st_sysfs_class);
44952d3a5d21SJohannes Thumshirn idr_destroy(&st_index_idr);
44961da177e4SLinus Torvalds printk(KERN_INFO "st: Unloaded.\n");
44971da177e4SLinus Torvalds }
44981da177e4SLinus Torvalds
44991da177e4SLinus Torvalds module_init(init_st);
45001da177e4SLinus Torvalds module_exit(exit_st);
45011da177e4SLinus Torvalds
45021da177e4SLinus Torvalds
45031da177e4SLinus Torvalds /* The sysfs driver interface. Read-only at the moment */
try_direct_io_show(struct device_driver * ddp,char * buf)450410978e48SSeymour, Shane M static ssize_t try_direct_io_show(struct device_driver *ddp, char *buf)
45051da177e4SLinus Torvalds {
450610978e48SSeymour, Shane M return scnprintf(buf, PAGE_SIZE, "%d\n", try_direct_io);
45071da177e4SLinus Torvalds }
450810978e48SSeymour, Shane M static DRIVER_ATTR_RO(try_direct_io);
45091da177e4SLinus Torvalds
fixed_buffer_size_show(struct device_driver * ddp,char * buf)451010978e48SSeymour, Shane M static ssize_t fixed_buffer_size_show(struct device_driver *ddp, char *buf)
45111da177e4SLinus Torvalds {
451210978e48SSeymour, Shane M return scnprintf(buf, PAGE_SIZE, "%d\n", st_fixed_buffer_size);
45131da177e4SLinus Torvalds }
451410978e48SSeymour, Shane M static DRIVER_ATTR_RO(fixed_buffer_size);
45151da177e4SLinus Torvalds
max_sg_segs_show(struct device_driver * ddp,char * buf)451610978e48SSeymour, Shane M static ssize_t max_sg_segs_show(struct device_driver *ddp, char *buf)
45171da177e4SLinus Torvalds {
451810978e48SSeymour, Shane M return scnprintf(buf, PAGE_SIZE, "%d\n", st_max_sg_segs);
45191da177e4SLinus Torvalds }
452010978e48SSeymour, Shane M static DRIVER_ATTR_RO(max_sg_segs);
45211da177e4SLinus Torvalds
version_show(struct device_driver * ddd,char * buf)452210978e48SSeymour, Shane M static ssize_t version_show(struct device_driver *ddd, char *buf)
45231da177e4SLinus Torvalds {
452410978e48SSeymour, Shane M return scnprintf(buf, PAGE_SIZE, "[%s]\n", verstr);
45251da177e4SLinus Torvalds }
452610978e48SSeymour, Shane M static DRIVER_ATTR_RO(version);
45271da177e4SLinus Torvalds
4528d9b43a10SSeymour, Shane M #if DEBUG
debug_flag_store(struct device_driver * ddp,const char * buf,size_t count)4529d9b43a10SSeymour, Shane M static ssize_t debug_flag_store(struct device_driver *ddp,
4530d9b43a10SSeymour, Shane M const char *buf, size_t count)
4531d9b43a10SSeymour, Shane M {
4532d9b43a10SSeymour, Shane M /* We only care what the first byte of the data is the rest is unused.
4533d9b43a10SSeymour, Shane M * if it's a '1' we turn on debug and if it's a '0' we disable it. All
4534d9b43a10SSeymour, Shane M * other values have -EINVAL returned if they are passed in.
4535d9b43a10SSeymour, Shane M */
4536d9b43a10SSeymour, Shane M if (count > 0) {
4537d9b43a10SSeymour, Shane M if (buf[0] == '0') {
4538d9b43a10SSeymour, Shane M debugging = NO_DEBUG;
4539d9b43a10SSeymour, Shane M return count;
4540d9b43a10SSeymour, Shane M } else if (buf[0] == '1') {
4541d9b43a10SSeymour, Shane M debugging = 1;
4542d9b43a10SSeymour, Shane M return count;
4543d9b43a10SSeymour, Shane M }
4544d9b43a10SSeymour, Shane M }
4545d9b43a10SSeymour, Shane M return -EINVAL;
4546d9b43a10SSeymour, Shane M }
4547d9b43a10SSeymour, Shane M
debug_flag_show(struct device_driver * ddp,char * buf)4548d9b43a10SSeymour, Shane M static ssize_t debug_flag_show(struct device_driver *ddp, char *buf)
4549d9b43a10SSeymour, Shane M {
4550d9b43a10SSeymour, Shane M return scnprintf(buf, PAGE_SIZE, "%d\n", debugging);
4551d9b43a10SSeymour, Shane M }
4552d9b43a10SSeymour, Shane M static DRIVER_ATTR_RW(debug_flag);
4553d9b43a10SSeymour, Shane M #endif
4554d9b43a10SSeymour, Shane M
4555442d7562SSeymour, Shane M static struct attribute *st_drv_attrs[] = {
4556442d7562SSeymour, Shane M &driver_attr_try_direct_io.attr,
4557442d7562SSeymour, Shane M &driver_attr_fixed_buffer_size.attr,
4558442d7562SSeymour, Shane M &driver_attr_max_sg_segs.attr,
4559442d7562SSeymour, Shane M &driver_attr_version.attr,
4560d9b43a10SSeymour, Shane M #if DEBUG
4561d9b43a10SSeymour, Shane M &driver_attr_debug_flag.attr,
4562d9b43a10SSeymour, Shane M #endif
4563442d7562SSeymour, Shane M NULL,
4564442d7562SSeymour, Shane M };
4565442d7562SSeymour, Shane M ATTRIBUTE_GROUPS(st_drv);
45661da177e4SLinus Torvalds
45671da177e4SLinus Torvalds /* The sysfs simple class interface */
4568ee959b00STony Jones static ssize_t
defined_show(struct device * dev,struct device_attribute * attr,char * buf)4569af23782bSJeff Mahoney defined_show(struct device *dev, struct device_attribute *attr, char *buf)
45701da177e4SLinus Torvalds {
45717d15d6a4SJames Bottomley struct st_modedef *STm = dev_get_drvdata(dev);
45721da177e4SLinus Torvalds ssize_t l = 0;
45731da177e4SLinus Torvalds
45741da177e4SLinus Torvalds l = snprintf(buf, PAGE_SIZE, "%d\n", STm->defined);
45751da177e4SLinus Torvalds return l;
45761da177e4SLinus Torvalds }
4577c69c6be5SGreg Kroah-Hartman static DEVICE_ATTR_RO(defined);
45781da177e4SLinus Torvalds
4579ee959b00STony Jones static ssize_t
default_blksize_show(struct device * dev,struct device_attribute * attr,char * buf)4580af23782bSJeff Mahoney default_blksize_show(struct device *dev, struct device_attribute *attr,
4581af23782bSJeff Mahoney char *buf)
45821da177e4SLinus Torvalds {
45837d15d6a4SJames Bottomley struct st_modedef *STm = dev_get_drvdata(dev);
45841da177e4SLinus Torvalds ssize_t l = 0;
45851da177e4SLinus Torvalds
45861da177e4SLinus Torvalds l = snprintf(buf, PAGE_SIZE, "%d\n", STm->default_blksize);
45871da177e4SLinus Torvalds return l;
45881da177e4SLinus Torvalds }
4589c69c6be5SGreg Kroah-Hartman static DEVICE_ATTR_RO(default_blksize);
45901da177e4SLinus Torvalds
4591ee959b00STony Jones static ssize_t
default_density_show(struct device * dev,struct device_attribute * attr,char * buf)4592af23782bSJeff Mahoney default_density_show(struct device *dev, struct device_attribute *attr,
4593af23782bSJeff Mahoney char *buf)
45941da177e4SLinus Torvalds {
45957d15d6a4SJames Bottomley struct st_modedef *STm = dev_get_drvdata(dev);
45961da177e4SLinus Torvalds ssize_t l = 0;
45971da177e4SLinus Torvalds char *fmt;
45981da177e4SLinus Torvalds
45991da177e4SLinus Torvalds fmt = STm->default_density >= 0 ? "0x%02x\n" : "%d\n";
46001da177e4SLinus Torvalds l = snprintf(buf, PAGE_SIZE, fmt, STm->default_density);
46011da177e4SLinus Torvalds return l;
46021da177e4SLinus Torvalds }
4603c69c6be5SGreg Kroah-Hartman static DEVICE_ATTR_RO(default_density);
46041da177e4SLinus Torvalds
4605ee959b00STony Jones static ssize_t
default_compression_show(struct device * dev,struct device_attribute * attr,char * buf)4606af23782bSJeff Mahoney default_compression_show(struct device *dev, struct device_attribute *attr,
4607ee959b00STony Jones char *buf)
46081da177e4SLinus Torvalds {
46097d15d6a4SJames Bottomley struct st_modedef *STm = dev_get_drvdata(dev);
46101da177e4SLinus Torvalds ssize_t l = 0;
46111da177e4SLinus Torvalds
46121da177e4SLinus Torvalds l = snprintf(buf, PAGE_SIZE, "%d\n", STm->default_compression - 1);
46131da177e4SLinus Torvalds return l;
46141da177e4SLinus Torvalds }
4615c69c6be5SGreg Kroah-Hartman static DEVICE_ATTR_RO(default_compression);
46161da177e4SLinus Torvalds
4617ee959b00STony Jones static ssize_t
options_show(struct device * dev,struct device_attribute * attr,char * buf)4618af23782bSJeff Mahoney options_show(struct device *dev, struct device_attribute *attr, char *buf)
4619b174be02SKai Makisara {
46207d15d6a4SJames Bottomley struct st_modedef *STm = dev_get_drvdata(dev);
46216c648d95SJeff Mahoney struct scsi_tape *STp = STm->tape;
46226c648d95SJeff Mahoney int options;
4623b174be02SKai Makisara ssize_t l = 0;
4624b174be02SKai Makisara
4625b174be02SKai Makisara options = STm->do_buffer_writes ? MT_ST_BUFFER_WRITES : 0;
4626b174be02SKai Makisara options |= STm->do_async_writes ? MT_ST_ASYNC_WRITES : 0;
4627b174be02SKai Makisara options |= STm->do_read_ahead ? MT_ST_READ_AHEAD : 0;
4628b174be02SKai Makisara DEB( options |= debugging ? MT_ST_DEBUGGING : 0 );
4629b174be02SKai Makisara options |= STp->two_fm ? MT_ST_TWO_FM : 0;
4630b174be02SKai Makisara options |= STp->fast_mteom ? MT_ST_FAST_MTEOM : 0;
4631b174be02SKai Makisara options |= STm->defaults_for_writes ? MT_ST_DEF_WRITES : 0;
4632b174be02SKai Makisara options |= STp->can_bsr ? MT_ST_CAN_BSR : 0;
4633b174be02SKai Makisara options |= STp->omit_blklims ? MT_ST_NO_BLKLIMS : 0;
4634b174be02SKai Makisara options |= STp->can_partitions ? MT_ST_CAN_PARTITIONS : 0;
4635b174be02SKai Makisara options |= STp->scsi2_logical ? MT_ST_SCSI2LOGICAL : 0;
4636b174be02SKai Makisara options |= STm->sysv ? MT_ST_SYSV : 0;
4637b174be02SKai Makisara options |= STp->immediate ? MT_ST_NOWAIT : 0;
4638c743e44fSLee Duncan options |= STp->immediate_filemark ? MT_ST_NOWAIT_EOF : 0;
4639b174be02SKai Makisara options |= STp->sili ? MT_ST_SILI : 0;
4640b174be02SKai Makisara
4641b174be02SKai Makisara l = snprintf(buf, PAGE_SIZE, "0x%08x\n", options);
4642b174be02SKai Makisara return l;
4643b174be02SKai Makisara }
4644c69c6be5SGreg Kroah-Hartman static DEVICE_ATTR_RO(options);
4645b174be02SKai Makisara
464605545c92SSeymour, Shane M /* Support for tape stats */
464705545c92SSeymour, Shane M
464805545c92SSeymour, Shane M /**
464905545c92SSeymour, Shane M * read_cnt_show - return read count - count of reads made from tape drive
465005545c92SSeymour, Shane M * @dev: struct device
465105545c92SSeymour, Shane M * @attr: attribute structure
465205545c92SSeymour, Shane M * @buf: buffer to return formatted data in
465305545c92SSeymour, Shane M */
read_cnt_show(struct device * dev,struct device_attribute * attr,char * buf)465405545c92SSeymour, Shane M static ssize_t read_cnt_show(struct device *dev,
465505545c92SSeymour, Shane M struct device_attribute *attr, char *buf)
465605545c92SSeymour, Shane M {
465705545c92SSeymour, Shane M struct st_modedef *STm = dev_get_drvdata(dev);
465805545c92SSeymour, Shane M
465905545c92SSeymour, Shane M return sprintf(buf, "%lld",
466005545c92SSeymour, Shane M (long long)atomic64_read(&STm->tape->stats->read_cnt));
466105545c92SSeymour, Shane M }
466205545c92SSeymour, Shane M static DEVICE_ATTR_RO(read_cnt);
466305545c92SSeymour, Shane M
466405545c92SSeymour, Shane M /**
466505545c92SSeymour, Shane M * read_byte_cnt_show - return read byte count - tape drives
466605545c92SSeymour, Shane M * may use blocks less than 512 bytes this gives the raw byte count of
466705545c92SSeymour, Shane M * of data read from the tape drive.
466805545c92SSeymour, Shane M * @dev: struct device
466905545c92SSeymour, Shane M * @attr: attribute structure
467005545c92SSeymour, Shane M * @buf: buffer to return formatted data in
467105545c92SSeymour, Shane M */
read_byte_cnt_show(struct device * dev,struct device_attribute * attr,char * buf)467205545c92SSeymour, Shane M static ssize_t read_byte_cnt_show(struct device *dev,
467305545c92SSeymour, Shane M struct device_attribute *attr, char *buf)
467405545c92SSeymour, Shane M {
467505545c92SSeymour, Shane M struct st_modedef *STm = dev_get_drvdata(dev);
467605545c92SSeymour, Shane M
467705545c92SSeymour, Shane M return sprintf(buf, "%lld",
467805545c92SSeymour, Shane M (long long)atomic64_read(&STm->tape->stats->read_byte_cnt));
467905545c92SSeymour, Shane M }
468005545c92SSeymour, Shane M static DEVICE_ATTR_RO(read_byte_cnt);
468105545c92SSeymour, Shane M
468205545c92SSeymour, Shane M /**
4683e2dca2a2SRandy Dunlap * read_ns_show - return read ns - overall time spent waiting on reads in ns.
468405545c92SSeymour, Shane M * @dev: struct device
468505545c92SSeymour, Shane M * @attr: attribute structure
468605545c92SSeymour, Shane M * @buf: buffer to return formatted data in
468705545c92SSeymour, Shane M */
read_ns_show(struct device * dev,struct device_attribute * attr,char * buf)468805545c92SSeymour, Shane M static ssize_t read_ns_show(struct device *dev,
468905545c92SSeymour, Shane M struct device_attribute *attr, char *buf)
469005545c92SSeymour, Shane M {
469105545c92SSeymour, Shane M struct st_modedef *STm = dev_get_drvdata(dev);
469205545c92SSeymour, Shane M
469305545c92SSeymour, Shane M return sprintf(buf, "%lld",
469405545c92SSeymour, Shane M (long long)atomic64_read(&STm->tape->stats->tot_read_time));
469505545c92SSeymour, Shane M }
469605545c92SSeymour, Shane M static DEVICE_ATTR_RO(read_ns);
469705545c92SSeymour, Shane M
469805545c92SSeymour, Shane M /**
469905545c92SSeymour, Shane M * write_cnt_show - write count - number of user calls
470005545c92SSeymour, Shane M * to write(2) that have written data to tape.
470105545c92SSeymour, Shane M * @dev: struct device
470205545c92SSeymour, Shane M * @attr: attribute structure
470305545c92SSeymour, Shane M * @buf: buffer to return formatted data in
470405545c92SSeymour, Shane M */
write_cnt_show(struct device * dev,struct device_attribute * attr,char * buf)470505545c92SSeymour, Shane M static ssize_t write_cnt_show(struct device *dev,
470605545c92SSeymour, Shane M struct device_attribute *attr, char *buf)
470705545c92SSeymour, Shane M {
470805545c92SSeymour, Shane M struct st_modedef *STm = dev_get_drvdata(dev);
470905545c92SSeymour, Shane M
471005545c92SSeymour, Shane M return sprintf(buf, "%lld",
471105545c92SSeymour, Shane M (long long)atomic64_read(&STm->tape->stats->write_cnt));
471205545c92SSeymour, Shane M }
471305545c92SSeymour, Shane M static DEVICE_ATTR_RO(write_cnt);
471405545c92SSeymour, Shane M
471505545c92SSeymour, Shane M /**
471605545c92SSeymour, Shane M * write_byte_cnt_show - write byte count - raw count of
471705545c92SSeymour, Shane M * bytes written to tape.
471805545c92SSeymour, Shane M * @dev: struct device
471905545c92SSeymour, Shane M * @attr: attribute structure
472005545c92SSeymour, Shane M * @buf: buffer to return formatted data in
472105545c92SSeymour, Shane M */
write_byte_cnt_show(struct device * dev,struct device_attribute * attr,char * buf)472205545c92SSeymour, Shane M static ssize_t write_byte_cnt_show(struct device *dev,
472305545c92SSeymour, Shane M struct device_attribute *attr, char *buf)
472405545c92SSeymour, Shane M {
472505545c92SSeymour, Shane M struct st_modedef *STm = dev_get_drvdata(dev);
472605545c92SSeymour, Shane M
472705545c92SSeymour, Shane M return sprintf(buf, "%lld",
472805545c92SSeymour, Shane M (long long)atomic64_read(&STm->tape->stats->write_byte_cnt));
472905545c92SSeymour, Shane M }
473005545c92SSeymour, Shane M static DEVICE_ATTR_RO(write_byte_cnt);
473105545c92SSeymour, Shane M
473205545c92SSeymour, Shane M /**
473305545c92SSeymour, Shane M * write_ns_show - write ns - number of nanoseconds waiting on write
473405545c92SSeymour, Shane M * requests to complete.
473505545c92SSeymour, Shane M * @dev: struct device
473605545c92SSeymour, Shane M * @attr: attribute structure
473705545c92SSeymour, Shane M * @buf: buffer to return formatted data in
473805545c92SSeymour, Shane M */
write_ns_show(struct device * dev,struct device_attribute * attr,char * buf)473905545c92SSeymour, Shane M static ssize_t write_ns_show(struct device *dev,
474005545c92SSeymour, Shane M struct device_attribute *attr, char *buf)
474105545c92SSeymour, Shane M {
474205545c92SSeymour, Shane M struct st_modedef *STm = dev_get_drvdata(dev);
474305545c92SSeymour, Shane M
474405545c92SSeymour, Shane M return sprintf(buf, "%lld",
474505545c92SSeymour, Shane M (long long)atomic64_read(&STm->tape->stats->tot_write_time));
474605545c92SSeymour, Shane M }
474705545c92SSeymour, Shane M static DEVICE_ATTR_RO(write_ns);
474805545c92SSeymour, Shane M
474905545c92SSeymour, Shane M /**
475005545c92SSeymour, Shane M * in_flight_show - number of I/Os currently in flight -
475105545c92SSeymour, Shane M * in most cases this will be either 0 or 1. It may be higher if someone
475205545c92SSeymour, Shane M * has also issued other SCSI commands such as via an ioctl.
475305545c92SSeymour, Shane M * @dev: struct device
475405545c92SSeymour, Shane M * @attr: attribute structure
475505545c92SSeymour, Shane M * @buf: buffer to return formatted data in
475605545c92SSeymour, Shane M */
in_flight_show(struct device * dev,struct device_attribute * attr,char * buf)475705545c92SSeymour, Shane M static ssize_t in_flight_show(struct device *dev,
475805545c92SSeymour, Shane M struct device_attribute *attr, char *buf)
475905545c92SSeymour, Shane M {
476005545c92SSeymour, Shane M struct st_modedef *STm = dev_get_drvdata(dev);
476105545c92SSeymour, Shane M
476205545c92SSeymour, Shane M return sprintf(buf, "%lld",
476305545c92SSeymour, Shane M (long long)atomic64_read(&STm->tape->stats->in_flight));
476405545c92SSeymour, Shane M }
476505545c92SSeymour, Shane M static DEVICE_ATTR_RO(in_flight);
476605545c92SSeymour, Shane M
476705545c92SSeymour, Shane M /**
476805545c92SSeymour, Shane M * io_ns_show - io wait ns - this is the number of ns spent
476905545c92SSeymour, Shane M * waiting on all I/O to complete. This includes tape movement commands
477005545c92SSeymour, Shane M * such as rewinding, seeking to end of file or tape, it also includes
477105545c92SSeymour, Shane M * read and write. To determine the time spent on tape movement
477205545c92SSeymour, Shane M * subtract the read and write ns from this value.
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 */
io_ns_show(struct device * dev,struct device_attribute * attr,char * buf)477705545c92SSeymour, Shane M static ssize_t io_ns_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->tot_io_time));
478405545c92SSeymour, Shane M }
478505545c92SSeymour, Shane M static DEVICE_ATTR_RO(io_ns);
478605545c92SSeymour, Shane M
478705545c92SSeymour, Shane M /**
478805545c92SSeymour, Shane M * other_cnt_show - other io count - this is the number of
478905545c92SSeymour, Shane M * I/O requests other than read and write requests.
479005545c92SSeymour, Shane M * Typically these are tape movement requests but will include driver
479105545c92SSeymour, Shane M * tape movement. This includes only requests issued by the st driver.
479205545c92SSeymour, Shane M * @dev: struct device
479305545c92SSeymour, Shane M * @attr: attribute structure
479405545c92SSeymour, Shane M * @buf: buffer to return formatted data in
479505545c92SSeymour, Shane M */
other_cnt_show(struct device * dev,struct device_attribute * attr,char * buf)479605545c92SSeymour, Shane M static ssize_t other_cnt_show(struct device *dev,
479705545c92SSeymour, Shane M struct device_attribute *attr, char *buf)
479805545c92SSeymour, Shane M {
479905545c92SSeymour, Shane M struct st_modedef *STm = dev_get_drvdata(dev);
480005545c92SSeymour, Shane M
480105545c92SSeymour, Shane M return sprintf(buf, "%lld",
480205545c92SSeymour, Shane M (long long)atomic64_read(&STm->tape->stats->other_cnt));
480305545c92SSeymour, Shane M }
480405545c92SSeymour, Shane M static DEVICE_ATTR_RO(other_cnt);
480505545c92SSeymour, Shane M
480605545c92SSeymour, Shane M /**
480705545c92SSeymour, Shane M * resid_cnt_show - A count of the number of times we get a residual
480805545c92SSeymour, Shane M * count - this should indicate someone issuing reads larger than the
480905545c92SSeymour, Shane M * block size on tape.
481005545c92SSeymour, Shane M * @dev: struct device
481105545c92SSeymour, Shane M * @attr: attribute structure
481205545c92SSeymour, Shane M * @buf: buffer to return formatted data in
481305545c92SSeymour, Shane M */
resid_cnt_show(struct device * dev,struct device_attribute * attr,char * buf)481405545c92SSeymour, Shane M static ssize_t resid_cnt_show(struct device *dev,
481505545c92SSeymour, Shane M struct device_attribute *attr, char *buf)
481605545c92SSeymour, Shane M {
481705545c92SSeymour, Shane M struct st_modedef *STm = dev_get_drvdata(dev);
481805545c92SSeymour, Shane M
481905545c92SSeymour, Shane M return sprintf(buf, "%lld",
482005545c92SSeymour, Shane M (long long)atomic64_read(&STm->tape->stats->resid_cnt));
482105545c92SSeymour, Shane M }
482205545c92SSeymour, Shane M static DEVICE_ATTR_RO(resid_cnt);
482305545c92SSeymour, Shane M
4824c69c6be5SGreg Kroah-Hartman static struct attribute *st_dev_attrs[] = {
4825c69c6be5SGreg Kroah-Hartman &dev_attr_defined.attr,
4826c69c6be5SGreg Kroah-Hartman &dev_attr_default_blksize.attr,
4827c69c6be5SGreg Kroah-Hartman &dev_attr_default_density.attr,
4828c69c6be5SGreg Kroah-Hartman &dev_attr_default_compression.attr,
4829c69c6be5SGreg Kroah-Hartman &dev_attr_options.attr,
4830c69c6be5SGreg Kroah-Hartman NULL,
4831af23782bSJeff Mahoney };
483205545c92SSeymour, Shane M
483305545c92SSeymour, Shane M static struct attribute *st_stats_attrs[] = {
483405545c92SSeymour, Shane M &dev_attr_read_cnt.attr,
483505545c92SSeymour, Shane M &dev_attr_read_byte_cnt.attr,
483605545c92SSeymour, Shane M &dev_attr_read_ns.attr,
483705545c92SSeymour, Shane M &dev_attr_write_cnt.attr,
483805545c92SSeymour, Shane M &dev_attr_write_byte_cnt.attr,
483905545c92SSeymour, Shane M &dev_attr_write_ns.attr,
484005545c92SSeymour, Shane M &dev_attr_in_flight.attr,
484105545c92SSeymour, Shane M &dev_attr_io_ns.attr,
484205545c92SSeymour, Shane M &dev_attr_other_cnt.attr,
484305545c92SSeymour, Shane M &dev_attr_resid_cnt.attr,
484405545c92SSeymour, Shane M NULL,
484505545c92SSeymour, Shane M };
484605545c92SSeymour, Shane M
484705545c92SSeymour, Shane M static struct attribute_group stats_group = {
484805545c92SSeymour, Shane M .name = "stats",
484905545c92SSeymour, Shane M .attrs = st_stats_attrs,
485005545c92SSeymour, Shane M };
485105545c92SSeymour, Shane M
485205545c92SSeymour, Shane M static struct attribute_group st_group = {
485305545c92SSeymour, Shane M .attrs = st_dev_attrs,
485405545c92SSeymour, Shane M };
485505545c92SSeymour, Shane M
485605545c92SSeymour, Shane M static const struct attribute_group *st_dev_groups[] = {
485705545c92SSeymour, Shane M &st_group,
485805545c92SSeymour, Shane M &stats_group,
485905545c92SSeymour, Shane M NULL,
486005545c92SSeymour, Shane M };
4861b174be02SKai Makisara
48621da177e4SLinus 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)48636620742fSFUJITA Tomonori static int sgl_map_user_pages(struct st_buffer *STbp,
48646620742fSFUJITA Tomonori const unsigned int max_pages, unsigned long uaddr,
48656620742fSFUJITA Tomonori size_t count, int rw)
48661da177e4SLinus Torvalds {
486707542b83SJames Bottomley unsigned long end = (uaddr + count + PAGE_SIZE - 1) >> PAGE_SHIFT;
486807542b83SJames Bottomley unsigned long start = uaddr >> PAGE_SHIFT;
486907542b83SJames Bottomley const int nr_pages = end - start;
487008e9cbe7SJohn Hubbard int res, i;
48711da177e4SLinus Torvalds struct page **pages;
48726620742fSFUJITA Tomonori struct rq_map_data *mdata = &STbp->map_data;
48731da177e4SLinus Torvalds
48741da177e4SLinus Torvalds /* User attempted Overflow! */
48751da177e4SLinus Torvalds if ((uaddr + count) < uaddr)
48761da177e4SLinus Torvalds return -EINVAL;
48771da177e4SLinus Torvalds
48781da177e4SLinus Torvalds /* Too big */
48791da177e4SLinus Torvalds if (nr_pages > max_pages)
48801da177e4SLinus Torvalds return -ENOMEM;
48811da177e4SLinus Torvalds
48821da177e4SLinus Torvalds /* Hmm? */
48831da177e4SLinus Torvalds if (count == 0)
48841da177e4SLinus Torvalds return 0;
48851da177e4SLinus Torvalds
48866da2ec56SKees Cook pages = kmalloc_array(max_pages, sizeof(*pages), GFP_KERNEL);
48876da2ec56SKees Cook if (pages == NULL)
48881da177e4SLinus Torvalds return -ENOMEM;
48891da177e4SLinus Torvalds
48901da177e4SLinus Torvalds /* Try to fault in all of the necessary pages */
48911da177e4SLinus Torvalds /* rw==READ means read from drive, write into memory area */
489208e9cbe7SJohn Hubbard res = pin_user_pages_fast(uaddr, nr_pages, rw == READ ? FOLL_WRITE : 0,
489373b0140bSIra Weiny pages);
48941da177e4SLinus Torvalds
48951da177e4SLinus Torvalds /* Errors and no page mapped should return here */
48961da177e4SLinus Torvalds if (res < nr_pages)
48971da177e4SLinus Torvalds goto out_unmap;
48981da177e4SLinus Torvalds
48991da177e4SLinus Torvalds for (i=0; i < nr_pages; i++) {
49001da177e4SLinus Torvalds /* FIXME: flush superflous for rw==READ,
49011da177e4SLinus Torvalds * probably wrong function for rw==WRITE
49021da177e4SLinus Torvalds */
49031da177e4SLinus Torvalds flush_dcache_page(pages[i]);
49041da177e4SLinus Torvalds }
49051da177e4SLinus Torvalds
49066620742fSFUJITA Tomonori mdata->offset = uaddr & ~PAGE_MASK;
49076620742fSFUJITA Tomonori STbp->mapped_pages = pages;
49081da177e4SLinus Torvalds
49091da177e4SLinus Torvalds return nr_pages;
49101da177e4SLinus Torvalds out_unmap:
49111da177e4SLinus Torvalds if (res > 0) {
491208e9cbe7SJohn Hubbard unpin_user_pages(pages, res);
49136bc733e9SHugh Dickins res = 0;
49141da177e4SLinus Torvalds }
49151da177e4SLinus Torvalds kfree(pages);
49161da177e4SLinus Torvalds return res;
49171da177e4SLinus Torvalds }
49181da177e4SLinus Torvalds
49191da177e4SLinus Torvalds
49201da177e4SLinus Torvalds /* And unmap them... */
sgl_unmap_user_pages(struct st_buffer * STbp,const unsigned int nr_pages,int dirtied)49216620742fSFUJITA Tomonori static int sgl_unmap_user_pages(struct st_buffer *STbp,
49226620742fSFUJITA Tomonori const unsigned int nr_pages, int dirtied)
49231da177e4SLinus Torvalds {
492408e9cbe7SJohn Hubbard /* FIXME: cache flush missing for rw==READ */
492508e9cbe7SJohn Hubbard unpin_user_pages_dirty_lock(STbp->mapped_pages, nr_pages, dirtied);
49261da177e4SLinus Torvalds
49276620742fSFUJITA Tomonori kfree(STbp->mapped_pages);
49286620742fSFUJITA Tomonori STbp->mapped_pages = NULL;
49291da177e4SLinus Torvalds
49301da177e4SLinus Torvalds return 0;
49311da177e4SLinus Torvalds }
4932