162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci SCSI Tape Driver for Linux version 1.1 and newer. See the accompanying 462306a36Sopenharmony_ci file Documentation/scsi/st.rst for more information. 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci History: 762306a36Sopenharmony_ci Rewritten from Dwayne Forsyth's SCSI tape driver by Kai Makisara. 862306a36Sopenharmony_ci Contribution and ideas from several people including (in alphabetical 962306a36Sopenharmony_ci order) Klaus Ehrenfried, Eugene Exarevsky, Eric Lee Green, Wolfgang Denk, 1062306a36Sopenharmony_ci Steve Hirsch, Andreas Koppenh"ofer, Michael Leodolter, Eyal Lebedinsky, 1162306a36Sopenharmony_ci Michael Schaefer, J"org Weule, and Eric Youngdale. 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci Copyright 1992 - 2016 Kai Makisara 1462306a36Sopenharmony_ci email Kai.Makisara@kolumbus.fi 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci Some small formal changes - aeb, 950809 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support 1962306a36Sopenharmony_ci */ 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistatic const char *verstr = "20160209"; 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#include <linux/module.h> 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#include <linux/compat.h> 2662306a36Sopenharmony_ci#include <linux/fs.h> 2762306a36Sopenharmony_ci#include <linux/kernel.h> 2862306a36Sopenharmony_ci#include <linux/sched/signal.h> 2962306a36Sopenharmony_ci#include <linux/mm.h> 3062306a36Sopenharmony_ci#include <linux/init.h> 3162306a36Sopenharmony_ci#include <linux/string.h> 3262306a36Sopenharmony_ci#include <linux/slab.h> 3362306a36Sopenharmony_ci#include <linux/errno.h> 3462306a36Sopenharmony_ci#include <linux/mtio.h> 3562306a36Sopenharmony_ci#include <linux/major.h> 3662306a36Sopenharmony_ci#include <linux/cdrom.h> 3762306a36Sopenharmony_ci#include <linux/ioctl.h> 3862306a36Sopenharmony_ci#include <linux/fcntl.h> 3962306a36Sopenharmony_ci#include <linux/spinlock.h> 4062306a36Sopenharmony_ci#include <linux/blkdev.h> 4162306a36Sopenharmony_ci#include <linux/moduleparam.h> 4262306a36Sopenharmony_ci#include <linux/cdev.h> 4362306a36Sopenharmony_ci#include <linux/idr.h> 4462306a36Sopenharmony_ci#include <linux/delay.h> 4562306a36Sopenharmony_ci#include <linux/mutex.h> 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci#include <linux/uaccess.h> 4862306a36Sopenharmony_ci#include <asm/dma.h> 4962306a36Sopenharmony_ci#include <asm/unaligned.h> 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci#include <scsi/scsi.h> 5262306a36Sopenharmony_ci#include <scsi/scsi_dbg.h> 5362306a36Sopenharmony_ci#include <scsi/scsi_device.h> 5462306a36Sopenharmony_ci#include <scsi/scsi_driver.h> 5562306a36Sopenharmony_ci#include <scsi/scsi_eh.h> 5662306a36Sopenharmony_ci#include <scsi/scsi_host.h> 5762306a36Sopenharmony_ci#include <scsi/scsi_ioctl.h> 5862306a36Sopenharmony_ci#include <scsi/sg.h> 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci/* The driver prints some debugging information on the console if DEBUG 6262306a36Sopenharmony_ci is defined and non-zero. */ 6362306a36Sopenharmony_ci#define DEBUG 1 6462306a36Sopenharmony_ci#define NO_DEBUG 0 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci#define ST_DEB_MSG KERN_NOTICE 6762306a36Sopenharmony_ci#if DEBUG 6862306a36Sopenharmony_ci/* The message level for the debug messages is currently set to KERN_NOTICE 6962306a36Sopenharmony_ci so that people can easily see the messages. Later when the debugging messages 7062306a36Sopenharmony_ci in the drivers are more widely classified, this may be changed to KERN_DEBUG. */ 7162306a36Sopenharmony_ci#define DEB(a) a 7262306a36Sopenharmony_ci#define DEBC(a) if (debugging) { a ; } 7362306a36Sopenharmony_ci#else 7462306a36Sopenharmony_ci#define DEB(a) 7562306a36Sopenharmony_ci#define DEBC(a) 7662306a36Sopenharmony_ci#endif 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci#define ST_KILOBYTE 1024 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci#include "st_options.h" 8162306a36Sopenharmony_ci#include "st.h" 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_cistatic int buffer_kbs; 8462306a36Sopenharmony_cistatic int max_sg_segs; 8562306a36Sopenharmony_cistatic int try_direct_io = TRY_DIRECT_IO; 8662306a36Sopenharmony_cistatic int try_rdio = 1; 8762306a36Sopenharmony_cistatic int try_wdio = 1; 8862306a36Sopenharmony_cistatic int debug_flag; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_cistatic struct class st_sysfs_class; 9162306a36Sopenharmony_cistatic const struct attribute_group *st_dev_groups[]; 9262306a36Sopenharmony_cistatic const struct attribute_group *st_drv_groups[]; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ciMODULE_AUTHOR("Kai Makisara"); 9562306a36Sopenharmony_ciMODULE_DESCRIPTION("SCSI tape (st) driver"); 9662306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 9762306a36Sopenharmony_ciMODULE_ALIAS_CHARDEV_MAJOR(SCSI_TAPE_MAJOR); 9862306a36Sopenharmony_ciMODULE_ALIAS_SCSI_DEVICE(TYPE_TAPE); 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci/* Set 'perm' (4th argument) to 0 to disable module_param's definition 10162306a36Sopenharmony_ci * of sysfs parameters (which module_param doesn't yet support). 10262306a36Sopenharmony_ci * Sysfs parameters defined explicitly later. 10362306a36Sopenharmony_ci */ 10462306a36Sopenharmony_cimodule_param_named(buffer_kbs, buffer_kbs, int, 0); 10562306a36Sopenharmony_ciMODULE_PARM_DESC(buffer_kbs, "Default driver buffer size for fixed block mode (KB; 32)"); 10662306a36Sopenharmony_cimodule_param_named(max_sg_segs, max_sg_segs, int, 0); 10762306a36Sopenharmony_ciMODULE_PARM_DESC(max_sg_segs, "Maximum number of scatter/gather segments to use (256)"); 10862306a36Sopenharmony_cimodule_param_named(try_direct_io, try_direct_io, int, 0); 10962306a36Sopenharmony_ciMODULE_PARM_DESC(try_direct_io, "Try direct I/O between user buffer and tape drive (1)"); 11062306a36Sopenharmony_cimodule_param_named(debug_flag, debug_flag, int, 0); 11162306a36Sopenharmony_ciMODULE_PARM_DESC(debug_flag, "Enable DEBUG, same as setting debugging=1"); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci/* Extra parameters for testing */ 11562306a36Sopenharmony_cimodule_param_named(try_rdio, try_rdio, int, 0); 11662306a36Sopenharmony_ciMODULE_PARM_DESC(try_rdio, "Try direct read i/o when possible"); 11762306a36Sopenharmony_cimodule_param_named(try_wdio, try_wdio, int, 0); 11862306a36Sopenharmony_ciMODULE_PARM_DESC(try_wdio, "Try direct write i/o when possible"); 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci#ifndef MODULE 12162306a36Sopenharmony_cistatic int write_threshold_kbs; /* retained for compatibility */ 12262306a36Sopenharmony_cistatic struct st_dev_parm { 12362306a36Sopenharmony_ci char *name; 12462306a36Sopenharmony_ci int *val; 12562306a36Sopenharmony_ci} parms[] __initdata = { 12662306a36Sopenharmony_ci { 12762306a36Sopenharmony_ci "buffer_kbs", &buffer_kbs 12862306a36Sopenharmony_ci }, 12962306a36Sopenharmony_ci { /* Retained for compatibility with 2.4 */ 13062306a36Sopenharmony_ci "write_threshold_kbs", &write_threshold_kbs 13162306a36Sopenharmony_ci }, 13262306a36Sopenharmony_ci { 13362306a36Sopenharmony_ci "max_sg_segs", NULL 13462306a36Sopenharmony_ci }, 13562306a36Sopenharmony_ci { 13662306a36Sopenharmony_ci "try_direct_io", &try_direct_io 13762306a36Sopenharmony_ci }, 13862306a36Sopenharmony_ci { 13962306a36Sopenharmony_ci "debug_flag", &debug_flag 14062306a36Sopenharmony_ci } 14162306a36Sopenharmony_ci}; 14262306a36Sopenharmony_ci#endif 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci/* Restrict the number of modes so that names for all are assigned */ 14562306a36Sopenharmony_ci#if ST_NBR_MODES > 16 14662306a36Sopenharmony_ci#error "Maximum number of modes is 16" 14762306a36Sopenharmony_ci#endif 14862306a36Sopenharmony_ci/* Bit reversed order to get same names for same minors with all 14962306a36Sopenharmony_ci mode counts */ 15062306a36Sopenharmony_cistatic const char *st_formats[] = { 15162306a36Sopenharmony_ci "", "r", "k", "s", "l", "t", "o", "u", 15262306a36Sopenharmony_ci "m", "v", "p", "x", "a", "y", "q", "z"}; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci/* The default definitions have been moved to st_options.h */ 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci#define ST_FIXED_BUFFER_SIZE (ST_FIXED_BUFFER_BLOCKS * ST_KILOBYTE) 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci/* The buffer size should fit into the 24 bits for length in the 15962306a36Sopenharmony_ci 6-byte SCSI read and write commands. */ 16062306a36Sopenharmony_ci#if ST_FIXED_BUFFER_SIZE >= (2 << 24 - 1) 16162306a36Sopenharmony_ci#error "Buffer size should not exceed (2 << 24 - 1) bytes!" 16262306a36Sopenharmony_ci#endif 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_cistatic int debugging = DEBUG; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci#define MAX_RETRIES 0 16762306a36Sopenharmony_ci#define MAX_WRITE_RETRIES 0 16862306a36Sopenharmony_ci#define MAX_READY_RETRIES 0 16962306a36Sopenharmony_ci#define NO_TAPE NOT_READY 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci#define ST_TIMEOUT (900 * HZ) 17262306a36Sopenharmony_ci#define ST_LONG_TIMEOUT (14000 * HZ) 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci/* Remove mode bits and auto-rewind bit (7) */ 17562306a36Sopenharmony_ci#define TAPE_NR(x) ( ((iminor(x) & ~255) >> (ST_NBR_MODE_BITS + 1)) | \ 17662306a36Sopenharmony_ci (iminor(x) & ((1 << ST_MODE_SHIFT)-1))) 17762306a36Sopenharmony_ci#define TAPE_MODE(x) ((iminor(x) & ST_MODE_MASK) >> ST_MODE_SHIFT) 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci/* Construct the minor number from the device (d), mode (m), and non-rewind (n) data */ 18062306a36Sopenharmony_ci#define TAPE_MINOR(d, m, n) (((d & ~(255 >> (ST_NBR_MODE_BITS + 1))) << (ST_NBR_MODE_BITS + 1)) | \ 18162306a36Sopenharmony_ci (d & (255 >> (ST_NBR_MODE_BITS + 1))) | (m << ST_MODE_SHIFT) | ((n != 0) << 7) ) 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci/* Internal ioctl to set both density (uppermost 8 bits) and blocksize (lower 18462306a36Sopenharmony_ci 24 bits) */ 18562306a36Sopenharmony_ci#define SET_DENS_AND_BLK 0x10001 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_cistatic int st_fixed_buffer_size = ST_FIXED_BUFFER_SIZE; 18862306a36Sopenharmony_cistatic int st_max_sg_segs = ST_MAX_SG; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_cistatic int modes_defined; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_cistatic int enlarge_buffer(struct st_buffer *, int); 19362306a36Sopenharmony_cistatic void clear_buffer(struct st_buffer *); 19462306a36Sopenharmony_cistatic void normalize_buffer(struct st_buffer *); 19562306a36Sopenharmony_cistatic int append_to_buffer(const char __user *, struct st_buffer *, int); 19662306a36Sopenharmony_cistatic int from_buffer(struct st_buffer *, char __user *, int); 19762306a36Sopenharmony_cistatic void move_buffer_data(struct st_buffer *, int); 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_cistatic int sgl_map_user_pages(struct st_buffer *, const unsigned int, 20062306a36Sopenharmony_ci unsigned long, size_t, int); 20162306a36Sopenharmony_cistatic int sgl_unmap_user_pages(struct st_buffer *, const unsigned int, int); 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_cistatic int st_probe(struct device *); 20462306a36Sopenharmony_cistatic int st_remove(struct device *); 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_cistatic struct scsi_driver st_template = { 20762306a36Sopenharmony_ci .gendrv = { 20862306a36Sopenharmony_ci .name = "st", 20962306a36Sopenharmony_ci .owner = THIS_MODULE, 21062306a36Sopenharmony_ci .probe = st_probe, 21162306a36Sopenharmony_ci .remove = st_remove, 21262306a36Sopenharmony_ci .groups = st_drv_groups, 21362306a36Sopenharmony_ci }, 21462306a36Sopenharmony_ci}; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_cistatic int st_compression(struct scsi_tape *, int); 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_cistatic int find_partition(struct scsi_tape *); 21962306a36Sopenharmony_cistatic int switch_partition(struct scsi_tape *); 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_cistatic int st_int_ioctl(struct scsi_tape *, unsigned int, unsigned long); 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_cistatic void scsi_tape_release(struct kref *); 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci#define to_scsi_tape(obj) container_of(obj, struct scsi_tape, kref) 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_cistatic DEFINE_MUTEX(st_ref_mutex); 22862306a36Sopenharmony_cistatic DEFINE_SPINLOCK(st_index_lock); 22962306a36Sopenharmony_cistatic DEFINE_SPINLOCK(st_use_lock); 23062306a36Sopenharmony_cistatic DEFINE_IDR(st_index_idr); 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci#ifndef SIGS_FROM_OSST 23562306a36Sopenharmony_ci#define SIGS_FROM_OSST \ 23662306a36Sopenharmony_ci {"OnStream", "SC-", "", "osst"}, \ 23762306a36Sopenharmony_ci {"OnStream", "DI-", "", "osst"}, \ 23862306a36Sopenharmony_ci {"OnStream", "DP-", "", "osst"}, \ 23962306a36Sopenharmony_ci {"OnStream", "USB", "", "osst"}, \ 24062306a36Sopenharmony_ci {"OnStream", "FW-", "", "osst"} 24162306a36Sopenharmony_ci#endif 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_cistatic struct scsi_tape *scsi_tape_get(int dev) 24462306a36Sopenharmony_ci{ 24562306a36Sopenharmony_ci struct scsi_tape *STp = NULL; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci mutex_lock(&st_ref_mutex); 24862306a36Sopenharmony_ci spin_lock(&st_index_lock); 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci STp = idr_find(&st_index_idr, dev); 25162306a36Sopenharmony_ci if (!STp) goto out; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci kref_get(&STp->kref); 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci if (!STp->device) 25662306a36Sopenharmony_ci goto out_put; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci if (scsi_device_get(STp->device)) 25962306a36Sopenharmony_ci goto out_put; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci goto out; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ciout_put: 26462306a36Sopenharmony_ci kref_put(&STp->kref, scsi_tape_release); 26562306a36Sopenharmony_ci STp = NULL; 26662306a36Sopenharmony_ciout: 26762306a36Sopenharmony_ci spin_unlock(&st_index_lock); 26862306a36Sopenharmony_ci mutex_unlock(&st_ref_mutex); 26962306a36Sopenharmony_ci return STp; 27062306a36Sopenharmony_ci} 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_cistatic void scsi_tape_put(struct scsi_tape *STp) 27362306a36Sopenharmony_ci{ 27462306a36Sopenharmony_ci struct scsi_device *sdev = STp->device; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci mutex_lock(&st_ref_mutex); 27762306a36Sopenharmony_ci kref_put(&STp->kref, scsi_tape_release); 27862306a36Sopenharmony_ci scsi_device_put(sdev); 27962306a36Sopenharmony_ci mutex_unlock(&st_ref_mutex); 28062306a36Sopenharmony_ci} 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_cistruct st_reject_data { 28362306a36Sopenharmony_ci char *vendor; 28462306a36Sopenharmony_ci char *model; 28562306a36Sopenharmony_ci char *rev; 28662306a36Sopenharmony_ci char *driver_hint; /* Name of the correct driver, NULL if unknown */ 28762306a36Sopenharmony_ci}; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_cistatic struct st_reject_data reject_list[] = { 29062306a36Sopenharmony_ci /* {"XXX", "Yy-", "", NULL}, example */ 29162306a36Sopenharmony_ci SIGS_FROM_OSST, 29262306a36Sopenharmony_ci {NULL, }}; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci/* If the device signature is on the list of incompatible drives, the 29562306a36Sopenharmony_ci function returns a pointer to the name of the correct driver (if known) */ 29662306a36Sopenharmony_cistatic char * st_incompatible(struct scsi_device* SDp) 29762306a36Sopenharmony_ci{ 29862306a36Sopenharmony_ci struct st_reject_data *rp; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci for (rp=&(reject_list[0]); rp->vendor != NULL; rp++) 30162306a36Sopenharmony_ci if (!strncmp(rp->vendor, SDp->vendor, strlen(rp->vendor)) && 30262306a36Sopenharmony_ci !strncmp(rp->model, SDp->model, strlen(rp->model)) && 30362306a36Sopenharmony_ci !strncmp(rp->rev, SDp->rev, strlen(rp->rev))) { 30462306a36Sopenharmony_ci if (rp->driver_hint) 30562306a36Sopenharmony_ci return rp->driver_hint; 30662306a36Sopenharmony_ci else 30762306a36Sopenharmony_ci return "unknown"; 30862306a36Sopenharmony_ci } 30962306a36Sopenharmony_ci return NULL; 31062306a36Sopenharmony_ci} 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci#define st_printk(prefix, t, fmt, a...) \ 31462306a36Sopenharmony_ci sdev_prefix_printk(prefix, (t)->device, (t)->name, fmt, ##a) 31562306a36Sopenharmony_ci#ifdef DEBUG 31662306a36Sopenharmony_ci#define DEBC_printk(t, fmt, a...) \ 31762306a36Sopenharmony_ci if (debugging) { st_printk(ST_DEB_MSG, t, fmt, ##a ); } 31862306a36Sopenharmony_ci#else 31962306a36Sopenharmony_ci#define DEBC_printk(t, fmt, a...) 32062306a36Sopenharmony_ci#endif 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_cistatic void st_analyze_sense(struct st_request *SRpnt, struct st_cmdstatus *s) 32362306a36Sopenharmony_ci{ 32462306a36Sopenharmony_ci const u8 *ucp; 32562306a36Sopenharmony_ci const u8 *sense = SRpnt->sense; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci s->have_sense = scsi_normalize_sense(SRpnt->sense, 32862306a36Sopenharmony_ci SCSI_SENSE_BUFFERSIZE, &s->sense_hdr); 32962306a36Sopenharmony_ci s->flags = 0; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci if (s->have_sense) { 33262306a36Sopenharmony_ci s->deferred = 0; 33362306a36Sopenharmony_ci s->remainder_valid = 33462306a36Sopenharmony_ci scsi_get_sense_info_fld(sense, SCSI_SENSE_BUFFERSIZE, &s->uremainder64); 33562306a36Sopenharmony_ci switch (sense[0] & 0x7f) { 33662306a36Sopenharmony_ci case 0x71: 33762306a36Sopenharmony_ci s->deferred = 1; 33862306a36Sopenharmony_ci fallthrough; 33962306a36Sopenharmony_ci case 0x70: 34062306a36Sopenharmony_ci s->fixed_format = 1; 34162306a36Sopenharmony_ci s->flags = sense[2] & 0xe0; 34262306a36Sopenharmony_ci break; 34362306a36Sopenharmony_ci case 0x73: 34462306a36Sopenharmony_ci s->deferred = 1; 34562306a36Sopenharmony_ci fallthrough; 34662306a36Sopenharmony_ci case 0x72: 34762306a36Sopenharmony_ci s->fixed_format = 0; 34862306a36Sopenharmony_ci ucp = scsi_sense_desc_find(sense, SCSI_SENSE_BUFFERSIZE, 4); 34962306a36Sopenharmony_ci s->flags = ucp ? (ucp[3] & 0xe0) : 0; 35062306a36Sopenharmony_ci break; 35162306a36Sopenharmony_ci } 35262306a36Sopenharmony_ci } 35362306a36Sopenharmony_ci} 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci/* Convert the result to success code */ 35762306a36Sopenharmony_cistatic int st_chk_result(struct scsi_tape *STp, struct st_request * SRpnt) 35862306a36Sopenharmony_ci{ 35962306a36Sopenharmony_ci int result = SRpnt->result; 36062306a36Sopenharmony_ci u8 scode; 36162306a36Sopenharmony_ci DEB(const char *stp;) 36262306a36Sopenharmony_ci char *name = STp->name; 36362306a36Sopenharmony_ci struct st_cmdstatus *cmdstatp; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci if (!result) 36662306a36Sopenharmony_ci return 0; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci cmdstatp = &STp->buffer->cmdstat; 36962306a36Sopenharmony_ci st_analyze_sense(SRpnt, cmdstatp); 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci if (cmdstatp->have_sense) 37262306a36Sopenharmony_ci scode = STp->buffer->cmdstat.sense_hdr.sense_key; 37362306a36Sopenharmony_ci else 37462306a36Sopenharmony_ci scode = 0; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci DEB( 37762306a36Sopenharmony_ci if (debugging) { 37862306a36Sopenharmony_ci st_printk(ST_DEB_MSG, STp, 37962306a36Sopenharmony_ci "Error: %x, cmd: %x %x %x %x %x %x\n", result, 38062306a36Sopenharmony_ci SRpnt->cmd[0], SRpnt->cmd[1], SRpnt->cmd[2], 38162306a36Sopenharmony_ci SRpnt->cmd[3], SRpnt->cmd[4], SRpnt->cmd[5]); 38262306a36Sopenharmony_ci if (cmdstatp->have_sense) 38362306a36Sopenharmony_ci __scsi_print_sense(STp->device, name, 38462306a36Sopenharmony_ci SRpnt->sense, SCSI_SENSE_BUFFERSIZE); 38562306a36Sopenharmony_ci } ) /* end DEB */ 38662306a36Sopenharmony_ci if (!debugging) { /* Abnormal conditions for tape */ 38762306a36Sopenharmony_ci if (!cmdstatp->have_sense) 38862306a36Sopenharmony_ci st_printk(KERN_WARNING, STp, 38962306a36Sopenharmony_ci "Error %x (driver bt 0, host bt 0x%x).\n", 39062306a36Sopenharmony_ci result, host_byte(result)); 39162306a36Sopenharmony_ci else if (cmdstatp->have_sense && 39262306a36Sopenharmony_ci scode != NO_SENSE && 39362306a36Sopenharmony_ci scode != RECOVERED_ERROR && 39462306a36Sopenharmony_ci /* scode != UNIT_ATTENTION && */ 39562306a36Sopenharmony_ci scode != BLANK_CHECK && 39662306a36Sopenharmony_ci scode != VOLUME_OVERFLOW && 39762306a36Sopenharmony_ci SRpnt->cmd[0] != MODE_SENSE && 39862306a36Sopenharmony_ci SRpnt->cmd[0] != TEST_UNIT_READY) { 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci __scsi_print_sense(STp->device, name, 40162306a36Sopenharmony_ci SRpnt->sense, SCSI_SENSE_BUFFERSIZE); 40262306a36Sopenharmony_ci } 40362306a36Sopenharmony_ci } 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci if (cmdstatp->fixed_format && 40662306a36Sopenharmony_ci STp->cln_mode >= EXTENDED_SENSE_START) { /* Only fixed format sense */ 40762306a36Sopenharmony_ci if (STp->cln_sense_value) 40862306a36Sopenharmony_ci STp->cleaning_req |= ((SRpnt->sense[STp->cln_mode] & 40962306a36Sopenharmony_ci STp->cln_sense_mask) == STp->cln_sense_value); 41062306a36Sopenharmony_ci else 41162306a36Sopenharmony_ci STp->cleaning_req |= ((SRpnt->sense[STp->cln_mode] & 41262306a36Sopenharmony_ci STp->cln_sense_mask) != 0); 41362306a36Sopenharmony_ci } 41462306a36Sopenharmony_ci if (cmdstatp->have_sense && 41562306a36Sopenharmony_ci cmdstatp->sense_hdr.asc == 0 && cmdstatp->sense_hdr.ascq == 0x17) 41662306a36Sopenharmony_ci STp->cleaning_req = 1; /* ASC and ASCQ => cleaning requested */ 41762306a36Sopenharmony_ci if (cmdstatp->have_sense && scode == UNIT_ATTENTION && cmdstatp->sense_hdr.asc == 0x29) 41862306a36Sopenharmony_ci STp->pos_unknown = 1; /* ASC => power on / reset */ 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci STp->pos_unknown |= STp->device->was_reset; 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci if (cmdstatp->have_sense && 42362306a36Sopenharmony_ci scode == RECOVERED_ERROR 42462306a36Sopenharmony_ci#if ST_RECOVERED_WRITE_FATAL 42562306a36Sopenharmony_ci && SRpnt->cmd[0] != WRITE_6 42662306a36Sopenharmony_ci && SRpnt->cmd[0] != WRITE_FILEMARKS 42762306a36Sopenharmony_ci#endif 42862306a36Sopenharmony_ci ) { 42962306a36Sopenharmony_ci STp->recover_count++; 43062306a36Sopenharmony_ci STp->recover_reg++; 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci DEB( 43362306a36Sopenharmony_ci if (debugging) { 43462306a36Sopenharmony_ci if (SRpnt->cmd[0] == READ_6) 43562306a36Sopenharmony_ci stp = "read"; 43662306a36Sopenharmony_ci else if (SRpnt->cmd[0] == WRITE_6) 43762306a36Sopenharmony_ci stp = "write"; 43862306a36Sopenharmony_ci else 43962306a36Sopenharmony_ci stp = "ioctl"; 44062306a36Sopenharmony_ci st_printk(ST_DEB_MSG, STp, 44162306a36Sopenharmony_ci "Recovered %s error (%d).\n", 44262306a36Sopenharmony_ci stp, STp->recover_count); 44362306a36Sopenharmony_ci } ) /* end DEB */ 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci if (cmdstatp->flags == 0) 44662306a36Sopenharmony_ci return 0; 44762306a36Sopenharmony_ci } 44862306a36Sopenharmony_ci return (-EIO); 44962306a36Sopenharmony_ci} 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_cistatic struct st_request *st_allocate_request(struct scsi_tape *stp) 45262306a36Sopenharmony_ci{ 45362306a36Sopenharmony_ci struct st_request *streq; 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci streq = kzalloc(sizeof(*streq), GFP_KERNEL); 45662306a36Sopenharmony_ci if (streq) 45762306a36Sopenharmony_ci streq->stp = stp; 45862306a36Sopenharmony_ci else { 45962306a36Sopenharmony_ci st_printk(KERN_ERR, stp, 46062306a36Sopenharmony_ci "Can't get SCSI request.\n"); 46162306a36Sopenharmony_ci if (signal_pending(current)) 46262306a36Sopenharmony_ci stp->buffer->syscall_result = -EINTR; 46362306a36Sopenharmony_ci else 46462306a36Sopenharmony_ci stp->buffer->syscall_result = -EBUSY; 46562306a36Sopenharmony_ci } 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci return streq; 46862306a36Sopenharmony_ci} 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_cistatic void st_release_request(struct st_request *streq) 47162306a36Sopenharmony_ci{ 47262306a36Sopenharmony_ci kfree(streq); 47362306a36Sopenharmony_ci} 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_cistatic void st_do_stats(struct scsi_tape *STp, struct request *req) 47662306a36Sopenharmony_ci{ 47762306a36Sopenharmony_ci struct scsi_cmnd *scmd = blk_mq_rq_to_pdu(req); 47862306a36Sopenharmony_ci ktime_t now; 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci now = ktime_get(); 48162306a36Sopenharmony_ci if (scmd->cmnd[0] == WRITE_6) { 48262306a36Sopenharmony_ci now = ktime_sub(now, STp->stats->write_time); 48362306a36Sopenharmony_ci atomic64_add(ktime_to_ns(now), &STp->stats->tot_write_time); 48462306a36Sopenharmony_ci atomic64_add(ktime_to_ns(now), &STp->stats->tot_io_time); 48562306a36Sopenharmony_ci atomic64_inc(&STp->stats->write_cnt); 48662306a36Sopenharmony_ci if (scmd->result) { 48762306a36Sopenharmony_ci atomic64_add(atomic_read(&STp->stats->last_write_size) 48862306a36Sopenharmony_ci - STp->buffer->cmdstat.residual, 48962306a36Sopenharmony_ci &STp->stats->write_byte_cnt); 49062306a36Sopenharmony_ci if (STp->buffer->cmdstat.residual > 0) 49162306a36Sopenharmony_ci atomic64_inc(&STp->stats->resid_cnt); 49262306a36Sopenharmony_ci } else 49362306a36Sopenharmony_ci atomic64_add(atomic_read(&STp->stats->last_write_size), 49462306a36Sopenharmony_ci &STp->stats->write_byte_cnt); 49562306a36Sopenharmony_ci } else if (scmd->cmnd[0] == READ_6) { 49662306a36Sopenharmony_ci now = ktime_sub(now, STp->stats->read_time); 49762306a36Sopenharmony_ci atomic64_add(ktime_to_ns(now), &STp->stats->tot_read_time); 49862306a36Sopenharmony_ci atomic64_add(ktime_to_ns(now), &STp->stats->tot_io_time); 49962306a36Sopenharmony_ci atomic64_inc(&STp->stats->read_cnt); 50062306a36Sopenharmony_ci if (scmd->result) { 50162306a36Sopenharmony_ci atomic64_add(atomic_read(&STp->stats->last_read_size) 50262306a36Sopenharmony_ci - STp->buffer->cmdstat.residual, 50362306a36Sopenharmony_ci &STp->stats->read_byte_cnt); 50462306a36Sopenharmony_ci if (STp->buffer->cmdstat.residual > 0) 50562306a36Sopenharmony_ci atomic64_inc(&STp->stats->resid_cnt); 50662306a36Sopenharmony_ci } else 50762306a36Sopenharmony_ci atomic64_add(atomic_read(&STp->stats->last_read_size), 50862306a36Sopenharmony_ci &STp->stats->read_byte_cnt); 50962306a36Sopenharmony_ci } else { 51062306a36Sopenharmony_ci now = ktime_sub(now, STp->stats->other_time); 51162306a36Sopenharmony_ci atomic64_add(ktime_to_ns(now), &STp->stats->tot_io_time); 51262306a36Sopenharmony_ci atomic64_inc(&STp->stats->other_cnt); 51362306a36Sopenharmony_ci } 51462306a36Sopenharmony_ci atomic64_dec(&STp->stats->in_flight); 51562306a36Sopenharmony_ci} 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_cistatic enum rq_end_io_ret st_scsi_execute_end(struct request *req, 51862306a36Sopenharmony_ci blk_status_t status) 51962306a36Sopenharmony_ci{ 52062306a36Sopenharmony_ci struct scsi_cmnd *scmd = blk_mq_rq_to_pdu(req); 52162306a36Sopenharmony_ci struct st_request *SRpnt = req->end_io_data; 52262306a36Sopenharmony_ci struct scsi_tape *STp = SRpnt->stp; 52362306a36Sopenharmony_ci struct bio *tmp; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci STp->buffer->cmdstat.midlevel_result = SRpnt->result = scmd->result; 52662306a36Sopenharmony_ci STp->buffer->cmdstat.residual = scmd->resid_len; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci st_do_stats(STp, req); 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci tmp = SRpnt->bio; 53162306a36Sopenharmony_ci if (scmd->sense_len) 53262306a36Sopenharmony_ci memcpy(SRpnt->sense, scmd->sense_buffer, SCSI_SENSE_BUFFERSIZE); 53362306a36Sopenharmony_ci if (SRpnt->waiting) 53462306a36Sopenharmony_ci complete(SRpnt->waiting); 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci blk_rq_unmap_user(tmp); 53762306a36Sopenharmony_ci blk_mq_free_request(req); 53862306a36Sopenharmony_ci return RQ_END_IO_NONE; 53962306a36Sopenharmony_ci} 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_cistatic int st_scsi_execute(struct st_request *SRpnt, const unsigned char *cmd, 54262306a36Sopenharmony_ci int data_direction, void *buffer, unsigned bufflen, 54362306a36Sopenharmony_ci int timeout, int retries) 54462306a36Sopenharmony_ci{ 54562306a36Sopenharmony_ci struct request *req; 54662306a36Sopenharmony_ci struct rq_map_data *mdata = &SRpnt->stp->buffer->map_data; 54762306a36Sopenharmony_ci int err = 0; 54862306a36Sopenharmony_ci struct scsi_tape *STp = SRpnt->stp; 54962306a36Sopenharmony_ci struct scsi_cmnd *scmd; 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci req = scsi_alloc_request(SRpnt->stp->device->request_queue, 55262306a36Sopenharmony_ci data_direction == DMA_TO_DEVICE ? 55362306a36Sopenharmony_ci REQ_OP_DRV_OUT : REQ_OP_DRV_IN, 0); 55462306a36Sopenharmony_ci if (IS_ERR(req)) 55562306a36Sopenharmony_ci return PTR_ERR(req); 55662306a36Sopenharmony_ci scmd = blk_mq_rq_to_pdu(req); 55762306a36Sopenharmony_ci req->rq_flags |= RQF_QUIET; 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci mdata->null_mapped = 1; 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci if (bufflen) { 56262306a36Sopenharmony_ci err = blk_rq_map_user(req->q, req, mdata, NULL, bufflen, 56362306a36Sopenharmony_ci GFP_KERNEL); 56462306a36Sopenharmony_ci if (err) { 56562306a36Sopenharmony_ci blk_mq_free_request(req); 56662306a36Sopenharmony_ci return err; 56762306a36Sopenharmony_ci } 56862306a36Sopenharmony_ci } 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci atomic64_inc(&STp->stats->in_flight); 57162306a36Sopenharmony_ci if (cmd[0] == WRITE_6) { 57262306a36Sopenharmony_ci atomic_set(&STp->stats->last_write_size, bufflen); 57362306a36Sopenharmony_ci STp->stats->write_time = ktime_get(); 57462306a36Sopenharmony_ci } else if (cmd[0] == READ_6) { 57562306a36Sopenharmony_ci atomic_set(&STp->stats->last_read_size, bufflen); 57662306a36Sopenharmony_ci STp->stats->read_time = ktime_get(); 57762306a36Sopenharmony_ci } else { 57862306a36Sopenharmony_ci STp->stats->other_time = ktime_get(); 57962306a36Sopenharmony_ci } 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci SRpnt->bio = req->bio; 58262306a36Sopenharmony_ci scmd->cmd_len = COMMAND_SIZE(cmd[0]); 58362306a36Sopenharmony_ci memcpy(scmd->cmnd, cmd, scmd->cmd_len); 58462306a36Sopenharmony_ci req->timeout = timeout; 58562306a36Sopenharmony_ci scmd->allowed = retries; 58662306a36Sopenharmony_ci req->end_io = st_scsi_execute_end; 58762306a36Sopenharmony_ci req->end_io_data = SRpnt; 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci blk_execute_rq_nowait(req, true); 59062306a36Sopenharmony_ci return 0; 59162306a36Sopenharmony_ci} 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci/* Do the scsi command. Waits until command performed if do_wait is true. 59462306a36Sopenharmony_ci Otherwise write_behind_check() is used to check that the command 59562306a36Sopenharmony_ci has finished. */ 59662306a36Sopenharmony_cistatic struct st_request * 59762306a36Sopenharmony_cist_do_scsi(struct st_request * SRpnt, struct scsi_tape * STp, unsigned char *cmd, 59862306a36Sopenharmony_ci int bytes, int direction, int timeout, int retries, int do_wait) 59962306a36Sopenharmony_ci{ 60062306a36Sopenharmony_ci struct completion *waiting; 60162306a36Sopenharmony_ci struct rq_map_data *mdata = &STp->buffer->map_data; 60262306a36Sopenharmony_ci int ret; 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci /* if async, make sure there's no command outstanding */ 60562306a36Sopenharmony_ci if (!do_wait && ((STp->buffer)->last_SRpnt)) { 60662306a36Sopenharmony_ci st_printk(KERN_ERR, STp, 60762306a36Sopenharmony_ci "Async command already active.\n"); 60862306a36Sopenharmony_ci if (signal_pending(current)) 60962306a36Sopenharmony_ci (STp->buffer)->syscall_result = (-EINTR); 61062306a36Sopenharmony_ci else 61162306a36Sopenharmony_ci (STp->buffer)->syscall_result = (-EBUSY); 61262306a36Sopenharmony_ci return NULL; 61362306a36Sopenharmony_ci } 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci if (!SRpnt) { 61662306a36Sopenharmony_ci SRpnt = st_allocate_request(STp); 61762306a36Sopenharmony_ci if (!SRpnt) 61862306a36Sopenharmony_ci return NULL; 61962306a36Sopenharmony_ci } 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci /* If async IO, set last_SRpnt. This ptr tells write_behind_check 62262306a36Sopenharmony_ci which IO is outstanding. It's nulled out when the IO completes. */ 62362306a36Sopenharmony_ci if (!do_wait) 62462306a36Sopenharmony_ci (STp->buffer)->last_SRpnt = SRpnt; 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci waiting = &STp->wait; 62762306a36Sopenharmony_ci init_completion(waiting); 62862306a36Sopenharmony_ci SRpnt->waiting = waiting; 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci if (STp->buffer->do_dio) { 63162306a36Sopenharmony_ci mdata->page_order = 0; 63262306a36Sopenharmony_ci mdata->nr_entries = STp->buffer->sg_segs; 63362306a36Sopenharmony_ci mdata->pages = STp->buffer->mapped_pages; 63462306a36Sopenharmony_ci } else { 63562306a36Sopenharmony_ci mdata->page_order = STp->buffer->reserved_page_order; 63662306a36Sopenharmony_ci mdata->nr_entries = 63762306a36Sopenharmony_ci DIV_ROUND_UP(bytes, PAGE_SIZE << mdata->page_order); 63862306a36Sopenharmony_ci mdata->pages = STp->buffer->reserved_pages; 63962306a36Sopenharmony_ci mdata->offset = 0; 64062306a36Sopenharmony_ci } 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci memcpy(SRpnt->cmd, cmd, sizeof(SRpnt->cmd)); 64362306a36Sopenharmony_ci STp->buffer->cmdstat.have_sense = 0; 64462306a36Sopenharmony_ci STp->buffer->syscall_result = 0; 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci ret = st_scsi_execute(SRpnt, cmd, direction, NULL, bytes, timeout, 64762306a36Sopenharmony_ci retries); 64862306a36Sopenharmony_ci if (ret) { 64962306a36Sopenharmony_ci /* could not allocate the buffer or request was too large */ 65062306a36Sopenharmony_ci (STp->buffer)->syscall_result = (-EBUSY); 65162306a36Sopenharmony_ci (STp->buffer)->last_SRpnt = NULL; 65262306a36Sopenharmony_ci } else if (do_wait) { 65362306a36Sopenharmony_ci wait_for_completion(waiting); 65462306a36Sopenharmony_ci SRpnt->waiting = NULL; 65562306a36Sopenharmony_ci (STp->buffer)->syscall_result = st_chk_result(STp, SRpnt); 65662306a36Sopenharmony_ci } 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci return SRpnt; 65962306a36Sopenharmony_ci} 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci/* Handle the write-behind checking (waits for completion). Returns -ENOSPC if 66362306a36Sopenharmony_ci write has been correct but EOM early warning reached, -EIO if write ended in 66462306a36Sopenharmony_ci error or zero if write successful. Asynchronous writes are used only in 66562306a36Sopenharmony_ci variable block mode. */ 66662306a36Sopenharmony_cistatic int write_behind_check(struct scsi_tape * STp) 66762306a36Sopenharmony_ci{ 66862306a36Sopenharmony_ci int retval = 0; 66962306a36Sopenharmony_ci struct st_buffer *STbuffer; 67062306a36Sopenharmony_ci struct st_partstat *STps; 67162306a36Sopenharmony_ci struct st_cmdstatus *cmdstatp; 67262306a36Sopenharmony_ci struct st_request *SRpnt; 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci STbuffer = STp->buffer; 67562306a36Sopenharmony_ci if (!STbuffer->writing) 67662306a36Sopenharmony_ci return 0; 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci DEB( 67962306a36Sopenharmony_ci if (STp->write_pending) 68062306a36Sopenharmony_ci STp->nbr_waits++; 68162306a36Sopenharmony_ci else 68262306a36Sopenharmony_ci STp->nbr_finished++; 68362306a36Sopenharmony_ci ) /* end DEB */ 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci wait_for_completion(&(STp->wait)); 68662306a36Sopenharmony_ci SRpnt = STbuffer->last_SRpnt; 68762306a36Sopenharmony_ci STbuffer->last_SRpnt = NULL; 68862306a36Sopenharmony_ci SRpnt->waiting = NULL; 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci (STp->buffer)->syscall_result = st_chk_result(STp, SRpnt); 69162306a36Sopenharmony_ci st_release_request(SRpnt); 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci STbuffer->buffer_bytes -= STbuffer->writing; 69462306a36Sopenharmony_ci STps = &(STp->ps[STp->partition]); 69562306a36Sopenharmony_ci if (STps->drv_block >= 0) { 69662306a36Sopenharmony_ci if (STp->block_size == 0) 69762306a36Sopenharmony_ci STps->drv_block++; 69862306a36Sopenharmony_ci else 69962306a36Sopenharmony_ci STps->drv_block += STbuffer->writing / STp->block_size; 70062306a36Sopenharmony_ci } 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci cmdstatp = &STbuffer->cmdstat; 70362306a36Sopenharmony_ci if (STbuffer->syscall_result) { 70462306a36Sopenharmony_ci retval = -EIO; 70562306a36Sopenharmony_ci if (cmdstatp->have_sense && !cmdstatp->deferred && 70662306a36Sopenharmony_ci (cmdstatp->flags & SENSE_EOM) && 70762306a36Sopenharmony_ci (cmdstatp->sense_hdr.sense_key == NO_SENSE || 70862306a36Sopenharmony_ci cmdstatp->sense_hdr.sense_key == RECOVERED_ERROR)) { 70962306a36Sopenharmony_ci /* EOM at write-behind, has all data been written? */ 71062306a36Sopenharmony_ci if (!cmdstatp->remainder_valid || 71162306a36Sopenharmony_ci cmdstatp->uremainder64 == 0) 71262306a36Sopenharmony_ci retval = -ENOSPC; 71362306a36Sopenharmony_ci } 71462306a36Sopenharmony_ci if (retval == -EIO) 71562306a36Sopenharmony_ci STps->drv_block = -1; 71662306a36Sopenharmony_ci } 71762306a36Sopenharmony_ci STbuffer->writing = 0; 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci DEB(if (debugging && retval) 72062306a36Sopenharmony_ci st_printk(ST_DEB_MSG, STp, 72162306a36Sopenharmony_ci "Async write error %x, return value %d.\n", 72262306a36Sopenharmony_ci STbuffer->cmdstat.midlevel_result, retval);) /* end DEB */ 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci return retval; 72562306a36Sopenharmony_ci} 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci/* Step over EOF if it has been inadvertently crossed (ioctl not used because 72962306a36Sopenharmony_ci it messes up the block number). */ 73062306a36Sopenharmony_cistatic int cross_eof(struct scsi_tape * STp, int forward) 73162306a36Sopenharmony_ci{ 73262306a36Sopenharmony_ci struct st_request *SRpnt; 73362306a36Sopenharmony_ci unsigned char cmd[MAX_COMMAND_SIZE]; 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci cmd[0] = SPACE; 73662306a36Sopenharmony_ci cmd[1] = 0x01; /* Space FileMarks */ 73762306a36Sopenharmony_ci if (forward) { 73862306a36Sopenharmony_ci cmd[2] = cmd[3] = 0; 73962306a36Sopenharmony_ci cmd[4] = 1; 74062306a36Sopenharmony_ci } else 74162306a36Sopenharmony_ci cmd[2] = cmd[3] = cmd[4] = 0xff; /* -1 filemarks */ 74262306a36Sopenharmony_ci cmd[5] = 0; 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci DEBC_printk(STp, "Stepping over filemark %s.\n", 74562306a36Sopenharmony_ci forward ? "forward" : "backward"); 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci SRpnt = st_do_scsi(NULL, STp, cmd, 0, DMA_NONE, 74862306a36Sopenharmony_ci STp->device->request_queue->rq_timeout, 74962306a36Sopenharmony_ci MAX_RETRIES, 1); 75062306a36Sopenharmony_ci if (!SRpnt) 75162306a36Sopenharmony_ci return (STp->buffer)->syscall_result; 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci st_release_request(SRpnt); 75462306a36Sopenharmony_ci SRpnt = NULL; 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci if ((STp->buffer)->cmdstat.midlevel_result != 0) 75762306a36Sopenharmony_ci st_printk(KERN_ERR, STp, 75862306a36Sopenharmony_ci "Stepping over filemark %s failed.\n", 75962306a36Sopenharmony_ci forward ? "forward" : "backward"); 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci return (STp->buffer)->syscall_result; 76262306a36Sopenharmony_ci} 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci/* Flush the write buffer (never need to write if variable blocksize). */ 76662306a36Sopenharmony_cistatic int st_flush_write_buffer(struct scsi_tape * STp) 76762306a36Sopenharmony_ci{ 76862306a36Sopenharmony_ci int transfer, blks; 76962306a36Sopenharmony_ci int result; 77062306a36Sopenharmony_ci unsigned char cmd[MAX_COMMAND_SIZE]; 77162306a36Sopenharmony_ci struct st_request *SRpnt; 77262306a36Sopenharmony_ci struct st_partstat *STps; 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci result = write_behind_check(STp); 77562306a36Sopenharmony_ci if (result) 77662306a36Sopenharmony_ci return result; 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci result = 0; 77962306a36Sopenharmony_ci if (STp->dirty == 1) { 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci transfer = STp->buffer->buffer_bytes; 78262306a36Sopenharmony_ci DEBC_printk(STp, "Flushing %d bytes.\n", transfer); 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci memset(cmd, 0, MAX_COMMAND_SIZE); 78562306a36Sopenharmony_ci cmd[0] = WRITE_6; 78662306a36Sopenharmony_ci cmd[1] = 1; 78762306a36Sopenharmony_ci blks = transfer / STp->block_size; 78862306a36Sopenharmony_ci cmd[2] = blks >> 16; 78962306a36Sopenharmony_ci cmd[3] = blks >> 8; 79062306a36Sopenharmony_ci cmd[4] = blks; 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci SRpnt = st_do_scsi(NULL, STp, cmd, transfer, DMA_TO_DEVICE, 79362306a36Sopenharmony_ci STp->device->request_queue->rq_timeout, 79462306a36Sopenharmony_ci MAX_WRITE_RETRIES, 1); 79562306a36Sopenharmony_ci if (!SRpnt) 79662306a36Sopenharmony_ci return (STp->buffer)->syscall_result; 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci STps = &(STp->ps[STp->partition]); 79962306a36Sopenharmony_ci if ((STp->buffer)->syscall_result != 0) { 80062306a36Sopenharmony_ci struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat; 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci if (cmdstatp->have_sense && !cmdstatp->deferred && 80362306a36Sopenharmony_ci (cmdstatp->flags & SENSE_EOM) && 80462306a36Sopenharmony_ci (cmdstatp->sense_hdr.sense_key == NO_SENSE || 80562306a36Sopenharmony_ci cmdstatp->sense_hdr.sense_key == RECOVERED_ERROR) && 80662306a36Sopenharmony_ci (!cmdstatp->remainder_valid || 80762306a36Sopenharmony_ci cmdstatp->uremainder64 == 0)) { /* All written at EOM early warning */ 80862306a36Sopenharmony_ci STp->dirty = 0; 80962306a36Sopenharmony_ci (STp->buffer)->buffer_bytes = 0; 81062306a36Sopenharmony_ci if (STps->drv_block >= 0) 81162306a36Sopenharmony_ci STps->drv_block += blks; 81262306a36Sopenharmony_ci result = (-ENOSPC); 81362306a36Sopenharmony_ci } else { 81462306a36Sopenharmony_ci st_printk(KERN_ERR, STp, "Error on flush.\n"); 81562306a36Sopenharmony_ci STps->drv_block = (-1); 81662306a36Sopenharmony_ci result = (-EIO); 81762306a36Sopenharmony_ci } 81862306a36Sopenharmony_ci } else { 81962306a36Sopenharmony_ci if (STps->drv_block >= 0) 82062306a36Sopenharmony_ci STps->drv_block += blks; 82162306a36Sopenharmony_ci STp->dirty = 0; 82262306a36Sopenharmony_ci (STp->buffer)->buffer_bytes = 0; 82362306a36Sopenharmony_ci } 82462306a36Sopenharmony_ci st_release_request(SRpnt); 82562306a36Sopenharmony_ci SRpnt = NULL; 82662306a36Sopenharmony_ci } 82762306a36Sopenharmony_ci return result; 82862306a36Sopenharmony_ci} 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci/* Flush the tape buffer. The tape will be positioned correctly unless 83262306a36Sopenharmony_ci seek_next is true. */ 83362306a36Sopenharmony_cistatic int flush_buffer(struct scsi_tape *STp, int seek_next) 83462306a36Sopenharmony_ci{ 83562306a36Sopenharmony_ci int backspace, result; 83662306a36Sopenharmony_ci struct st_partstat *STps; 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci /* 83962306a36Sopenharmony_ci * If there was a bus reset, block further access 84062306a36Sopenharmony_ci * to this device. 84162306a36Sopenharmony_ci */ 84262306a36Sopenharmony_ci if (STp->pos_unknown) 84362306a36Sopenharmony_ci return (-EIO); 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci if (STp->ready != ST_READY) 84662306a36Sopenharmony_ci return 0; 84762306a36Sopenharmony_ci STps = &(STp->ps[STp->partition]); 84862306a36Sopenharmony_ci if (STps->rw == ST_WRITING) /* Writing */ 84962306a36Sopenharmony_ci return st_flush_write_buffer(STp); 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci if (STp->block_size == 0) 85262306a36Sopenharmony_ci return 0; 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci backspace = ((STp->buffer)->buffer_bytes + 85562306a36Sopenharmony_ci (STp->buffer)->read_pointer) / STp->block_size - 85662306a36Sopenharmony_ci ((STp->buffer)->read_pointer + STp->block_size - 1) / 85762306a36Sopenharmony_ci STp->block_size; 85862306a36Sopenharmony_ci (STp->buffer)->buffer_bytes = 0; 85962306a36Sopenharmony_ci (STp->buffer)->read_pointer = 0; 86062306a36Sopenharmony_ci result = 0; 86162306a36Sopenharmony_ci if (!seek_next) { 86262306a36Sopenharmony_ci if (STps->eof == ST_FM_HIT) { 86362306a36Sopenharmony_ci result = cross_eof(STp, 0); /* Back over the EOF hit */ 86462306a36Sopenharmony_ci if (!result) 86562306a36Sopenharmony_ci STps->eof = ST_NOEOF; 86662306a36Sopenharmony_ci else { 86762306a36Sopenharmony_ci if (STps->drv_file >= 0) 86862306a36Sopenharmony_ci STps->drv_file++; 86962306a36Sopenharmony_ci STps->drv_block = 0; 87062306a36Sopenharmony_ci } 87162306a36Sopenharmony_ci } 87262306a36Sopenharmony_ci if (!result && backspace > 0) 87362306a36Sopenharmony_ci result = st_int_ioctl(STp, MTBSR, backspace); 87462306a36Sopenharmony_ci } else if (STps->eof == ST_FM_HIT) { 87562306a36Sopenharmony_ci if (STps->drv_file >= 0) 87662306a36Sopenharmony_ci STps->drv_file++; 87762306a36Sopenharmony_ci STps->drv_block = 0; 87862306a36Sopenharmony_ci STps->eof = ST_NOEOF; 87962306a36Sopenharmony_ci } 88062306a36Sopenharmony_ci return result; 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci} 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci/* Set the mode parameters */ 88562306a36Sopenharmony_cistatic int set_mode_densblk(struct scsi_tape * STp, struct st_modedef * STm) 88662306a36Sopenharmony_ci{ 88762306a36Sopenharmony_ci int set_it = 0; 88862306a36Sopenharmony_ci unsigned long arg; 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci if (!STp->density_changed && 89162306a36Sopenharmony_ci STm->default_density >= 0 && 89262306a36Sopenharmony_ci STm->default_density != STp->density) { 89362306a36Sopenharmony_ci arg = STm->default_density; 89462306a36Sopenharmony_ci set_it = 1; 89562306a36Sopenharmony_ci } else 89662306a36Sopenharmony_ci arg = STp->density; 89762306a36Sopenharmony_ci arg <<= MT_ST_DENSITY_SHIFT; 89862306a36Sopenharmony_ci if (!STp->blksize_changed && 89962306a36Sopenharmony_ci STm->default_blksize >= 0 && 90062306a36Sopenharmony_ci STm->default_blksize != STp->block_size) { 90162306a36Sopenharmony_ci arg |= STm->default_blksize; 90262306a36Sopenharmony_ci set_it = 1; 90362306a36Sopenharmony_ci } else 90462306a36Sopenharmony_ci arg |= STp->block_size; 90562306a36Sopenharmony_ci if (set_it && 90662306a36Sopenharmony_ci st_int_ioctl(STp, SET_DENS_AND_BLK, arg)) { 90762306a36Sopenharmony_ci st_printk(KERN_WARNING, STp, 90862306a36Sopenharmony_ci "Can't set default block size to %d bytes " 90962306a36Sopenharmony_ci "and density %x.\n", 91062306a36Sopenharmony_ci STm->default_blksize, STm->default_density); 91162306a36Sopenharmony_ci if (modes_defined) 91262306a36Sopenharmony_ci return (-EINVAL); 91362306a36Sopenharmony_ci } 91462306a36Sopenharmony_ci return 0; 91562306a36Sopenharmony_ci} 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci/* Lock or unlock the drive door. Don't use when st_request allocated. */ 91962306a36Sopenharmony_cistatic int do_door_lock(struct scsi_tape * STp, int do_lock) 92062306a36Sopenharmony_ci{ 92162306a36Sopenharmony_ci int retval; 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci DEBC_printk(STp, "%socking drive door.\n", do_lock ? "L" : "Unl"); 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci retval = scsi_set_medium_removal(STp->device, 92662306a36Sopenharmony_ci do_lock ? SCSI_REMOVAL_PREVENT : SCSI_REMOVAL_ALLOW); 92762306a36Sopenharmony_ci if (!retval) 92862306a36Sopenharmony_ci STp->door_locked = do_lock ? ST_LOCKED_EXPLICIT : ST_UNLOCKED; 92962306a36Sopenharmony_ci else 93062306a36Sopenharmony_ci STp->door_locked = ST_LOCK_FAILS; 93162306a36Sopenharmony_ci return retval; 93262306a36Sopenharmony_ci} 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci/* Set the internal state after reset */ 93662306a36Sopenharmony_cistatic void reset_state(struct scsi_tape *STp) 93762306a36Sopenharmony_ci{ 93862306a36Sopenharmony_ci int i; 93962306a36Sopenharmony_ci struct st_partstat *STps; 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci STp->pos_unknown = 0; 94262306a36Sopenharmony_ci for (i = 0; i < ST_NBR_PARTITIONS; i++) { 94362306a36Sopenharmony_ci STps = &(STp->ps[i]); 94462306a36Sopenharmony_ci STps->rw = ST_IDLE; 94562306a36Sopenharmony_ci STps->eof = ST_NOEOF; 94662306a36Sopenharmony_ci STps->at_sm = 0; 94762306a36Sopenharmony_ci STps->last_block_valid = 0; 94862306a36Sopenharmony_ci STps->drv_block = -1; 94962306a36Sopenharmony_ci STps->drv_file = -1; 95062306a36Sopenharmony_ci } 95162306a36Sopenharmony_ci if (STp->can_partitions) { 95262306a36Sopenharmony_ci STp->partition = find_partition(STp); 95362306a36Sopenharmony_ci if (STp->partition < 0) 95462306a36Sopenharmony_ci STp->partition = 0; 95562306a36Sopenharmony_ci STp->new_partition = STp->partition; 95662306a36Sopenharmony_ci } 95762306a36Sopenharmony_ci} 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci/* Test if the drive is ready. Returns either one of the codes below or a negative system 96062306a36Sopenharmony_ci error code. */ 96162306a36Sopenharmony_ci#define CHKRES_READY 0 96262306a36Sopenharmony_ci#define CHKRES_NEW_SESSION 1 96362306a36Sopenharmony_ci#define CHKRES_NOT_READY 2 96462306a36Sopenharmony_ci#define CHKRES_NO_TAPE 3 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci#define MAX_ATTENTIONS 10 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_cistatic int test_ready(struct scsi_tape *STp, int do_wait) 96962306a36Sopenharmony_ci{ 97062306a36Sopenharmony_ci int attentions, waits, max_wait, scode; 97162306a36Sopenharmony_ci int retval = CHKRES_READY, new_session = 0; 97262306a36Sopenharmony_ci unsigned char cmd[MAX_COMMAND_SIZE]; 97362306a36Sopenharmony_ci struct st_request *SRpnt = NULL; 97462306a36Sopenharmony_ci struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat; 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_ci max_wait = do_wait ? ST_BLOCK_SECONDS : 0; 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci for (attentions=waits=0; ; ) { 97962306a36Sopenharmony_ci memset((void *) &cmd[0], 0, MAX_COMMAND_SIZE); 98062306a36Sopenharmony_ci cmd[0] = TEST_UNIT_READY; 98162306a36Sopenharmony_ci SRpnt = st_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE, 98262306a36Sopenharmony_ci STp->long_timeout, MAX_READY_RETRIES, 1); 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci if (!SRpnt) { 98562306a36Sopenharmony_ci retval = (STp->buffer)->syscall_result; 98662306a36Sopenharmony_ci break; 98762306a36Sopenharmony_ci } 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci if (cmdstatp->have_sense) { 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci scode = cmdstatp->sense_hdr.sense_key; 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci if (scode == UNIT_ATTENTION) { /* New media? */ 99462306a36Sopenharmony_ci new_session = 1; 99562306a36Sopenharmony_ci if (attentions < MAX_ATTENTIONS) { 99662306a36Sopenharmony_ci attentions++; 99762306a36Sopenharmony_ci continue; 99862306a36Sopenharmony_ci } 99962306a36Sopenharmony_ci else { 100062306a36Sopenharmony_ci retval = (-EIO); 100162306a36Sopenharmony_ci break; 100262306a36Sopenharmony_ci } 100362306a36Sopenharmony_ci } 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci if (scode == NOT_READY) { 100662306a36Sopenharmony_ci if (waits < max_wait) { 100762306a36Sopenharmony_ci if (msleep_interruptible(1000)) { 100862306a36Sopenharmony_ci retval = (-EINTR); 100962306a36Sopenharmony_ci break; 101062306a36Sopenharmony_ci } 101162306a36Sopenharmony_ci waits++; 101262306a36Sopenharmony_ci continue; 101362306a36Sopenharmony_ci } 101462306a36Sopenharmony_ci else { 101562306a36Sopenharmony_ci if ((STp->device)->scsi_level >= SCSI_2 && 101662306a36Sopenharmony_ci cmdstatp->sense_hdr.asc == 0x3a) /* Check ASC */ 101762306a36Sopenharmony_ci retval = CHKRES_NO_TAPE; 101862306a36Sopenharmony_ci else 101962306a36Sopenharmony_ci retval = CHKRES_NOT_READY; 102062306a36Sopenharmony_ci break; 102162306a36Sopenharmony_ci } 102262306a36Sopenharmony_ci } 102362306a36Sopenharmony_ci } 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci retval = (STp->buffer)->syscall_result; 102662306a36Sopenharmony_ci if (!retval) 102762306a36Sopenharmony_ci retval = new_session ? CHKRES_NEW_SESSION : CHKRES_READY; 102862306a36Sopenharmony_ci break; 102962306a36Sopenharmony_ci } 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ci if (SRpnt != NULL) 103262306a36Sopenharmony_ci st_release_request(SRpnt); 103362306a36Sopenharmony_ci return retval; 103462306a36Sopenharmony_ci} 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci/* See if the drive is ready and gather information about the tape. Return values: 103862306a36Sopenharmony_ci < 0 negative error code from errno.h 103962306a36Sopenharmony_ci 0 drive ready 104062306a36Sopenharmony_ci 1 drive not ready (possibly no tape) 104162306a36Sopenharmony_ci*/ 104262306a36Sopenharmony_cistatic int check_tape(struct scsi_tape *STp, struct file *filp) 104362306a36Sopenharmony_ci{ 104462306a36Sopenharmony_ci int i, retval, new_session = 0, do_wait; 104562306a36Sopenharmony_ci unsigned char cmd[MAX_COMMAND_SIZE], saved_cleaning; 104662306a36Sopenharmony_ci unsigned short st_flags = filp->f_flags; 104762306a36Sopenharmony_ci struct st_request *SRpnt = NULL; 104862306a36Sopenharmony_ci struct st_modedef *STm; 104962306a36Sopenharmony_ci struct st_partstat *STps; 105062306a36Sopenharmony_ci struct inode *inode = file_inode(filp); 105162306a36Sopenharmony_ci int mode = TAPE_MODE(inode); 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ci STp->ready = ST_READY; 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci if (mode != STp->current_mode) { 105662306a36Sopenharmony_ci DEBC_printk(STp, "Mode change from %d to %d.\n", 105762306a36Sopenharmony_ci STp->current_mode, mode); 105862306a36Sopenharmony_ci new_session = 1; 105962306a36Sopenharmony_ci STp->current_mode = mode; 106062306a36Sopenharmony_ci } 106162306a36Sopenharmony_ci STm = &(STp->modes[STp->current_mode]); 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ci saved_cleaning = STp->cleaning_req; 106462306a36Sopenharmony_ci STp->cleaning_req = 0; 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_ci do_wait = ((filp->f_flags & O_NONBLOCK) == 0); 106762306a36Sopenharmony_ci retval = test_ready(STp, do_wait); 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci if (retval < 0) 107062306a36Sopenharmony_ci goto err_out; 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci if (retval == CHKRES_NEW_SESSION) { 107362306a36Sopenharmony_ci STp->pos_unknown = 0; 107462306a36Sopenharmony_ci STp->partition = STp->new_partition = 0; 107562306a36Sopenharmony_ci if (STp->can_partitions) 107662306a36Sopenharmony_ci STp->nbr_partitions = 1; /* This guess will be updated later 107762306a36Sopenharmony_ci if necessary */ 107862306a36Sopenharmony_ci for (i = 0; i < ST_NBR_PARTITIONS; i++) { 107962306a36Sopenharmony_ci STps = &(STp->ps[i]); 108062306a36Sopenharmony_ci STps->rw = ST_IDLE; 108162306a36Sopenharmony_ci STps->eof = ST_NOEOF; 108262306a36Sopenharmony_ci STps->at_sm = 0; 108362306a36Sopenharmony_ci STps->last_block_valid = 0; 108462306a36Sopenharmony_ci STps->drv_block = 0; 108562306a36Sopenharmony_ci STps->drv_file = 0; 108662306a36Sopenharmony_ci } 108762306a36Sopenharmony_ci new_session = 1; 108862306a36Sopenharmony_ci } 108962306a36Sopenharmony_ci else { 109062306a36Sopenharmony_ci STp->cleaning_req |= saved_cleaning; 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_ci if (retval == CHKRES_NOT_READY || retval == CHKRES_NO_TAPE) { 109362306a36Sopenharmony_ci if (retval == CHKRES_NO_TAPE) 109462306a36Sopenharmony_ci STp->ready = ST_NO_TAPE; 109562306a36Sopenharmony_ci else 109662306a36Sopenharmony_ci STp->ready = ST_NOT_READY; 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci STp->density = 0; /* Clear the erroneous "residue" */ 109962306a36Sopenharmony_ci STp->write_prot = 0; 110062306a36Sopenharmony_ci STp->block_size = 0; 110162306a36Sopenharmony_ci STp->ps[0].drv_file = STp->ps[0].drv_block = (-1); 110262306a36Sopenharmony_ci STp->partition = STp->new_partition = 0; 110362306a36Sopenharmony_ci STp->door_locked = ST_UNLOCKED; 110462306a36Sopenharmony_ci return CHKRES_NOT_READY; 110562306a36Sopenharmony_ci } 110662306a36Sopenharmony_ci } 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_ci if (STp->omit_blklims) 110962306a36Sopenharmony_ci STp->min_block = STp->max_block = (-1); 111062306a36Sopenharmony_ci else { 111162306a36Sopenharmony_ci memset((void *) &cmd[0], 0, MAX_COMMAND_SIZE); 111262306a36Sopenharmony_ci cmd[0] = READ_BLOCK_LIMITS; 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_ci SRpnt = st_do_scsi(SRpnt, STp, cmd, 6, DMA_FROM_DEVICE, 111562306a36Sopenharmony_ci STp->device->request_queue->rq_timeout, 111662306a36Sopenharmony_ci MAX_READY_RETRIES, 1); 111762306a36Sopenharmony_ci if (!SRpnt) { 111862306a36Sopenharmony_ci retval = (STp->buffer)->syscall_result; 111962306a36Sopenharmony_ci goto err_out; 112062306a36Sopenharmony_ci } 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ci if (!SRpnt->result && !STp->buffer->cmdstat.have_sense) { 112362306a36Sopenharmony_ci STp->max_block = ((STp->buffer)->b_data[1] << 16) | 112462306a36Sopenharmony_ci ((STp->buffer)->b_data[2] << 8) | (STp->buffer)->b_data[3]; 112562306a36Sopenharmony_ci STp->min_block = ((STp->buffer)->b_data[4] << 8) | 112662306a36Sopenharmony_ci (STp->buffer)->b_data[5]; 112762306a36Sopenharmony_ci if ( DEB( debugging || ) !STp->inited) 112862306a36Sopenharmony_ci st_printk(KERN_INFO, STp, 112962306a36Sopenharmony_ci "Block limits %d - %d bytes.\n", 113062306a36Sopenharmony_ci STp->min_block, STp->max_block); 113162306a36Sopenharmony_ci } else { 113262306a36Sopenharmony_ci STp->min_block = STp->max_block = (-1); 113362306a36Sopenharmony_ci DEBC_printk(STp, "Can't read block limits.\n"); 113462306a36Sopenharmony_ci } 113562306a36Sopenharmony_ci } 113662306a36Sopenharmony_ci 113762306a36Sopenharmony_ci memset((void *) &cmd[0], 0, MAX_COMMAND_SIZE); 113862306a36Sopenharmony_ci cmd[0] = MODE_SENSE; 113962306a36Sopenharmony_ci cmd[4] = 12; 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci SRpnt = st_do_scsi(SRpnt, STp, cmd, 12, DMA_FROM_DEVICE, 114262306a36Sopenharmony_ci STp->device->request_queue->rq_timeout, 114362306a36Sopenharmony_ci MAX_READY_RETRIES, 1); 114462306a36Sopenharmony_ci if (!SRpnt) { 114562306a36Sopenharmony_ci retval = (STp->buffer)->syscall_result; 114662306a36Sopenharmony_ci goto err_out; 114762306a36Sopenharmony_ci } 114862306a36Sopenharmony_ci 114962306a36Sopenharmony_ci if ((STp->buffer)->syscall_result != 0) { 115062306a36Sopenharmony_ci DEBC_printk(STp, "No Mode Sense.\n"); 115162306a36Sopenharmony_ci STp->block_size = ST_DEFAULT_BLOCK; /* Educated guess (?) */ 115262306a36Sopenharmony_ci (STp->buffer)->syscall_result = 0; /* Prevent error propagation */ 115362306a36Sopenharmony_ci STp->drv_write_prot = 0; 115462306a36Sopenharmony_ci } else { 115562306a36Sopenharmony_ci DEBC_printk(STp,"Mode sense. Length %d, " 115662306a36Sopenharmony_ci "medium %x, WBS %x, BLL %d\n", 115762306a36Sopenharmony_ci (STp->buffer)->b_data[0], 115862306a36Sopenharmony_ci (STp->buffer)->b_data[1], 115962306a36Sopenharmony_ci (STp->buffer)->b_data[2], 116062306a36Sopenharmony_ci (STp->buffer)->b_data[3]); 116162306a36Sopenharmony_ci 116262306a36Sopenharmony_ci if ((STp->buffer)->b_data[3] >= 8) { 116362306a36Sopenharmony_ci STp->drv_buffer = ((STp->buffer)->b_data[2] >> 4) & 7; 116462306a36Sopenharmony_ci STp->density = (STp->buffer)->b_data[4]; 116562306a36Sopenharmony_ci STp->block_size = (STp->buffer)->b_data[9] * 65536 + 116662306a36Sopenharmony_ci (STp->buffer)->b_data[10] * 256 + (STp->buffer)->b_data[11]; 116762306a36Sopenharmony_ci DEBC_printk(STp, "Density %x, tape length: %x, " 116862306a36Sopenharmony_ci "drv buffer: %d\n", 116962306a36Sopenharmony_ci STp->density, 117062306a36Sopenharmony_ci (STp->buffer)->b_data[5] * 65536 + 117162306a36Sopenharmony_ci (STp->buffer)->b_data[6] * 256 + 117262306a36Sopenharmony_ci (STp->buffer)->b_data[7], 117362306a36Sopenharmony_ci STp->drv_buffer); 117462306a36Sopenharmony_ci } 117562306a36Sopenharmony_ci STp->drv_write_prot = ((STp->buffer)->b_data[2] & 0x80) != 0; 117662306a36Sopenharmony_ci if (!STp->drv_buffer && STp->immediate_filemark) { 117762306a36Sopenharmony_ci st_printk(KERN_WARNING, STp, 117862306a36Sopenharmony_ci "non-buffered tape: disabling " 117962306a36Sopenharmony_ci "writing immediate filemarks\n"); 118062306a36Sopenharmony_ci STp->immediate_filemark = 0; 118162306a36Sopenharmony_ci } 118262306a36Sopenharmony_ci } 118362306a36Sopenharmony_ci st_release_request(SRpnt); 118462306a36Sopenharmony_ci SRpnt = NULL; 118562306a36Sopenharmony_ci STp->inited = 1; 118662306a36Sopenharmony_ci 118762306a36Sopenharmony_ci if (STp->block_size > 0) 118862306a36Sopenharmony_ci (STp->buffer)->buffer_blocks = 118962306a36Sopenharmony_ci (STp->buffer)->buffer_size / STp->block_size; 119062306a36Sopenharmony_ci else 119162306a36Sopenharmony_ci (STp->buffer)->buffer_blocks = 1; 119262306a36Sopenharmony_ci (STp->buffer)->buffer_bytes = (STp->buffer)->read_pointer = 0; 119362306a36Sopenharmony_ci 119462306a36Sopenharmony_ci DEBC_printk(STp, "Block size: %d, buffer size: %d (%d blocks).\n", 119562306a36Sopenharmony_ci STp->block_size, (STp->buffer)->buffer_size, 119662306a36Sopenharmony_ci (STp->buffer)->buffer_blocks); 119762306a36Sopenharmony_ci 119862306a36Sopenharmony_ci if (STp->drv_write_prot) { 119962306a36Sopenharmony_ci STp->write_prot = 1; 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_ci DEBC_printk(STp, "Write protected\n"); 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci if (do_wait && 120462306a36Sopenharmony_ci ((st_flags & O_ACCMODE) == O_WRONLY || 120562306a36Sopenharmony_ci (st_flags & O_ACCMODE) == O_RDWR)) { 120662306a36Sopenharmony_ci retval = (-EROFS); 120762306a36Sopenharmony_ci goto err_out; 120862306a36Sopenharmony_ci } 120962306a36Sopenharmony_ci } 121062306a36Sopenharmony_ci 121162306a36Sopenharmony_ci if (STp->can_partitions && STp->nbr_partitions < 1) { 121262306a36Sopenharmony_ci /* This code is reached when the device is opened for the first time 121362306a36Sopenharmony_ci after the driver has been initialized with tape in the drive and the 121462306a36Sopenharmony_ci partition support has been enabled. */ 121562306a36Sopenharmony_ci DEBC_printk(STp, "Updating partition number in status.\n"); 121662306a36Sopenharmony_ci if ((STp->partition = find_partition(STp)) < 0) { 121762306a36Sopenharmony_ci retval = STp->partition; 121862306a36Sopenharmony_ci goto err_out; 121962306a36Sopenharmony_ci } 122062306a36Sopenharmony_ci STp->new_partition = STp->partition; 122162306a36Sopenharmony_ci STp->nbr_partitions = 1; /* This guess will be updated when necessary */ 122262306a36Sopenharmony_ci } 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_ci if (new_session) { /* Change the drive parameters for the new mode */ 122562306a36Sopenharmony_ci STp->density_changed = STp->blksize_changed = 0; 122662306a36Sopenharmony_ci STp->compression_changed = 0; 122762306a36Sopenharmony_ci if (!(STm->defaults_for_writes) && 122862306a36Sopenharmony_ci (retval = set_mode_densblk(STp, STm)) < 0) 122962306a36Sopenharmony_ci goto err_out; 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_ci if (STp->default_drvbuffer != 0xff) { 123262306a36Sopenharmony_ci if (st_int_ioctl(STp, MTSETDRVBUFFER, STp->default_drvbuffer)) 123362306a36Sopenharmony_ci st_printk(KERN_WARNING, STp, 123462306a36Sopenharmony_ci "Can't set default drive " 123562306a36Sopenharmony_ci "buffering to %d.\n", 123662306a36Sopenharmony_ci STp->default_drvbuffer); 123762306a36Sopenharmony_ci } 123862306a36Sopenharmony_ci } 123962306a36Sopenharmony_ci 124062306a36Sopenharmony_ci return CHKRES_READY; 124162306a36Sopenharmony_ci 124262306a36Sopenharmony_ci err_out: 124362306a36Sopenharmony_ci return retval; 124462306a36Sopenharmony_ci} 124562306a36Sopenharmony_ci 124662306a36Sopenharmony_ci 124762306a36Sopenharmony_ci/* Open the device. Needs to take the BKL only because of incrementing the SCSI host 124862306a36Sopenharmony_ci module count. */ 124962306a36Sopenharmony_cistatic int st_open(struct inode *inode, struct file *filp) 125062306a36Sopenharmony_ci{ 125162306a36Sopenharmony_ci int i, retval = (-EIO); 125262306a36Sopenharmony_ci int resumed = 0; 125362306a36Sopenharmony_ci struct scsi_tape *STp; 125462306a36Sopenharmony_ci struct st_partstat *STps; 125562306a36Sopenharmony_ci int dev = TAPE_NR(inode); 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_ci /* 125862306a36Sopenharmony_ci * We really want to do nonseekable_open(inode, filp); here, but some 125962306a36Sopenharmony_ci * versions of tar incorrectly call lseek on tapes and bail out if that 126062306a36Sopenharmony_ci * fails. So we disallow pread() and pwrite(), but permit lseeks. 126162306a36Sopenharmony_ci */ 126262306a36Sopenharmony_ci filp->f_mode &= ~(FMODE_PREAD | FMODE_PWRITE); 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_ci if (!(STp = scsi_tape_get(dev))) { 126562306a36Sopenharmony_ci return -ENXIO; 126662306a36Sopenharmony_ci } 126762306a36Sopenharmony_ci 126862306a36Sopenharmony_ci filp->private_data = STp; 126962306a36Sopenharmony_ci 127062306a36Sopenharmony_ci spin_lock(&st_use_lock); 127162306a36Sopenharmony_ci if (STp->in_use) { 127262306a36Sopenharmony_ci spin_unlock(&st_use_lock); 127362306a36Sopenharmony_ci DEBC_printk(STp, "Device already in use.\n"); 127462306a36Sopenharmony_ci scsi_tape_put(STp); 127562306a36Sopenharmony_ci return (-EBUSY); 127662306a36Sopenharmony_ci } 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_ci STp->in_use = 1; 127962306a36Sopenharmony_ci spin_unlock(&st_use_lock); 128062306a36Sopenharmony_ci STp->rew_at_close = STp->autorew_dev = (iminor(inode) & 0x80) == 0; 128162306a36Sopenharmony_ci 128262306a36Sopenharmony_ci if (scsi_autopm_get_device(STp->device) < 0) { 128362306a36Sopenharmony_ci retval = -EIO; 128462306a36Sopenharmony_ci goto err_out; 128562306a36Sopenharmony_ci } 128662306a36Sopenharmony_ci resumed = 1; 128762306a36Sopenharmony_ci if (!scsi_block_when_processing_errors(STp->device)) { 128862306a36Sopenharmony_ci retval = (-ENXIO); 128962306a36Sopenharmony_ci goto err_out; 129062306a36Sopenharmony_ci } 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_ci /* See that we have at least a one page buffer available */ 129362306a36Sopenharmony_ci if (!enlarge_buffer(STp->buffer, PAGE_SIZE)) { 129462306a36Sopenharmony_ci st_printk(KERN_WARNING, STp, 129562306a36Sopenharmony_ci "Can't allocate one page tape buffer.\n"); 129662306a36Sopenharmony_ci retval = (-EOVERFLOW); 129762306a36Sopenharmony_ci goto err_out; 129862306a36Sopenharmony_ci } 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_ci (STp->buffer)->cleared = 0; 130162306a36Sopenharmony_ci (STp->buffer)->writing = 0; 130262306a36Sopenharmony_ci (STp->buffer)->syscall_result = 0; 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_ci STp->write_prot = ((filp->f_flags & O_ACCMODE) == O_RDONLY); 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_ci STp->dirty = 0; 130762306a36Sopenharmony_ci for (i = 0; i < ST_NBR_PARTITIONS; i++) { 130862306a36Sopenharmony_ci STps = &(STp->ps[i]); 130962306a36Sopenharmony_ci STps->rw = ST_IDLE; 131062306a36Sopenharmony_ci } 131162306a36Sopenharmony_ci STp->try_dio_now = STp->try_dio; 131262306a36Sopenharmony_ci STp->recover_count = 0; 131362306a36Sopenharmony_ci DEB( STp->nbr_waits = STp->nbr_finished = 0; 131462306a36Sopenharmony_ci STp->nbr_requests = STp->nbr_dio = STp->nbr_pages = 0; ) 131562306a36Sopenharmony_ci 131662306a36Sopenharmony_ci retval = check_tape(STp, filp); 131762306a36Sopenharmony_ci if (retval < 0) 131862306a36Sopenharmony_ci goto err_out; 131962306a36Sopenharmony_ci if ((filp->f_flags & O_NONBLOCK) == 0 && 132062306a36Sopenharmony_ci retval != CHKRES_READY) { 132162306a36Sopenharmony_ci if (STp->ready == NO_TAPE) 132262306a36Sopenharmony_ci retval = (-ENOMEDIUM); 132362306a36Sopenharmony_ci else 132462306a36Sopenharmony_ci retval = (-EIO); 132562306a36Sopenharmony_ci goto err_out; 132662306a36Sopenharmony_ci } 132762306a36Sopenharmony_ci return 0; 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_ci err_out: 133062306a36Sopenharmony_ci normalize_buffer(STp->buffer); 133162306a36Sopenharmony_ci spin_lock(&st_use_lock); 133262306a36Sopenharmony_ci STp->in_use = 0; 133362306a36Sopenharmony_ci spin_unlock(&st_use_lock); 133462306a36Sopenharmony_ci if (resumed) 133562306a36Sopenharmony_ci scsi_autopm_put_device(STp->device); 133662306a36Sopenharmony_ci scsi_tape_put(STp); 133762306a36Sopenharmony_ci return retval; 133862306a36Sopenharmony_ci 133962306a36Sopenharmony_ci} 134062306a36Sopenharmony_ci 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_ci/* Flush the tape buffer before close */ 134362306a36Sopenharmony_cistatic int st_flush(struct file *filp, fl_owner_t id) 134462306a36Sopenharmony_ci{ 134562306a36Sopenharmony_ci int result = 0, result2; 134662306a36Sopenharmony_ci unsigned char cmd[MAX_COMMAND_SIZE]; 134762306a36Sopenharmony_ci struct st_request *SRpnt; 134862306a36Sopenharmony_ci struct scsi_tape *STp = filp->private_data; 134962306a36Sopenharmony_ci struct st_modedef *STm = &(STp->modes[STp->current_mode]); 135062306a36Sopenharmony_ci struct st_partstat *STps = &(STp->ps[STp->partition]); 135162306a36Sopenharmony_ci 135262306a36Sopenharmony_ci if (file_count(filp) > 1) 135362306a36Sopenharmony_ci return 0; 135462306a36Sopenharmony_ci 135562306a36Sopenharmony_ci if (STps->rw == ST_WRITING && !STp->pos_unknown) { 135662306a36Sopenharmony_ci result = st_flush_write_buffer(STp); 135762306a36Sopenharmony_ci if (result != 0 && result != (-ENOSPC)) 135862306a36Sopenharmony_ci goto out; 135962306a36Sopenharmony_ci } 136062306a36Sopenharmony_ci 136162306a36Sopenharmony_ci if (STp->can_partitions && 136262306a36Sopenharmony_ci (result2 = switch_partition(STp)) < 0) { 136362306a36Sopenharmony_ci DEBC_printk(STp, "switch_partition at close failed.\n"); 136462306a36Sopenharmony_ci if (result == 0) 136562306a36Sopenharmony_ci result = result2; 136662306a36Sopenharmony_ci goto out; 136762306a36Sopenharmony_ci } 136862306a36Sopenharmony_ci 136962306a36Sopenharmony_ci DEBC( if (STp->nbr_requests) 137062306a36Sopenharmony_ci st_printk(KERN_DEBUG, STp, 137162306a36Sopenharmony_ci "Number of r/w requests %d, dio used in %d, " 137262306a36Sopenharmony_ci "pages %d.\n", STp->nbr_requests, STp->nbr_dio, 137362306a36Sopenharmony_ci STp->nbr_pages)); 137462306a36Sopenharmony_ci 137562306a36Sopenharmony_ci if (STps->rw == ST_WRITING && !STp->pos_unknown) { 137662306a36Sopenharmony_ci struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat; 137762306a36Sopenharmony_ci 137862306a36Sopenharmony_ci#if DEBUG 137962306a36Sopenharmony_ci DEBC_printk(STp, "Async write waits %d, finished %d.\n", 138062306a36Sopenharmony_ci STp->nbr_waits, STp->nbr_finished); 138162306a36Sopenharmony_ci#endif 138262306a36Sopenharmony_ci memset(cmd, 0, MAX_COMMAND_SIZE); 138362306a36Sopenharmony_ci cmd[0] = WRITE_FILEMARKS; 138462306a36Sopenharmony_ci if (STp->immediate_filemark) 138562306a36Sopenharmony_ci cmd[1] = 1; 138662306a36Sopenharmony_ci cmd[4] = 1 + STp->two_fm; 138762306a36Sopenharmony_ci 138862306a36Sopenharmony_ci SRpnt = st_do_scsi(NULL, STp, cmd, 0, DMA_NONE, 138962306a36Sopenharmony_ci STp->device->request_queue->rq_timeout, 139062306a36Sopenharmony_ci MAX_WRITE_RETRIES, 1); 139162306a36Sopenharmony_ci if (!SRpnt) { 139262306a36Sopenharmony_ci result = (STp->buffer)->syscall_result; 139362306a36Sopenharmony_ci goto out; 139462306a36Sopenharmony_ci } 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_ci if (STp->buffer->syscall_result == 0 || 139762306a36Sopenharmony_ci (cmdstatp->have_sense && !cmdstatp->deferred && 139862306a36Sopenharmony_ci (cmdstatp->flags & SENSE_EOM) && 139962306a36Sopenharmony_ci (cmdstatp->sense_hdr.sense_key == NO_SENSE || 140062306a36Sopenharmony_ci cmdstatp->sense_hdr.sense_key == RECOVERED_ERROR) && 140162306a36Sopenharmony_ci (!cmdstatp->remainder_valid || cmdstatp->uremainder64 == 0))) { 140262306a36Sopenharmony_ci /* Write successful at EOM */ 140362306a36Sopenharmony_ci st_release_request(SRpnt); 140462306a36Sopenharmony_ci SRpnt = NULL; 140562306a36Sopenharmony_ci if (STps->drv_file >= 0) 140662306a36Sopenharmony_ci STps->drv_file++; 140762306a36Sopenharmony_ci STps->drv_block = 0; 140862306a36Sopenharmony_ci if (STp->two_fm) 140962306a36Sopenharmony_ci cross_eof(STp, 0); 141062306a36Sopenharmony_ci STps->eof = ST_FM; 141162306a36Sopenharmony_ci } 141262306a36Sopenharmony_ci else { /* Write error */ 141362306a36Sopenharmony_ci st_release_request(SRpnt); 141462306a36Sopenharmony_ci SRpnt = NULL; 141562306a36Sopenharmony_ci st_printk(KERN_ERR, STp, 141662306a36Sopenharmony_ci "Error on write filemark.\n"); 141762306a36Sopenharmony_ci if (result == 0) 141862306a36Sopenharmony_ci result = (-EIO); 141962306a36Sopenharmony_ci } 142062306a36Sopenharmony_ci 142162306a36Sopenharmony_ci DEBC_printk(STp, "Buffer flushed, %d EOF(s) written\n", cmd[4]); 142262306a36Sopenharmony_ci } else if (!STp->rew_at_close) { 142362306a36Sopenharmony_ci STps = &(STp->ps[STp->partition]); 142462306a36Sopenharmony_ci if (!STm->sysv || STps->rw != ST_READING) { 142562306a36Sopenharmony_ci if (STp->can_bsr) 142662306a36Sopenharmony_ci result = flush_buffer(STp, 0); 142762306a36Sopenharmony_ci else if (STps->eof == ST_FM_HIT) { 142862306a36Sopenharmony_ci result = cross_eof(STp, 0); 142962306a36Sopenharmony_ci if (result) { 143062306a36Sopenharmony_ci if (STps->drv_file >= 0) 143162306a36Sopenharmony_ci STps->drv_file++; 143262306a36Sopenharmony_ci STps->drv_block = 0; 143362306a36Sopenharmony_ci STps->eof = ST_FM; 143462306a36Sopenharmony_ci } else 143562306a36Sopenharmony_ci STps->eof = ST_NOEOF; 143662306a36Sopenharmony_ci } 143762306a36Sopenharmony_ci } else if ((STps->eof == ST_NOEOF && 143862306a36Sopenharmony_ci !(result = cross_eof(STp, 1))) || 143962306a36Sopenharmony_ci STps->eof == ST_FM_HIT) { 144062306a36Sopenharmony_ci if (STps->drv_file >= 0) 144162306a36Sopenharmony_ci STps->drv_file++; 144262306a36Sopenharmony_ci STps->drv_block = 0; 144362306a36Sopenharmony_ci STps->eof = ST_FM; 144462306a36Sopenharmony_ci } 144562306a36Sopenharmony_ci } 144662306a36Sopenharmony_ci 144762306a36Sopenharmony_ci out: 144862306a36Sopenharmony_ci if (STp->rew_at_close) { 144962306a36Sopenharmony_ci result2 = st_int_ioctl(STp, MTREW, 1); 145062306a36Sopenharmony_ci if (result == 0) 145162306a36Sopenharmony_ci result = result2; 145262306a36Sopenharmony_ci } 145362306a36Sopenharmony_ci return result; 145462306a36Sopenharmony_ci} 145562306a36Sopenharmony_ci 145662306a36Sopenharmony_ci 145762306a36Sopenharmony_ci/* Close the device and release it. BKL is not needed: this is the only thread 145862306a36Sopenharmony_ci accessing this tape. */ 145962306a36Sopenharmony_cistatic int st_release(struct inode *inode, struct file *filp) 146062306a36Sopenharmony_ci{ 146162306a36Sopenharmony_ci struct scsi_tape *STp = filp->private_data; 146262306a36Sopenharmony_ci 146362306a36Sopenharmony_ci if (STp->door_locked == ST_LOCKED_AUTO) 146462306a36Sopenharmony_ci do_door_lock(STp, 0); 146562306a36Sopenharmony_ci 146662306a36Sopenharmony_ci normalize_buffer(STp->buffer); 146762306a36Sopenharmony_ci spin_lock(&st_use_lock); 146862306a36Sopenharmony_ci STp->in_use = 0; 146962306a36Sopenharmony_ci spin_unlock(&st_use_lock); 147062306a36Sopenharmony_ci scsi_autopm_put_device(STp->device); 147162306a36Sopenharmony_ci scsi_tape_put(STp); 147262306a36Sopenharmony_ci 147362306a36Sopenharmony_ci return 0; 147462306a36Sopenharmony_ci} 147562306a36Sopenharmony_ci 147662306a36Sopenharmony_ci/* The checks common to both reading and writing */ 147762306a36Sopenharmony_cistatic ssize_t rw_checks(struct scsi_tape *STp, struct file *filp, size_t count) 147862306a36Sopenharmony_ci{ 147962306a36Sopenharmony_ci ssize_t retval = 0; 148062306a36Sopenharmony_ci 148162306a36Sopenharmony_ci /* 148262306a36Sopenharmony_ci * If we are in the middle of error recovery, don't let anyone 148362306a36Sopenharmony_ci * else try and use this device. Also, if error recovery fails, it 148462306a36Sopenharmony_ci * may try and take the device offline, in which case all further 148562306a36Sopenharmony_ci * access to the device is prohibited. 148662306a36Sopenharmony_ci */ 148762306a36Sopenharmony_ci if (!scsi_block_when_processing_errors(STp->device)) { 148862306a36Sopenharmony_ci retval = (-ENXIO); 148962306a36Sopenharmony_ci goto out; 149062306a36Sopenharmony_ci } 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_ci if (STp->ready != ST_READY) { 149362306a36Sopenharmony_ci if (STp->ready == ST_NO_TAPE) 149462306a36Sopenharmony_ci retval = (-ENOMEDIUM); 149562306a36Sopenharmony_ci else 149662306a36Sopenharmony_ci retval = (-EIO); 149762306a36Sopenharmony_ci goto out; 149862306a36Sopenharmony_ci } 149962306a36Sopenharmony_ci 150062306a36Sopenharmony_ci if (! STp->modes[STp->current_mode].defined) { 150162306a36Sopenharmony_ci retval = (-ENXIO); 150262306a36Sopenharmony_ci goto out; 150362306a36Sopenharmony_ci } 150462306a36Sopenharmony_ci 150562306a36Sopenharmony_ci 150662306a36Sopenharmony_ci /* 150762306a36Sopenharmony_ci * If there was a bus reset, block further access 150862306a36Sopenharmony_ci * to this device. 150962306a36Sopenharmony_ci */ 151062306a36Sopenharmony_ci if (STp->pos_unknown) { 151162306a36Sopenharmony_ci retval = (-EIO); 151262306a36Sopenharmony_ci goto out; 151362306a36Sopenharmony_ci } 151462306a36Sopenharmony_ci 151562306a36Sopenharmony_ci if (count == 0) 151662306a36Sopenharmony_ci goto out; 151762306a36Sopenharmony_ci 151862306a36Sopenharmony_ci DEB( 151962306a36Sopenharmony_ci if (!STp->in_use) { 152062306a36Sopenharmony_ci st_printk(ST_DEB_MSG, STp, 152162306a36Sopenharmony_ci "Incorrect device.\n"); 152262306a36Sopenharmony_ci retval = (-EIO); 152362306a36Sopenharmony_ci goto out; 152462306a36Sopenharmony_ci } ) /* end DEB */ 152562306a36Sopenharmony_ci 152662306a36Sopenharmony_ci if (STp->can_partitions && 152762306a36Sopenharmony_ci (retval = switch_partition(STp)) < 0) 152862306a36Sopenharmony_ci goto out; 152962306a36Sopenharmony_ci 153062306a36Sopenharmony_ci if (STp->block_size == 0 && STp->max_block > 0 && 153162306a36Sopenharmony_ci (count < STp->min_block || count > STp->max_block)) { 153262306a36Sopenharmony_ci retval = (-EINVAL); 153362306a36Sopenharmony_ci goto out; 153462306a36Sopenharmony_ci } 153562306a36Sopenharmony_ci 153662306a36Sopenharmony_ci if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED && 153762306a36Sopenharmony_ci !do_door_lock(STp, 1)) 153862306a36Sopenharmony_ci STp->door_locked = ST_LOCKED_AUTO; 153962306a36Sopenharmony_ci 154062306a36Sopenharmony_ci out: 154162306a36Sopenharmony_ci return retval; 154262306a36Sopenharmony_ci} 154362306a36Sopenharmony_ci 154462306a36Sopenharmony_ci 154562306a36Sopenharmony_cistatic int setup_buffering(struct scsi_tape *STp, const char __user *buf, 154662306a36Sopenharmony_ci size_t count, int is_read) 154762306a36Sopenharmony_ci{ 154862306a36Sopenharmony_ci int i, bufsize, retval = 0; 154962306a36Sopenharmony_ci struct st_buffer *STbp = STp->buffer; 155062306a36Sopenharmony_ci 155162306a36Sopenharmony_ci if (is_read) 155262306a36Sopenharmony_ci i = STp->try_dio_now && try_rdio; 155362306a36Sopenharmony_ci else 155462306a36Sopenharmony_ci i = STp->try_dio_now && try_wdio; 155562306a36Sopenharmony_ci 155662306a36Sopenharmony_ci if (i && ((unsigned long)buf & queue_dma_alignment( 155762306a36Sopenharmony_ci STp->device->request_queue)) == 0) { 155862306a36Sopenharmony_ci i = sgl_map_user_pages(STbp, STbp->use_sg, (unsigned long)buf, 155962306a36Sopenharmony_ci count, (is_read ? READ : WRITE)); 156062306a36Sopenharmony_ci if (i > 0) { 156162306a36Sopenharmony_ci STbp->do_dio = i; 156262306a36Sopenharmony_ci STbp->buffer_bytes = 0; /* can be used as transfer counter */ 156362306a36Sopenharmony_ci } 156462306a36Sopenharmony_ci else 156562306a36Sopenharmony_ci STbp->do_dio = 0; /* fall back to buffering with any error */ 156662306a36Sopenharmony_ci STbp->sg_segs = STbp->do_dio; 156762306a36Sopenharmony_ci DEB( 156862306a36Sopenharmony_ci if (STbp->do_dio) { 156962306a36Sopenharmony_ci STp->nbr_dio++; 157062306a36Sopenharmony_ci STp->nbr_pages += STbp->do_dio; 157162306a36Sopenharmony_ci } 157262306a36Sopenharmony_ci ) 157362306a36Sopenharmony_ci } else 157462306a36Sopenharmony_ci STbp->do_dio = 0; 157562306a36Sopenharmony_ci DEB( STp->nbr_requests++; ) 157662306a36Sopenharmony_ci 157762306a36Sopenharmony_ci if (!STbp->do_dio) { 157862306a36Sopenharmony_ci if (STp->block_size) 157962306a36Sopenharmony_ci bufsize = STp->block_size > st_fixed_buffer_size ? 158062306a36Sopenharmony_ci STp->block_size : st_fixed_buffer_size; 158162306a36Sopenharmony_ci else { 158262306a36Sopenharmony_ci bufsize = count; 158362306a36Sopenharmony_ci /* Make sure that data from previous user is not leaked even if 158462306a36Sopenharmony_ci HBA does not return correct residual */ 158562306a36Sopenharmony_ci if (is_read && STp->sili && !STbp->cleared) 158662306a36Sopenharmony_ci clear_buffer(STbp); 158762306a36Sopenharmony_ci } 158862306a36Sopenharmony_ci 158962306a36Sopenharmony_ci if (bufsize > STbp->buffer_size && 159062306a36Sopenharmony_ci !enlarge_buffer(STbp, bufsize)) { 159162306a36Sopenharmony_ci st_printk(KERN_WARNING, STp, 159262306a36Sopenharmony_ci "Can't allocate %d byte tape buffer.\n", 159362306a36Sopenharmony_ci bufsize); 159462306a36Sopenharmony_ci retval = (-EOVERFLOW); 159562306a36Sopenharmony_ci goto out; 159662306a36Sopenharmony_ci } 159762306a36Sopenharmony_ci if (STp->block_size) 159862306a36Sopenharmony_ci STbp->buffer_blocks = bufsize / STp->block_size; 159962306a36Sopenharmony_ci } 160062306a36Sopenharmony_ci 160162306a36Sopenharmony_ci out: 160262306a36Sopenharmony_ci return retval; 160362306a36Sopenharmony_ci} 160462306a36Sopenharmony_ci 160562306a36Sopenharmony_ci 160662306a36Sopenharmony_ci/* Can be called more than once after each setup_buffer() */ 160762306a36Sopenharmony_cistatic void release_buffering(struct scsi_tape *STp, int is_read) 160862306a36Sopenharmony_ci{ 160962306a36Sopenharmony_ci struct st_buffer *STbp; 161062306a36Sopenharmony_ci 161162306a36Sopenharmony_ci STbp = STp->buffer; 161262306a36Sopenharmony_ci if (STbp->do_dio) { 161362306a36Sopenharmony_ci sgl_unmap_user_pages(STbp, STbp->do_dio, is_read); 161462306a36Sopenharmony_ci STbp->do_dio = 0; 161562306a36Sopenharmony_ci STbp->sg_segs = 0; 161662306a36Sopenharmony_ci } 161762306a36Sopenharmony_ci} 161862306a36Sopenharmony_ci 161962306a36Sopenharmony_ci 162062306a36Sopenharmony_ci/* Write command */ 162162306a36Sopenharmony_cistatic ssize_t 162262306a36Sopenharmony_cist_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos) 162362306a36Sopenharmony_ci{ 162462306a36Sopenharmony_ci ssize_t total; 162562306a36Sopenharmony_ci ssize_t i, do_count, blks, transfer; 162662306a36Sopenharmony_ci ssize_t retval; 162762306a36Sopenharmony_ci int undone, retry_eot = 0, scode; 162862306a36Sopenharmony_ci int async_write; 162962306a36Sopenharmony_ci unsigned char cmd[MAX_COMMAND_SIZE]; 163062306a36Sopenharmony_ci const char __user *b_point; 163162306a36Sopenharmony_ci struct st_request *SRpnt = NULL; 163262306a36Sopenharmony_ci struct scsi_tape *STp = filp->private_data; 163362306a36Sopenharmony_ci struct st_modedef *STm; 163462306a36Sopenharmony_ci struct st_partstat *STps; 163562306a36Sopenharmony_ci struct st_buffer *STbp; 163662306a36Sopenharmony_ci 163762306a36Sopenharmony_ci if (mutex_lock_interruptible(&STp->lock)) 163862306a36Sopenharmony_ci return -ERESTARTSYS; 163962306a36Sopenharmony_ci 164062306a36Sopenharmony_ci retval = rw_checks(STp, filp, count); 164162306a36Sopenharmony_ci if (retval || count == 0) 164262306a36Sopenharmony_ci goto out; 164362306a36Sopenharmony_ci 164462306a36Sopenharmony_ci /* Write must be integral number of blocks */ 164562306a36Sopenharmony_ci if (STp->block_size != 0 && (count % STp->block_size) != 0) { 164662306a36Sopenharmony_ci st_printk(KERN_WARNING, STp, 164762306a36Sopenharmony_ci "Write not multiple of tape block size.\n"); 164862306a36Sopenharmony_ci retval = (-EINVAL); 164962306a36Sopenharmony_ci goto out; 165062306a36Sopenharmony_ci } 165162306a36Sopenharmony_ci 165262306a36Sopenharmony_ci STm = &(STp->modes[STp->current_mode]); 165362306a36Sopenharmony_ci STps = &(STp->ps[STp->partition]); 165462306a36Sopenharmony_ci 165562306a36Sopenharmony_ci if (STp->write_prot) { 165662306a36Sopenharmony_ci retval = (-EACCES); 165762306a36Sopenharmony_ci goto out; 165862306a36Sopenharmony_ci } 165962306a36Sopenharmony_ci 166062306a36Sopenharmony_ci 166162306a36Sopenharmony_ci if (STps->rw == ST_READING) { 166262306a36Sopenharmony_ci retval = flush_buffer(STp, 0); 166362306a36Sopenharmony_ci if (retval) 166462306a36Sopenharmony_ci goto out; 166562306a36Sopenharmony_ci STps->rw = ST_WRITING; 166662306a36Sopenharmony_ci } else if (STps->rw != ST_WRITING && 166762306a36Sopenharmony_ci STps->drv_file == 0 && STps->drv_block == 0) { 166862306a36Sopenharmony_ci if ((retval = set_mode_densblk(STp, STm)) < 0) 166962306a36Sopenharmony_ci goto out; 167062306a36Sopenharmony_ci if (STm->default_compression != ST_DONT_TOUCH && 167162306a36Sopenharmony_ci !(STp->compression_changed)) { 167262306a36Sopenharmony_ci if (st_compression(STp, (STm->default_compression == ST_YES))) { 167362306a36Sopenharmony_ci st_printk(KERN_WARNING, STp, 167462306a36Sopenharmony_ci "Can't set default compression.\n"); 167562306a36Sopenharmony_ci if (modes_defined) { 167662306a36Sopenharmony_ci retval = (-EINVAL); 167762306a36Sopenharmony_ci goto out; 167862306a36Sopenharmony_ci } 167962306a36Sopenharmony_ci } 168062306a36Sopenharmony_ci } 168162306a36Sopenharmony_ci } 168262306a36Sopenharmony_ci 168362306a36Sopenharmony_ci STbp = STp->buffer; 168462306a36Sopenharmony_ci i = write_behind_check(STp); 168562306a36Sopenharmony_ci if (i) { 168662306a36Sopenharmony_ci if (i == -ENOSPC) 168762306a36Sopenharmony_ci STps->eof = ST_EOM_OK; 168862306a36Sopenharmony_ci else 168962306a36Sopenharmony_ci STps->eof = ST_EOM_ERROR; 169062306a36Sopenharmony_ci } 169162306a36Sopenharmony_ci 169262306a36Sopenharmony_ci if (STps->eof == ST_EOM_OK) { 169362306a36Sopenharmony_ci STps->eof = ST_EOD_1; /* allow next write */ 169462306a36Sopenharmony_ci retval = (-ENOSPC); 169562306a36Sopenharmony_ci goto out; 169662306a36Sopenharmony_ci } 169762306a36Sopenharmony_ci else if (STps->eof == ST_EOM_ERROR) { 169862306a36Sopenharmony_ci retval = (-EIO); 169962306a36Sopenharmony_ci goto out; 170062306a36Sopenharmony_ci } 170162306a36Sopenharmony_ci 170262306a36Sopenharmony_ci /* Check the buffer readability in cases where copy_user might catch 170362306a36Sopenharmony_ci the problems after some tape movement. */ 170462306a36Sopenharmony_ci if (STp->block_size != 0 && 170562306a36Sopenharmony_ci !STbp->do_dio && 170662306a36Sopenharmony_ci (copy_from_user(&i, buf, 1) != 0 || 170762306a36Sopenharmony_ci copy_from_user(&i, buf + count - 1, 1) != 0)) { 170862306a36Sopenharmony_ci retval = (-EFAULT); 170962306a36Sopenharmony_ci goto out; 171062306a36Sopenharmony_ci } 171162306a36Sopenharmony_ci 171262306a36Sopenharmony_ci retval = setup_buffering(STp, buf, count, 0); 171362306a36Sopenharmony_ci if (retval) 171462306a36Sopenharmony_ci goto out; 171562306a36Sopenharmony_ci 171662306a36Sopenharmony_ci total = count; 171762306a36Sopenharmony_ci 171862306a36Sopenharmony_ci memset(cmd, 0, MAX_COMMAND_SIZE); 171962306a36Sopenharmony_ci cmd[0] = WRITE_6; 172062306a36Sopenharmony_ci cmd[1] = (STp->block_size != 0); 172162306a36Sopenharmony_ci 172262306a36Sopenharmony_ci STps->rw = ST_WRITING; 172362306a36Sopenharmony_ci 172462306a36Sopenharmony_ci b_point = buf; 172562306a36Sopenharmony_ci while (count > 0 && !retry_eot) { 172662306a36Sopenharmony_ci 172762306a36Sopenharmony_ci if (STbp->do_dio) { 172862306a36Sopenharmony_ci do_count = count; 172962306a36Sopenharmony_ci } 173062306a36Sopenharmony_ci else { 173162306a36Sopenharmony_ci if (STp->block_size == 0) 173262306a36Sopenharmony_ci do_count = count; 173362306a36Sopenharmony_ci else { 173462306a36Sopenharmony_ci do_count = STbp->buffer_blocks * STp->block_size - 173562306a36Sopenharmony_ci STbp->buffer_bytes; 173662306a36Sopenharmony_ci if (do_count > count) 173762306a36Sopenharmony_ci do_count = count; 173862306a36Sopenharmony_ci } 173962306a36Sopenharmony_ci 174062306a36Sopenharmony_ci i = append_to_buffer(b_point, STbp, do_count); 174162306a36Sopenharmony_ci if (i) { 174262306a36Sopenharmony_ci retval = i; 174362306a36Sopenharmony_ci goto out; 174462306a36Sopenharmony_ci } 174562306a36Sopenharmony_ci } 174662306a36Sopenharmony_ci count -= do_count; 174762306a36Sopenharmony_ci b_point += do_count; 174862306a36Sopenharmony_ci 174962306a36Sopenharmony_ci async_write = STp->block_size == 0 && !STbp->do_dio && 175062306a36Sopenharmony_ci STm->do_async_writes && STps->eof < ST_EOM_OK; 175162306a36Sopenharmony_ci 175262306a36Sopenharmony_ci if (STp->block_size != 0 && STm->do_buffer_writes && 175362306a36Sopenharmony_ci !(STp->try_dio_now && try_wdio) && STps->eof < ST_EOM_OK && 175462306a36Sopenharmony_ci STbp->buffer_bytes < STbp->buffer_size) { 175562306a36Sopenharmony_ci STp->dirty = 1; 175662306a36Sopenharmony_ci /* Don't write a buffer that is not full enough. */ 175762306a36Sopenharmony_ci if (!async_write && count == 0) 175862306a36Sopenharmony_ci break; 175962306a36Sopenharmony_ci } 176062306a36Sopenharmony_ci 176162306a36Sopenharmony_ci retry_write: 176262306a36Sopenharmony_ci if (STp->block_size == 0) 176362306a36Sopenharmony_ci blks = transfer = do_count; 176462306a36Sopenharmony_ci else { 176562306a36Sopenharmony_ci if (!STbp->do_dio) 176662306a36Sopenharmony_ci blks = STbp->buffer_bytes; 176762306a36Sopenharmony_ci else 176862306a36Sopenharmony_ci blks = do_count; 176962306a36Sopenharmony_ci blks /= STp->block_size; 177062306a36Sopenharmony_ci transfer = blks * STp->block_size; 177162306a36Sopenharmony_ci } 177262306a36Sopenharmony_ci cmd[2] = blks >> 16; 177362306a36Sopenharmony_ci cmd[3] = blks >> 8; 177462306a36Sopenharmony_ci cmd[4] = blks; 177562306a36Sopenharmony_ci 177662306a36Sopenharmony_ci SRpnt = st_do_scsi(SRpnt, STp, cmd, transfer, DMA_TO_DEVICE, 177762306a36Sopenharmony_ci STp->device->request_queue->rq_timeout, 177862306a36Sopenharmony_ci MAX_WRITE_RETRIES, !async_write); 177962306a36Sopenharmony_ci if (!SRpnt) { 178062306a36Sopenharmony_ci retval = STbp->syscall_result; 178162306a36Sopenharmony_ci goto out; 178262306a36Sopenharmony_ci } 178362306a36Sopenharmony_ci if (async_write && !STbp->syscall_result) { 178462306a36Sopenharmony_ci STbp->writing = transfer; 178562306a36Sopenharmony_ci STp->dirty = !(STbp->writing == 178662306a36Sopenharmony_ci STbp->buffer_bytes); 178762306a36Sopenharmony_ci SRpnt = NULL; /* Prevent releasing this request! */ 178862306a36Sopenharmony_ci DEB( STp->write_pending = 1; ) 178962306a36Sopenharmony_ci break; 179062306a36Sopenharmony_ci } 179162306a36Sopenharmony_ci 179262306a36Sopenharmony_ci if (STbp->syscall_result != 0) { 179362306a36Sopenharmony_ci struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat; 179462306a36Sopenharmony_ci 179562306a36Sopenharmony_ci DEBC_printk(STp, "Error on write:\n"); 179662306a36Sopenharmony_ci if (cmdstatp->have_sense && (cmdstatp->flags & SENSE_EOM)) { 179762306a36Sopenharmony_ci scode = cmdstatp->sense_hdr.sense_key; 179862306a36Sopenharmony_ci if (cmdstatp->remainder_valid) 179962306a36Sopenharmony_ci undone = (int)cmdstatp->uremainder64; 180062306a36Sopenharmony_ci else if (STp->block_size == 0 && 180162306a36Sopenharmony_ci scode == VOLUME_OVERFLOW) 180262306a36Sopenharmony_ci undone = transfer; 180362306a36Sopenharmony_ci else 180462306a36Sopenharmony_ci undone = 0; 180562306a36Sopenharmony_ci if (STp->block_size != 0) 180662306a36Sopenharmony_ci undone *= STp->block_size; 180762306a36Sopenharmony_ci if (undone <= do_count) { 180862306a36Sopenharmony_ci /* Only data from this write is not written */ 180962306a36Sopenharmony_ci count += undone; 181062306a36Sopenharmony_ci b_point -= undone; 181162306a36Sopenharmony_ci do_count -= undone; 181262306a36Sopenharmony_ci if (STp->block_size) 181362306a36Sopenharmony_ci blks = (transfer - undone) / STp->block_size; 181462306a36Sopenharmony_ci STps->eof = ST_EOM_OK; 181562306a36Sopenharmony_ci /* Continue in fixed block mode if all written 181662306a36Sopenharmony_ci in this request but still something left to write 181762306a36Sopenharmony_ci (retval left to zero) 181862306a36Sopenharmony_ci */ 181962306a36Sopenharmony_ci if (STp->block_size == 0 || 182062306a36Sopenharmony_ci undone > 0 || count == 0) 182162306a36Sopenharmony_ci retval = (-ENOSPC); /* EOM within current request */ 182262306a36Sopenharmony_ci DEBC_printk(STp, "EOM with %d " 182362306a36Sopenharmony_ci "bytes unwritten.\n", 182462306a36Sopenharmony_ci (int)count); 182562306a36Sopenharmony_ci } else { 182662306a36Sopenharmony_ci /* EOT within data buffered earlier (possible only 182762306a36Sopenharmony_ci in fixed block mode without direct i/o) */ 182862306a36Sopenharmony_ci if (!retry_eot && !cmdstatp->deferred && 182962306a36Sopenharmony_ci (scode == NO_SENSE || scode == RECOVERED_ERROR)) { 183062306a36Sopenharmony_ci move_buffer_data(STp->buffer, transfer - undone); 183162306a36Sopenharmony_ci retry_eot = 1; 183262306a36Sopenharmony_ci if (STps->drv_block >= 0) { 183362306a36Sopenharmony_ci STps->drv_block += (transfer - undone) / 183462306a36Sopenharmony_ci STp->block_size; 183562306a36Sopenharmony_ci } 183662306a36Sopenharmony_ci STps->eof = ST_EOM_OK; 183762306a36Sopenharmony_ci DEBC_printk(STp, "Retry " 183862306a36Sopenharmony_ci "write of %d " 183962306a36Sopenharmony_ci "bytes at EOM.\n", 184062306a36Sopenharmony_ci STp->buffer->buffer_bytes); 184162306a36Sopenharmony_ci goto retry_write; 184262306a36Sopenharmony_ci } 184362306a36Sopenharmony_ci else { 184462306a36Sopenharmony_ci /* Either error within data buffered by driver or 184562306a36Sopenharmony_ci failed retry */ 184662306a36Sopenharmony_ci count -= do_count; 184762306a36Sopenharmony_ci blks = do_count = 0; 184862306a36Sopenharmony_ci STps->eof = ST_EOM_ERROR; 184962306a36Sopenharmony_ci STps->drv_block = (-1); /* Too cautious? */ 185062306a36Sopenharmony_ci retval = (-EIO); /* EOM for old data */ 185162306a36Sopenharmony_ci DEBC_printk(STp, "EOM with " 185262306a36Sopenharmony_ci "lost data.\n"); 185362306a36Sopenharmony_ci } 185462306a36Sopenharmony_ci } 185562306a36Sopenharmony_ci } else { 185662306a36Sopenharmony_ci count += do_count; 185762306a36Sopenharmony_ci STps->drv_block = (-1); /* Too cautious? */ 185862306a36Sopenharmony_ci retval = STbp->syscall_result; 185962306a36Sopenharmony_ci } 186062306a36Sopenharmony_ci 186162306a36Sopenharmony_ci } 186262306a36Sopenharmony_ci 186362306a36Sopenharmony_ci if (STps->drv_block >= 0) { 186462306a36Sopenharmony_ci if (STp->block_size == 0) 186562306a36Sopenharmony_ci STps->drv_block += (do_count > 0); 186662306a36Sopenharmony_ci else 186762306a36Sopenharmony_ci STps->drv_block += blks; 186862306a36Sopenharmony_ci } 186962306a36Sopenharmony_ci 187062306a36Sopenharmony_ci STbp->buffer_bytes = 0; 187162306a36Sopenharmony_ci STp->dirty = 0; 187262306a36Sopenharmony_ci 187362306a36Sopenharmony_ci if (retval || retry_eot) { 187462306a36Sopenharmony_ci if (count < total) 187562306a36Sopenharmony_ci retval = total - count; 187662306a36Sopenharmony_ci goto out; 187762306a36Sopenharmony_ci } 187862306a36Sopenharmony_ci } 187962306a36Sopenharmony_ci 188062306a36Sopenharmony_ci if (STps->eof == ST_EOD_1) 188162306a36Sopenharmony_ci STps->eof = ST_EOM_OK; 188262306a36Sopenharmony_ci else if (STps->eof != ST_EOM_OK) 188362306a36Sopenharmony_ci STps->eof = ST_NOEOF; 188462306a36Sopenharmony_ci retval = total - count; 188562306a36Sopenharmony_ci 188662306a36Sopenharmony_ci out: 188762306a36Sopenharmony_ci if (SRpnt != NULL) 188862306a36Sopenharmony_ci st_release_request(SRpnt); 188962306a36Sopenharmony_ci release_buffering(STp, 0); 189062306a36Sopenharmony_ci mutex_unlock(&STp->lock); 189162306a36Sopenharmony_ci 189262306a36Sopenharmony_ci return retval; 189362306a36Sopenharmony_ci} 189462306a36Sopenharmony_ci 189562306a36Sopenharmony_ci/* Read data from the tape. Returns zero in the normal case, one if the 189662306a36Sopenharmony_ci eof status has changed, and the negative error code in case of a 189762306a36Sopenharmony_ci fatal error. Otherwise updates the buffer and the eof state. 189862306a36Sopenharmony_ci 189962306a36Sopenharmony_ci Does release user buffer mapping if it is set. 190062306a36Sopenharmony_ci*/ 190162306a36Sopenharmony_cistatic long read_tape(struct scsi_tape *STp, long count, 190262306a36Sopenharmony_ci struct st_request ** aSRpnt) 190362306a36Sopenharmony_ci{ 190462306a36Sopenharmony_ci int transfer, blks, bytes; 190562306a36Sopenharmony_ci unsigned char cmd[MAX_COMMAND_SIZE]; 190662306a36Sopenharmony_ci struct st_request *SRpnt; 190762306a36Sopenharmony_ci struct st_modedef *STm; 190862306a36Sopenharmony_ci struct st_partstat *STps; 190962306a36Sopenharmony_ci struct st_buffer *STbp; 191062306a36Sopenharmony_ci int retval = 0; 191162306a36Sopenharmony_ci 191262306a36Sopenharmony_ci if (count == 0) 191362306a36Sopenharmony_ci return 0; 191462306a36Sopenharmony_ci 191562306a36Sopenharmony_ci STm = &(STp->modes[STp->current_mode]); 191662306a36Sopenharmony_ci STps = &(STp->ps[STp->partition]); 191762306a36Sopenharmony_ci if (STps->eof == ST_FM_HIT) 191862306a36Sopenharmony_ci return 1; 191962306a36Sopenharmony_ci STbp = STp->buffer; 192062306a36Sopenharmony_ci 192162306a36Sopenharmony_ci if (STp->block_size == 0) 192262306a36Sopenharmony_ci blks = bytes = count; 192362306a36Sopenharmony_ci else { 192462306a36Sopenharmony_ci if (!(STp->try_dio_now && try_rdio) && STm->do_read_ahead) { 192562306a36Sopenharmony_ci blks = (STp->buffer)->buffer_blocks; 192662306a36Sopenharmony_ci bytes = blks * STp->block_size; 192762306a36Sopenharmony_ci } else { 192862306a36Sopenharmony_ci bytes = count; 192962306a36Sopenharmony_ci if (!STbp->do_dio && bytes > (STp->buffer)->buffer_size) 193062306a36Sopenharmony_ci bytes = (STp->buffer)->buffer_size; 193162306a36Sopenharmony_ci blks = bytes / STp->block_size; 193262306a36Sopenharmony_ci bytes = blks * STp->block_size; 193362306a36Sopenharmony_ci } 193462306a36Sopenharmony_ci } 193562306a36Sopenharmony_ci 193662306a36Sopenharmony_ci memset(cmd, 0, MAX_COMMAND_SIZE); 193762306a36Sopenharmony_ci cmd[0] = READ_6; 193862306a36Sopenharmony_ci cmd[1] = (STp->block_size != 0); 193962306a36Sopenharmony_ci if (!cmd[1] && STp->sili) 194062306a36Sopenharmony_ci cmd[1] |= 2; 194162306a36Sopenharmony_ci cmd[2] = blks >> 16; 194262306a36Sopenharmony_ci cmd[3] = blks >> 8; 194362306a36Sopenharmony_ci cmd[4] = blks; 194462306a36Sopenharmony_ci 194562306a36Sopenharmony_ci SRpnt = *aSRpnt; 194662306a36Sopenharmony_ci SRpnt = st_do_scsi(SRpnt, STp, cmd, bytes, DMA_FROM_DEVICE, 194762306a36Sopenharmony_ci STp->device->request_queue->rq_timeout, 194862306a36Sopenharmony_ci MAX_RETRIES, 1); 194962306a36Sopenharmony_ci release_buffering(STp, 1); 195062306a36Sopenharmony_ci *aSRpnt = SRpnt; 195162306a36Sopenharmony_ci if (!SRpnt) 195262306a36Sopenharmony_ci return STbp->syscall_result; 195362306a36Sopenharmony_ci 195462306a36Sopenharmony_ci STbp->read_pointer = 0; 195562306a36Sopenharmony_ci STps->at_sm = 0; 195662306a36Sopenharmony_ci 195762306a36Sopenharmony_ci /* Something to check */ 195862306a36Sopenharmony_ci if (STbp->syscall_result) { 195962306a36Sopenharmony_ci struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat; 196062306a36Sopenharmony_ci 196162306a36Sopenharmony_ci retval = 1; 196262306a36Sopenharmony_ci DEBC_printk(STp, 196362306a36Sopenharmony_ci "Sense: %2x %2x %2x %2x %2x %2x %2x %2x\n", 196462306a36Sopenharmony_ci SRpnt->sense[0], SRpnt->sense[1], 196562306a36Sopenharmony_ci SRpnt->sense[2], SRpnt->sense[3], 196662306a36Sopenharmony_ci SRpnt->sense[4], SRpnt->sense[5], 196762306a36Sopenharmony_ci SRpnt->sense[6], SRpnt->sense[7]); 196862306a36Sopenharmony_ci if (cmdstatp->have_sense) { 196962306a36Sopenharmony_ci 197062306a36Sopenharmony_ci if (cmdstatp->sense_hdr.sense_key == BLANK_CHECK) 197162306a36Sopenharmony_ci cmdstatp->flags &= 0xcf; /* No need for EOM in this case */ 197262306a36Sopenharmony_ci 197362306a36Sopenharmony_ci if (cmdstatp->flags != 0) { /* EOF, EOM, or ILI */ 197462306a36Sopenharmony_ci /* Compute the residual count */ 197562306a36Sopenharmony_ci if (cmdstatp->remainder_valid) 197662306a36Sopenharmony_ci transfer = (int)cmdstatp->uremainder64; 197762306a36Sopenharmony_ci else 197862306a36Sopenharmony_ci transfer = 0; 197962306a36Sopenharmony_ci if (cmdstatp->sense_hdr.sense_key == MEDIUM_ERROR) { 198062306a36Sopenharmony_ci if (STp->block_size == 0) 198162306a36Sopenharmony_ci transfer = bytes; 198262306a36Sopenharmony_ci /* Some drives set ILI with MEDIUM ERROR */ 198362306a36Sopenharmony_ci cmdstatp->flags &= ~SENSE_ILI; 198462306a36Sopenharmony_ci } 198562306a36Sopenharmony_ci 198662306a36Sopenharmony_ci if (cmdstatp->flags & SENSE_ILI) { /* ILI */ 198762306a36Sopenharmony_ci if (STp->block_size == 0 && 198862306a36Sopenharmony_ci transfer < 0) { 198962306a36Sopenharmony_ci st_printk(KERN_NOTICE, STp, 199062306a36Sopenharmony_ci "Failed to read %d " 199162306a36Sopenharmony_ci "byte block with %d " 199262306a36Sopenharmony_ci "byte transfer.\n", 199362306a36Sopenharmony_ci bytes - transfer, 199462306a36Sopenharmony_ci bytes); 199562306a36Sopenharmony_ci if (STps->drv_block >= 0) 199662306a36Sopenharmony_ci STps->drv_block += 1; 199762306a36Sopenharmony_ci STbp->buffer_bytes = 0; 199862306a36Sopenharmony_ci return (-ENOMEM); 199962306a36Sopenharmony_ci } else if (STp->block_size == 0) { 200062306a36Sopenharmony_ci STbp->buffer_bytes = bytes - transfer; 200162306a36Sopenharmony_ci } else { 200262306a36Sopenharmony_ci st_release_request(SRpnt); 200362306a36Sopenharmony_ci SRpnt = *aSRpnt = NULL; 200462306a36Sopenharmony_ci if (transfer == blks) { /* We did not get anything, error */ 200562306a36Sopenharmony_ci st_printk(KERN_NOTICE, STp, 200662306a36Sopenharmony_ci "Incorrect " 200762306a36Sopenharmony_ci "block size.\n"); 200862306a36Sopenharmony_ci if (STps->drv_block >= 0) 200962306a36Sopenharmony_ci STps->drv_block += blks - transfer + 1; 201062306a36Sopenharmony_ci st_int_ioctl(STp, MTBSR, 1); 201162306a36Sopenharmony_ci return (-EIO); 201262306a36Sopenharmony_ci } 201362306a36Sopenharmony_ci /* We have some data, deliver it */ 201462306a36Sopenharmony_ci STbp->buffer_bytes = (blks - transfer) * 201562306a36Sopenharmony_ci STp->block_size; 201662306a36Sopenharmony_ci DEBC_printk(STp, "ILI but " 201762306a36Sopenharmony_ci "enough data " 201862306a36Sopenharmony_ci "received %ld " 201962306a36Sopenharmony_ci "%d.\n", count, 202062306a36Sopenharmony_ci STbp->buffer_bytes); 202162306a36Sopenharmony_ci if (STps->drv_block >= 0) 202262306a36Sopenharmony_ci STps->drv_block += 1; 202362306a36Sopenharmony_ci if (st_int_ioctl(STp, MTBSR, 1)) 202462306a36Sopenharmony_ci return (-EIO); 202562306a36Sopenharmony_ci } 202662306a36Sopenharmony_ci } else if (cmdstatp->flags & SENSE_FMK) { /* FM overrides EOM */ 202762306a36Sopenharmony_ci if (STps->eof != ST_FM_HIT) 202862306a36Sopenharmony_ci STps->eof = ST_FM_HIT; 202962306a36Sopenharmony_ci else 203062306a36Sopenharmony_ci STps->eof = ST_EOD_2; 203162306a36Sopenharmony_ci if (STp->block_size == 0) 203262306a36Sopenharmony_ci STbp->buffer_bytes = 0; 203362306a36Sopenharmony_ci else 203462306a36Sopenharmony_ci STbp->buffer_bytes = 203562306a36Sopenharmony_ci bytes - transfer * STp->block_size; 203662306a36Sopenharmony_ci DEBC_printk(STp, "EOF detected (%d " 203762306a36Sopenharmony_ci "bytes read).\n", 203862306a36Sopenharmony_ci STbp->buffer_bytes); 203962306a36Sopenharmony_ci } else if (cmdstatp->flags & SENSE_EOM) { 204062306a36Sopenharmony_ci if (STps->eof == ST_FM) 204162306a36Sopenharmony_ci STps->eof = ST_EOD_1; 204262306a36Sopenharmony_ci else 204362306a36Sopenharmony_ci STps->eof = ST_EOM_OK; 204462306a36Sopenharmony_ci if (STp->block_size == 0) 204562306a36Sopenharmony_ci STbp->buffer_bytes = bytes - transfer; 204662306a36Sopenharmony_ci else 204762306a36Sopenharmony_ci STbp->buffer_bytes = 204862306a36Sopenharmony_ci bytes - transfer * STp->block_size; 204962306a36Sopenharmony_ci 205062306a36Sopenharmony_ci DEBC_printk(STp, "EOM detected (%d " 205162306a36Sopenharmony_ci "bytes read).\n", 205262306a36Sopenharmony_ci STbp->buffer_bytes); 205362306a36Sopenharmony_ci } 205462306a36Sopenharmony_ci } 205562306a36Sopenharmony_ci /* end of EOF, EOM, ILI test */ 205662306a36Sopenharmony_ci else { /* nonzero sense key */ 205762306a36Sopenharmony_ci DEBC_printk(STp, "Tape error while reading.\n"); 205862306a36Sopenharmony_ci STps->drv_block = (-1); 205962306a36Sopenharmony_ci if (STps->eof == ST_FM && 206062306a36Sopenharmony_ci cmdstatp->sense_hdr.sense_key == BLANK_CHECK) { 206162306a36Sopenharmony_ci DEBC_printk(STp, "Zero returned for " 206262306a36Sopenharmony_ci "first BLANK CHECK " 206362306a36Sopenharmony_ci "after EOF.\n"); 206462306a36Sopenharmony_ci STps->eof = ST_EOD_2; /* First BLANK_CHECK after FM */ 206562306a36Sopenharmony_ci } else /* Some other extended sense code */ 206662306a36Sopenharmony_ci retval = (-EIO); 206762306a36Sopenharmony_ci } 206862306a36Sopenharmony_ci 206962306a36Sopenharmony_ci if (STbp->buffer_bytes < 0) /* Caused by bogus sense data */ 207062306a36Sopenharmony_ci STbp->buffer_bytes = 0; 207162306a36Sopenharmony_ci } 207262306a36Sopenharmony_ci /* End of extended sense test */ 207362306a36Sopenharmony_ci else { /* Non-extended sense */ 207462306a36Sopenharmony_ci retval = STbp->syscall_result; 207562306a36Sopenharmony_ci } 207662306a36Sopenharmony_ci 207762306a36Sopenharmony_ci } 207862306a36Sopenharmony_ci /* End of error handling */ 207962306a36Sopenharmony_ci else { /* Read successful */ 208062306a36Sopenharmony_ci STbp->buffer_bytes = bytes; 208162306a36Sopenharmony_ci if (STp->sili) /* In fixed block mode residual is always zero here */ 208262306a36Sopenharmony_ci STbp->buffer_bytes -= STp->buffer->cmdstat.residual; 208362306a36Sopenharmony_ci } 208462306a36Sopenharmony_ci 208562306a36Sopenharmony_ci if (STps->drv_block >= 0) { 208662306a36Sopenharmony_ci if (STp->block_size == 0) 208762306a36Sopenharmony_ci STps->drv_block++; 208862306a36Sopenharmony_ci else 208962306a36Sopenharmony_ci STps->drv_block += STbp->buffer_bytes / STp->block_size; 209062306a36Sopenharmony_ci } 209162306a36Sopenharmony_ci return retval; 209262306a36Sopenharmony_ci} 209362306a36Sopenharmony_ci 209462306a36Sopenharmony_ci 209562306a36Sopenharmony_ci/* Read command */ 209662306a36Sopenharmony_cistatic ssize_t 209762306a36Sopenharmony_cist_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos) 209862306a36Sopenharmony_ci{ 209962306a36Sopenharmony_ci ssize_t total; 210062306a36Sopenharmony_ci ssize_t retval = 0; 210162306a36Sopenharmony_ci ssize_t i, transfer; 210262306a36Sopenharmony_ci int special, do_dio = 0; 210362306a36Sopenharmony_ci struct st_request *SRpnt = NULL; 210462306a36Sopenharmony_ci struct scsi_tape *STp = filp->private_data; 210562306a36Sopenharmony_ci struct st_modedef *STm; 210662306a36Sopenharmony_ci struct st_partstat *STps; 210762306a36Sopenharmony_ci struct st_buffer *STbp = STp->buffer; 210862306a36Sopenharmony_ci 210962306a36Sopenharmony_ci if (mutex_lock_interruptible(&STp->lock)) 211062306a36Sopenharmony_ci return -ERESTARTSYS; 211162306a36Sopenharmony_ci 211262306a36Sopenharmony_ci retval = rw_checks(STp, filp, count); 211362306a36Sopenharmony_ci if (retval || count == 0) 211462306a36Sopenharmony_ci goto out; 211562306a36Sopenharmony_ci 211662306a36Sopenharmony_ci STm = &(STp->modes[STp->current_mode]); 211762306a36Sopenharmony_ci if (STp->block_size != 0 && (count % STp->block_size) != 0) { 211862306a36Sopenharmony_ci if (!STm->do_read_ahead) { 211962306a36Sopenharmony_ci retval = (-EINVAL); /* Read must be integral number of blocks */ 212062306a36Sopenharmony_ci goto out; 212162306a36Sopenharmony_ci } 212262306a36Sopenharmony_ci STp->try_dio_now = 0; /* Direct i/o can't handle split blocks */ 212362306a36Sopenharmony_ci } 212462306a36Sopenharmony_ci 212562306a36Sopenharmony_ci STps = &(STp->ps[STp->partition]); 212662306a36Sopenharmony_ci if (STps->rw == ST_WRITING) { 212762306a36Sopenharmony_ci retval = flush_buffer(STp, 0); 212862306a36Sopenharmony_ci if (retval) 212962306a36Sopenharmony_ci goto out; 213062306a36Sopenharmony_ci STps->rw = ST_READING; 213162306a36Sopenharmony_ci } 213262306a36Sopenharmony_ci DEB( 213362306a36Sopenharmony_ci if (debugging && STps->eof != ST_NOEOF) 213462306a36Sopenharmony_ci st_printk(ST_DEB_MSG, STp, 213562306a36Sopenharmony_ci "EOF/EOM flag up (%d). Bytes %d\n", 213662306a36Sopenharmony_ci STps->eof, STbp->buffer_bytes); 213762306a36Sopenharmony_ci ) /* end DEB */ 213862306a36Sopenharmony_ci 213962306a36Sopenharmony_ci retval = setup_buffering(STp, buf, count, 1); 214062306a36Sopenharmony_ci if (retval) 214162306a36Sopenharmony_ci goto out; 214262306a36Sopenharmony_ci do_dio = STbp->do_dio; 214362306a36Sopenharmony_ci 214462306a36Sopenharmony_ci if (STbp->buffer_bytes == 0 && 214562306a36Sopenharmony_ci STps->eof >= ST_EOD_1) { 214662306a36Sopenharmony_ci if (STps->eof < ST_EOD) { 214762306a36Sopenharmony_ci STps->eof += 1; 214862306a36Sopenharmony_ci retval = 0; 214962306a36Sopenharmony_ci goto out; 215062306a36Sopenharmony_ci } 215162306a36Sopenharmony_ci retval = (-EIO); /* EOM or Blank Check */ 215262306a36Sopenharmony_ci goto out; 215362306a36Sopenharmony_ci } 215462306a36Sopenharmony_ci 215562306a36Sopenharmony_ci if (do_dio) { 215662306a36Sopenharmony_ci /* Check the buffer writability before any tape movement. Don't alter 215762306a36Sopenharmony_ci buffer data. */ 215862306a36Sopenharmony_ci if (copy_from_user(&i, buf, 1) != 0 || 215962306a36Sopenharmony_ci copy_to_user(buf, &i, 1) != 0 || 216062306a36Sopenharmony_ci copy_from_user(&i, buf + count - 1, 1) != 0 || 216162306a36Sopenharmony_ci copy_to_user(buf + count - 1, &i, 1) != 0) { 216262306a36Sopenharmony_ci retval = (-EFAULT); 216362306a36Sopenharmony_ci goto out; 216462306a36Sopenharmony_ci } 216562306a36Sopenharmony_ci } 216662306a36Sopenharmony_ci 216762306a36Sopenharmony_ci STps->rw = ST_READING; 216862306a36Sopenharmony_ci 216962306a36Sopenharmony_ci 217062306a36Sopenharmony_ci /* Loop until enough data in buffer or a special condition found */ 217162306a36Sopenharmony_ci for (total = 0, special = 0; total < count && !special;) { 217262306a36Sopenharmony_ci 217362306a36Sopenharmony_ci /* Get new data if the buffer is empty */ 217462306a36Sopenharmony_ci if (STbp->buffer_bytes == 0) { 217562306a36Sopenharmony_ci special = read_tape(STp, count - total, &SRpnt); 217662306a36Sopenharmony_ci if (special < 0) { /* No need to continue read */ 217762306a36Sopenharmony_ci retval = special; 217862306a36Sopenharmony_ci goto out; 217962306a36Sopenharmony_ci } 218062306a36Sopenharmony_ci } 218162306a36Sopenharmony_ci 218262306a36Sopenharmony_ci /* Move the data from driver buffer to user buffer */ 218362306a36Sopenharmony_ci if (STbp->buffer_bytes > 0) { 218462306a36Sopenharmony_ci DEB( 218562306a36Sopenharmony_ci if (debugging && STps->eof != ST_NOEOF) 218662306a36Sopenharmony_ci st_printk(ST_DEB_MSG, STp, 218762306a36Sopenharmony_ci "EOF up (%d). Left %d, needed %d.\n", 218862306a36Sopenharmony_ci STps->eof, STbp->buffer_bytes, 218962306a36Sopenharmony_ci (int)(count - total)); 219062306a36Sopenharmony_ci ) /* end DEB */ 219162306a36Sopenharmony_ci transfer = STbp->buffer_bytes < count - total ? 219262306a36Sopenharmony_ci STbp->buffer_bytes : count - total; 219362306a36Sopenharmony_ci if (!do_dio) { 219462306a36Sopenharmony_ci i = from_buffer(STbp, buf, transfer); 219562306a36Sopenharmony_ci if (i) { 219662306a36Sopenharmony_ci retval = i; 219762306a36Sopenharmony_ci goto out; 219862306a36Sopenharmony_ci } 219962306a36Sopenharmony_ci } 220062306a36Sopenharmony_ci buf += transfer; 220162306a36Sopenharmony_ci total += transfer; 220262306a36Sopenharmony_ci } 220362306a36Sopenharmony_ci 220462306a36Sopenharmony_ci if (STp->block_size == 0) 220562306a36Sopenharmony_ci break; /* Read only one variable length block */ 220662306a36Sopenharmony_ci 220762306a36Sopenharmony_ci } /* for (total = 0, special = 0; 220862306a36Sopenharmony_ci total < count && !special; ) */ 220962306a36Sopenharmony_ci 221062306a36Sopenharmony_ci /* Change the eof state if no data from tape or buffer */ 221162306a36Sopenharmony_ci if (total == 0) { 221262306a36Sopenharmony_ci if (STps->eof == ST_FM_HIT) { 221362306a36Sopenharmony_ci STps->eof = ST_FM; 221462306a36Sopenharmony_ci STps->drv_block = 0; 221562306a36Sopenharmony_ci if (STps->drv_file >= 0) 221662306a36Sopenharmony_ci STps->drv_file++; 221762306a36Sopenharmony_ci } else if (STps->eof == ST_EOD_1) { 221862306a36Sopenharmony_ci STps->eof = ST_EOD_2; 221962306a36Sopenharmony_ci STps->drv_block = 0; 222062306a36Sopenharmony_ci if (STps->drv_file >= 0) 222162306a36Sopenharmony_ci STps->drv_file++; 222262306a36Sopenharmony_ci } else if (STps->eof == ST_EOD_2) 222362306a36Sopenharmony_ci STps->eof = ST_EOD; 222462306a36Sopenharmony_ci } else if (STps->eof == ST_FM) 222562306a36Sopenharmony_ci STps->eof = ST_NOEOF; 222662306a36Sopenharmony_ci retval = total; 222762306a36Sopenharmony_ci 222862306a36Sopenharmony_ci out: 222962306a36Sopenharmony_ci if (SRpnt != NULL) { 223062306a36Sopenharmony_ci st_release_request(SRpnt); 223162306a36Sopenharmony_ci SRpnt = NULL; 223262306a36Sopenharmony_ci } 223362306a36Sopenharmony_ci if (do_dio) { 223462306a36Sopenharmony_ci release_buffering(STp, 1); 223562306a36Sopenharmony_ci STbp->buffer_bytes = 0; 223662306a36Sopenharmony_ci } 223762306a36Sopenharmony_ci mutex_unlock(&STp->lock); 223862306a36Sopenharmony_ci 223962306a36Sopenharmony_ci return retval; 224062306a36Sopenharmony_ci} 224162306a36Sopenharmony_ci 224262306a36Sopenharmony_ci 224362306a36Sopenharmony_ci 224462306a36Sopenharmony_ciDEB( 224562306a36Sopenharmony_ci/* Set the driver options */ 224662306a36Sopenharmony_cistatic void st_log_options(struct scsi_tape * STp, struct st_modedef * STm) 224762306a36Sopenharmony_ci{ 224862306a36Sopenharmony_ci if (debugging) { 224962306a36Sopenharmony_ci st_printk(KERN_INFO, STp, 225062306a36Sopenharmony_ci "Mode %d options: buffer writes: %d, " 225162306a36Sopenharmony_ci "async writes: %d, read ahead: %d\n", 225262306a36Sopenharmony_ci STp->current_mode, STm->do_buffer_writes, 225362306a36Sopenharmony_ci STm->do_async_writes, STm->do_read_ahead); 225462306a36Sopenharmony_ci st_printk(KERN_INFO, STp, 225562306a36Sopenharmony_ci " can bsr: %d, two FMs: %d, " 225662306a36Sopenharmony_ci "fast mteom: %d, auto lock: %d,\n", 225762306a36Sopenharmony_ci STp->can_bsr, STp->two_fm, STp->fast_mteom, 225862306a36Sopenharmony_ci STp->do_auto_lock); 225962306a36Sopenharmony_ci st_printk(KERN_INFO, STp, 226062306a36Sopenharmony_ci " defs for wr: %d, no block limits: %d, " 226162306a36Sopenharmony_ci "partitions: %d, s2 log: %d\n", 226262306a36Sopenharmony_ci STm->defaults_for_writes, STp->omit_blklims, 226362306a36Sopenharmony_ci STp->can_partitions, STp->scsi2_logical); 226462306a36Sopenharmony_ci st_printk(KERN_INFO, STp, 226562306a36Sopenharmony_ci " sysv: %d nowait: %d sili: %d " 226662306a36Sopenharmony_ci "nowait_filemark: %d\n", 226762306a36Sopenharmony_ci STm->sysv, STp->immediate, STp->sili, 226862306a36Sopenharmony_ci STp->immediate_filemark); 226962306a36Sopenharmony_ci st_printk(KERN_INFO, STp, " debugging: %d\n", debugging); 227062306a36Sopenharmony_ci } 227162306a36Sopenharmony_ci} 227262306a36Sopenharmony_ci ) 227362306a36Sopenharmony_ci 227462306a36Sopenharmony_ci 227562306a36Sopenharmony_cistatic int st_set_options(struct scsi_tape *STp, long options) 227662306a36Sopenharmony_ci{ 227762306a36Sopenharmony_ci int value; 227862306a36Sopenharmony_ci long code; 227962306a36Sopenharmony_ci struct st_modedef *STm; 228062306a36Sopenharmony_ci struct cdev *cd0, *cd1; 228162306a36Sopenharmony_ci struct device *d0, *d1; 228262306a36Sopenharmony_ci 228362306a36Sopenharmony_ci STm = &(STp->modes[STp->current_mode]); 228462306a36Sopenharmony_ci if (!STm->defined) { 228562306a36Sopenharmony_ci cd0 = STm->cdevs[0]; 228662306a36Sopenharmony_ci cd1 = STm->cdevs[1]; 228762306a36Sopenharmony_ci d0 = STm->devs[0]; 228862306a36Sopenharmony_ci d1 = STm->devs[1]; 228962306a36Sopenharmony_ci memcpy(STm, &(STp->modes[0]), sizeof(struct st_modedef)); 229062306a36Sopenharmony_ci STm->cdevs[0] = cd0; 229162306a36Sopenharmony_ci STm->cdevs[1] = cd1; 229262306a36Sopenharmony_ci STm->devs[0] = d0; 229362306a36Sopenharmony_ci STm->devs[1] = d1; 229462306a36Sopenharmony_ci modes_defined = 1; 229562306a36Sopenharmony_ci DEBC_printk(STp, "Initialized mode %d definition from mode 0\n", 229662306a36Sopenharmony_ci STp->current_mode); 229762306a36Sopenharmony_ci } 229862306a36Sopenharmony_ci 229962306a36Sopenharmony_ci code = options & MT_ST_OPTIONS; 230062306a36Sopenharmony_ci if (code == MT_ST_BOOLEANS) { 230162306a36Sopenharmony_ci STm->do_buffer_writes = (options & MT_ST_BUFFER_WRITES) != 0; 230262306a36Sopenharmony_ci STm->do_async_writes = (options & MT_ST_ASYNC_WRITES) != 0; 230362306a36Sopenharmony_ci STm->defaults_for_writes = (options & MT_ST_DEF_WRITES) != 0; 230462306a36Sopenharmony_ci STm->do_read_ahead = (options & MT_ST_READ_AHEAD) != 0; 230562306a36Sopenharmony_ci STp->two_fm = (options & MT_ST_TWO_FM) != 0; 230662306a36Sopenharmony_ci STp->fast_mteom = (options & MT_ST_FAST_MTEOM) != 0; 230762306a36Sopenharmony_ci STp->do_auto_lock = (options & MT_ST_AUTO_LOCK) != 0; 230862306a36Sopenharmony_ci STp->can_bsr = (options & MT_ST_CAN_BSR) != 0; 230962306a36Sopenharmony_ci STp->omit_blklims = (options & MT_ST_NO_BLKLIMS) != 0; 231062306a36Sopenharmony_ci if ((STp->device)->scsi_level >= SCSI_2) 231162306a36Sopenharmony_ci STp->can_partitions = (options & MT_ST_CAN_PARTITIONS) != 0; 231262306a36Sopenharmony_ci STp->scsi2_logical = (options & MT_ST_SCSI2LOGICAL) != 0; 231362306a36Sopenharmony_ci STp->immediate = (options & MT_ST_NOWAIT) != 0; 231462306a36Sopenharmony_ci STp->immediate_filemark = (options & MT_ST_NOWAIT_EOF) != 0; 231562306a36Sopenharmony_ci STm->sysv = (options & MT_ST_SYSV) != 0; 231662306a36Sopenharmony_ci STp->sili = (options & MT_ST_SILI) != 0; 231762306a36Sopenharmony_ci DEB( debugging = (options & MT_ST_DEBUGGING) != 0; 231862306a36Sopenharmony_ci st_log_options(STp, STm); ) 231962306a36Sopenharmony_ci } else if (code == MT_ST_SETBOOLEANS || code == MT_ST_CLEARBOOLEANS) { 232062306a36Sopenharmony_ci value = (code == MT_ST_SETBOOLEANS); 232162306a36Sopenharmony_ci if ((options & MT_ST_BUFFER_WRITES) != 0) 232262306a36Sopenharmony_ci STm->do_buffer_writes = value; 232362306a36Sopenharmony_ci if ((options & MT_ST_ASYNC_WRITES) != 0) 232462306a36Sopenharmony_ci STm->do_async_writes = value; 232562306a36Sopenharmony_ci if ((options & MT_ST_DEF_WRITES) != 0) 232662306a36Sopenharmony_ci STm->defaults_for_writes = value; 232762306a36Sopenharmony_ci if ((options & MT_ST_READ_AHEAD) != 0) 232862306a36Sopenharmony_ci STm->do_read_ahead = value; 232962306a36Sopenharmony_ci if ((options & MT_ST_TWO_FM) != 0) 233062306a36Sopenharmony_ci STp->two_fm = value; 233162306a36Sopenharmony_ci if ((options & MT_ST_FAST_MTEOM) != 0) 233262306a36Sopenharmony_ci STp->fast_mteom = value; 233362306a36Sopenharmony_ci if ((options & MT_ST_AUTO_LOCK) != 0) 233462306a36Sopenharmony_ci STp->do_auto_lock = value; 233562306a36Sopenharmony_ci if ((options & MT_ST_CAN_BSR) != 0) 233662306a36Sopenharmony_ci STp->can_bsr = value; 233762306a36Sopenharmony_ci if ((options & MT_ST_NO_BLKLIMS) != 0) 233862306a36Sopenharmony_ci STp->omit_blklims = value; 233962306a36Sopenharmony_ci if ((STp->device)->scsi_level >= SCSI_2 && 234062306a36Sopenharmony_ci (options & MT_ST_CAN_PARTITIONS) != 0) 234162306a36Sopenharmony_ci STp->can_partitions = value; 234262306a36Sopenharmony_ci if ((options & MT_ST_SCSI2LOGICAL) != 0) 234362306a36Sopenharmony_ci STp->scsi2_logical = value; 234462306a36Sopenharmony_ci if ((options & MT_ST_NOWAIT) != 0) 234562306a36Sopenharmony_ci STp->immediate = value; 234662306a36Sopenharmony_ci if ((options & MT_ST_NOWAIT_EOF) != 0) 234762306a36Sopenharmony_ci STp->immediate_filemark = value; 234862306a36Sopenharmony_ci if ((options & MT_ST_SYSV) != 0) 234962306a36Sopenharmony_ci STm->sysv = value; 235062306a36Sopenharmony_ci if ((options & MT_ST_SILI) != 0) 235162306a36Sopenharmony_ci STp->sili = value; 235262306a36Sopenharmony_ci DEB( 235362306a36Sopenharmony_ci if ((options & MT_ST_DEBUGGING) != 0) 235462306a36Sopenharmony_ci debugging = value; 235562306a36Sopenharmony_ci st_log_options(STp, STm); ) 235662306a36Sopenharmony_ci } else if (code == MT_ST_WRITE_THRESHOLD) { 235762306a36Sopenharmony_ci /* Retained for compatibility */ 235862306a36Sopenharmony_ci } else if (code == MT_ST_DEF_BLKSIZE) { 235962306a36Sopenharmony_ci value = (options & ~MT_ST_OPTIONS); 236062306a36Sopenharmony_ci if (value == ~MT_ST_OPTIONS) { 236162306a36Sopenharmony_ci STm->default_blksize = (-1); 236262306a36Sopenharmony_ci DEBC_printk(STp, "Default block size disabled.\n"); 236362306a36Sopenharmony_ci } else { 236462306a36Sopenharmony_ci STm->default_blksize = value; 236562306a36Sopenharmony_ci DEBC_printk(STp,"Default block size set to " 236662306a36Sopenharmony_ci "%d bytes.\n", STm->default_blksize); 236762306a36Sopenharmony_ci if (STp->ready == ST_READY) { 236862306a36Sopenharmony_ci STp->blksize_changed = 0; 236962306a36Sopenharmony_ci set_mode_densblk(STp, STm); 237062306a36Sopenharmony_ci } 237162306a36Sopenharmony_ci } 237262306a36Sopenharmony_ci } else if (code == MT_ST_TIMEOUTS) { 237362306a36Sopenharmony_ci value = (options & ~MT_ST_OPTIONS); 237462306a36Sopenharmony_ci if ((value & MT_ST_SET_LONG_TIMEOUT) != 0) { 237562306a36Sopenharmony_ci STp->long_timeout = (value & ~MT_ST_SET_LONG_TIMEOUT) * HZ; 237662306a36Sopenharmony_ci DEBC_printk(STp, "Long timeout set to %d seconds.\n", 237762306a36Sopenharmony_ci (value & ~MT_ST_SET_LONG_TIMEOUT)); 237862306a36Sopenharmony_ci } else { 237962306a36Sopenharmony_ci blk_queue_rq_timeout(STp->device->request_queue, 238062306a36Sopenharmony_ci value * HZ); 238162306a36Sopenharmony_ci DEBC_printk(STp, "Normal timeout set to %d seconds.\n", 238262306a36Sopenharmony_ci value); 238362306a36Sopenharmony_ci } 238462306a36Sopenharmony_ci } else if (code == MT_ST_SET_CLN) { 238562306a36Sopenharmony_ci value = (options & ~MT_ST_OPTIONS) & 0xff; 238662306a36Sopenharmony_ci if (value != 0 && 238762306a36Sopenharmony_ci (value < EXTENDED_SENSE_START || 238862306a36Sopenharmony_ci value >= SCSI_SENSE_BUFFERSIZE)) 238962306a36Sopenharmony_ci return (-EINVAL); 239062306a36Sopenharmony_ci STp->cln_mode = value; 239162306a36Sopenharmony_ci STp->cln_sense_mask = (options >> 8) & 0xff; 239262306a36Sopenharmony_ci STp->cln_sense_value = (options >> 16) & 0xff; 239362306a36Sopenharmony_ci st_printk(KERN_INFO, STp, 239462306a36Sopenharmony_ci "Cleaning request mode %d, mask %02x, value %02x\n", 239562306a36Sopenharmony_ci value, STp->cln_sense_mask, STp->cln_sense_value); 239662306a36Sopenharmony_ci } else if (code == MT_ST_DEF_OPTIONS) { 239762306a36Sopenharmony_ci code = (options & ~MT_ST_CLEAR_DEFAULT); 239862306a36Sopenharmony_ci value = (options & MT_ST_CLEAR_DEFAULT); 239962306a36Sopenharmony_ci if (code == MT_ST_DEF_DENSITY) { 240062306a36Sopenharmony_ci if (value == MT_ST_CLEAR_DEFAULT) { 240162306a36Sopenharmony_ci STm->default_density = (-1); 240262306a36Sopenharmony_ci DEBC_printk(STp, 240362306a36Sopenharmony_ci "Density default disabled.\n"); 240462306a36Sopenharmony_ci } else { 240562306a36Sopenharmony_ci STm->default_density = value & 0xff; 240662306a36Sopenharmony_ci DEBC_printk(STp, "Density default set to %x\n", 240762306a36Sopenharmony_ci STm->default_density); 240862306a36Sopenharmony_ci if (STp->ready == ST_READY) { 240962306a36Sopenharmony_ci STp->density_changed = 0; 241062306a36Sopenharmony_ci set_mode_densblk(STp, STm); 241162306a36Sopenharmony_ci } 241262306a36Sopenharmony_ci } 241362306a36Sopenharmony_ci } else if (code == MT_ST_DEF_DRVBUFFER) { 241462306a36Sopenharmony_ci if (value == MT_ST_CLEAR_DEFAULT) { 241562306a36Sopenharmony_ci STp->default_drvbuffer = 0xff; 241662306a36Sopenharmony_ci DEBC_printk(STp, 241762306a36Sopenharmony_ci "Drive buffer default disabled.\n"); 241862306a36Sopenharmony_ci } else { 241962306a36Sopenharmony_ci STp->default_drvbuffer = value & 7; 242062306a36Sopenharmony_ci DEBC_printk(STp, 242162306a36Sopenharmony_ci "Drive buffer default set to %x\n", 242262306a36Sopenharmony_ci STp->default_drvbuffer); 242362306a36Sopenharmony_ci if (STp->ready == ST_READY) 242462306a36Sopenharmony_ci st_int_ioctl(STp, MTSETDRVBUFFER, STp->default_drvbuffer); 242562306a36Sopenharmony_ci } 242662306a36Sopenharmony_ci } else if (code == MT_ST_DEF_COMPRESSION) { 242762306a36Sopenharmony_ci if (value == MT_ST_CLEAR_DEFAULT) { 242862306a36Sopenharmony_ci STm->default_compression = ST_DONT_TOUCH; 242962306a36Sopenharmony_ci DEBC_printk(STp, 243062306a36Sopenharmony_ci "Compression default disabled.\n"); 243162306a36Sopenharmony_ci } else { 243262306a36Sopenharmony_ci if ((value & 0xff00) != 0) { 243362306a36Sopenharmony_ci STp->c_algo = (value & 0xff00) >> 8; 243462306a36Sopenharmony_ci DEBC_printk(STp, "Compression " 243562306a36Sopenharmony_ci "algorithm set to 0x%x.\n", 243662306a36Sopenharmony_ci STp->c_algo); 243762306a36Sopenharmony_ci } 243862306a36Sopenharmony_ci if ((value & 0xff) != 0xff) { 243962306a36Sopenharmony_ci STm->default_compression = (value & 1 ? ST_YES : ST_NO); 244062306a36Sopenharmony_ci DEBC_printk(STp, "Compression default " 244162306a36Sopenharmony_ci "set to %x\n", 244262306a36Sopenharmony_ci (value & 1)); 244362306a36Sopenharmony_ci if (STp->ready == ST_READY) { 244462306a36Sopenharmony_ci STp->compression_changed = 0; 244562306a36Sopenharmony_ci st_compression(STp, (STm->default_compression == ST_YES)); 244662306a36Sopenharmony_ci } 244762306a36Sopenharmony_ci } 244862306a36Sopenharmony_ci } 244962306a36Sopenharmony_ci } 245062306a36Sopenharmony_ci } else 245162306a36Sopenharmony_ci return (-EIO); 245262306a36Sopenharmony_ci 245362306a36Sopenharmony_ci return 0; 245462306a36Sopenharmony_ci} 245562306a36Sopenharmony_ci 245662306a36Sopenharmony_ci#define MODE_HEADER_LENGTH 4 245762306a36Sopenharmony_ci 245862306a36Sopenharmony_ci/* Mode header and page byte offsets */ 245962306a36Sopenharmony_ci#define MH_OFF_DATA_LENGTH 0 246062306a36Sopenharmony_ci#define MH_OFF_MEDIUM_TYPE 1 246162306a36Sopenharmony_ci#define MH_OFF_DEV_SPECIFIC 2 246262306a36Sopenharmony_ci#define MH_OFF_BDESCS_LENGTH 3 246362306a36Sopenharmony_ci#define MP_OFF_PAGE_NBR 0 246462306a36Sopenharmony_ci#define MP_OFF_PAGE_LENGTH 1 246562306a36Sopenharmony_ci 246662306a36Sopenharmony_ci/* Mode header and page bit masks */ 246762306a36Sopenharmony_ci#define MH_BIT_WP 0x80 246862306a36Sopenharmony_ci#define MP_MSK_PAGE_NBR 0x3f 246962306a36Sopenharmony_ci 247062306a36Sopenharmony_ci/* Don't return block descriptors */ 247162306a36Sopenharmony_ci#define MODE_SENSE_OMIT_BDESCS 0x08 247262306a36Sopenharmony_ci 247362306a36Sopenharmony_ci#define MODE_SELECT_PAGE_FORMAT 0x10 247462306a36Sopenharmony_ci 247562306a36Sopenharmony_ci/* Read a mode page into the tape buffer. The block descriptors are included 247662306a36Sopenharmony_ci if incl_block_descs is true. The page control is ored to the page number 247762306a36Sopenharmony_ci parameter, if necessary. */ 247862306a36Sopenharmony_cistatic int read_mode_page(struct scsi_tape *STp, int page, int omit_block_descs) 247962306a36Sopenharmony_ci{ 248062306a36Sopenharmony_ci unsigned char cmd[MAX_COMMAND_SIZE]; 248162306a36Sopenharmony_ci struct st_request *SRpnt; 248262306a36Sopenharmony_ci 248362306a36Sopenharmony_ci memset(cmd, 0, MAX_COMMAND_SIZE); 248462306a36Sopenharmony_ci cmd[0] = MODE_SENSE; 248562306a36Sopenharmony_ci if (omit_block_descs) 248662306a36Sopenharmony_ci cmd[1] = MODE_SENSE_OMIT_BDESCS; 248762306a36Sopenharmony_ci cmd[2] = page; 248862306a36Sopenharmony_ci cmd[4] = 255; 248962306a36Sopenharmony_ci 249062306a36Sopenharmony_ci SRpnt = st_do_scsi(NULL, STp, cmd, cmd[4], DMA_FROM_DEVICE, 249162306a36Sopenharmony_ci STp->device->request_queue->rq_timeout, 0, 1); 249262306a36Sopenharmony_ci if (SRpnt == NULL) 249362306a36Sopenharmony_ci return (STp->buffer)->syscall_result; 249462306a36Sopenharmony_ci 249562306a36Sopenharmony_ci st_release_request(SRpnt); 249662306a36Sopenharmony_ci 249762306a36Sopenharmony_ci return STp->buffer->syscall_result; 249862306a36Sopenharmony_ci} 249962306a36Sopenharmony_ci 250062306a36Sopenharmony_ci 250162306a36Sopenharmony_ci/* Send the mode page in the tape buffer to the drive. Assumes that the mode data 250262306a36Sopenharmony_ci in the buffer is correctly formatted. The long timeout is used if slow is non-zero. */ 250362306a36Sopenharmony_cistatic int write_mode_page(struct scsi_tape *STp, int page, int slow) 250462306a36Sopenharmony_ci{ 250562306a36Sopenharmony_ci int pgo; 250662306a36Sopenharmony_ci unsigned char cmd[MAX_COMMAND_SIZE]; 250762306a36Sopenharmony_ci struct st_request *SRpnt; 250862306a36Sopenharmony_ci int timeout; 250962306a36Sopenharmony_ci 251062306a36Sopenharmony_ci memset(cmd, 0, MAX_COMMAND_SIZE); 251162306a36Sopenharmony_ci cmd[0] = MODE_SELECT; 251262306a36Sopenharmony_ci cmd[1] = MODE_SELECT_PAGE_FORMAT; 251362306a36Sopenharmony_ci pgo = MODE_HEADER_LENGTH + (STp->buffer)->b_data[MH_OFF_BDESCS_LENGTH]; 251462306a36Sopenharmony_ci cmd[4] = pgo + (STp->buffer)->b_data[pgo + MP_OFF_PAGE_LENGTH] + 2; 251562306a36Sopenharmony_ci 251662306a36Sopenharmony_ci /* Clear reserved fields */ 251762306a36Sopenharmony_ci (STp->buffer)->b_data[MH_OFF_DATA_LENGTH] = 0; 251862306a36Sopenharmony_ci (STp->buffer)->b_data[MH_OFF_MEDIUM_TYPE] = 0; 251962306a36Sopenharmony_ci (STp->buffer)->b_data[MH_OFF_DEV_SPECIFIC] &= ~MH_BIT_WP; 252062306a36Sopenharmony_ci (STp->buffer)->b_data[pgo + MP_OFF_PAGE_NBR] &= MP_MSK_PAGE_NBR; 252162306a36Sopenharmony_ci 252262306a36Sopenharmony_ci timeout = slow ? 252362306a36Sopenharmony_ci STp->long_timeout : STp->device->request_queue->rq_timeout; 252462306a36Sopenharmony_ci SRpnt = st_do_scsi(NULL, STp, cmd, cmd[4], DMA_TO_DEVICE, 252562306a36Sopenharmony_ci timeout, 0, 1); 252662306a36Sopenharmony_ci if (SRpnt == NULL) 252762306a36Sopenharmony_ci return (STp->buffer)->syscall_result; 252862306a36Sopenharmony_ci 252962306a36Sopenharmony_ci st_release_request(SRpnt); 253062306a36Sopenharmony_ci 253162306a36Sopenharmony_ci return STp->buffer->syscall_result; 253262306a36Sopenharmony_ci} 253362306a36Sopenharmony_ci 253462306a36Sopenharmony_ci 253562306a36Sopenharmony_ci#define COMPRESSION_PAGE 0x0f 253662306a36Sopenharmony_ci#define COMPRESSION_PAGE_LENGTH 16 253762306a36Sopenharmony_ci 253862306a36Sopenharmony_ci#define CP_OFF_DCE_DCC 2 253962306a36Sopenharmony_ci#define CP_OFF_C_ALGO 7 254062306a36Sopenharmony_ci 254162306a36Sopenharmony_ci#define DCE_MASK 0x80 254262306a36Sopenharmony_ci#define DCC_MASK 0x40 254362306a36Sopenharmony_ci#define RED_MASK 0x60 254462306a36Sopenharmony_ci 254562306a36Sopenharmony_ci 254662306a36Sopenharmony_ci/* Control the compression with mode page 15. Algorithm not changed if zero. 254762306a36Sopenharmony_ci 254862306a36Sopenharmony_ci The block descriptors are read and written because Sony SDT-7000 does not 254962306a36Sopenharmony_ci work without this (suggestion from Michael Schaefer <Michael.Schaefer@dlr.de>). 255062306a36Sopenharmony_ci Including block descriptors should not cause any harm to other drives. */ 255162306a36Sopenharmony_ci 255262306a36Sopenharmony_cistatic int st_compression(struct scsi_tape * STp, int state) 255362306a36Sopenharmony_ci{ 255462306a36Sopenharmony_ci int retval; 255562306a36Sopenharmony_ci int mpoffs; /* Offset to mode page start */ 255662306a36Sopenharmony_ci unsigned char *b_data = (STp->buffer)->b_data; 255762306a36Sopenharmony_ci 255862306a36Sopenharmony_ci if (STp->ready != ST_READY) 255962306a36Sopenharmony_ci return (-EIO); 256062306a36Sopenharmony_ci 256162306a36Sopenharmony_ci /* Read the current page contents */ 256262306a36Sopenharmony_ci retval = read_mode_page(STp, COMPRESSION_PAGE, 0); 256362306a36Sopenharmony_ci if (retval) { 256462306a36Sopenharmony_ci DEBC_printk(STp, "Compression mode page not supported.\n"); 256562306a36Sopenharmony_ci return (-EIO); 256662306a36Sopenharmony_ci } 256762306a36Sopenharmony_ci 256862306a36Sopenharmony_ci mpoffs = MODE_HEADER_LENGTH + b_data[MH_OFF_BDESCS_LENGTH]; 256962306a36Sopenharmony_ci DEBC_printk(STp, "Compression state is %d.\n", 257062306a36Sopenharmony_ci (b_data[mpoffs + CP_OFF_DCE_DCC] & DCE_MASK ? 1 : 0)); 257162306a36Sopenharmony_ci 257262306a36Sopenharmony_ci /* Check if compression can be changed */ 257362306a36Sopenharmony_ci if ((b_data[mpoffs + CP_OFF_DCE_DCC] & DCC_MASK) == 0) { 257462306a36Sopenharmony_ci DEBC_printk(STp, "Compression not supported.\n"); 257562306a36Sopenharmony_ci return (-EIO); 257662306a36Sopenharmony_ci } 257762306a36Sopenharmony_ci 257862306a36Sopenharmony_ci /* Do the change */ 257962306a36Sopenharmony_ci if (state) { 258062306a36Sopenharmony_ci b_data[mpoffs + CP_OFF_DCE_DCC] |= DCE_MASK; 258162306a36Sopenharmony_ci if (STp->c_algo != 0) 258262306a36Sopenharmony_ci b_data[mpoffs + CP_OFF_C_ALGO] = STp->c_algo; 258362306a36Sopenharmony_ci } 258462306a36Sopenharmony_ci else { 258562306a36Sopenharmony_ci b_data[mpoffs + CP_OFF_DCE_DCC] &= ~DCE_MASK; 258662306a36Sopenharmony_ci if (STp->c_algo != 0) 258762306a36Sopenharmony_ci b_data[mpoffs + CP_OFF_C_ALGO] = 0; /* no compression */ 258862306a36Sopenharmony_ci } 258962306a36Sopenharmony_ci 259062306a36Sopenharmony_ci retval = write_mode_page(STp, COMPRESSION_PAGE, 0); 259162306a36Sopenharmony_ci if (retval) { 259262306a36Sopenharmony_ci DEBC_printk(STp, "Compression change failed.\n"); 259362306a36Sopenharmony_ci return (-EIO); 259462306a36Sopenharmony_ci } 259562306a36Sopenharmony_ci DEBC_printk(STp, "Compression state changed to %d.\n", state); 259662306a36Sopenharmony_ci 259762306a36Sopenharmony_ci STp->compression_changed = 1; 259862306a36Sopenharmony_ci return 0; 259962306a36Sopenharmony_ci} 260062306a36Sopenharmony_ci 260162306a36Sopenharmony_ci 260262306a36Sopenharmony_ci/* Process the load and unload commands (does unload if the load code is zero) */ 260362306a36Sopenharmony_cistatic int do_load_unload(struct scsi_tape *STp, struct file *filp, int load_code) 260462306a36Sopenharmony_ci{ 260562306a36Sopenharmony_ci int retval = (-EIO), timeout; 260662306a36Sopenharmony_ci unsigned char cmd[MAX_COMMAND_SIZE]; 260762306a36Sopenharmony_ci struct st_partstat *STps; 260862306a36Sopenharmony_ci struct st_request *SRpnt; 260962306a36Sopenharmony_ci 261062306a36Sopenharmony_ci if (STp->ready != ST_READY && !load_code) { 261162306a36Sopenharmony_ci if (STp->ready == ST_NO_TAPE) 261262306a36Sopenharmony_ci return (-ENOMEDIUM); 261362306a36Sopenharmony_ci else 261462306a36Sopenharmony_ci return (-EIO); 261562306a36Sopenharmony_ci } 261662306a36Sopenharmony_ci 261762306a36Sopenharmony_ci memset(cmd, 0, MAX_COMMAND_SIZE); 261862306a36Sopenharmony_ci cmd[0] = START_STOP; 261962306a36Sopenharmony_ci if (load_code) 262062306a36Sopenharmony_ci cmd[4] |= 1; 262162306a36Sopenharmony_ci /* 262262306a36Sopenharmony_ci * If arg >= 1 && arg <= 6 Enhanced load/unload in HP C1553A 262362306a36Sopenharmony_ci */ 262462306a36Sopenharmony_ci if (load_code >= 1 + MT_ST_HPLOADER_OFFSET 262562306a36Sopenharmony_ci && load_code <= 6 + MT_ST_HPLOADER_OFFSET) { 262662306a36Sopenharmony_ci DEBC_printk(STp, " Enhanced %sload slot %2d.\n", 262762306a36Sopenharmony_ci (cmd[4]) ? "" : "un", 262862306a36Sopenharmony_ci load_code - MT_ST_HPLOADER_OFFSET); 262962306a36Sopenharmony_ci cmd[3] = load_code - MT_ST_HPLOADER_OFFSET; /* MediaID field of C1553A */ 263062306a36Sopenharmony_ci } 263162306a36Sopenharmony_ci if (STp->immediate) { 263262306a36Sopenharmony_ci cmd[1] = 1; /* Don't wait for completion */ 263362306a36Sopenharmony_ci timeout = STp->device->request_queue->rq_timeout; 263462306a36Sopenharmony_ci } 263562306a36Sopenharmony_ci else 263662306a36Sopenharmony_ci timeout = STp->long_timeout; 263762306a36Sopenharmony_ci 263862306a36Sopenharmony_ci DEBC( 263962306a36Sopenharmony_ci if (!load_code) 264062306a36Sopenharmony_ci st_printk(ST_DEB_MSG, STp, "Unloading tape.\n"); 264162306a36Sopenharmony_ci else 264262306a36Sopenharmony_ci st_printk(ST_DEB_MSG, STp, "Loading tape.\n"); 264362306a36Sopenharmony_ci ); 264462306a36Sopenharmony_ci 264562306a36Sopenharmony_ci SRpnt = st_do_scsi(NULL, STp, cmd, 0, DMA_NONE, 264662306a36Sopenharmony_ci timeout, MAX_RETRIES, 1); 264762306a36Sopenharmony_ci if (!SRpnt) 264862306a36Sopenharmony_ci return (STp->buffer)->syscall_result; 264962306a36Sopenharmony_ci 265062306a36Sopenharmony_ci retval = (STp->buffer)->syscall_result; 265162306a36Sopenharmony_ci st_release_request(SRpnt); 265262306a36Sopenharmony_ci 265362306a36Sopenharmony_ci if (!retval) { /* SCSI command successful */ 265462306a36Sopenharmony_ci 265562306a36Sopenharmony_ci if (!load_code) { 265662306a36Sopenharmony_ci STp->rew_at_close = 0; 265762306a36Sopenharmony_ci STp->ready = ST_NO_TAPE; 265862306a36Sopenharmony_ci } 265962306a36Sopenharmony_ci else { 266062306a36Sopenharmony_ci STp->rew_at_close = STp->autorew_dev; 266162306a36Sopenharmony_ci retval = check_tape(STp, filp); 266262306a36Sopenharmony_ci if (retval > 0) 266362306a36Sopenharmony_ci retval = 0; 266462306a36Sopenharmony_ci } 266562306a36Sopenharmony_ci } 266662306a36Sopenharmony_ci else { 266762306a36Sopenharmony_ci STps = &(STp->ps[STp->partition]); 266862306a36Sopenharmony_ci STps->drv_file = STps->drv_block = (-1); 266962306a36Sopenharmony_ci } 267062306a36Sopenharmony_ci 267162306a36Sopenharmony_ci return retval; 267262306a36Sopenharmony_ci} 267362306a36Sopenharmony_ci 267462306a36Sopenharmony_ci#if DEBUG 267562306a36Sopenharmony_ci#define ST_DEB_FORWARD 0 267662306a36Sopenharmony_ci#define ST_DEB_BACKWARD 1 267762306a36Sopenharmony_cistatic void deb_space_print(struct scsi_tape *STp, int direction, char *units, unsigned char *cmd) 267862306a36Sopenharmony_ci{ 267962306a36Sopenharmony_ci s32 sc; 268062306a36Sopenharmony_ci 268162306a36Sopenharmony_ci if (!debugging) 268262306a36Sopenharmony_ci return; 268362306a36Sopenharmony_ci 268462306a36Sopenharmony_ci sc = sign_extend32(get_unaligned_be24(&cmd[2]), 23); 268562306a36Sopenharmony_ci if (direction) 268662306a36Sopenharmony_ci sc = -sc; 268762306a36Sopenharmony_ci st_printk(ST_DEB_MSG, STp, "Spacing tape %s over %d %s.\n", 268862306a36Sopenharmony_ci direction ? "backward" : "forward", sc, units); 268962306a36Sopenharmony_ci} 269062306a36Sopenharmony_ci#else 269162306a36Sopenharmony_ci#define ST_DEB_FORWARD 0 269262306a36Sopenharmony_ci#define ST_DEB_BACKWARD 1 269362306a36Sopenharmony_cistatic void deb_space_print(struct scsi_tape *STp, int direction, char *units, unsigned char *cmd) {} 269462306a36Sopenharmony_ci#endif 269562306a36Sopenharmony_ci 269662306a36Sopenharmony_ci 269762306a36Sopenharmony_ci/* Internal ioctl function */ 269862306a36Sopenharmony_cistatic int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned long arg) 269962306a36Sopenharmony_ci{ 270062306a36Sopenharmony_ci int timeout; 270162306a36Sopenharmony_ci long ltmp; 270262306a36Sopenharmony_ci int ioctl_result; 270362306a36Sopenharmony_ci int chg_eof = 1; 270462306a36Sopenharmony_ci unsigned char cmd[MAX_COMMAND_SIZE]; 270562306a36Sopenharmony_ci struct st_request *SRpnt; 270662306a36Sopenharmony_ci struct st_partstat *STps; 270762306a36Sopenharmony_ci int fileno, blkno, at_sm, undone; 270862306a36Sopenharmony_ci int datalen = 0, direction = DMA_NONE; 270962306a36Sopenharmony_ci 271062306a36Sopenharmony_ci WARN_ON(STp->buffer->do_dio != 0); 271162306a36Sopenharmony_ci if (STp->ready != ST_READY) { 271262306a36Sopenharmony_ci if (STp->ready == ST_NO_TAPE) 271362306a36Sopenharmony_ci return (-ENOMEDIUM); 271462306a36Sopenharmony_ci else 271562306a36Sopenharmony_ci return (-EIO); 271662306a36Sopenharmony_ci } 271762306a36Sopenharmony_ci timeout = STp->long_timeout; 271862306a36Sopenharmony_ci STps = &(STp->ps[STp->partition]); 271962306a36Sopenharmony_ci fileno = STps->drv_file; 272062306a36Sopenharmony_ci blkno = STps->drv_block; 272162306a36Sopenharmony_ci at_sm = STps->at_sm; 272262306a36Sopenharmony_ci 272362306a36Sopenharmony_ci memset(cmd, 0, MAX_COMMAND_SIZE); 272462306a36Sopenharmony_ci switch (cmd_in) { 272562306a36Sopenharmony_ci case MTFSFM: 272662306a36Sopenharmony_ci chg_eof = 0; /* Changed from the FSF after this */ 272762306a36Sopenharmony_ci fallthrough; 272862306a36Sopenharmony_ci case MTFSF: 272962306a36Sopenharmony_ci cmd[0] = SPACE; 273062306a36Sopenharmony_ci cmd[1] = 0x01; /* Space FileMarks */ 273162306a36Sopenharmony_ci cmd[2] = (arg >> 16); 273262306a36Sopenharmony_ci cmd[3] = (arg >> 8); 273362306a36Sopenharmony_ci cmd[4] = arg; 273462306a36Sopenharmony_ci deb_space_print(STp, ST_DEB_FORWARD, "filemarks", cmd); 273562306a36Sopenharmony_ci if (fileno >= 0) 273662306a36Sopenharmony_ci fileno += arg; 273762306a36Sopenharmony_ci blkno = 0; 273862306a36Sopenharmony_ci at_sm &= (arg == 0); 273962306a36Sopenharmony_ci break; 274062306a36Sopenharmony_ci case MTBSFM: 274162306a36Sopenharmony_ci chg_eof = 0; /* Changed from the FSF after this */ 274262306a36Sopenharmony_ci fallthrough; 274362306a36Sopenharmony_ci case MTBSF: 274462306a36Sopenharmony_ci cmd[0] = SPACE; 274562306a36Sopenharmony_ci cmd[1] = 0x01; /* Space FileMarks */ 274662306a36Sopenharmony_ci ltmp = (-arg); 274762306a36Sopenharmony_ci cmd[2] = (ltmp >> 16); 274862306a36Sopenharmony_ci cmd[3] = (ltmp >> 8); 274962306a36Sopenharmony_ci cmd[4] = ltmp; 275062306a36Sopenharmony_ci deb_space_print(STp, ST_DEB_BACKWARD, "filemarks", cmd); 275162306a36Sopenharmony_ci if (fileno >= 0) 275262306a36Sopenharmony_ci fileno -= arg; 275362306a36Sopenharmony_ci blkno = (-1); /* We can't know the block number */ 275462306a36Sopenharmony_ci at_sm &= (arg == 0); 275562306a36Sopenharmony_ci break; 275662306a36Sopenharmony_ci case MTFSR: 275762306a36Sopenharmony_ci cmd[0] = SPACE; 275862306a36Sopenharmony_ci cmd[1] = 0x00; /* Space Blocks */ 275962306a36Sopenharmony_ci cmd[2] = (arg >> 16); 276062306a36Sopenharmony_ci cmd[3] = (arg >> 8); 276162306a36Sopenharmony_ci cmd[4] = arg; 276262306a36Sopenharmony_ci deb_space_print(STp, ST_DEB_FORWARD, "blocks", cmd); 276362306a36Sopenharmony_ci if (blkno >= 0) 276462306a36Sopenharmony_ci blkno += arg; 276562306a36Sopenharmony_ci at_sm &= (arg == 0); 276662306a36Sopenharmony_ci break; 276762306a36Sopenharmony_ci case MTBSR: 276862306a36Sopenharmony_ci cmd[0] = SPACE; 276962306a36Sopenharmony_ci cmd[1] = 0x00; /* Space Blocks */ 277062306a36Sopenharmony_ci ltmp = (-arg); 277162306a36Sopenharmony_ci cmd[2] = (ltmp >> 16); 277262306a36Sopenharmony_ci cmd[3] = (ltmp >> 8); 277362306a36Sopenharmony_ci cmd[4] = ltmp; 277462306a36Sopenharmony_ci deb_space_print(STp, ST_DEB_BACKWARD, "blocks", cmd); 277562306a36Sopenharmony_ci if (blkno >= 0) 277662306a36Sopenharmony_ci blkno -= arg; 277762306a36Sopenharmony_ci at_sm &= (arg == 0); 277862306a36Sopenharmony_ci break; 277962306a36Sopenharmony_ci case MTFSS: 278062306a36Sopenharmony_ci cmd[0] = SPACE; 278162306a36Sopenharmony_ci cmd[1] = 0x04; /* Space Setmarks */ 278262306a36Sopenharmony_ci cmd[2] = (arg >> 16); 278362306a36Sopenharmony_ci cmd[3] = (arg >> 8); 278462306a36Sopenharmony_ci cmd[4] = arg; 278562306a36Sopenharmony_ci deb_space_print(STp, ST_DEB_FORWARD, "setmarks", cmd); 278662306a36Sopenharmony_ci if (arg != 0) { 278762306a36Sopenharmony_ci blkno = fileno = (-1); 278862306a36Sopenharmony_ci at_sm = 1; 278962306a36Sopenharmony_ci } 279062306a36Sopenharmony_ci break; 279162306a36Sopenharmony_ci case MTBSS: 279262306a36Sopenharmony_ci cmd[0] = SPACE; 279362306a36Sopenharmony_ci cmd[1] = 0x04; /* Space Setmarks */ 279462306a36Sopenharmony_ci ltmp = (-arg); 279562306a36Sopenharmony_ci cmd[2] = (ltmp >> 16); 279662306a36Sopenharmony_ci cmd[3] = (ltmp >> 8); 279762306a36Sopenharmony_ci cmd[4] = ltmp; 279862306a36Sopenharmony_ci deb_space_print(STp, ST_DEB_BACKWARD, "setmarks", cmd); 279962306a36Sopenharmony_ci if (arg != 0) { 280062306a36Sopenharmony_ci blkno = fileno = (-1); 280162306a36Sopenharmony_ci at_sm = 1; 280262306a36Sopenharmony_ci } 280362306a36Sopenharmony_ci break; 280462306a36Sopenharmony_ci case MTWEOF: 280562306a36Sopenharmony_ci case MTWEOFI: 280662306a36Sopenharmony_ci case MTWSM: 280762306a36Sopenharmony_ci if (STp->write_prot) 280862306a36Sopenharmony_ci return (-EACCES); 280962306a36Sopenharmony_ci cmd[0] = WRITE_FILEMARKS; 281062306a36Sopenharmony_ci if (cmd_in == MTWSM) 281162306a36Sopenharmony_ci cmd[1] = 2; 281262306a36Sopenharmony_ci if (cmd_in == MTWEOFI || 281362306a36Sopenharmony_ci (cmd_in == MTWEOF && STp->immediate_filemark)) 281462306a36Sopenharmony_ci cmd[1] |= 1; 281562306a36Sopenharmony_ci cmd[2] = (arg >> 16); 281662306a36Sopenharmony_ci cmd[3] = (arg >> 8); 281762306a36Sopenharmony_ci cmd[4] = arg; 281862306a36Sopenharmony_ci timeout = STp->device->request_queue->rq_timeout; 281962306a36Sopenharmony_ci DEBC( 282062306a36Sopenharmony_ci if (cmd_in != MTWSM) 282162306a36Sopenharmony_ci st_printk(ST_DEB_MSG, STp, 282262306a36Sopenharmony_ci "Writing %d filemarks.\n", 282362306a36Sopenharmony_ci cmd[2] * 65536 + 282462306a36Sopenharmony_ci cmd[3] * 256 + 282562306a36Sopenharmony_ci cmd[4]); 282662306a36Sopenharmony_ci else 282762306a36Sopenharmony_ci st_printk(ST_DEB_MSG, STp, 282862306a36Sopenharmony_ci "Writing %d setmarks.\n", 282962306a36Sopenharmony_ci cmd[2] * 65536 + 283062306a36Sopenharmony_ci cmd[3] * 256 + 283162306a36Sopenharmony_ci cmd[4]); 283262306a36Sopenharmony_ci ) 283362306a36Sopenharmony_ci if (fileno >= 0) 283462306a36Sopenharmony_ci fileno += arg; 283562306a36Sopenharmony_ci blkno = 0; 283662306a36Sopenharmony_ci at_sm = (cmd_in == MTWSM); 283762306a36Sopenharmony_ci break; 283862306a36Sopenharmony_ci case MTREW: 283962306a36Sopenharmony_ci cmd[0] = REZERO_UNIT; 284062306a36Sopenharmony_ci if (STp->immediate) { 284162306a36Sopenharmony_ci cmd[1] = 1; /* Don't wait for completion */ 284262306a36Sopenharmony_ci timeout = STp->device->request_queue->rq_timeout; 284362306a36Sopenharmony_ci } 284462306a36Sopenharmony_ci DEBC_printk(STp, "Rewinding tape.\n"); 284562306a36Sopenharmony_ci fileno = blkno = at_sm = 0; 284662306a36Sopenharmony_ci break; 284762306a36Sopenharmony_ci case MTNOP: 284862306a36Sopenharmony_ci DEBC_printk(STp, "No op on tape.\n"); 284962306a36Sopenharmony_ci return 0; /* Should do something ? */ 285062306a36Sopenharmony_ci case MTRETEN: 285162306a36Sopenharmony_ci cmd[0] = START_STOP; 285262306a36Sopenharmony_ci if (STp->immediate) { 285362306a36Sopenharmony_ci cmd[1] = 1; /* Don't wait for completion */ 285462306a36Sopenharmony_ci timeout = STp->device->request_queue->rq_timeout; 285562306a36Sopenharmony_ci } 285662306a36Sopenharmony_ci cmd[4] = 3; 285762306a36Sopenharmony_ci DEBC_printk(STp, "Retensioning tape.\n"); 285862306a36Sopenharmony_ci fileno = blkno = at_sm = 0; 285962306a36Sopenharmony_ci break; 286062306a36Sopenharmony_ci case MTEOM: 286162306a36Sopenharmony_ci if (!STp->fast_mteom) { 286262306a36Sopenharmony_ci /* space to the end of tape */ 286362306a36Sopenharmony_ci ioctl_result = st_int_ioctl(STp, MTFSF, 0x7fffff); 286462306a36Sopenharmony_ci fileno = STps->drv_file; 286562306a36Sopenharmony_ci if (STps->eof >= ST_EOD_1) 286662306a36Sopenharmony_ci return 0; 286762306a36Sopenharmony_ci /* The next lines would hide the number of spaced FileMarks 286862306a36Sopenharmony_ci That's why I inserted the previous lines. I had no luck 286962306a36Sopenharmony_ci with detecting EOM with FSF, so we go now to EOM. 287062306a36Sopenharmony_ci Joerg Weule */ 287162306a36Sopenharmony_ci } else 287262306a36Sopenharmony_ci fileno = (-1); 287362306a36Sopenharmony_ci cmd[0] = SPACE; 287462306a36Sopenharmony_ci cmd[1] = 3; 287562306a36Sopenharmony_ci DEBC_printk(STp, "Spacing to end of recorded medium.\n"); 287662306a36Sopenharmony_ci blkno = -1; 287762306a36Sopenharmony_ci at_sm = 0; 287862306a36Sopenharmony_ci break; 287962306a36Sopenharmony_ci case MTERASE: 288062306a36Sopenharmony_ci if (STp->write_prot) 288162306a36Sopenharmony_ci return (-EACCES); 288262306a36Sopenharmony_ci cmd[0] = ERASE; 288362306a36Sopenharmony_ci cmd[1] = (arg ? 1 : 0); /* Long erase with non-zero argument */ 288462306a36Sopenharmony_ci if (STp->immediate) { 288562306a36Sopenharmony_ci cmd[1] |= 2; /* Don't wait for completion */ 288662306a36Sopenharmony_ci timeout = STp->device->request_queue->rq_timeout; 288762306a36Sopenharmony_ci } 288862306a36Sopenharmony_ci else 288962306a36Sopenharmony_ci timeout = STp->long_timeout * 8; 289062306a36Sopenharmony_ci 289162306a36Sopenharmony_ci DEBC_printk(STp, "Erasing tape.\n"); 289262306a36Sopenharmony_ci fileno = blkno = at_sm = 0; 289362306a36Sopenharmony_ci break; 289462306a36Sopenharmony_ci case MTSETBLK: /* Set block length */ 289562306a36Sopenharmony_ci case MTSETDENSITY: /* Set tape density */ 289662306a36Sopenharmony_ci case MTSETDRVBUFFER: /* Set drive buffering */ 289762306a36Sopenharmony_ci case SET_DENS_AND_BLK: /* Set density and block size */ 289862306a36Sopenharmony_ci chg_eof = 0; 289962306a36Sopenharmony_ci if (STp->dirty || (STp->buffer)->buffer_bytes != 0) 290062306a36Sopenharmony_ci return (-EIO); /* Not allowed if data in buffer */ 290162306a36Sopenharmony_ci if ((cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) && 290262306a36Sopenharmony_ci (arg & MT_ST_BLKSIZE_MASK) != 0 && 290362306a36Sopenharmony_ci STp->max_block > 0 && 290462306a36Sopenharmony_ci ((arg & MT_ST_BLKSIZE_MASK) < STp->min_block || 290562306a36Sopenharmony_ci (arg & MT_ST_BLKSIZE_MASK) > STp->max_block)) { 290662306a36Sopenharmony_ci st_printk(KERN_WARNING, STp, "Illegal block size.\n"); 290762306a36Sopenharmony_ci return (-EINVAL); 290862306a36Sopenharmony_ci } 290962306a36Sopenharmony_ci cmd[0] = MODE_SELECT; 291062306a36Sopenharmony_ci if ((STp->use_pf & USE_PF)) 291162306a36Sopenharmony_ci cmd[1] = MODE_SELECT_PAGE_FORMAT; 291262306a36Sopenharmony_ci cmd[4] = datalen = 12; 291362306a36Sopenharmony_ci direction = DMA_TO_DEVICE; 291462306a36Sopenharmony_ci 291562306a36Sopenharmony_ci memset((STp->buffer)->b_data, 0, 12); 291662306a36Sopenharmony_ci if (cmd_in == MTSETDRVBUFFER) 291762306a36Sopenharmony_ci (STp->buffer)->b_data[2] = (arg & 7) << 4; 291862306a36Sopenharmony_ci else 291962306a36Sopenharmony_ci (STp->buffer)->b_data[2] = 292062306a36Sopenharmony_ci STp->drv_buffer << 4; 292162306a36Sopenharmony_ci (STp->buffer)->b_data[3] = 8; /* block descriptor length */ 292262306a36Sopenharmony_ci if (cmd_in == MTSETDENSITY) { 292362306a36Sopenharmony_ci (STp->buffer)->b_data[4] = arg; 292462306a36Sopenharmony_ci STp->density_changed = 1; /* At least we tried ;-) */ 292562306a36Sopenharmony_ci } else if (cmd_in == SET_DENS_AND_BLK) 292662306a36Sopenharmony_ci (STp->buffer)->b_data[4] = arg >> 24; 292762306a36Sopenharmony_ci else 292862306a36Sopenharmony_ci (STp->buffer)->b_data[4] = STp->density; 292962306a36Sopenharmony_ci if (cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) { 293062306a36Sopenharmony_ci ltmp = arg & MT_ST_BLKSIZE_MASK; 293162306a36Sopenharmony_ci if (cmd_in == MTSETBLK) 293262306a36Sopenharmony_ci STp->blksize_changed = 1; /* At least we tried ;-) */ 293362306a36Sopenharmony_ci } else 293462306a36Sopenharmony_ci ltmp = STp->block_size; 293562306a36Sopenharmony_ci (STp->buffer)->b_data[9] = (ltmp >> 16); 293662306a36Sopenharmony_ci (STp->buffer)->b_data[10] = (ltmp >> 8); 293762306a36Sopenharmony_ci (STp->buffer)->b_data[11] = ltmp; 293862306a36Sopenharmony_ci timeout = STp->device->request_queue->rq_timeout; 293962306a36Sopenharmony_ci DEBC( 294062306a36Sopenharmony_ci if (cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) 294162306a36Sopenharmony_ci st_printk(ST_DEB_MSG, STp, 294262306a36Sopenharmony_ci "Setting block size to %d bytes.\n", 294362306a36Sopenharmony_ci (STp->buffer)->b_data[9] * 65536 + 294462306a36Sopenharmony_ci (STp->buffer)->b_data[10] * 256 + 294562306a36Sopenharmony_ci (STp->buffer)->b_data[11]); 294662306a36Sopenharmony_ci if (cmd_in == MTSETDENSITY || cmd_in == SET_DENS_AND_BLK) 294762306a36Sopenharmony_ci st_printk(ST_DEB_MSG, STp, 294862306a36Sopenharmony_ci "Setting density code to %x.\n", 294962306a36Sopenharmony_ci (STp->buffer)->b_data[4]); 295062306a36Sopenharmony_ci if (cmd_in == MTSETDRVBUFFER) 295162306a36Sopenharmony_ci st_printk(ST_DEB_MSG, STp, 295262306a36Sopenharmony_ci "Setting drive buffer code to %d.\n", 295362306a36Sopenharmony_ci ((STp->buffer)->b_data[2] >> 4) & 7); 295462306a36Sopenharmony_ci ) 295562306a36Sopenharmony_ci break; 295662306a36Sopenharmony_ci default: 295762306a36Sopenharmony_ci return (-ENOSYS); 295862306a36Sopenharmony_ci } 295962306a36Sopenharmony_ci 296062306a36Sopenharmony_ci SRpnt = st_do_scsi(NULL, STp, cmd, datalen, direction, 296162306a36Sopenharmony_ci timeout, MAX_RETRIES, 1); 296262306a36Sopenharmony_ci if (!SRpnt) 296362306a36Sopenharmony_ci return (STp->buffer)->syscall_result; 296462306a36Sopenharmony_ci 296562306a36Sopenharmony_ci ioctl_result = (STp->buffer)->syscall_result; 296662306a36Sopenharmony_ci 296762306a36Sopenharmony_ci if (!ioctl_result) { /* SCSI command successful */ 296862306a36Sopenharmony_ci st_release_request(SRpnt); 296962306a36Sopenharmony_ci SRpnt = NULL; 297062306a36Sopenharmony_ci STps->drv_block = blkno; 297162306a36Sopenharmony_ci STps->drv_file = fileno; 297262306a36Sopenharmony_ci STps->at_sm = at_sm; 297362306a36Sopenharmony_ci 297462306a36Sopenharmony_ci if (cmd_in == MTBSFM) 297562306a36Sopenharmony_ci ioctl_result = st_int_ioctl(STp, MTFSF, 1); 297662306a36Sopenharmony_ci else if (cmd_in == MTFSFM) 297762306a36Sopenharmony_ci ioctl_result = st_int_ioctl(STp, MTBSF, 1); 297862306a36Sopenharmony_ci 297962306a36Sopenharmony_ci if (cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) { 298062306a36Sopenharmony_ci STp->block_size = arg & MT_ST_BLKSIZE_MASK; 298162306a36Sopenharmony_ci if (STp->block_size != 0) { 298262306a36Sopenharmony_ci (STp->buffer)->buffer_blocks = 298362306a36Sopenharmony_ci (STp->buffer)->buffer_size / STp->block_size; 298462306a36Sopenharmony_ci } 298562306a36Sopenharmony_ci (STp->buffer)->buffer_bytes = (STp->buffer)->read_pointer = 0; 298662306a36Sopenharmony_ci if (cmd_in == SET_DENS_AND_BLK) 298762306a36Sopenharmony_ci STp->density = arg >> MT_ST_DENSITY_SHIFT; 298862306a36Sopenharmony_ci } else if (cmd_in == MTSETDRVBUFFER) 298962306a36Sopenharmony_ci STp->drv_buffer = (arg & 7); 299062306a36Sopenharmony_ci else if (cmd_in == MTSETDENSITY) 299162306a36Sopenharmony_ci STp->density = arg; 299262306a36Sopenharmony_ci 299362306a36Sopenharmony_ci if (cmd_in == MTEOM) 299462306a36Sopenharmony_ci STps->eof = ST_EOD; 299562306a36Sopenharmony_ci else if (cmd_in == MTFSF) 299662306a36Sopenharmony_ci STps->eof = ST_FM; 299762306a36Sopenharmony_ci else if (chg_eof) 299862306a36Sopenharmony_ci STps->eof = ST_NOEOF; 299962306a36Sopenharmony_ci 300062306a36Sopenharmony_ci if (cmd_in == MTWEOF || cmd_in == MTWEOFI) 300162306a36Sopenharmony_ci STps->rw = ST_IDLE; /* prevent automatic WEOF at close */ 300262306a36Sopenharmony_ci } else { /* SCSI command was not completely successful. Don't return 300362306a36Sopenharmony_ci from this block without releasing the SCSI command block! */ 300462306a36Sopenharmony_ci struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat; 300562306a36Sopenharmony_ci 300662306a36Sopenharmony_ci if (cmdstatp->flags & SENSE_EOM) { 300762306a36Sopenharmony_ci if (cmd_in != MTBSF && cmd_in != MTBSFM && 300862306a36Sopenharmony_ci cmd_in != MTBSR && cmd_in != MTBSS) 300962306a36Sopenharmony_ci STps->eof = ST_EOM_OK; 301062306a36Sopenharmony_ci STps->drv_block = 0; 301162306a36Sopenharmony_ci } 301262306a36Sopenharmony_ci 301362306a36Sopenharmony_ci if (cmdstatp->remainder_valid) 301462306a36Sopenharmony_ci undone = (int)cmdstatp->uremainder64; 301562306a36Sopenharmony_ci else 301662306a36Sopenharmony_ci undone = 0; 301762306a36Sopenharmony_ci 301862306a36Sopenharmony_ci if ((cmd_in == MTWEOF || cmd_in == MTWEOFI) && 301962306a36Sopenharmony_ci cmdstatp->have_sense && 302062306a36Sopenharmony_ci (cmdstatp->flags & SENSE_EOM)) { 302162306a36Sopenharmony_ci if (cmdstatp->sense_hdr.sense_key == NO_SENSE || 302262306a36Sopenharmony_ci cmdstatp->sense_hdr.sense_key == RECOVERED_ERROR) { 302362306a36Sopenharmony_ci ioctl_result = 0; /* EOF(s) written successfully at EOM */ 302462306a36Sopenharmony_ci STps->eof = ST_NOEOF; 302562306a36Sopenharmony_ci } else { /* Writing EOF(s) failed */ 302662306a36Sopenharmony_ci if (fileno >= 0) 302762306a36Sopenharmony_ci fileno -= undone; 302862306a36Sopenharmony_ci if (undone < arg) 302962306a36Sopenharmony_ci STps->eof = ST_NOEOF; 303062306a36Sopenharmony_ci } 303162306a36Sopenharmony_ci STps->drv_file = fileno; 303262306a36Sopenharmony_ci } else if ((cmd_in == MTFSF) || (cmd_in == MTFSFM)) { 303362306a36Sopenharmony_ci if (fileno >= 0) 303462306a36Sopenharmony_ci STps->drv_file = fileno - undone; 303562306a36Sopenharmony_ci else 303662306a36Sopenharmony_ci STps->drv_file = fileno; 303762306a36Sopenharmony_ci STps->drv_block = -1; 303862306a36Sopenharmony_ci STps->eof = ST_NOEOF; 303962306a36Sopenharmony_ci } else if ((cmd_in == MTBSF) || (cmd_in == MTBSFM)) { 304062306a36Sopenharmony_ci if (arg > 0 && undone < 0) /* Some drives get this wrong */ 304162306a36Sopenharmony_ci undone = (-undone); 304262306a36Sopenharmony_ci if (STps->drv_file >= 0) 304362306a36Sopenharmony_ci STps->drv_file = fileno + undone; 304462306a36Sopenharmony_ci STps->drv_block = 0; 304562306a36Sopenharmony_ci STps->eof = ST_NOEOF; 304662306a36Sopenharmony_ci } else if (cmd_in == MTFSR) { 304762306a36Sopenharmony_ci if (cmdstatp->flags & SENSE_FMK) { /* Hit filemark */ 304862306a36Sopenharmony_ci if (STps->drv_file >= 0) 304962306a36Sopenharmony_ci STps->drv_file++; 305062306a36Sopenharmony_ci STps->drv_block = 0; 305162306a36Sopenharmony_ci STps->eof = ST_FM; 305262306a36Sopenharmony_ci } else { 305362306a36Sopenharmony_ci if (blkno >= undone) 305462306a36Sopenharmony_ci STps->drv_block = blkno - undone; 305562306a36Sopenharmony_ci else 305662306a36Sopenharmony_ci STps->drv_block = (-1); 305762306a36Sopenharmony_ci STps->eof = ST_NOEOF; 305862306a36Sopenharmony_ci } 305962306a36Sopenharmony_ci } else if (cmd_in == MTBSR) { 306062306a36Sopenharmony_ci if (cmdstatp->flags & SENSE_FMK) { /* Hit filemark */ 306162306a36Sopenharmony_ci STps->drv_file--; 306262306a36Sopenharmony_ci STps->drv_block = (-1); 306362306a36Sopenharmony_ci } else { 306462306a36Sopenharmony_ci if (arg > 0 && undone < 0) /* Some drives get this wrong */ 306562306a36Sopenharmony_ci undone = (-undone); 306662306a36Sopenharmony_ci if (STps->drv_block >= 0) 306762306a36Sopenharmony_ci STps->drv_block = blkno + undone; 306862306a36Sopenharmony_ci } 306962306a36Sopenharmony_ci STps->eof = ST_NOEOF; 307062306a36Sopenharmony_ci } else if (cmd_in == MTEOM) { 307162306a36Sopenharmony_ci STps->drv_file = (-1); 307262306a36Sopenharmony_ci STps->drv_block = (-1); 307362306a36Sopenharmony_ci STps->eof = ST_EOD; 307462306a36Sopenharmony_ci } else if (cmd_in == MTSETBLK || 307562306a36Sopenharmony_ci cmd_in == MTSETDENSITY || 307662306a36Sopenharmony_ci cmd_in == MTSETDRVBUFFER || 307762306a36Sopenharmony_ci cmd_in == SET_DENS_AND_BLK) { 307862306a36Sopenharmony_ci if (cmdstatp->sense_hdr.sense_key == ILLEGAL_REQUEST && 307962306a36Sopenharmony_ci !(STp->use_pf & PF_TESTED)) { 308062306a36Sopenharmony_ci /* Try the other possible state of Page Format if not 308162306a36Sopenharmony_ci already tried */ 308262306a36Sopenharmony_ci STp->use_pf = (STp->use_pf ^ USE_PF) | PF_TESTED; 308362306a36Sopenharmony_ci st_release_request(SRpnt); 308462306a36Sopenharmony_ci SRpnt = NULL; 308562306a36Sopenharmony_ci return st_int_ioctl(STp, cmd_in, arg); 308662306a36Sopenharmony_ci } 308762306a36Sopenharmony_ci } else if (chg_eof) 308862306a36Sopenharmony_ci STps->eof = ST_NOEOF; 308962306a36Sopenharmony_ci 309062306a36Sopenharmony_ci if (cmdstatp->sense_hdr.sense_key == BLANK_CHECK) 309162306a36Sopenharmony_ci STps->eof = ST_EOD; 309262306a36Sopenharmony_ci 309362306a36Sopenharmony_ci st_release_request(SRpnt); 309462306a36Sopenharmony_ci SRpnt = NULL; 309562306a36Sopenharmony_ci } 309662306a36Sopenharmony_ci 309762306a36Sopenharmony_ci return ioctl_result; 309862306a36Sopenharmony_ci} 309962306a36Sopenharmony_ci 310062306a36Sopenharmony_ci 310162306a36Sopenharmony_ci/* Get the tape position. If bt == 2, arg points into a kernel space mt_loc 310262306a36Sopenharmony_ci structure. */ 310362306a36Sopenharmony_ci 310462306a36Sopenharmony_cistatic int get_location(struct scsi_tape *STp, unsigned int *block, int *partition, 310562306a36Sopenharmony_ci int logical) 310662306a36Sopenharmony_ci{ 310762306a36Sopenharmony_ci int result; 310862306a36Sopenharmony_ci unsigned char scmd[MAX_COMMAND_SIZE]; 310962306a36Sopenharmony_ci struct st_request *SRpnt; 311062306a36Sopenharmony_ci 311162306a36Sopenharmony_ci if (STp->ready != ST_READY) 311262306a36Sopenharmony_ci return (-EIO); 311362306a36Sopenharmony_ci 311462306a36Sopenharmony_ci memset(scmd, 0, MAX_COMMAND_SIZE); 311562306a36Sopenharmony_ci if ((STp->device)->scsi_level < SCSI_2) { 311662306a36Sopenharmony_ci scmd[0] = QFA_REQUEST_BLOCK; 311762306a36Sopenharmony_ci scmd[4] = 3; 311862306a36Sopenharmony_ci } else { 311962306a36Sopenharmony_ci scmd[0] = READ_POSITION; 312062306a36Sopenharmony_ci if (!logical && !STp->scsi2_logical) 312162306a36Sopenharmony_ci scmd[1] = 1; 312262306a36Sopenharmony_ci } 312362306a36Sopenharmony_ci SRpnt = st_do_scsi(NULL, STp, scmd, 20, DMA_FROM_DEVICE, 312462306a36Sopenharmony_ci STp->device->request_queue->rq_timeout, 312562306a36Sopenharmony_ci MAX_READY_RETRIES, 1); 312662306a36Sopenharmony_ci if (!SRpnt) 312762306a36Sopenharmony_ci return (STp->buffer)->syscall_result; 312862306a36Sopenharmony_ci 312962306a36Sopenharmony_ci if ((STp->buffer)->syscall_result != 0 || 313062306a36Sopenharmony_ci (STp->device->scsi_level >= SCSI_2 && 313162306a36Sopenharmony_ci ((STp->buffer)->b_data[0] & 4) != 0)) { 313262306a36Sopenharmony_ci *block = *partition = 0; 313362306a36Sopenharmony_ci DEBC_printk(STp, " Can't read tape position.\n"); 313462306a36Sopenharmony_ci result = (-EIO); 313562306a36Sopenharmony_ci } else { 313662306a36Sopenharmony_ci result = 0; 313762306a36Sopenharmony_ci if ((STp->device)->scsi_level < SCSI_2) { 313862306a36Sopenharmony_ci *block = ((STp->buffer)->b_data[0] << 16) 313962306a36Sopenharmony_ci + ((STp->buffer)->b_data[1] << 8) 314062306a36Sopenharmony_ci + (STp->buffer)->b_data[2]; 314162306a36Sopenharmony_ci *partition = 0; 314262306a36Sopenharmony_ci } else { 314362306a36Sopenharmony_ci *block = ((STp->buffer)->b_data[4] << 24) 314462306a36Sopenharmony_ci + ((STp->buffer)->b_data[5] << 16) 314562306a36Sopenharmony_ci + ((STp->buffer)->b_data[6] << 8) 314662306a36Sopenharmony_ci + (STp->buffer)->b_data[7]; 314762306a36Sopenharmony_ci *partition = (STp->buffer)->b_data[1]; 314862306a36Sopenharmony_ci if (((STp->buffer)->b_data[0] & 0x80) && 314962306a36Sopenharmony_ci (STp->buffer)->b_data[1] == 0) /* BOP of partition 0 */ 315062306a36Sopenharmony_ci STp->ps[0].drv_block = STp->ps[0].drv_file = 0; 315162306a36Sopenharmony_ci } 315262306a36Sopenharmony_ci DEBC_printk(STp, "Got tape pos. blk %d part %d.\n", 315362306a36Sopenharmony_ci *block, *partition); 315462306a36Sopenharmony_ci } 315562306a36Sopenharmony_ci st_release_request(SRpnt); 315662306a36Sopenharmony_ci SRpnt = NULL; 315762306a36Sopenharmony_ci 315862306a36Sopenharmony_ci return result; 315962306a36Sopenharmony_ci} 316062306a36Sopenharmony_ci 316162306a36Sopenharmony_ci 316262306a36Sopenharmony_ci/* Set the tape block and partition. Negative partition means that only the 316362306a36Sopenharmony_ci block should be set in vendor specific way. */ 316462306a36Sopenharmony_cistatic int set_location(struct scsi_tape *STp, unsigned int block, int partition, 316562306a36Sopenharmony_ci int logical) 316662306a36Sopenharmony_ci{ 316762306a36Sopenharmony_ci struct st_partstat *STps; 316862306a36Sopenharmony_ci int result, p; 316962306a36Sopenharmony_ci unsigned int blk; 317062306a36Sopenharmony_ci int timeout; 317162306a36Sopenharmony_ci unsigned char scmd[MAX_COMMAND_SIZE]; 317262306a36Sopenharmony_ci struct st_request *SRpnt; 317362306a36Sopenharmony_ci 317462306a36Sopenharmony_ci if (STp->ready != ST_READY) 317562306a36Sopenharmony_ci return (-EIO); 317662306a36Sopenharmony_ci timeout = STp->long_timeout; 317762306a36Sopenharmony_ci STps = &(STp->ps[STp->partition]); 317862306a36Sopenharmony_ci 317962306a36Sopenharmony_ci DEBC_printk(STp, "Setting block to %d and partition to %d.\n", 318062306a36Sopenharmony_ci block, partition); 318162306a36Sopenharmony_ci DEB(if (partition < 0) 318262306a36Sopenharmony_ci return (-EIO); ) 318362306a36Sopenharmony_ci 318462306a36Sopenharmony_ci /* Update the location at the partition we are leaving */ 318562306a36Sopenharmony_ci if ((!STp->can_partitions && partition != 0) || 318662306a36Sopenharmony_ci partition >= ST_NBR_PARTITIONS) 318762306a36Sopenharmony_ci return (-EINVAL); 318862306a36Sopenharmony_ci if (partition != STp->partition) { 318962306a36Sopenharmony_ci if (get_location(STp, &blk, &p, 1)) 319062306a36Sopenharmony_ci STps->last_block_valid = 0; 319162306a36Sopenharmony_ci else { 319262306a36Sopenharmony_ci STps->last_block_valid = 1; 319362306a36Sopenharmony_ci STps->last_block_visited = blk; 319462306a36Sopenharmony_ci DEBC_printk(STp, "Visited block %d for " 319562306a36Sopenharmony_ci "partition %d saved.\n", 319662306a36Sopenharmony_ci blk, STp->partition); 319762306a36Sopenharmony_ci } 319862306a36Sopenharmony_ci } 319962306a36Sopenharmony_ci 320062306a36Sopenharmony_ci memset(scmd, 0, MAX_COMMAND_SIZE); 320162306a36Sopenharmony_ci if ((STp->device)->scsi_level < SCSI_2) { 320262306a36Sopenharmony_ci scmd[0] = QFA_SEEK_BLOCK; 320362306a36Sopenharmony_ci scmd[2] = (block >> 16); 320462306a36Sopenharmony_ci scmd[3] = (block >> 8); 320562306a36Sopenharmony_ci scmd[4] = block; 320662306a36Sopenharmony_ci scmd[5] = 0; 320762306a36Sopenharmony_ci } else { 320862306a36Sopenharmony_ci scmd[0] = SEEK_10; 320962306a36Sopenharmony_ci scmd[3] = (block >> 24); 321062306a36Sopenharmony_ci scmd[4] = (block >> 16); 321162306a36Sopenharmony_ci scmd[5] = (block >> 8); 321262306a36Sopenharmony_ci scmd[6] = block; 321362306a36Sopenharmony_ci if (!logical && !STp->scsi2_logical) 321462306a36Sopenharmony_ci scmd[1] = 4; 321562306a36Sopenharmony_ci if (STp->partition != partition) { 321662306a36Sopenharmony_ci scmd[1] |= 2; 321762306a36Sopenharmony_ci scmd[8] = partition; 321862306a36Sopenharmony_ci DEBC_printk(STp, "Trying to change partition " 321962306a36Sopenharmony_ci "from %d to %d\n", STp->partition, 322062306a36Sopenharmony_ci partition); 322162306a36Sopenharmony_ci } 322262306a36Sopenharmony_ci } 322362306a36Sopenharmony_ci if (STp->immediate) { 322462306a36Sopenharmony_ci scmd[1] |= 1; /* Don't wait for completion */ 322562306a36Sopenharmony_ci timeout = STp->device->request_queue->rq_timeout; 322662306a36Sopenharmony_ci } 322762306a36Sopenharmony_ci 322862306a36Sopenharmony_ci SRpnt = st_do_scsi(NULL, STp, scmd, 0, DMA_NONE, 322962306a36Sopenharmony_ci timeout, MAX_READY_RETRIES, 1); 323062306a36Sopenharmony_ci if (!SRpnt) 323162306a36Sopenharmony_ci return (STp->buffer)->syscall_result; 323262306a36Sopenharmony_ci 323362306a36Sopenharmony_ci STps->drv_block = STps->drv_file = (-1); 323462306a36Sopenharmony_ci STps->eof = ST_NOEOF; 323562306a36Sopenharmony_ci if ((STp->buffer)->syscall_result != 0) { 323662306a36Sopenharmony_ci result = (-EIO); 323762306a36Sopenharmony_ci if (STp->can_partitions && 323862306a36Sopenharmony_ci (STp->device)->scsi_level >= SCSI_2 && 323962306a36Sopenharmony_ci (p = find_partition(STp)) >= 0) 324062306a36Sopenharmony_ci STp->partition = p; 324162306a36Sopenharmony_ci } else { 324262306a36Sopenharmony_ci if (STp->can_partitions) { 324362306a36Sopenharmony_ci STp->partition = partition; 324462306a36Sopenharmony_ci STps = &(STp->ps[partition]); 324562306a36Sopenharmony_ci if (!STps->last_block_valid || 324662306a36Sopenharmony_ci STps->last_block_visited != block) { 324762306a36Sopenharmony_ci STps->at_sm = 0; 324862306a36Sopenharmony_ci STps->rw = ST_IDLE; 324962306a36Sopenharmony_ci } 325062306a36Sopenharmony_ci } else 325162306a36Sopenharmony_ci STps->at_sm = 0; 325262306a36Sopenharmony_ci if (block == 0) 325362306a36Sopenharmony_ci STps->drv_block = STps->drv_file = 0; 325462306a36Sopenharmony_ci result = 0; 325562306a36Sopenharmony_ci } 325662306a36Sopenharmony_ci 325762306a36Sopenharmony_ci st_release_request(SRpnt); 325862306a36Sopenharmony_ci SRpnt = NULL; 325962306a36Sopenharmony_ci 326062306a36Sopenharmony_ci return result; 326162306a36Sopenharmony_ci} 326262306a36Sopenharmony_ci 326362306a36Sopenharmony_ci 326462306a36Sopenharmony_ci/* Find the current partition number for the drive status. Called from open and 326562306a36Sopenharmony_ci returns either partition number of negative error code. */ 326662306a36Sopenharmony_cistatic int find_partition(struct scsi_tape *STp) 326762306a36Sopenharmony_ci{ 326862306a36Sopenharmony_ci int i, partition; 326962306a36Sopenharmony_ci unsigned int block; 327062306a36Sopenharmony_ci 327162306a36Sopenharmony_ci if ((i = get_location(STp, &block, &partition, 1)) < 0) 327262306a36Sopenharmony_ci return i; 327362306a36Sopenharmony_ci if (partition >= ST_NBR_PARTITIONS) 327462306a36Sopenharmony_ci return (-EIO); 327562306a36Sopenharmony_ci return partition; 327662306a36Sopenharmony_ci} 327762306a36Sopenharmony_ci 327862306a36Sopenharmony_ci 327962306a36Sopenharmony_ci/* Change the partition if necessary */ 328062306a36Sopenharmony_cistatic int switch_partition(struct scsi_tape *STp) 328162306a36Sopenharmony_ci{ 328262306a36Sopenharmony_ci struct st_partstat *STps; 328362306a36Sopenharmony_ci 328462306a36Sopenharmony_ci if (STp->partition == STp->new_partition) 328562306a36Sopenharmony_ci return 0; 328662306a36Sopenharmony_ci STps = &(STp->ps[STp->new_partition]); 328762306a36Sopenharmony_ci if (!STps->last_block_valid) 328862306a36Sopenharmony_ci STps->last_block_visited = 0; 328962306a36Sopenharmony_ci return set_location(STp, STps->last_block_visited, STp->new_partition, 1); 329062306a36Sopenharmony_ci} 329162306a36Sopenharmony_ci 329262306a36Sopenharmony_ci/* Functions for reading and writing the medium partition mode page. */ 329362306a36Sopenharmony_ci 329462306a36Sopenharmony_ci#define PART_PAGE 0x11 329562306a36Sopenharmony_ci#define PART_PAGE_FIXED_LENGTH 8 329662306a36Sopenharmony_ci 329762306a36Sopenharmony_ci#define PP_OFF_MAX_ADD_PARTS 2 329862306a36Sopenharmony_ci#define PP_OFF_NBR_ADD_PARTS 3 329962306a36Sopenharmony_ci#define PP_OFF_FLAGS 4 330062306a36Sopenharmony_ci#define PP_OFF_PART_UNITS 6 330162306a36Sopenharmony_ci#define PP_OFF_RESERVED 7 330262306a36Sopenharmony_ci 330362306a36Sopenharmony_ci#define PP_BIT_IDP 0x20 330462306a36Sopenharmony_ci#define PP_BIT_FDP 0x80 330562306a36Sopenharmony_ci#define PP_MSK_PSUM_MB 0x10 330662306a36Sopenharmony_ci#define PP_MSK_PSUM_UNITS 0x18 330762306a36Sopenharmony_ci#define PP_MSK_POFM 0x04 330862306a36Sopenharmony_ci 330962306a36Sopenharmony_ci/* Get the number of partitions on the tape. As a side effect reads the 331062306a36Sopenharmony_ci mode page into the tape buffer. */ 331162306a36Sopenharmony_cistatic int nbr_partitions(struct scsi_tape *STp) 331262306a36Sopenharmony_ci{ 331362306a36Sopenharmony_ci int result; 331462306a36Sopenharmony_ci 331562306a36Sopenharmony_ci if (STp->ready != ST_READY) 331662306a36Sopenharmony_ci return (-EIO); 331762306a36Sopenharmony_ci 331862306a36Sopenharmony_ci result = read_mode_page(STp, PART_PAGE, 1); 331962306a36Sopenharmony_ci 332062306a36Sopenharmony_ci if (result) { 332162306a36Sopenharmony_ci DEBC_printk(STp, "Can't read medium partition page.\n"); 332262306a36Sopenharmony_ci result = (-EIO); 332362306a36Sopenharmony_ci } else { 332462306a36Sopenharmony_ci result = (STp->buffer)->b_data[MODE_HEADER_LENGTH + 332562306a36Sopenharmony_ci PP_OFF_NBR_ADD_PARTS] + 1; 332662306a36Sopenharmony_ci DEBC_printk(STp, "Number of partitions %d.\n", result); 332762306a36Sopenharmony_ci } 332862306a36Sopenharmony_ci 332962306a36Sopenharmony_ci return result; 333062306a36Sopenharmony_ci} 333162306a36Sopenharmony_ci 333262306a36Sopenharmony_ci 333362306a36Sopenharmony_cistatic int format_medium(struct scsi_tape *STp, int format) 333462306a36Sopenharmony_ci{ 333562306a36Sopenharmony_ci int result = 0; 333662306a36Sopenharmony_ci int timeout = STp->long_timeout; 333762306a36Sopenharmony_ci unsigned char scmd[MAX_COMMAND_SIZE]; 333862306a36Sopenharmony_ci struct st_request *SRpnt; 333962306a36Sopenharmony_ci 334062306a36Sopenharmony_ci memset(scmd, 0, MAX_COMMAND_SIZE); 334162306a36Sopenharmony_ci scmd[0] = FORMAT_UNIT; 334262306a36Sopenharmony_ci scmd[2] = format; 334362306a36Sopenharmony_ci if (STp->immediate) { 334462306a36Sopenharmony_ci scmd[1] |= 1; /* Don't wait for completion */ 334562306a36Sopenharmony_ci timeout = STp->device->request_queue->rq_timeout; 334662306a36Sopenharmony_ci } 334762306a36Sopenharmony_ci DEBC_printk(STp, "Sending FORMAT MEDIUM\n"); 334862306a36Sopenharmony_ci SRpnt = st_do_scsi(NULL, STp, scmd, 0, DMA_NONE, 334962306a36Sopenharmony_ci timeout, MAX_RETRIES, 1); 335062306a36Sopenharmony_ci if (!SRpnt) 335162306a36Sopenharmony_ci result = STp->buffer->syscall_result; 335262306a36Sopenharmony_ci return result; 335362306a36Sopenharmony_ci} 335462306a36Sopenharmony_ci 335562306a36Sopenharmony_ci 335662306a36Sopenharmony_ci/* Partition the tape into two partitions if size > 0 or one partition if 335762306a36Sopenharmony_ci size == 0. 335862306a36Sopenharmony_ci 335962306a36Sopenharmony_ci The block descriptors are read and written because Sony SDT-7000 does not 336062306a36Sopenharmony_ci work without this (suggestion from Michael Schaefer <Michael.Schaefer@dlr.de>). 336162306a36Sopenharmony_ci 336262306a36Sopenharmony_ci My HP C1533A drive returns only one partition size field. This is used to 336362306a36Sopenharmony_ci set the size of partition 1. There is no size field for the default partition. 336462306a36Sopenharmony_ci Michael Schaefer's Sony SDT-7000 returns two descriptors and the second is 336562306a36Sopenharmony_ci used to set the size of partition 1 (this is what the SCSI-3 standard specifies). 336662306a36Sopenharmony_ci The following algorithm is used to accommodate both drives: if the number of 336762306a36Sopenharmony_ci partition size fields is greater than the maximum number of additional partitions 336862306a36Sopenharmony_ci in the mode page, the second field is used. Otherwise the first field is used. 336962306a36Sopenharmony_ci 337062306a36Sopenharmony_ci For Seagate DDS drives the page length must be 8 when no partitions is defined 337162306a36Sopenharmony_ci and 10 when 1 partition is defined (information from Eric Lee Green). This is 337262306a36Sopenharmony_ci is acceptable also to some other old drives and enforced if the first partition 337362306a36Sopenharmony_ci size field is used for the first additional partition size. 337462306a36Sopenharmony_ci 337562306a36Sopenharmony_ci For drives that advertize SCSI-3 or newer, use the SSC-3 methods. 337662306a36Sopenharmony_ci */ 337762306a36Sopenharmony_cistatic int partition_tape(struct scsi_tape *STp, int size) 337862306a36Sopenharmony_ci{ 337962306a36Sopenharmony_ci int result; 338062306a36Sopenharmony_ci int target_partition; 338162306a36Sopenharmony_ci bool scsi3 = STp->device->scsi_level >= SCSI_3, needs_format = false; 338262306a36Sopenharmony_ci int pgo, psd_cnt, psdo; 338362306a36Sopenharmony_ci int psum = PP_MSK_PSUM_MB, units = 0; 338462306a36Sopenharmony_ci unsigned char *bp; 338562306a36Sopenharmony_ci 338662306a36Sopenharmony_ci result = read_mode_page(STp, PART_PAGE, 0); 338762306a36Sopenharmony_ci if (result) { 338862306a36Sopenharmony_ci DEBC_printk(STp, "Can't read partition mode page.\n"); 338962306a36Sopenharmony_ci return result; 339062306a36Sopenharmony_ci } 339162306a36Sopenharmony_ci target_partition = 1; 339262306a36Sopenharmony_ci if (size < 0) { 339362306a36Sopenharmony_ci target_partition = 0; 339462306a36Sopenharmony_ci size = -size; 339562306a36Sopenharmony_ci } 339662306a36Sopenharmony_ci 339762306a36Sopenharmony_ci /* The mode page is in the buffer. Let's modify it and write it. */ 339862306a36Sopenharmony_ci bp = (STp->buffer)->b_data; 339962306a36Sopenharmony_ci pgo = MODE_HEADER_LENGTH + bp[MH_OFF_BDESCS_LENGTH]; 340062306a36Sopenharmony_ci DEBC_printk(STp, "Partition page length is %d bytes.\n", 340162306a36Sopenharmony_ci bp[pgo + MP_OFF_PAGE_LENGTH] + 2); 340262306a36Sopenharmony_ci 340362306a36Sopenharmony_ci psd_cnt = (bp[pgo + MP_OFF_PAGE_LENGTH] + 2 - PART_PAGE_FIXED_LENGTH) / 2; 340462306a36Sopenharmony_ci 340562306a36Sopenharmony_ci if (scsi3) { 340662306a36Sopenharmony_ci needs_format = (bp[pgo + PP_OFF_FLAGS] & PP_MSK_POFM) != 0; 340762306a36Sopenharmony_ci if (needs_format && size == 0) { 340862306a36Sopenharmony_ci /* No need to write the mode page when clearing 340962306a36Sopenharmony_ci * partitioning 341062306a36Sopenharmony_ci */ 341162306a36Sopenharmony_ci DEBC_printk(STp, "Formatting tape with one partition.\n"); 341262306a36Sopenharmony_ci result = format_medium(STp, 0); 341362306a36Sopenharmony_ci goto out; 341462306a36Sopenharmony_ci } 341562306a36Sopenharmony_ci if (needs_format) /* Leave the old value for HP DATs claiming SCSI_3 */ 341662306a36Sopenharmony_ci psd_cnt = 2; 341762306a36Sopenharmony_ci if ((bp[pgo + PP_OFF_FLAGS] & PP_MSK_PSUM_UNITS) == PP_MSK_PSUM_UNITS) { 341862306a36Sopenharmony_ci /* Use units scaling for large partitions if the device 341962306a36Sopenharmony_ci * suggests it and no precision lost. Required for IBM 342062306a36Sopenharmony_ci * TS1140/50 drives that don't support MB units. 342162306a36Sopenharmony_ci */ 342262306a36Sopenharmony_ci if (size >= 1000 && (size % 1000) == 0) { 342362306a36Sopenharmony_ci size /= 1000; 342462306a36Sopenharmony_ci psum = PP_MSK_PSUM_UNITS; 342562306a36Sopenharmony_ci units = 9; /* GB */ 342662306a36Sopenharmony_ci } 342762306a36Sopenharmony_ci } 342862306a36Sopenharmony_ci /* Try it anyway if too large to specify in MB */ 342962306a36Sopenharmony_ci if (psum == PP_MSK_PSUM_MB && size >= 65534) { 343062306a36Sopenharmony_ci size /= 1000; 343162306a36Sopenharmony_ci psum = PP_MSK_PSUM_UNITS; 343262306a36Sopenharmony_ci units = 9; /* GB */ 343362306a36Sopenharmony_ci } 343462306a36Sopenharmony_ci } 343562306a36Sopenharmony_ci 343662306a36Sopenharmony_ci if (size >= 65535 || /* Does not fit into two bytes */ 343762306a36Sopenharmony_ci (target_partition == 0 && psd_cnt < 2)) { 343862306a36Sopenharmony_ci result = -EINVAL; 343962306a36Sopenharmony_ci goto out; 344062306a36Sopenharmony_ci } 344162306a36Sopenharmony_ci 344262306a36Sopenharmony_ci psdo = pgo + PART_PAGE_FIXED_LENGTH; 344362306a36Sopenharmony_ci /* The second condition is for HP DDS which use only one partition size 344462306a36Sopenharmony_ci * descriptor 344562306a36Sopenharmony_ci */ 344662306a36Sopenharmony_ci if (target_partition > 0 && 344762306a36Sopenharmony_ci (psd_cnt > bp[pgo + PP_OFF_MAX_ADD_PARTS] || 344862306a36Sopenharmony_ci bp[pgo + PP_OFF_MAX_ADD_PARTS] != 1)) { 344962306a36Sopenharmony_ci bp[psdo] = bp[psdo + 1] = 0xff; /* Rest to partition 0 */ 345062306a36Sopenharmony_ci psdo += 2; 345162306a36Sopenharmony_ci } 345262306a36Sopenharmony_ci memset(bp + psdo, 0, bp[pgo + PP_OFF_NBR_ADD_PARTS] * 2); 345362306a36Sopenharmony_ci 345462306a36Sopenharmony_ci DEBC_printk(STp, "psd_cnt %d, max.parts %d, nbr_parts %d\n", 345562306a36Sopenharmony_ci psd_cnt, bp[pgo + PP_OFF_MAX_ADD_PARTS], 345662306a36Sopenharmony_ci bp[pgo + PP_OFF_NBR_ADD_PARTS]); 345762306a36Sopenharmony_ci 345862306a36Sopenharmony_ci if (size == 0) { 345962306a36Sopenharmony_ci bp[pgo + PP_OFF_NBR_ADD_PARTS] = 0; 346062306a36Sopenharmony_ci if (psd_cnt <= bp[pgo + PP_OFF_MAX_ADD_PARTS]) 346162306a36Sopenharmony_ci bp[pgo + MP_OFF_PAGE_LENGTH] = 6; 346262306a36Sopenharmony_ci DEBC_printk(STp, "Formatting tape with one partition.\n"); 346362306a36Sopenharmony_ci } else { 346462306a36Sopenharmony_ci bp[psdo] = (size >> 8) & 0xff; 346562306a36Sopenharmony_ci bp[psdo + 1] = size & 0xff; 346662306a36Sopenharmony_ci if (target_partition == 0) 346762306a36Sopenharmony_ci bp[psdo + 2] = bp[psdo + 3] = 0xff; 346862306a36Sopenharmony_ci bp[pgo + 3] = 1; 346962306a36Sopenharmony_ci if (bp[pgo + MP_OFF_PAGE_LENGTH] < 8) 347062306a36Sopenharmony_ci bp[pgo + MP_OFF_PAGE_LENGTH] = 8; 347162306a36Sopenharmony_ci DEBC_printk(STp, 347262306a36Sopenharmony_ci "Formatting tape with two partitions (%i = %d MB).\n", 347362306a36Sopenharmony_ci target_partition, units > 0 ? size * 1000 : size); 347462306a36Sopenharmony_ci } 347562306a36Sopenharmony_ci bp[pgo + PP_OFF_PART_UNITS] = 0; 347662306a36Sopenharmony_ci bp[pgo + PP_OFF_RESERVED] = 0; 347762306a36Sopenharmony_ci if (size != 1 || units != 0) { 347862306a36Sopenharmony_ci bp[pgo + PP_OFF_FLAGS] = PP_BIT_IDP | psum | 347962306a36Sopenharmony_ci (bp[pgo + PP_OFF_FLAGS] & 0x07); 348062306a36Sopenharmony_ci bp[pgo + PP_OFF_PART_UNITS] = units; 348162306a36Sopenharmony_ci } else 348262306a36Sopenharmony_ci bp[pgo + PP_OFF_FLAGS] = PP_BIT_FDP | 348362306a36Sopenharmony_ci (bp[pgo + PP_OFF_FLAGS] & 0x1f); 348462306a36Sopenharmony_ci bp[pgo + MP_OFF_PAGE_LENGTH] = 6 + psd_cnt * 2; 348562306a36Sopenharmony_ci 348662306a36Sopenharmony_ci result = write_mode_page(STp, PART_PAGE, 1); 348762306a36Sopenharmony_ci 348862306a36Sopenharmony_ci if (!result && needs_format) 348962306a36Sopenharmony_ci result = format_medium(STp, 1); 349062306a36Sopenharmony_ci 349162306a36Sopenharmony_ci if (result) { 349262306a36Sopenharmony_ci st_printk(KERN_INFO, STp, "Partitioning of tape failed.\n"); 349362306a36Sopenharmony_ci result = (-EIO); 349462306a36Sopenharmony_ci } 349562306a36Sopenharmony_ci 349662306a36Sopenharmony_ciout: 349762306a36Sopenharmony_ci return result; 349862306a36Sopenharmony_ci} 349962306a36Sopenharmony_ci 350062306a36Sopenharmony_ci 350162306a36Sopenharmony_ci 350262306a36Sopenharmony_ci/* The ioctl command */ 350362306a36Sopenharmony_cistatic long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg) 350462306a36Sopenharmony_ci{ 350562306a36Sopenharmony_ci void __user *p = (void __user *)arg; 350662306a36Sopenharmony_ci int i, cmd_nr, cmd_type, bt; 350762306a36Sopenharmony_ci int retval = 0; 350862306a36Sopenharmony_ci unsigned int blk; 350962306a36Sopenharmony_ci struct scsi_tape *STp = file->private_data; 351062306a36Sopenharmony_ci struct st_modedef *STm; 351162306a36Sopenharmony_ci struct st_partstat *STps; 351262306a36Sopenharmony_ci 351362306a36Sopenharmony_ci if (mutex_lock_interruptible(&STp->lock)) 351462306a36Sopenharmony_ci return -ERESTARTSYS; 351562306a36Sopenharmony_ci 351662306a36Sopenharmony_ci DEB( 351762306a36Sopenharmony_ci if (debugging && !STp->in_use) { 351862306a36Sopenharmony_ci st_printk(ST_DEB_MSG, STp, "Incorrect device.\n"); 351962306a36Sopenharmony_ci retval = (-EIO); 352062306a36Sopenharmony_ci goto out; 352162306a36Sopenharmony_ci } ) /* end DEB */ 352262306a36Sopenharmony_ci 352362306a36Sopenharmony_ci STm = &(STp->modes[STp->current_mode]); 352462306a36Sopenharmony_ci STps = &(STp->ps[STp->partition]); 352562306a36Sopenharmony_ci 352662306a36Sopenharmony_ci /* 352762306a36Sopenharmony_ci * If we are in the middle of error recovery, don't let anyone 352862306a36Sopenharmony_ci * else try and use this device. Also, if error recovery fails, it 352962306a36Sopenharmony_ci * may try and take the device offline, in which case all further 353062306a36Sopenharmony_ci * access to the device is prohibited. 353162306a36Sopenharmony_ci */ 353262306a36Sopenharmony_ci retval = scsi_ioctl_block_when_processing_errors(STp->device, cmd_in, 353362306a36Sopenharmony_ci file->f_flags & O_NDELAY); 353462306a36Sopenharmony_ci if (retval) 353562306a36Sopenharmony_ci goto out; 353662306a36Sopenharmony_ci 353762306a36Sopenharmony_ci cmd_type = _IOC_TYPE(cmd_in); 353862306a36Sopenharmony_ci cmd_nr = _IOC_NR(cmd_in); 353962306a36Sopenharmony_ci 354062306a36Sopenharmony_ci if (cmd_type == _IOC_TYPE(MTIOCTOP) && cmd_nr == _IOC_NR(MTIOCTOP)) { 354162306a36Sopenharmony_ci struct mtop mtc; 354262306a36Sopenharmony_ci 354362306a36Sopenharmony_ci if (_IOC_SIZE(cmd_in) != sizeof(mtc)) { 354462306a36Sopenharmony_ci retval = (-EINVAL); 354562306a36Sopenharmony_ci goto out; 354662306a36Sopenharmony_ci } 354762306a36Sopenharmony_ci 354862306a36Sopenharmony_ci i = copy_from_user(&mtc, p, sizeof(struct mtop)); 354962306a36Sopenharmony_ci if (i) { 355062306a36Sopenharmony_ci retval = (-EFAULT); 355162306a36Sopenharmony_ci goto out; 355262306a36Sopenharmony_ci } 355362306a36Sopenharmony_ci 355462306a36Sopenharmony_ci if (mtc.mt_op == MTSETDRVBUFFER && !capable(CAP_SYS_ADMIN)) { 355562306a36Sopenharmony_ci st_printk(KERN_WARNING, STp, 355662306a36Sopenharmony_ci "MTSETDRVBUFFER only allowed for root.\n"); 355762306a36Sopenharmony_ci retval = (-EPERM); 355862306a36Sopenharmony_ci goto out; 355962306a36Sopenharmony_ci } 356062306a36Sopenharmony_ci if (!STm->defined && 356162306a36Sopenharmony_ci (mtc.mt_op != MTSETDRVBUFFER && 356262306a36Sopenharmony_ci (mtc.mt_count & MT_ST_OPTIONS) == 0)) { 356362306a36Sopenharmony_ci retval = (-ENXIO); 356462306a36Sopenharmony_ci goto out; 356562306a36Sopenharmony_ci } 356662306a36Sopenharmony_ci 356762306a36Sopenharmony_ci if (!STp->pos_unknown) { 356862306a36Sopenharmony_ci 356962306a36Sopenharmony_ci if (STps->eof == ST_FM_HIT) { 357062306a36Sopenharmony_ci if (mtc.mt_op == MTFSF || mtc.mt_op == MTFSFM || 357162306a36Sopenharmony_ci mtc.mt_op == MTEOM) { 357262306a36Sopenharmony_ci mtc.mt_count -= 1; 357362306a36Sopenharmony_ci if (STps->drv_file >= 0) 357462306a36Sopenharmony_ci STps->drv_file += 1; 357562306a36Sopenharmony_ci } else if (mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM) { 357662306a36Sopenharmony_ci mtc.mt_count += 1; 357762306a36Sopenharmony_ci if (STps->drv_file >= 0) 357862306a36Sopenharmony_ci STps->drv_file += 1; 357962306a36Sopenharmony_ci } 358062306a36Sopenharmony_ci } 358162306a36Sopenharmony_ci 358262306a36Sopenharmony_ci if (mtc.mt_op == MTSEEK) { 358362306a36Sopenharmony_ci /* Old position must be restored if partition will be 358462306a36Sopenharmony_ci changed */ 358562306a36Sopenharmony_ci i = !STp->can_partitions || 358662306a36Sopenharmony_ci (STp->new_partition != STp->partition); 358762306a36Sopenharmony_ci } else { 358862306a36Sopenharmony_ci i = mtc.mt_op == MTREW || mtc.mt_op == MTOFFL || 358962306a36Sopenharmony_ci mtc.mt_op == MTRETEN || mtc.mt_op == MTEOM || 359062306a36Sopenharmony_ci mtc.mt_op == MTLOCK || mtc.mt_op == MTLOAD || 359162306a36Sopenharmony_ci mtc.mt_op == MTFSF || mtc.mt_op == MTFSFM || 359262306a36Sopenharmony_ci mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM || 359362306a36Sopenharmony_ci mtc.mt_op == MTCOMPRESSION; 359462306a36Sopenharmony_ci } 359562306a36Sopenharmony_ci i = flush_buffer(STp, i); 359662306a36Sopenharmony_ci if (i < 0) { 359762306a36Sopenharmony_ci retval = i; 359862306a36Sopenharmony_ci goto out; 359962306a36Sopenharmony_ci } 360062306a36Sopenharmony_ci if (STps->rw == ST_WRITING && 360162306a36Sopenharmony_ci (mtc.mt_op == MTREW || mtc.mt_op == MTOFFL || 360262306a36Sopenharmony_ci mtc.mt_op == MTSEEK || 360362306a36Sopenharmony_ci mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM)) { 360462306a36Sopenharmony_ci i = st_int_ioctl(STp, MTWEOF, 1); 360562306a36Sopenharmony_ci if (i < 0) { 360662306a36Sopenharmony_ci retval = i; 360762306a36Sopenharmony_ci goto out; 360862306a36Sopenharmony_ci } 360962306a36Sopenharmony_ci if (mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM) 361062306a36Sopenharmony_ci mtc.mt_count++; 361162306a36Sopenharmony_ci STps->rw = ST_IDLE; 361262306a36Sopenharmony_ci } 361362306a36Sopenharmony_ci 361462306a36Sopenharmony_ci } else { 361562306a36Sopenharmony_ci /* 361662306a36Sopenharmony_ci * If there was a bus reset, block further access 361762306a36Sopenharmony_ci * to this device. If the user wants to rewind the tape, 361862306a36Sopenharmony_ci * then reset the flag and allow access again. 361962306a36Sopenharmony_ci */ 362062306a36Sopenharmony_ci if (mtc.mt_op != MTREW && 362162306a36Sopenharmony_ci mtc.mt_op != MTOFFL && 362262306a36Sopenharmony_ci mtc.mt_op != MTRETEN && 362362306a36Sopenharmony_ci mtc.mt_op != MTERASE && 362462306a36Sopenharmony_ci mtc.mt_op != MTSEEK && 362562306a36Sopenharmony_ci mtc.mt_op != MTEOM) { 362662306a36Sopenharmony_ci retval = (-EIO); 362762306a36Sopenharmony_ci goto out; 362862306a36Sopenharmony_ci } 362962306a36Sopenharmony_ci reset_state(STp); 363062306a36Sopenharmony_ci /* remove this when the midlevel properly clears was_reset */ 363162306a36Sopenharmony_ci STp->device->was_reset = 0; 363262306a36Sopenharmony_ci } 363362306a36Sopenharmony_ci 363462306a36Sopenharmony_ci if (mtc.mt_op != MTNOP && mtc.mt_op != MTSETBLK && 363562306a36Sopenharmony_ci mtc.mt_op != MTSETDENSITY && mtc.mt_op != MTWSM && 363662306a36Sopenharmony_ci mtc.mt_op != MTSETDRVBUFFER && mtc.mt_op != MTSETPART) 363762306a36Sopenharmony_ci STps->rw = ST_IDLE; /* Prevent automatic WEOF and fsf */ 363862306a36Sopenharmony_ci 363962306a36Sopenharmony_ci if (mtc.mt_op == MTOFFL && STp->door_locked != ST_UNLOCKED) 364062306a36Sopenharmony_ci do_door_lock(STp, 0); /* Ignore result! */ 364162306a36Sopenharmony_ci 364262306a36Sopenharmony_ci if (mtc.mt_op == MTSETDRVBUFFER && 364362306a36Sopenharmony_ci (mtc.mt_count & MT_ST_OPTIONS) != 0) { 364462306a36Sopenharmony_ci retval = st_set_options(STp, mtc.mt_count); 364562306a36Sopenharmony_ci goto out; 364662306a36Sopenharmony_ci } 364762306a36Sopenharmony_ci 364862306a36Sopenharmony_ci if (mtc.mt_op == MTSETPART) { 364962306a36Sopenharmony_ci if (!STp->can_partitions || 365062306a36Sopenharmony_ci mtc.mt_count < 0 || mtc.mt_count >= ST_NBR_PARTITIONS) { 365162306a36Sopenharmony_ci retval = (-EINVAL); 365262306a36Sopenharmony_ci goto out; 365362306a36Sopenharmony_ci } 365462306a36Sopenharmony_ci if (mtc.mt_count >= STp->nbr_partitions && 365562306a36Sopenharmony_ci (STp->nbr_partitions = nbr_partitions(STp)) < 0) { 365662306a36Sopenharmony_ci retval = (-EIO); 365762306a36Sopenharmony_ci goto out; 365862306a36Sopenharmony_ci } 365962306a36Sopenharmony_ci if (mtc.mt_count >= STp->nbr_partitions) { 366062306a36Sopenharmony_ci retval = (-EINVAL); 366162306a36Sopenharmony_ci goto out; 366262306a36Sopenharmony_ci } 366362306a36Sopenharmony_ci STp->new_partition = mtc.mt_count; 366462306a36Sopenharmony_ci retval = 0; 366562306a36Sopenharmony_ci goto out; 366662306a36Sopenharmony_ci } 366762306a36Sopenharmony_ci 366862306a36Sopenharmony_ci if (mtc.mt_op == MTMKPART) { 366962306a36Sopenharmony_ci if (!STp->can_partitions) { 367062306a36Sopenharmony_ci retval = (-EINVAL); 367162306a36Sopenharmony_ci goto out; 367262306a36Sopenharmony_ci } 367362306a36Sopenharmony_ci i = do_load_unload(STp, file, 1); 367462306a36Sopenharmony_ci if (i < 0) { 367562306a36Sopenharmony_ci retval = i; 367662306a36Sopenharmony_ci goto out; 367762306a36Sopenharmony_ci } 367862306a36Sopenharmony_ci i = partition_tape(STp, mtc.mt_count); 367962306a36Sopenharmony_ci if (i < 0) { 368062306a36Sopenharmony_ci retval = i; 368162306a36Sopenharmony_ci goto out; 368262306a36Sopenharmony_ci } 368362306a36Sopenharmony_ci for (i = 0; i < ST_NBR_PARTITIONS; i++) { 368462306a36Sopenharmony_ci STp->ps[i].rw = ST_IDLE; 368562306a36Sopenharmony_ci STp->ps[i].at_sm = 0; 368662306a36Sopenharmony_ci STp->ps[i].last_block_valid = 0; 368762306a36Sopenharmony_ci } 368862306a36Sopenharmony_ci STp->partition = STp->new_partition = 0; 368962306a36Sopenharmony_ci STp->nbr_partitions = mtc.mt_count != 0 ? 2 : 1; 369062306a36Sopenharmony_ci STps->drv_block = STps->drv_file = 0; 369162306a36Sopenharmony_ci retval = 0; 369262306a36Sopenharmony_ci goto out; 369362306a36Sopenharmony_ci } 369462306a36Sopenharmony_ci 369562306a36Sopenharmony_ci if (mtc.mt_op == MTSEEK) { 369662306a36Sopenharmony_ci i = set_location(STp, mtc.mt_count, STp->new_partition, 0); 369762306a36Sopenharmony_ci if (!STp->can_partitions) 369862306a36Sopenharmony_ci STp->ps[0].rw = ST_IDLE; 369962306a36Sopenharmony_ci retval = i; 370062306a36Sopenharmony_ci goto out; 370162306a36Sopenharmony_ci } 370262306a36Sopenharmony_ci 370362306a36Sopenharmony_ci if (mtc.mt_op == MTUNLOAD || mtc.mt_op == MTOFFL) { 370462306a36Sopenharmony_ci retval = do_load_unload(STp, file, 0); 370562306a36Sopenharmony_ci goto out; 370662306a36Sopenharmony_ci } 370762306a36Sopenharmony_ci 370862306a36Sopenharmony_ci if (mtc.mt_op == MTLOAD) { 370962306a36Sopenharmony_ci retval = do_load_unload(STp, file, max(1, mtc.mt_count)); 371062306a36Sopenharmony_ci goto out; 371162306a36Sopenharmony_ci } 371262306a36Sopenharmony_ci 371362306a36Sopenharmony_ci if (mtc.mt_op == MTLOCK || mtc.mt_op == MTUNLOCK) { 371462306a36Sopenharmony_ci retval = do_door_lock(STp, (mtc.mt_op == MTLOCK)); 371562306a36Sopenharmony_ci goto out; 371662306a36Sopenharmony_ci } 371762306a36Sopenharmony_ci 371862306a36Sopenharmony_ci if (STp->can_partitions && STp->ready == ST_READY && 371962306a36Sopenharmony_ci (i = switch_partition(STp)) < 0) { 372062306a36Sopenharmony_ci retval = i; 372162306a36Sopenharmony_ci goto out; 372262306a36Sopenharmony_ci } 372362306a36Sopenharmony_ci 372462306a36Sopenharmony_ci if (mtc.mt_op == MTCOMPRESSION) 372562306a36Sopenharmony_ci retval = st_compression(STp, (mtc.mt_count & 1)); 372662306a36Sopenharmony_ci else 372762306a36Sopenharmony_ci retval = st_int_ioctl(STp, mtc.mt_op, mtc.mt_count); 372862306a36Sopenharmony_ci goto out; 372962306a36Sopenharmony_ci } 373062306a36Sopenharmony_ci if (!STm->defined) { 373162306a36Sopenharmony_ci retval = (-ENXIO); 373262306a36Sopenharmony_ci goto out; 373362306a36Sopenharmony_ci } 373462306a36Sopenharmony_ci 373562306a36Sopenharmony_ci if ((i = flush_buffer(STp, 0)) < 0) { 373662306a36Sopenharmony_ci retval = i; 373762306a36Sopenharmony_ci goto out; 373862306a36Sopenharmony_ci } 373962306a36Sopenharmony_ci if (STp->can_partitions && 374062306a36Sopenharmony_ci (i = switch_partition(STp)) < 0) { 374162306a36Sopenharmony_ci retval = i; 374262306a36Sopenharmony_ci goto out; 374362306a36Sopenharmony_ci } 374462306a36Sopenharmony_ci 374562306a36Sopenharmony_ci if (cmd_type == _IOC_TYPE(MTIOCGET) && cmd_nr == _IOC_NR(MTIOCGET)) { 374662306a36Sopenharmony_ci struct mtget mt_status; 374762306a36Sopenharmony_ci 374862306a36Sopenharmony_ci if (_IOC_SIZE(cmd_in) != sizeof(struct mtget)) { 374962306a36Sopenharmony_ci retval = (-EINVAL); 375062306a36Sopenharmony_ci goto out; 375162306a36Sopenharmony_ci } 375262306a36Sopenharmony_ci 375362306a36Sopenharmony_ci mt_status.mt_type = STp->tape_type; 375462306a36Sopenharmony_ci mt_status.mt_dsreg = 375562306a36Sopenharmony_ci ((STp->block_size << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK) | 375662306a36Sopenharmony_ci ((STp->density << MT_ST_DENSITY_SHIFT) & MT_ST_DENSITY_MASK); 375762306a36Sopenharmony_ci mt_status.mt_blkno = STps->drv_block; 375862306a36Sopenharmony_ci mt_status.mt_fileno = STps->drv_file; 375962306a36Sopenharmony_ci if (STp->block_size != 0) { 376062306a36Sopenharmony_ci if (STps->rw == ST_WRITING) 376162306a36Sopenharmony_ci mt_status.mt_blkno += 376262306a36Sopenharmony_ci (STp->buffer)->buffer_bytes / STp->block_size; 376362306a36Sopenharmony_ci else if (STps->rw == ST_READING) 376462306a36Sopenharmony_ci mt_status.mt_blkno -= 376562306a36Sopenharmony_ci ((STp->buffer)->buffer_bytes + 376662306a36Sopenharmony_ci STp->block_size - 1) / STp->block_size; 376762306a36Sopenharmony_ci } 376862306a36Sopenharmony_ci 376962306a36Sopenharmony_ci mt_status.mt_gstat = 0; 377062306a36Sopenharmony_ci if (STp->drv_write_prot) 377162306a36Sopenharmony_ci mt_status.mt_gstat |= GMT_WR_PROT(0xffffffff); 377262306a36Sopenharmony_ci if (mt_status.mt_blkno == 0) { 377362306a36Sopenharmony_ci if (mt_status.mt_fileno == 0) 377462306a36Sopenharmony_ci mt_status.mt_gstat |= GMT_BOT(0xffffffff); 377562306a36Sopenharmony_ci else 377662306a36Sopenharmony_ci mt_status.mt_gstat |= GMT_EOF(0xffffffff); 377762306a36Sopenharmony_ci } 377862306a36Sopenharmony_ci mt_status.mt_erreg = (STp->recover_reg << MT_ST_SOFTERR_SHIFT); 377962306a36Sopenharmony_ci mt_status.mt_resid = STp->partition; 378062306a36Sopenharmony_ci if (STps->eof == ST_EOM_OK || STps->eof == ST_EOM_ERROR) 378162306a36Sopenharmony_ci mt_status.mt_gstat |= GMT_EOT(0xffffffff); 378262306a36Sopenharmony_ci else if (STps->eof >= ST_EOM_OK) 378362306a36Sopenharmony_ci mt_status.mt_gstat |= GMT_EOD(0xffffffff); 378462306a36Sopenharmony_ci if (STp->density == 1) 378562306a36Sopenharmony_ci mt_status.mt_gstat |= GMT_D_800(0xffffffff); 378662306a36Sopenharmony_ci else if (STp->density == 2) 378762306a36Sopenharmony_ci mt_status.mt_gstat |= GMT_D_1600(0xffffffff); 378862306a36Sopenharmony_ci else if (STp->density == 3) 378962306a36Sopenharmony_ci mt_status.mt_gstat |= GMT_D_6250(0xffffffff); 379062306a36Sopenharmony_ci if (STp->ready == ST_READY) 379162306a36Sopenharmony_ci mt_status.mt_gstat |= GMT_ONLINE(0xffffffff); 379262306a36Sopenharmony_ci if (STp->ready == ST_NO_TAPE) 379362306a36Sopenharmony_ci mt_status.mt_gstat |= GMT_DR_OPEN(0xffffffff); 379462306a36Sopenharmony_ci if (STps->at_sm) 379562306a36Sopenharmony_ci mt_status.mt_gstat |= GMT_SM(0xffffffff); 379662306a36Sopenharmony_ci if (STm->do_async_writes || 379762306a36Sopenharmony_ci (STm->do_buffer_writes && STp->block_size != 0) || 379862306a36Sopenharmony_ci STp->drv_buffer != 0) 379962306a36Sopenharmony_ci mt_status.mt_gstat |= GMT_IM_REP_EN(0xffffffff); 380062306a36Sopenharmony_ci if (STp->cleaning_req) 380162306a36Sopenharmony_ci mt_status.mt_gstat |= GMT_CLN(0xffffffff); 380262306a36Sopenharmony_ci 380362306a36Sopenharmony_ci retval = put_user_mtget(p, &mt_status); 380462306a36Sopenharmony_ci if (retval) 380562306a36Sopenharmony_ci goto out; 380662306a36Sopenharmony_ci 380762306a36Sopenharmony_ci STp->recover_reg = 0; /* Clear after read */ 380862306a36Sopenharmony_ci goto out; 380962306a36Sopenharmony_ci } /* End of MTIOCGET */ 381062306a36Sopenharmony_ci if (cmd_type == _IOC_TYPE(MTIOCPOS) && cmd_nr == _IOC_NR(MTIOCPOS)) { 381162306a36Sopenharmony_ci struct mtpos mt_pos; 381262306a36Sopenharmony_ci if (_IOC_SIZE(cmd_in) != sizeof(struct mtpos)) { 381362306a36Sopenharmony_ci retval = (-EINVAL); 381462306a36Sopenharmony_ci goto out; 381562306a36Sopenharmony_ci } 381662306a36Sopenharmony_ci if ((i = get_location(STp, &blk, &bt, 0)) < 0) { 381762306a36Sopenharmony_ci retval = i; 381862306a36Sopenharmony_ci goto out; 381962306a36Sopenharmony_ci } 382062306a36Sopenharmony_ci mt_pos.mt_blkno = blk; 382162306a36Sopenharmony_ci retval = put_user_mtpos(p, &mt_pos); 382262306a36Sopenharmony_ci goto out; 382362306a36Sopenharmony_ci } 382462306a36Sopenharmony_ci mutex_unlock(&STp->lock); 382562306a36Sopenharmony_ci 382662306a36Sopenharmony_ci switch (cmd_in) { 382762306a36Sopenharmony_ci case SG_IO: 382862306a36Sopenharmony_ci case SCSI_IOCTL_SEND_COMMAND: 382962306a36Sopenharmony_ci case CDROM_SEND_PACKET: 383062306a36Sopenharmony_ci if (!capable(CAP_SYS_RAWIO)) 383162306a36Sopenharmony_ci return -EPERM; 383262306a36Sopenharmony_ci break; 383362306a36Sopenharmony_ci default: 383462306a36Sopenharmony_ci break; 383562306a36Sopenharmony_ci } 383662306a36Sopenharmony_ci 383762306a36Sopenharmony_ci retval = scsi_ioctl(STp->device, file->f_mode & FMODE_WRITE, cmd_in, p); 383862306a36Sopenharmony_ci if (!retval && cmd_in == SCSI_IOCTL_STOP_UNIT) { 383962306a36Sopenharmony_ci /* unload */ 384062306a36Sopenharmony_ci STp->rew_at_close = 0; 384162306a36Sopenharmony_ci STp->ready = ST_NO_TAPE; 384262306a36Sopenharmony_ci } 384362306a36Sopenharmony_ci return retval; 384462306a36Sopenharmony_ci 384562306a36Sopenharmony_ci out: 384662306a36Sopenharmony_ci mutex_unlock(&STp->lock); 384762306a36Sopenharmony_ci return retval; 384862306a36Sopenharmony_ci} 384962306a36Sopenharmony_ci 385062306a36Sopenharmony_ci#ifdef CONFIG_COMPAT 385162306a36Sopenharmony_cistatic long st_compat_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg) 385262306a36Sopenharmony_ci{ 385362306a36Sopenharmony_ci /* argument conversion is handled using put_user_mtpos/put_user_mtget */ 385462306a36Sopenharmony_ci switch (cmd_in) { 385562306a36Sopenharmony_ci case MTIOCPOS32: 385662306a36Sopenharmony_ci cmd_in = MTIOCPOS; 385762306a36Sopenharmony_ci break; 385862306a36Sopenharmony_ci case MTIOCGET32: 385962306a36Sopenharmony_ci cmd_in = MTIOCGET; 386062306a36Sopenharmony_ci break; 386162306a36Sopenharmony_ci } 386262306a36Sopenharmony_ci 386362306a36Sopenharmony_ci return st_ioctl(file, cmd_in, arg); 386462306a36Sopenharmony_ci} 386562306a36Sopenharmony_ci#endif 386662306a36Sopenharmony_ci 386762306a36Sopenharmony_ci 386862306a36Sopenharmony_ci 386962306a36Sopenharmony_ci/* Try to allocate a new tape buffer. Calling function must not hold 387062306a36Sopenharmony_ci dev_arr_lock. */ 387162306a36Sopenharmony_cistatic struct st_buffer *new_tape_buffer(int max_sg) 387262306a36Sopenharmony_ci{ 387362306a36Sopenharmony_ci struct st_buffer *tb; 387462306a36Sopenharmony_ci 387562306a36Sopenharmony_ci tb = kzalloc(sizeof(struct st_buffer), GFP_KERNEL); 387662306a36Sopenharmony_ci if (!tb) { 387762306a36Sopenharmony_ci printk(KERN_NOTICE "st: Can't allocate new tape buffer.\n"); 387862306a36Sopenharmony_ci return NULL; 387962306a36Sopenharmony_ci } 388062306a36Sopenharmony_ci tb->frp_segs = 0; 388162306a36Sopenharmony_ci tb->use_sg = max_sg; 388262306a36Sopenharmony_ci tb->buffer_size = 0; 388362306a36Sopenharmony_ci 388462306a36Sopenharmony_ci tb->reserved_pages = kcalloc(max_sg, sizeof(struct page *), 388562306a36Sopenharmony_ci GFP_KERNEL); 388662306a36Sopenharmony_ci if (!tb->reserved_pages) { 388762306a36Sopenharmony_ci kfree(tb); 388862306a36Sopenharmony_ci return NULL; 388962306a36Sopenharmony_ci } 389062306a36Sopenharmony_ci 389162306a36Sopenharmony_ci return tb; 389262306a36Sopenharmony_ci} 389362306a36Sopenharmony_ci 389462306a36Sopenharmony_ci 389562306a36Sopenharmony_ci/* Try to allocate enough space in the tape buffer */ 389662306a36Sopenharmony_ci#define ST_MAX_ORDER 6 389762306a36Sopenharmony_ci 389862306a36Sopenharmony_cistatic int enlarge_buffer(struct st_buffer * STbuffer, int new_size) 389962306a36Sopenharmony_ci{ 390062306a36Sopenharmony_ci int segs, max_segs, b_size, order, got; 390162306a36Sopenharmony_ci gfp_t priority; 390262306a36Sopenharmony_ci 390362306a36Sopenharmony_ci if (new_size <= STbuffer->buffer_size) 390462306a36Sopenharmony_ci return 1; 390562306a36Sopenharmony_ci 390662306a36Sopenharmony_ci if (STbuffer->buffer_size <= PAGE_SIZE) 390762306a36Sopenharmony_ci normalize_buffer(STbuffer); /* Avoid extra segment */ 390862306a36Sopenharmony_ci 390962306a36Sopenharmony_ci max_segs = STbuffer->use_sg; 391062306a36Sopenharmony_ci 391162306a36Sopenharmony_ci priority = GFP_KERNEL | __GFP_NOWARN; 391262306a36Sopenharmony_ci 391362306a36Sopenharmony_ci if (STbuffer->cleared) 391462306a36Sopenharmony_ci priority |= __GFP_ZERO; 391562306a36Sopenharmony_ci 391662306a36Sopenharmony_ci if (STbuffer->frp_segs) { 391762306a36Sopenharmony_ci order = STbuffer->reserved_page_order; 391862306a36Sopenharmony_ci b_size = PAGE_SIZE << order; 391962306a36Sopenharmony_ci } else { 392062306a36Sopenharmony_ci for (b_size = PAGE_SIZE, order = 0; 392162306a36Sopenharmony_ci order < ST_MAX_ORDER && 392262306a36Sopenharmony_ci max_segs * (PAGE_SIZE << order) < new_size; 392362306a36Sopenharmony_ci order++, b_size *= 2) 392462306a36Sopenharmony_ci ; /* empty */ 392562306a36Sopenharmony_ci STbuffer->reserved_page_order = order; 392662306a36Sopenharmony_ci } 392762306a36Sopenharmony_ci if (max_segs * (PAGE_SIZE << order) < new_size) { 392862306a36Sopenharmony_ci if (order == ST_MAX_ORDER) 392962306a36Sopenharmony_ci return 0; 393062306a36Sopenharmony_ci normalize_buffer(STbuffer); 393162306a36Sopenharmony_ci return enlarge_buffer(STbuffer, new_size); 393262306a36Sopenharmony_ci } 393362306a36Sopenharmony_ci 393462306a36Sopenharmony_ci for (segs = STbuffer->frp_segs, got = STbuffer->buffer_size; 393562306a36Sopenharmony_ci segs < max_segs && got < new_size;) { 393662306a36Sopenharmony_ci struct page *page; 393762306a36Sopenharmony_ci 393862306a36Sopenharmony_ci page = alloc_pages(priority, order); 393962306a36Sopenharmony_ci if (!page) { 394062306a36Sopenharmony_ci DEB(STbuffer->buffer_size = got); 394162306a36Sopenharmony_ci normalize_buffer(STbuffer); 394262306a36Sopenharmony_ci return 0; 394362306a36Sopenharmony_ci } 394462306a36Sopenharmony_ci 394562306a36Sopenharmony_ci STbuffer->frp_segs += 1; 394662306a36Sopenharmony_ci got += b_size; 394762306a36Sopenharmony_ci STbuffer->buffer_size = got; 394862306a36Sopenharmony_ci STbuffer->reserved_pages[segs] = page; 394962306a36Sopenharmony_ci segs++; 395062306a36Sopenharmony_ci } 395162306a36Sopenharmony_ci STbuffer->b_data = page_address(STbuffer->reserved_pages[0]); 395262306a36Sopenharmony_ci 395362306a36Sopenharmony_ci return 1; 395462306a36Sopenharmony_ci} 395562306a36Sopenharmony_ci 395662306a36Sopenharmony_ci 395762306a36Sopenharmony_ci/* Make sure that no data from previous user is in the internal buffer */ 395862306a36Sopenharmony_cistatic void clear_buffer(struct st_buffer * st_bp) 395962306a36Sopenharmony_ci{ 396062306a36Sopenharmony_ci int i; 396162306a36Sopenharmony_ci 396262306a36Sopenharmony_ci for (i=0; i < st_bp->frp_segs; i++) 396362306a36Sopenharmony_ci memset(page_address(st_bp->reserved_pages[i]), 0, 396462306a36Sopenharmony_ci PAGE_SIZE << st_bp->reserved_page_order); 396562306a36Sopenharmony_ci st_bp->cleared = 1; 396662306a36Sopenharmony_ci} 396762306a36Sopenharmony_ci 396862306a36Sopenharmony_ci 396962306a36Sopenharmony_ci/* Release the extra buffer */ 397062306a36Sopenharmony_cistatic void normalize_buffer(struct st_buffer * STbuffer) 397162306a36Sopenharmony_ci{ 397262306a36Sopenharmony_ci int i, order = STbuffer->reserved_page_order; 397362306a36Sopenharmony_ci 397462306a36Sopenharmony_ci for (i = 0; i < STbuffer->frp_segs; i++) { 397562306a36Sopenharmony_ci __free_pages(STbuffer->reserved_pages[i], order); 397662306a36Sopenharmony_ci STbuffer->buffer_size -= (PAGE_SIZE << order); 397762306a36Sopenharmony_ci } 397862306a36Sopenharmony_ci STbuffer->frp_segs = 0; 397962306a36Sopenharmony_ci STbuffer->sg_segs = 0; 398062306a36Sopenharmony_ci STbuffer->reserved_page_order = 0; 398162306a36Sopenharmony_ci STbuffer->map_data.offset = 0; 398262306a36Sopenharmony_ci} 398362306a36Sopenharmony_ci 398462306a36Sopenharmony_ci 398562306a36Sopenharmony_ci/* Move data from the user buffer to the tape buffer. Returns zero (success) or 398662306a36Sopenharmony_ci negative error code. */ 398762306a36Sopenharmony_cistatic int append_to_buffer(const char __user *ubp, struct st_buffer * st_bp, int do_count) 398862306a36Sopenharmony_ci{ 398962306a36Sopenharmony_ci int i, cnt, res, offset; 399062306a36Sopenharmony_ci int length = PAGE_SIZE << st_bp->reserved_page_order; 399162306a36Sopenharmony_ci 399262306a36Sopenharmony_ci for (i = 0, offset = st_bp->buffer_bytes; 399362306a36Sopenharmony_ci i < st_bp->frp_segs && offset >= length; i++) 399462306a36Sopenharmony_ci offset -= length; 399562306a36Sopenharmony_ci if (i == st_bp->frp_segs) { /* Should never happen */ 399662306a36Sopenharmony_ci printk(KERN_WARNING "st: append_to_buffer offset overflow.\n"); 399762306a36Sopenharmony_ci return (-EIO); 399862306a36Sopenharmony_ci } 399962306a36Sopenharmony_ci for (; i < st_bp->frp_segs && do_count > 0; i++) { 400062306a36Sopenharmony_ci struct page *page = st_bp->reserved_pages[i]; 400162306a36Sopenharmony_ci cnt = length - offset < do_count ? length - offset : do_count; 400262306a36Sopenharmony_ci res = copy_from_user(page_address(page) + offset, ubp, cnt); 400362306a36Sopenharmony_ci if (res) 400462306a36Sopenharmony_ci return (-EFAULT); 400562306a36Sopenharmony_ci do_count -= cnt; 400662306a36Sopenharmony_ci st_bp->buffer_bytes += cnt; 400762306a36Sopenharmony_ci ubp += cnt; 400862306a36Sopenharmony_ci offset = 0; 400962306a36Sopenharmony_ci } 401062306a36Sopenharmony_ci if (do_count) /* Should never happen */ 401162306a36Sopenharmony_ci return (-EIO); 401262306a36Sopenharmony_ci 401362306a36Sopenharmony_ci return 0; 401462306a36Sopenharmony_ci} 401562306a36Sopenharmony_ci 401662306a36Sopenharmony_ci 401762306a36Sopenharmony_ci/* Move data from the tape buffer to the user buffer. Returns zero (success) or 401862306a36Sopenharmony_ci negative error code. */ 401962306a36Sopenharmony_cistatic int from_buffer(struct st_buffer * st_bp, char __user *ubp, int do_count) 402062306a36Sopenharmony_ci{ 402162306a36Sopenharmony_ci int i, cnt, res, offset; 402262306a36Sopenharmony_ci int length = PAGE_SIZE << st_bp->reserved_page_order; 402362306a36Sopenharmony_ci 402462306a36Sopenharmony_ci for (i = 0, offset = st_bp->read_pointer; 402562306a36Sopenharmony_ci i < st_bp->frp_segs && offset >= length; i++) 402662306a36Sopenharmony_ci offset -= length; 402762306a36Sopenharmony_ci if (i == st_bp->frp_segs) { /* Should never happen */ 402862306a36Sopenharmony_ci printk(KERN_WARNING "st: from_buffer offset overflow.\n"); 402962306a36Sopenharmony_ci return (-EIO); 403062306a36Sopenharmony_ci } 403162306a36Sopenharmony_ci for (; i < st_bp->frp_segs && do_count > 0; i++) { 403262306a36Sopenharmony_ci struct page *page = st_bp->reserved_pages[i]; 403362306a36Sopenharmony_ci cnt = length - offset < do_count ? length - offset : do_count; 403462306a36Sopenharmony_ci res = copy_to_user(ubp, page_address(page) + offset, cnt); 403562306a36Sopenharmony_ci if (res) 403662306a36Sopenharmony_ci return (-EFAULT); 403762306a36Sopenharmony_ci do_count -= cnt; 403862306a36Sopenharmony_ci st_bp->buffer_bytes -= cnt; 403962306a36Sopenharmony_ci st_bp->read_pointer += cnt; 404062306a36Sopenharmony_ci ubp += cnt; 404162306a36Sopenharmony_ci offset = 0; 404262306a36Sopenharmony_ci } 404362306a36Sopenharmony_ci if (do_count) /* Should never happen */ 404462306a36Sopenharmony_ci return (-EIO); 404562306a36Sopenharmony_ci 404662306a36Sopenharmony_ci return 0; 404762306a36Sopenharmony_ci} 404862306a36Sopenharmony_ci 404962306a36Sopenharmony_ci 405062306a36Sopenharmony_ci/* Move data towards start of buffer */ 405162306a36Sopenharmony_cistatic void move_buffer_data(struct st_buffer * st_bp, int offset) 405262306a36Sopenharmony_ci{ 405362306a36Sopenharmony_ci int src_seg, dst_seg, src_offset = 0, dst_offset; 405462306a36Sopenharmony_ci int count, total; 405562306a36Sopenharmony_ci int length = PAGE_SIZE << st_bp->reserved_page_order; 405662306a36Sopenharmony_ci 405762306a36Sopenharmony_ci if (offset == 0) 405862306a36Sopenharmony_ci return; 405962306a36Sopenharmony_ci 406062306a36Sopenharmony_ci total=st_bp->buffer_bytes - offset; 406162306a36Sopenharmony_ci for (src_seg=0; src_seg < st_bp->frp_segs; src_seg++) { 406262306a36Sopenharmony_ci src_offset = offset; 406362306a36Sopenharmony_ci if (src_offset < length) 406462306a36Sopenharmony_ci break; 406562306a36Sopenharmony_ci offset -= length; 406662306a36Sopenharmony_ci } 406762306a36Sopenharmony_ci 406862306a36Sopenharmony_ci st_bp->buffer_bytes = st_bp->read_pointer = total; 406962306a36Sopenharmony_ci for (dst_seg=dst_offset=0; total > 0; ) { 407062306a36Sopenharmony_ci struct page *dpage = st_bp->reserved_pages[dst_seg]; 407162306a36Sopenharmony_ci struct page *spage = st_bp->reserved_pages[src_seg]; 407262306a36Sopenharmony_ci 407362306a36Sopenharmony_ci count = min(length - dst_offset, length - src_offset); 407462306a36Sopenharmony_ci memmove(page_address(dpage) + dst_offset, 407562306a36Sopenharmony_ci page_address(spage) + src_offset, count); 407662306a36Sopenharmony_ci src_offset += count; 407762306a36Sopenharmony_ci if (src_offset >= length) { 407862306a36Sopenharmony_ci src_seg++; 407962306a36Sopenharmony_ci src_offset = 0; 408062306a36Sopenharmony_ci } 408162306a36Sopenharmony_ci dst_offset += count; 408262306a36Sopenharmony_ci if (dst_offset >= length) { 408362306a36Sopenharmony_ci dst_seg++; 408462306a36Sopenharmony_ci dst_offset = 0; 408562306a36Sopenharmony_ci } 408662306a36Sopenharmony_ci total -= count; 408762306a36Sopenharmony_ci } 408862306a36Sopenharmony_ci} 408962306a36Sopenharmony_ci 409062306a36Sopenharmony_ci/* Validate the options from command line or module parameters */ 409162306a36Sopenharmony_cistatic void validate_options(void) 409262306a36Sopenharmony_ci{ 409362306a36Sopenharmony_ci if (buffer_kbs > 0) 409462306a36Sopenharmony_ci st_fixed_buffer_size = buffer_kbs * ST_KILOBYTE; 409562306a36Sopenharmony_ci if (max_sg_segs >= ST_FIRST_SG) 409662306a36Sopenharmony_ci st_max_sg_segs = max_sg_segs; 409762306a36Sopenharmony_ci} 409862306a36Sopenharmony_ci 409962306a36Sopenharmony_ci#ifndef MODULE 410062306a36Sopenharmony_ci/* Set the boot options. Syntax is defined in Documenation/scsi/st.txt. 410162306a36Sopenharmony_ci */ 410262306a36Sopenharmony_cistatic int __init st_setup(char *str) 410362306a36Sopenharmony_ci{ 410462306a36Sopenharmony_ci int i, len, ints[5]; 410562306a36Sopenharmony_ci char *stp; 410662306a36Sopenharmony_ci 410762306a36Sopenharmony_ci stp = get_options(str, ARRAY_SIZE(ints), ints); 410862306a36Sopenharmony_ci 410962306a36Sopenharmony_ci if (ints[0] > 0) { 411062306a36Sopenharmony_ci for (i = 0; i < ints[0] && i < ARRAY_SIZE(parms); i++) 411162306a36Sopenharmony_ci if (parms[i].val) 411262306a36Sopenharmony_ci *parms[i].val = ints[i + 1]; 411362306a36Sopenharmony_ci } else { 411462306a36Sopenharmony_ci while (stp != NULL) { 411562306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(parms); i++) { 411662306a36Sopenharmony_ci len = strlen(parms[i].name); 411762306a36Sopenharmony_ci if (!strncmp(stp, parms[i].name, len) && 411862306a36Sopenharmony_ci (*(stp + len) == ':' || *(stp + len) == '=')) { 411962306a36Sopenharmony_ci if (parms[i].val) 412062306a36Sopenharmony_ci *parms[i].val = 412162306a36Sopenharmony_ci simple_strtoul(stp + len + 1, NULL, 0); 412262306a36Sopenharmony_ci else 412362306a36Sopenharmony_ci printk(KERN_WARNING "st: Obsolete parameter %s\n", 412462306a36Sopenharmony_ci parms[i].name); 412562306a36Sopenharmony_ci break; 412662306a36Sopenharmony_ci } 412762306a36Sopenharmony_ci } 412862306a36Sopenharmony_ci if (i >= ARRAY_SIZE(parms)) 412962306a36Sopenharmony_ci printk(KERN_WARNING "st: invalid parameter in '%s'\n", 413062306a36Sopenharmony_ci stp); 413162306a36Sopenharmony_ci stp = strchr(stp, ','); 413262306a36Sopenharmony_ci if (stp) 413362306a36Sopenharmony_ci stp++; 413462306a36Sopenharmony_ci } 413562306a36Sopenharmony_ci } 413662306a36Sopenharmony_ci 413762306a36Sopenharmony_ci validate_options(); 413862306a36Sopenharmony_ci 413962306a36Sopenharmony_ci return 1; 414062306a36Sopenharmony_ci} 414162306a36Sopenharmony_ci 414262306a36Sopenharmony_ci__setup("st=", st_setup); 414362306a36Sopenharmony_ci 414462306a36Sopenharmony_ci#endif 414562306a36Sopenharmony_ci 414662306a36Sopenharmony_cistatic const struct file_operations st_fops = 414762306a36Sopenharmony_ci{ 414862306a36Sopenharmony_ci .owner = THIS_MODULE, 414962306a36Sopenharmony_ci .read = st_read, 415062306a36Sopenharmony_ci .write = st_write, 415162306a36Sopenharmony_ci .unlocked_ioctl = st_ioctl, 415262306a36Sopenharmony_ci#ifdef CONFIG_COMPAT 415362306a36Sopenharmony_ci .compat_ioctl = st_compat_ioctl, 415462306a36Sopenharmony_ci#endif 415562306a36Sopenharmony_ci .open = st_open, 415662306a36Sopenharmony_ci .flush = st_flush, 415762306a36Sopenharmony_ci .release = st_release, 415862306a36Sopenharmony_ci .llseek = noop_llseek, 415962306a36Sopenharmony_ci}; 416062306a36Sopenharmony_ci 416162306a36Sopenharmony_cistatic int create_one_cdev(struct scsi_tape *tape, int mode, int rew) 416262306a36Sopenharmony_ci{ 416362306a36Sopenharmony_ci int i, error; 416462306a36Sopenharmony_ci dev_t cdev_devno; 416562306a36Sopenharmony_ci struct cdev *cdev; 416662306a36Sopenharmony_ci struct device *dev; 416762306a36Sopenharmony_ci struct st_modedef *STm = &(tape->modes[mode]); 416862306a36Sopenharmony_ci char name[10]; 416962306a36Sopenharmony_ci int dev_num = tape->index; 417062306a36Sopenharmony_ci 417162306a36Sopenharmony_ci cdev_devno = MKDEV(SCSI_TAPE_MAJOR, TAPE_MINOR(dev_num, mode, rew)); 417262306a36Sopenharmony_ci 417362306a36Sopenharmony_ci cdev = cdev_alloc(); 417462306a36Sopenharmony_ci if (!cdev) { 417562306a36Sopenharmony_ci pr_err("st%d: out of memory. Device not attached.\n", dev_num); 417662306a36Sopenharmony_ci error = -ENOMEM; 417762306a36Sopenharmony_ci goto out; 417862306a36Sopenharmony_ci } 417962306a36Sopenharmony_ci cdev->owner = THIS_MODULE; 418062306a36Sopenharmony_ci cdev->ops = &st_fops; 418162306a36Sopenharmony_ci STm->cdevs[rew] = cdev; 418262306a36Sopenharmony_ci 418362306a36Sopenharmony_ci error = cdev_add(cdev, cdev_devno, 1); 418462306a36Sopenharmony_ci if (error) { 418562306a36Sopenharmony_ci pr_err("st%d: Can't add %s-rewind mode %d\n", dev_num, 418662306a36Sopenharmony_ci rew ? "non" : "auto", mode); 418762306a36Sopenharmony_ci pr_err("st%d: Device not attached.\n", dev_num); 418862306a36Sopenharmony_ci goto out_free; 418962306a36Sopenharmony_ci } 419062306a36Sopenharmony_ci 419162306a36Sopenharmony_ci i = mode << (4 - ST_NBR_MODE_BITS); 419262306a36Sopenharmony_ci snprintf(name, 10, "%s%s%s", rew ? "n" : "", 419362306a36Sopenharmony_ci tape->name, st_formats[i]); 419462306a36Sopenharmony_ci 419562306a36Sopenharmony_ci dev = device_create(&st_sysfs_class, &tape->device->sdev_gendev, 419662306a36Sopenharmony_ci cdev_devno, &tape->modes[mode], "%s", name); 419762306a36Sopenharmony_ci if (IS_ERR(dev)) { 419862306a36Sopenharmony_ci pr_err("st%d: device_create failed\n", dev_num); 419962306a36Sopenharmony_ci error = PTR_ERR(dev); 420062306a36Sopenharmony_ci goto out_free; 420162306a36Sopenharmony_ci } 420262306a36Sopenharmony_ci 420362306a36Sopenharmony_ci STm->devs[rew] = dev; 420462306a36Sopenharmony_ci 420562306a36Sopenharmony_ci return 0; 420662306a36Sopenharmony_ciout_free: 420762306a36Sopenharmony_ci cdev_del(STm->cdevs[rew]); 420862306a36Sopenharmony_ciout: 420962306a36Sopenharmony_ci STm->cdevs[rew] = NULL; 421062306a36Sopenharmony_ci STm->devs[rew] = NULL; 421162306a36Sopenharmony_ci return error; 421262306a36Sopenharmony_ci} 421362306a36Sopenharmony_ci 421462306a36Sopenharmony_cistatic int create_cdevs(struct scsi_tape *tape) 421562306a36Sopenharmony_ci{ 421662306a36Sopenharmony_ci int mode, error; 421762306a36Sopenharmony_ci for (mode = 0; mode < ST_NBR_MODES; ++mode) { 421862306a36Sopenharmony_ci error = create_one_cdev(tape, mode, 0); 421962306a36Sopenharmony_ci if (error) 422062306a36Sopenharmony_ci return error; 422162306a36Sopenharmony_ci error = create_one_cdev(tape, mode, 1); 422262306a36Sopenharmony_ci if (error) 422362306a36Sopenharmony_ci return error; 422462306a36Sopenharmony_ci } 422562306a36Sopenharmony_ci 422662306a36Sopenharmony_ci return sysfs_create_link(&tape->device->sdev_gendev.kobj, 422762306a36Sopenharmony_ci &tape->modes[0].devs[0]->kobj, "tape"); 422862306a36Sopenharmony_ci} 422962306a36Sopenharmony_ci 423062306a36Sopenharmony_cistatic void remove_cdevs(struct scsi_tape *tape) 423162306a36Sopenharmony_ci{ 423262306a36Sopenharmony_ci int mode, rew; 423362306a36Sopenharmony_ci sysfs_remove_link(&tape->device->sdev_gendev.kobj, "tape"); 423462306a36Sopenharmony_ci for (mode = 0; mode < ST_NBR_MODES; mode++) { 423562306a36Sopenharmony_ci struct st_modedef *STm = &(tape->modes[mode]); 423662306a36Sopenharmony_ci for (rew = 0; rew < 2; rew++) { 423762306a36Sopenharmony_ci if (STm->cdevs[rew]) 423862306a36Sopenharmony_ci cdev_del(STm->cdevs[rew]); 423962306a36Sopenharmony_ci if (STm->devs[rew]) 424062306a36Sopenharmony_ci device_unregister(STm->devs[rew]); 424162306a36Sopenharmony_ci } 424262306a36Sopenharmony_ci } 424362306a36Sopenharmony_ci} 424462306a36Sopenharmony_ci 424562306a36Sopenharmony_cistatic int st_probe(struct device *dev) 424662306a36Sopenharmony_ci{ 424762306a36Sopenharmony_ci struct scsi_device *SDp = to_scsi_device(dev); 424862306a36Sopenharmony_ci struct scsi_tape *tpnt = NULL; 424962306a36Sopenharmony_ci struct st_modedef *STm; 425062306a36Sopenharmony_ci struct st_partstat *STps; 425162306a36Sopenharmony_ci struct st_buffer *buffer; 425262306a36Sopenharmony_ci int i, error; 425362306a36Sopenharmony_ci 425462306a36Sopenharmony_ci if (SDp->type != TYPE_TAPE) 425562306a36Sopenharmony_ci return -ENODEV; 425662306a36Sopenharmony_ci if (st_incompatible(SDp)) { 425762306a36Sopenharmony_ci sdev_printk(KERN_INFO, SDp, 425862306a36Sopenharmony_ci "OnStream tapes are no longer supported;\n"); 425962306a36Sopenharmony_ci sdev_printk(KERN_INFO, SDp, 426062306a36Sopenharmony_ci "please mail to linux-scsi@vger.kernel.org.\n"); 426162306a36Sopenharmony_ci return -ENODEV; 426262306a36Sopenharmony_ci } 426362306a36Sopenharmony_ci 426462306a36Sopenharmony_ci scsi_autopm_get_device(SDp); 426562306a36Sopenharmony_ci i = queue_max_segments(SDp->request_queue); 426662306a36Sopenharmony_ci if (st_max_sg_segs < i) 426762306a36Sopenharmony_ci i = st_max_sg_segs; 426862306a36Sopenharmony_ci buffer = new_tape_buffer(i); 426962306a36Sopenharmony_ci if (buffer == NULL) { 427062306a36Sopenharmony_ci sdev_printk(KERN_ERR, SDp, 427162306a36Sopenharmony_ci "st: Can't allocate new tape buffer. " 427262306a36Sopenharmony_ci "Device not attached.\n"); 427362306a36Sopenharmony_ci goto out; 427462306a36Sopenharmony_ci } 427562306a36Sopenharmony_ci 427662306a36Sopenharmony_ci tpnt = kzalloc(sizeof(struct scsi_tape), GFP_KERNEL); 427762306a36Sopenharmony_ci if (tpnt == NULL) { 427862306a36Sopenharmony_ci sdev_printk(KERN_ERR, SDp, 427962306a36Sopenharmony_ci "st: Can't allocate device descriptor.\n"); 428062306a36Sopenharmony_ci goto out_buffer_free; 428162306a36Sopenharmony_ci } 428262306a36Sopenharmony_ci kref_init(&tpnt->kref); 428362306a36Sopenharmony_ci 428462306a36Sopenharmony_ci tpnt->device = SDp; 428562306a36Sopenharmony_ci if (SDp->scsi_level <= 2) 428662306a36Sopenharmony_ci tpnt->tape_type = MT_ISSCSI1; 428762306a36Sopenharmony_ci else 428862306a36Sopenharmony_ci tpnt->tape_type = MT_ISSCSI2; 428962306a36Sopenharmony_ci 429062306a36Sopenharmony_ci tpnt->buffer = buffer; 429162306a36Sopenharmony_ci tpnt->buffer->last_SRpnt = NULL; 429262306a36Sopenharmony_ci 429362306a36Sopenharmony_ci tpnt->inited = 0; 429462306a36Sopenharmony_ci tpnt->dirty = 0; 429562306a36Sopenharmony_ci tpnt->in_use = 0; 429662306a36Sopenharmony_ci tpnt->drv_buffer = 1; /* Try buffering if no mode sense */ 429762306a36Sopenharmony_ci tpnt->use_pf = (SDp->scsi_level >= SCSI_2); 429862306a36Sopenharmony_ci tpnt->density = 0; 429962306a36Sopenharmony_ci tpnt->do_auto_lock = ST_AUTO_LOCK; 430062306a36Sopenharmony_ci tpnt->can_bsr = (SDp->scsi_level > 2 ? 1 : ST_IN_FILE_POS); /* BSR mandatory in SCSI3 */ 430162306a36Sopenharmony_ci tpnt->can_partitions = 0; 430262306a36Sopenharmony_ci tpnt->two_fm = ST_TWO_FM; 430362306a36Sopenharmony_ci tpnt->fast_mteom = ST_FAST_MTEOM; 430462306a36Sopenharmony_ci tpnt->scsi2_logical = ST_SCSI2LOGICAL; 430562306a36Sopenharmony_ci tpnt->sili = ST_SILI; 430662306a36Sopenharmony_ci tpnt->immediate = ST_NOWAIT; 430762306a36Sopenharmony_ci tpnt->immediate_filemark = 0; 430862306a36Sopenharmony_ci tpnt->default_drvbuffer = 0xff; /* No forced buffering */ 430962306a36Sopenharmony_ci tpnt->partition = 0; 431062306a36Sopenharmony_ci tpnt->new_partition = 0; 431162306a36Sopenharmony_ci tpnt->nbr_partitions = 0; 431262306a36Sopenharmony_ci blk_queue_rq_timeout(tpnt->device->request_queue, ST_TIMEOUT); 431362306a36Sopenharmony_ci tpnt->long_timeout = ST_LONG_TIMEOUT; 431462306a36Sopenharmony_ci tpnt->try_dio = try_direct_io; 431562306a36Sopenharmony_ci 431662306a36Sopenharmony_ci for (i = 0; i < ST_NBR_MODES; i++) { 431762306a36Sopenharmony_ci STm = &(tpnt->modes[i]); 431862306a36Sopenharmony_ci STm->defined = 0; 431962306a36Sopenharmony_ci STm->sysv = ST_SYSV; 432062306a36Sopenharmony_ci STm->defaults_for_writes = 0; 432162306a36Sopenharmony_ci STm->do_async_writes = ST_ASYNC_WRITES; 432262306a36Sopenharmony_ci STm->do_buffer_writes = ST_BUFFER_WRITES; 432362306a36Sopenharmony_ci STm->do_read_ahead = ST_READ_AHEAD; 432462306a36Sopenharmony_ci STm->default_compression = ST_DONT_TOUCH; 432562306a36Sopenharmony_ci STm->default_blksize = (-1); /* No forced size */ 432662306a36Sopenharmony_ci STm->default_density = (-1); /* No forced density */ 432762306a36Sopenharmony_ci STm->tape = tpnt; 432862306a36Sopenharmony_ci } 432962306a36Sopenharmony_ci 433062306a36Sopenharmony_ci for (i = 0; i < ST_NBR_PARTITIONS; i++) { 433162306a36Sopenharmony_ci STps = &(tpnt->ps[i]); 433262306a36Sopenharmony_ci STps->rw = ST_IDLE; 433362306a36Sopenharmony_ci STps->eof = ST_NOEOF; 433462306a36Sopenharmony_ci STps->at_sm = 0; 433562306a36Sopenharmony_ci STps->last_block_valid = 0; 433662306a36Sopenharmony_ci STps->drv_block = (-1); 433762306a36Sopenharmony_ci STps->drv_file = (-1); 433862306a36Sopenharmony_ci } 433962306a36Sopenharmony_ci 434062306a36Sopenharmony_ci tpnt->current_mode = 0; 434162306a36Sopenharmony_ci tpnt->modes[0].defined = 1; 434262306a36Sopenharmony_ci 434362306a36Sopenharmony_ci tpnt->density_changed = tpnt->compression_changed = 434462306a36Sopenharmony_ci tpnt->blksize_changed = 0; 434562306a36Sopenharmony_ci mutex_init(&tpnt->lock); 434662306a36Sopenharmony_ci 434762306a36Sopenharmony_ci idr_preload(GFP_KERNEL); 434862306a36Sopenharmony_ci spin_lock(&st_index_lock); 434962306a36Sopenharmony_ci error = idr_alloc(&st_index_idr, tpnt, 0, ST_MAX_TAPES + 1, GFP_NOWAIT); 435062306a36Sopenharmony_ci spin_unlock(&st_index_lock); 435162306a36Sopenharmony_ci idr_preload_end(); 435262306a36Sopenharmony_ci if (error < 0) { 435362306a36Sopenharmony_ci pr_warn("st: idr allocation failed: %d\n", error); 435462306a36Sopenharmony_ci goto out_free_tape; 435562306a36Sopenharmony_ci } 435662306a36Sopenharmony_ci tpnt->index = error; 435762306a36Sopenharmony_ci sprintf(tpnt->name, "st%d", tpnt->index); 435862306a36Sopenharmony_ci tpnt->stats = kzalloc(sizeof(struct scsi_tape_stats), GFP_KERNEL); 435962306a36Sopenharmony_ci if (tpnt->stats == NULL) { 436062306a36Sopenharmony_ci sdev_printk(KERN_ERR, SDp, 436162306a36Sopenharmony_ci "st: Can't allocate statistics.\n"); 436262306a36Sopenharmony_ci goto out_idr_remove; 436362306a36Sopenharmony_ci } 436462306a36Sopenharmony_ci 436562306a36Sopenharmony_ci dev_set_drvdata(dev, tpnt); 436662306a36Sopenharmony_ci 436762306a36Sopenharmony_ci 436862306a36Sopenharmony_ci error = create_cdevs(tpnt); 436962306a36Sopenharmony_ci if (error) 437062306a36Sopenharmony_ci goto out_remove_devs; 437162306a36Sopenharmony_ci scsi_autopm_put_device(SDp); 437262306a36Sopenharmony_ci 437362306a36Sopenharmony_ci sdev_printk(KERN_NOTICE, SDp, 437462306a36Sopenharmony_ci "Attached scsi tape %s\n", tpnt->name); 437562306a36Sopenharmony_ci sdev_printk(KERN_INFO, SDp, "%s: try direct i/o: %s (alignment %d B)\n", 437662306a36Sopenharmony_ci tpnt->name, tpnt->try_dio ? "yes" : "no", 437762306a36Sopenharmony_ci queue_dma_alignment(SDp->request_queue) + 1); 437862306a36Sopenharmony_ci 437962306a36Sopenharmony_ci return 0; 438062306a36Sopenharmony_ci 438162306a36Sopenharmony_ciout_remove_devs: 438262306a36Sopenharmony_ci remove_cdevs(tpnt); 438362306a36Sopenharmony_ci kfree(tpnt->stats); 438462306a36Sopenharmony_ciout_idr_remove: 438562306a36Sopenharmony_ci spin_lock(&st_index_lock); 438662306a36Sopenharmony_ci idr_remove(&st_index_idr, tpnt->index); 438762306a36Sopenharmony_ci spin_unlock(&st_index_lock); 438862306a36Sopenharmony_ciout_free_tape: 438962306a36Sopenharmony_ci kfree(tpnt); 439062306a36Sopenharmony_ciout_buffer_free: 439162306a36Sopenharmony_ci kfree(buffer); 439262306a36Sopenharmony_ciout: 439362306a36Sopenharmony_ci scsi_autopm_put_device(SDp); 439462306a36Sopenharmony_ci return -ENODEV; 439562306a36Sopenharmony_ci}; 439662306a36Sopenharmony_ci 439762306a36Sopenharmony_ci 439862306a36Sopenharmony_cistatic int st_remove(struct device *dev) 439962306a36Sopenharmony_ci{ 440062306a36Sopenharmony_ci struct scsi_tape *tpnt = dev_get_drvdata(dev); 440162306a36Sopenharmony_ci int index = tpnt->index; 440262306a36Sopenharmony_ci 440362306a36Sopenharmony_ci scsi_autopm_get_device(to_scsi_device(dev)); 440462306a36Sopenharmony_ci remove_cdevs(tpnt); 440562306a36Sopenharmony_ci 440662306a36Sopenharmony_ci mutex_lock(&st_ref_mutex); 440762306a36Sopenharmony_ci kref_put(&tpnt->kref, scsi_tape_release); 440862306a36Sopenharmony_ci mutex_unlock(&st_ref_mutex); 440962306a36Sopenharmony_ci spin_lock(&st_index_lock); 441062306a36Sopenharmony_ci idr_remove(&st_index_idr, index); 441162306a36Sopenharmony_ci spin_unlock(&st_index_lock); 441262306a36Sopenharmony_ci return 0; 441362306a36Sopenharmony_ci} 441462306a36Sopenharmony_ci 441562306a36Sopenharmony_ci/** 441662306a36Sopenharmony_ci * scsi_tape_release - Called to free the Scsi_Tape structure 441762306a36Sopenharmony_ci * @kref: pointer to embedded kref 441862306a36Sopenharmony_ci * 441962306a36Sopenharmony_ci * st_ref_mutex must be held entering this routine. Because it is 442062306a36Sopenharmony_ci * called on last put, you should always use the scsi_tape_get() 442162306a36Sopenharmony_ci * scsi_tape_put() helpers which manipulate the semaphore directly 442262306a36Sopenharmony_ci * and never do a direct kref_put(). 442362306a36Sopenharmony_ci **/ 442462306a36Sopenharmony_cistatic void scsi_tape_release(struct kref *kref) 442562306a36Sopenharmony_ci{ 442662306a36Sopenharmony_ci struct scsi_tape *tpnt = to_scsi_tape(kref); 442762306a36Sopenharmony_ci 442862306a36Sopenharmony_ci tpnt->device = NULL; 442962306a36Sopenharmony_ci 443062306a36Sopenharmony_ci if (tpnt->buffer) { 443162306a36Sopenharmony_ci normalize_buffer(tpnt->buffer); 443262306a36Sopenharmony_ci kfree(tpnt->buffer->reserved_pages); 443362306a36Sopenharmony_ci kfree(tpnt->buffer); 443462306a36Sopenharmony_ci } 443562306a36Sopenharmony_ci 443662306a36Sopenharmony_ci kfree(tpnt->stats); 443762306a36Sopenharmony_ci kfree(tpnt); 443862306a36Sopenharmony_ci return; 443962306a36Sopenharmony_ci} 444062306a36Sopenharmony_ci 444162306a36Sopenharmony_cistatic struct class st_sysfs_class = { 444262306a36Sopenharmony_ci .name = "scsi_tape", 444362306a36Sopenharmony_ci .dev_groups = st_dev_groups, 444462306a36Sopenharmony_ci}; 444562306a36Sopenharmony_ci 444662306a36Sopenharmony_cistatic int __init init_st(void) 444762306a36Sopenharmony_ci{ 444862306a36Sopenharmony_ci int err; 444962306a36Sopenharmony_ci 445062306a36Sopenharmony_ci validate_options(); 445162306a36Sopenharmony_ci 445262306a36Sopenharmony_ci printk(KERN_INFO "st: Version %s, fixed bufsize %d, s/g segs %d\n", 445362306a36Sopenharmony_ci verstr, st_fixed_buffer_size, st_max_sg_segs); 445462306a36Sopenharmony_ci 445562306a36Sopenharmony_ci debugging = (debug_flag > 0) ? debug_flag : NO_DEBUG; 445662306a36Sopenharmony_ci if (debugging) { 445762306a36Sopenharmony_ci printk(KERN_INFO "st: Debugging enabled debug_flag = %d\n", 445862306a36Sopenharmony_ci debugging); 445962306a36Sopenharmony_ci } 446062306a36Sopenharmony_ci 446162306a36Sopenharmony_ci err = class_register(&st_sysfs_class); 446262306a36Sopenharmony_ci if (err) { 446362306a36Sopenharmony_ci pr_err("Unable register sysfs class for SCSI tapes\n"); 446462306a36Sopenharmony_ci return err; 446562306a36Sopenharmony_ci } 446662306a36Sopenharmony_ci 446762306a36Sopenharmony_ci err = register_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0), 446862306a36Sopenharmony_ci ST_MAX_TAPE_ENTRIES, "st"); 446962306a36Sopenharmony_ci if (err) { 447062306a36Sopenharmony_ci printk(KERN_ERR "Unable to get major %d for SCSI tapes\n", 447162306a36Sopenharmony_ci SCSI_TAPE_MAJOR); 447262306a36Sopenharmony_ci goto err_class; 447362306a36Sopenharmony_ci } 447462306a36Sopenharmony_ci 447562306a36Sopenharmony_ci err = scsi_register_driver(&st_template.gendrv); 447662306a36Sopenharmony_ci if (err) 447762306a36Sopenharmony_ci goto err_chrdev; 447862306a36Sopenharmony_ci 447962306a36Sopenharmony_ci return 0; 448062306a36Sopenharmony_ci 448162306a36Sopenharmony_cierr_chrdev: 448262306a36Sopenharmony_ci unregister_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0), 448362306a36Sopenharmony_ci ST_MAX_TAPE_ENTRIES); 448462306a36Sopenharmony_cierr_class: 448562306a36Sopenharmony_ci class_unregister(&st_sysfs_class); 448662306a36Sopenharmony_ci return err; 448762306a36Sopenharmony_ci} 448862306a36Sopenharmony_ci 448962306a36Sopenharmony_cistatic void __exit exit_st(void) 449062306a36Sopenharmony_ci{ 449162306a36Sopenharmony_ci scsi_unregister_driver(&st_template.gendrv); 449262306a36Sopenharmony_ci unregister_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0), 449362306a36Sopenharmony_ci ST_MAX_TAPE_ENTRIES); 449462306a36Sopenharmony_ci class_unregister(&st_sysfs_class); 449562306a36Sopenharmony_ci idr_destroy(&st_index_idr); 449662306a36Sopenharmony_ci printk(KERN_INFO "st: Unloaded.\n"); 449762306a36Sopenharmony_ci} 449862306a36Sopenharmony_ci 449962306a36Sopenharmony_cimodule_init(init_st); 450062306a36Sopenharmony_cimodule_exit(exit_st); 450162306a36Sopenharmony_ci 450262306a36Sopenharmony_ci 450362306a36Sopenharmony_ci/* The sysfs driver interface. Read-only at the moment */ 450462306a36Sopenharmony_cistatic ssize_t try_direct_io_show(struct device_driver *ddp, char *buf) 450562306a36Sopenharmony_ci{ 450662306a36Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%d\n", try_direct_io); 450762306a36Sopenharmony_ci} 450862306a36Sopenharmony_cistatic DRIVER_ATTR_RO(try_direct_io); 450962306a36Sopenharmony_ci 451062306a36Sopenharmony_cistatic ssize_t fixed_buffer_size_show(struct device_driver *ddp, char *buf) 451162306a36Sopenharmony_ci{ 451262306a36Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%d\n", st_fixed_buffer_size); 451362306a36Sopenharmony_ci} 451462306a36Sopenharmony_cistatic DRIVER_ATTR_RO(fixed_buffer_size); 451562306a36Sopenharmony_ci 451662306a36Sopenharmony_cistatic ssize_t max_sg_segs_show(struct device_driver *ddp, char *buf) 451762306a36Sopenharmony_ci{ 451862306a36Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%d\n", st_max_sg_segs); 451962306a36Sopenharmony_ci} 452062306a36Sopenharmony_cistatic DRIVER_ATTR_RO(max_sg_segs); 452162306a36Sopenharmony_ci 452262306a36Sopenharmony_cistatic ssize_t version_show(struct device_driver *ddd, char *buf) 452362306a36Sopenharmony_ci{ 452462306a36Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "[%s]\n", verstr); 452562306a36Sopenharmony_ci} 452662306a36Sopenharmony_cistatic DRIVER_ATTR_RO(version); 452762306a36Sopenharmony_ci 452862306a36Sopenharmony_ci#if DEBUG 452962306a36Sopenharmony_cistatic ssize_t debug_flag_store(struct device_driver *ddp, 453062306a36Sopenharmony_ci const char *buf, size_t count) 453162306a36Sopenharmony_ci{ 453262306a36Sopenharmony_ci/* We only care what the first byte of the data is the rest is unused. 453362306a36Sopenharmony_ci * if it's a '1' we turn on debug and if it's a '0' we disable it. All 453462306a36Sopenharmony_ci * other values have -EINVAL returned if they are passed in. 453562306a36Sopenharmony_ci */ 453662306a36Sopenharmony_ci if (count > 0) { 453762306a36Sopenharmony_ci if (buf[0] == '0') { 453862306a36Sopenharmony_ci debugging = NO_DEBUG; 453962306a36Sopenharmony_ci return count; 454062306a36Sopenharmony_ci } else if (buf[0] == '1') { 454162306a36Sopenharmony_ci debugging = 1; 454262306a36Sopenharmony_ci return count; 454362306a36Sopenharmony_ci } 454462306a36Sopenharmony_ci } 454562306a36Sopenharmony_ci return -EINVAL; 454662306a36Sopenharmony_ci} 454762306a36Sopenharmony_ci 454862306a36Sopenharmony_cistatic ssize_t debug_flag_show(struct device_driver *ddp, char *buf) 454962306a36Sopenharmony_ci{ 455062306a36Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%d\n", debugging); 455162306a36Sopenharmony_ci} 455262306a36Sopenharmony_cistatic DRIVER_ATTR_RW(debug_flag); 455362306a36Sopenharmony_ci#endif 455462306a36Sopenharmony_ci 455562306a36Sopenharmony_cistatic struct attribute *st_drv_attrs[] = { 455662306a36Sopenharmony_ci &driver_attr_try_direct_io.attr, 455762306a36Sopenharmony_ci &driver_attr_fixed_buffer_size.attr, 455862306a36Sopenharmony_ci &driver_attr_max_sg_segs.attr, 455962306a36Sopenharmony_ci &driver_attr_version.attr, 456062306a36Sopenharmony_ci#if DEBUG 456162306a36Sopenharmony_ci &driver_attr_debug_flag.attr, 456262306a36Sopenharmony_ci#endif 456362306a36Sopenharmony_ci NULL, 456462306a36Sopenharmony_ci}; 456562306a36Sopenharmony_ciATTRIBUTE_GROUPS(st_drv); 456662306a36Sopenharmony_ci 456762306a36Sopenharmony_ci/* The sysfs simple class interface */ 456862306a36Sopenharmony_cistatic ssize_t 456962306a36Sopenharmony_cidefined_show(struct device *dev, struct device_attribute *attr, char *buf) 457062306a36Sopenharmony_ci{ 457162306a36Sopenharmony_ci struct st_modedef *STm = dev_get_drvdata(dev); 457262306a36Sopenharmony_ci ssize_t l = 0; 457362306a36Sopenharmony_ci 457462306a36Sopenharmony_ci l = snprintf(buf, PAGE_SIZE, "%d\n", STm->defined); 457562306a36Sopenharmony_ci return l; 457662306a36Sopenharmony_ci} 457762306a36Sopenharmony_cistatic DEVICE_ATTR_RO(defined); 457862306a36Sopenharmony_ci 457962306a36Sopenharmony_cistatic ssize_t 458062306a36Sopenharmony_cidefault_blksize_show(struct device *dev, struct device_attribute *attr, 458162306a36Sopenharmony_ci char *buf) 458262306a36Sopenharmony_ci{ 458362306a36Sopenharmony_ci struct st_modedef *STm = dev_get_drvdata(dev); 458462306a36Sopenharmony_ci ssize_t l = 0; 458562306a36Sopenharmony_ci 458662306a36Sopenharmony_ci l = snprintf(buf, PAGE_SIZE, "%d\n", STm->default_blksize); 458762306a36Sopenharmony_ci return l; 458862306a36Sopenharmony_ci} 458962306a36Sopenharmony_cistatic DEVICE_ATTR_RO(default_blksize); 459062306a36Sopenharmony_ci 459162306a36Sopenharmony_cistatic ssize_t 459262306a36Sopenharmony_cidefault_density_show(struct device *dev, struct device_attribute *attr, 459362306a36Sopenharmony_ci char *buf) 459462306a36Sopenharmony_ci{ 459562306a36Sopenharmony_ci struct st_modedef *STm = dev_get_drvdata(dev); 459662306a36Sopenharmony_ci ssize_t l = 0; 459762306a36Sopenharmony_ci char *fmt; 459862306a36Sopenharmony_ci 459962306a36Sopenharmony_ci fmt = STm->default_density >= 0 ? "0x%02x\n" : "%d\n"; 460062306a36Sopenharmony_ci l = snprintf(buf, PAGE_SIZE, fmt, STm->default_density); 460162306a36Sopenharmony_ci return l; 460262306a36Sopenharmony_ci} 460362306a36Sopenharmony_cistatic DEVICE_ATTR_RO(default_density); 460462306a36Sopenharmony_ci 460562306a36Sopenharmony_cistatic ssize_t 460662306a36Sopenharmony_cidefault_compression_show(struct device *dev, struct device_attribute *attr, 460762306a36Sopenharmony_ci char *buf) 460862306a36Sopenharmony_ci{ 460962306a36Sopenharmony_ci struct st_modedef *STm = dev_get_drvdata(dev); 461062306a36Sopenharmony_ci ssize_t l = 0; 461162306a36Sopenharmony_ci 461262306a36Sopenharmony_ci l = snprintf(buf, PAGE_SIZE, "%d\n", STm->default_compression - 1); 461362306a36Sopenharmony_ci return l; 461462306a36Sopenharmony_ci} 461562306a36Sopenharmony_cistatic DEVICE_ATTR_RO(default_compression); 461662306a36Sopenharmony_ci 461762306a36Sopenharmony_cistatic ssize_t 461862306a36Sopenharmony_cioptions_show(struct device *dev, struct device_attribute *attr, char *buf) 461962306a36Sopenharmony_ci{ 462062306a36Sopenharmony_ci struct st_modedef *STm = dev_get_drvdata(dev); 462162306a36Sopenharmony_ci struct scsi_tape *STp = STm->tape; 462262306a36Sopenharmony_ci int options; 462362306a36Sopenharmony_ci ssize_t l = 0; 462462306a36Sopenharmony_ci 462562306a36Sopenharmony_ci options = STm->do_buffer_writes ? MT_ST_BUFFER_WRITES : 0; 462662306a36Sopenharmony_ci options |= STm->do_async_writes ? MT_ST_ASYNC_WRITES : 0; 462762306a36Sopenharmony_ci options |= STm->do_read_ahead ? MT_ST_READ_AHEAD : 0; 462862306a36Sopenharmony_ci DEB( options |= debugging ? MT_ST_DEBUGGING : 0 ); 462962306a36Sopenharmony_ci options |= STp->two_fm ? MT_ST_TWO_FM : 0; 463062306a36Sopenharmony_ci options |= STp->fast_mteom ? MT_ST_FAST_MTEOM : 0; 463162306a36Sopenharmony_ci options |= STm->defaults_for_writes ? MT_ST_DEF_WRITES : 0; 463262306a36Sopenharmony_ci options |= STp->can_bsr ? MT_ST_CAN_BSR : 0; 463362306a36Sopenharmony_ci options |= STp->omit_blklims ? MT_ST_NO_BLKLIMS : 0; 463462306a36Sopenharmony_ci options |= STp->can_partitions ? MT_ST_CAN_PARTITIONS : 0; 463562306a36Sopenharmony_ci options |= STp->scsi2_logical ? MT_ST_SCSI2LOGICAL : 0; 463662306a36Sopenharmony_ci options |= STm->sysv ? MT_ST_SYSV : 0; 463762306a36Sopenharmony_ci options |= STp->immediate ? MT_ST_NOWAIT : 0; 463862306a36Sopenharmony_ci options |= STp->immediate_filemark ? MT_ST_NOWAIT_EOF : 0; 463962306a36Sopenharmony_ci options |= STp->sili ? MT_ST_SILI : 0; 464062306a36Sopenharmony_ci 464162306a36Sopenharmony_ci l = snprintf(buf, PAGE_SIZE, "0x%08x\n", options); 464262306a36Sopenharmony_ci return l; 464362306a36Sopenharmony_ci} 464462306a36Sopenharmony_cistatic DEVICE_ATTR_RO(options); 464562306a36Sopenharmony_ci 464662306a36Sopenharmony_ci/* Support for tape stats */ 464762306a36Sopenharmony_ci 464862306a36Sopenharmony_ci/** 464962306a36Sopenharmony_ci * read_cnt_show - return read count - count of reads made from tape drive 465062306a36Sopenharmony_ci * @dev: struct device 465162306a36Sopenharmony_ci * @attr: attribute structure 465262306a36Sopenharmony_ci * @buf: buffer to return formatted data in 465362306a36Sopenharmony_ci */ 465462306a36Sopenharmony_cistatic ssize_t read_cnt_show(struct device *dev, 465562306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 465662306a36Sopenharmony_ci{ 465762306a36Sopenharmony_ci struct st_modedef *STm = dev_get_drvdata(dev); 465862306a36Sopenharmony_ci 465962306a36Sopenharmony_ci return sprintf(buf, "%lld", 466062306a36Sopenharmony_ci (long long)atomic64_read(&STm->tape->stats->read_cnt)); 466162306a36Sopenharmony_ci} 466262306a36Sopenharmony_cistatic DEVICE_ATTR_RO(read_cnt); 466362306a36Sopenharmony_ci 466462306a36Sopenharmony_ci/** 466562306a36Sopenharmony_ci * read_byte_cnt_show - return read byte count - tape drives 466662306a36Sopenharmony_ci * may use blocks less than 512 bytes this gives the raw byte count of 466762306a36Sopenharmony_ci * of data read from the tape drive. 466862306a36Sopenharmony_ci * @dev: struct device 466962306a36Sopenharmony_ci * @attr: attribute structure 467062306a36Sopenharmony_ci * @buf: buffer to return formatted data in 467162306a36Sopenharmony_ci */ 467262306a36Sopenharmony_cistatic ssize_t read_byte_cnt_show(struct device *dev, 467362306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 467462306a36Sopenharmony_ci{ 467562306a36Sopenharmony_ci struct st_modedef *STm = dev_get_drvdata(dev); 467662306a36Sopenharmony_ci 467762306a36Sopenharmony_ci return sprintf(buf, "%lld", 467862306a36Sopenharmony_ci (long long)atomic64_read(&STm->tape->stats->read_byte_cnt)); 467962306a36Sopenharmony_ci} 468062306a36Sopenharmony_cistatic DEVICE_ATTR_RO(read_byte_cnt); 468162306a36Sopenharmony_ci 468262306a36Sopenharmony_ci/** 468362306a36Sopenharmony_ci * read_ns_show - return read ns - overall time spent waiting on reads in ns. 468462306a36Sopenharmony_ci * @dev: struct device 468562306a36Sopenharmony_ci * @attr: attribute structure 468662306a36Sopenharmony_ci * @buf: buffer to return formatted data in 468762306a36Sopenharmony_ci */ 468862306a36Sopenharmony_cistatic ssize_t read_ns_show(struct device *dev, 468962306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 469062306a36Sopenharmony_ci{ 469162306a36Sopenharmony_ci struct st_modedef *STm = dev_get_drvdata(dev); 469262306a36Sopenharmony_ci 469362306a36Sopenharmony_ci return sprintf(buf, "%lld", 469462306a36Sopenharmony_ci (long long)atomic64_read(&STm->tape->stats->tot_read_time)); 469562306a36Sopenharmony_ci} 469662306a36Sopenharmony_cistatic DEVICE_ATTR_RO(read_ns); 469762306a36Sopenharmony_ci 469862306a36Sopenharmony_ci/** 469962306a36Sopenharmony_ci * write_cnt_show - write count - number of user calls 470062306a36Sopenharmony_ci * to write(2) that have written data to tape. 470162306a36Sopenharmony_ci * @dev: struct device 470262306a36Sopenharmony_ci * @attr: attribute structure 470362306a36Sopenharmony_ci * @buf: buffer to return formatted data in 470462306a36Sopenharmony_ci */ 470562306a36Sopenharmony_cistatic ssize_t write_cnt_show(struct device *dev, 470662306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 470762306a36Sopenharmony_ci{ 470862306a36Sopenharmony_ci struct st_modedef *STm = dev_get_drvdata(dev); 470962306a36Sopenharmony_ci 471062306a36Sopenharmony_ci return sprintf(buf, "%lld", 471162306a36Sopenharmony_ci (long long)atomic64_read(&STm->tape->stats->write_cnt)); 471262306a36Sopenharmony_ci} 471362306a36Sopenharmony_cistatic DEVICE_ATTR_RO(write_cnt); 471462306a36Sopenharmony_ci 471562306a36Sopenharmony_ci/** 471662306a36Sopenharmony_ci * write_byte_cnt_show - write byte count - raw count of 471762306a36Sopenharmony_ci * bytes written to tape. 471862306a36Sopenharmony_ci * @dev: struct device 471962306a36Sopenharmony_ci * @attr: attribute structure 472062306a36Sopenharmony_ci * @buf: buffer to return formatted data in 472162306a36Sopenharmony_ci */ 472262306a36Sopenharmony_cistatic ssize_t write_byte_cnt_show(struct device *dev, 472362306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 472462306a36Sopenharmony_ci{ 472562306a36Sopenharmony_ci struct st_modedef *STm = dev_get_drvdata(dev); 472662306a36Sopenharmony_ci 472762306a36Sopenharmony_ci return sprintf(buf, "%lld", 472862306a36Sopenharmony_ci (long long)atomic64_read(&STm->tape->stats->write_byte_cnt)); 472962306a36Sopenharmony_ci} 473062306a36Sopenharmony_cistatic DEVICE_ATTR_RO(write_byte_cnt); 473162306a36Sopenharmony_ci 473262306a36Sopenharmony_ci/** 473362306a36Sopenharmony_ci * write_ns_show - write ns - number of nanoseconds waiting on write 473462306a36Sopenharmony_ci * requests to complete. 473562306a36Sopenharmony_ci * @dev: struct device 473662306a36Sopenharmony_ci * @attr: attribute structure 473762306a36Sopenharmony_ci * @buf: buffer to return formatted data in 473862306a36Sopenharmony_ci */ 473962306a36Sopenharmony_cistatic ssize_t write_ns_show(struct device *dev, 474062306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 474162306a36Sopenharmony_ci{ 474262306a36Sopenharmony_ci struct st_modedef *STm = dev_get_drvdata(dev); 474362306a36Sopenharmony_ci 474462306a36Sopenharmony_ci return sprintf(buf, "%lld", 474562306a36Sopenharmony_ci (long long)atomic64_read(&STm->tape->stats->tot_write_time)); 474662306a36Sopenharmony_ci} 474762306a36Sopenharmony_cistatic DEVICE_ATTR_RO(write_ns); 474862306a36Sopenharmony_ci 474962306a36Sopenharmony_ci/** 475062306a36Sopenharmony_ci * in_flight_show - number of I/Os currently in flight - 475162306a36Sopenharmony_ci * in most cases this will be either 0 or 1. It may be higher if someone 475262306a36Sopenharmony_ci * has also issued other SCSI commands such as via an ioctl. 475362306a36Sopenharmony_ci * @dev: struct device 475462306a36Sopenharmony_ci * @attr: attribute structure 475562306a36Sopenharmony_ci * @buf: buffer to return formatted data in 475662306a36Sopenharmony_ci */ 475762306a36Sopenharmony_cistatic ssize_t in_flight_show(struct device *dev, 475862306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 475962306a36Sopenharmony_ci{ 476062306a36Sopenharmony_ci struct st_modedef *STm = dev_get_drvdata(dev); 476162306a36Sopenharmony_ci 476262306a36Sopenharmony_ci return sprintf(buf, "%lld", 476362306a36Sopenharmony_ci (long long)atomic64_read(&STm->tape->stats->in_flight)); 476462306a36Sopenharmony_ci} 476562306a36Sopenharmony_cistatic DEVICE_ATTR_RO(in_flight); 476662306a36Sopenharmony_ci 476762306a36Sopenharmony_ci/** 476862306a36Sopenharmony_ci * io_ns_show - io wait ns - this is the number of ns spent 476962306a36Sopenharmony_ci * waiting on all I/O to complete. This includes tape movement commands 477062306a36Sopenharmony_ci * such as rewinding, seeking to end of file or tape, it also includes 477162306a36Sopenharmony_ci * read and write. To determine the time spent on tape movement 477262306a36Sopenharmony_ci * subtract the read and write ns from this value. 477362306a36Sopenharmony_ci * @dev: struct device 477462306a36Sopenharmony_ci * @attr: attribute structure 477562306a36Sopenharmony_ci * @buf: buffer to return formatted data in 477662306a36Sopenharmony_ci */ 477762306a36Sopenharmony_cistatic ssize_t io_ns_show(struct device *dev, 477862306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 477962306a36Sopenharmony_ci{ 478062306a36Sopenharmony_ci struct st_modedef *STm = dev_get_drvdata(dev); 478162306a36Sopenharmony_ci 478262306a36Sopenharmony_ci return sprintf(buf, "%lld", 478362306a36Sopenharmony_ci (long long)atomic64_read(&STm->tape->stats->tot_io_time)); 478462306a36Sopenharmony_ci} 478562306a36Sopenharmony_cistatic DEVICE_ATTR_RO(io_ns); 478662306a36Sopenharmony_ci 478762306a36Sopenharmony_ci/** 478862306a36Sopenharmony_ci * other_cnt_show - other io count - this is the number of 478962306a36Sopenharmony_ci * I/O requests other than read and write requests. 479062306a36Sopenharmony_ci * Typically these are tape movement requests but will include driver 479162306a36Sopenharmony_ci * tape movement. This includes only requests issued by the st driver. 479262306a36Sopenharmony_ci * @dev: struct device 479362306a36Sopenharmony_ci * @attr: attribute structure 479462306a36Sopenharmony_ci * @buf: buffer to return formatted data in 479562306a36Sopenharmony_ci */ 479662306a36Sopenharmony_cistatic ssize_t other_cnt_show(struct device *dev, 479762306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 479862306a36Sopenharmony_ci{ 479962306a36Sopenharmony_ci struct st_modedef *STm = dev_get_drvdata(dev); 480062306a36Sopenharmony_ci 480162306a36Sopenharmony_ci return sprintf(buf, "%lld", 480262306a36Sopenharmony_ci (long long)atomic64_read(&STm->tape->stats->other_cnt)); 480362306a36Sopenharmony_ci} 480462306a36Sopenharmony_cistatic DEVICE_ATTR_RO(other_cnt); 480562306a36Sopenharmony_ci 480662306a36Sopenharmony_ci/** 480762306a36Sopenharmony_ci * resid_cnt_show - A count of the number of times we get a residual 480862306a36Sopenharmony_ci * count - this should indicate someone issuing reads larger than the 480962306a36Sopenharmony_ci * block size on tape. 481062306a36Sopenharmony_ci * @dev: struct device 481162306a36Sopenharmony_ci * @attr: attribute structure 481262306a36Sopenharmony_ci * @buf: buffer to return formatted data in 481362306a36Sopenharmony_ci */ 481462306a36Sopenharmony_cistatic ssize_t resid_cnt_show(struct device *dev, 481562306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 481662306a36Sopenharmony_ci{ 481762306a36Sopenharmony_ci struct st_modedef *STm = dev_get_drvdata(dev); 481862306a36Sopenharmony_ci 481962306a36Sopenharmony_ci return sprintf(buf, "%lld", 482062306a36Sopenharmony_ci (long long)atomic64_read(&STm->tape->stats->resid_cnt)); 482162306a36Sopenharmony_ci} 482262306a36Sopenharmony_cistatic DEVICE_ATTR_RO(resid_cnt); 482362306a36Sopenharmony_ci 482462306a36Sopenharmony_cistatic struct attribute *st_dev_attrs[] = { 482562306a36Sopenharmony_ci &dev_attr_defined.attr, 482662306a36Sopenharmony_ci &dev_attr_default_blksize.attr, 482762306a36Sopenharmony_ci &dev_attr_default_density.attr, 482862306a36Sopenharmony_ci &dev_attr_default_compression.attr, 482962306a36Sopenharmony_ci &dev_attr_options.attr, 483062306a36Sopenharmony_ci NULL, 483162306a36Sopenharmony_ci}; 483262306a36Sopenharmony_ci 483362306a36Sopenharmony_cistatic struct attribute *st_stats_attrs[] = { 483462306a36Sopenharmony_ci &dev_attr_read_cnt.attr, 483562306a36Sopenharmony_ci &dev_attr_read_byte_cnt.attr, 483662306a36Sopenharmony_ci &dev_attr_read_ns.attr, 483762306a36Sopenharmony_ci &dev_attr_write_cnt.attr, 483862306a36Sopenharmony_ci &dev_attr_write_byte_cnt.attr, 483962306a36Sopenharmony_ci &dev_attr_write_ns.attr, 484062306a36Sopenharmony_ci &dev_attr_in_flight.attr, 484162306a36Sopenharmony_ci &dev_attr_io_ns.attr, 484262306a36Sopenharmony_ci &dev_attr_other_cnt.attr, 484362306a36Sopenharmony_ci &dev_attr_resid_cnt.attr, 484462306a36Sopenharmony_ci NULL, 484562306a36Sopenharmony_ci}; 484662306a36Sopenharmony_ci 484762306a36Sopenharmony_cistatic struct attribute_group stats_group = { 484862306a36Sopenharmony_ci .name = "stats", 484962306a36Sopenharmony_ci .attrs = st_stats_attrs, 485062306a36Sopenharmony_ci}; 485162306a36Sopenharmony_ci 485262306a36Sopenharmony_cistatic struct attribute_group st_group = { 485362306a36Sopenharmony_ci .attrs = st_dev_attrs, 485462306a36Sopenharmony_ci}; 485562306a36Sopenharmony_ci 485662306a36Sopenharmony_cistatic const struct attribute_group *st_dev_groups[] = { 485762306a36Sopenharmony_ci &st_group, 485862306a36Sopenharmony_ci &stats_group, 485962306a36Sopenharmony_ci NULL, 486062306a36Sopenharmony_ci}; 486162306a36Sopenharmony_ci 486262306a36Sopenharmony_ci/* The following functions may be useful for a larger audience. */ 486362306a36Sopenharmony_cistatic int sgl_map_user_pages(struct st_buffer *STbp, 486462306a36Sopenharmony_ci const unsigned int max_pages, unsigned long uaddr, 486562306a36Sopenharmony_ci size_t count, int rw) 486662306a36Sopenharmony_ci{ 486762306a36Sopenharmony_ci unsigned long end = (uaddr + count + PAGE_SIZE - 1) >> PAGE_SHIFT; 486862306a36Sopenharmony_ci unsigned long start = uaddr >> PAGE_SHIFT; 486962306a36Sopenharmony_ci const int nr_pages = end - start; 487062306a36Sopenharmony_ci int res, i; 487162306a36Sopenharmony_ci struct page **pages; 487262306a36Sopenharmony_ci struct rq_map_data *mdata = &STbp->map_data; 487362306a36Sopenharmony_ci 487462306a36Sopenharmony_ci /* User attempted Overflow! */ 487562306a36Sopenharmony_ci if ((uaddr + count) < uaddr) 487662306a36Sopenharmony_ci return -EINVAL; 487762306a36Sopenharmony_ci 487862306a36Sopenharmony_ci /* Too big */ 487962306a36Sopenharmony_ci if (nr_pages > max_pages) 488062306a36Sopenharmony_ci return -ENOMEM; 488162306a36Sopenharmony_ci 488262306a36Sopenharmony_ci /* Hmm? */ 488362306a36Sopenharmony_ci if (count == 0) 488462306a36Sopenharmony_ci return 0; 488562306a36Sopenharmony_ci 488662306a36Sopenharmony_ci pages = kmalloc_array(max_pages, sizeof(*pages), GFP_KERNEL); 488762306a36Sopenharmony_ci if (pages == NULL) 488862306a36Sopenharmony_ci return -ENOMEM; 488962306a36Sopenharmony_ci 489062306a36Sopenharmony_ci /* Try to fault in all of the necessary pages */ 489162306a36Sopenharmony_ci /* rw==READ means read from drive, write into memory area */ 489262306a36Sopenharmony_ci res = pin_user_pages_fast(uaddr, nr_pages, rw == READ ? FOLL_WRITE : 0, 489362306a36Sopenharmony_ci pages); 489462306a36Sopenharmony_ci 489562306a36Sopenharmony_ci /* Errors and no page mapped should return here */ 489662306a36Sopenharmony_ci if (res < nr_pages) 489762306a36Sopenharmony_ci goto out_unmap; 489862306a36Sopenharmony_ci 489962306a36Sopenharmony_ci for (i=0; i < nr_pages; i++) { 490062306a36Sopenharmony_ci /* FIXME: flush superflous for rw==READ, 490162306a36Sopenharmony_ci * probably wrong function for rw==WRITE 490262306a36Sopenharmony_ci */ 490362306a36Sopenharmony_ci flush_dcache_page(pages[i]); 490462306a36Sopenharmony_ci } 490562306a36Sopenharmony_ci 490662306a36Sopenharmony_ci mdata->offset = uaddr & ~PAGE_MASK; 490762306a36Sopenharmony_ci STbp->mapped_pages = pages; 490862306a36Sopenharmony_ci 490962306a36Sopenharmony_ci return nr_pages; 491062306a36Sopenharmony_ci out_unmap: 491162306a36Sopenharmony_ci if (res > 0) { 491262306a36Sopenharmony_ci unpin_user_pages(pages, res); 491362306a36Sopenharmony_ci res = 0; 491462306a36Sopenharmony_ci } 491562306a36Sopenharmony_ci kfree(pages); 491662306a36Sopenharmony_ci return res; 491762306a36Sopenharmony_ci} 491862306a36Sopenharmony_ci 491962306a36Sopenharmony_ci 492062306a36Sopenharmony_ci/* And unmap them... */ 492162306a36Sopenharmony_cistatic int sgl_unmap_user_pages(struct st_buffer *STbp, 492262306a36Sopenharmony_ci const unsigned int nr_pages, int dirtied) 492362306a36Sopenharmony_ci{ 492462306a36Sopenharmony_ci /* FIXME: cache flush missing for rw==READ */ 492562306a36Sopenharmony_ci unpin_user_pages_dirty_lock(STbp->mapped_pages, nr_pages, dirtied); 492662306a36Sopenharmony_ci 492762306a36Sopenharmony_ci kfree(STbp->mapped_pages); 492862306a36Sopenharmony_ci STbp->mapped_pages = NULL; 492962306a36Sopenharmony_ci 493062306a36Sopenharmony_ci return 0; 493162306a36Sopenharmony_ci} 4932