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