blob: 0ea78d9a37db1a6b0da5b0a18f93fba2aa826a4e [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 SCSI Tape Driver for Linux version 1.1 and newer. See the accompanying
3 file Documentation/scsi/st.txt for more information.
4
5 History:
6
7 OnStream SCSI Tape support (osst) cloned from st.c by
8 Willem Riede (osst@riede.org) Feb 2000
9 Fixes ... Kurt Garloff <garloff@suse.de> Mar 2000
10
11 Rewritten from Dwayne Forsyth's SCSI tape driver by Kai Makisara.
12 Contribution and ideas from several people including (in alphabetical
13 order) Klaus Ehrenfried, Wolfgang Denk, Steve Hirsch, Andreas Koppenh"ofer,
14 Michael Leodolter, Eyal Lebedinsky, J"org Weule, and Eric Youngdale.
15
Willem Riede5e6575c2006-02-11 14:46:56 -050016 Copyright 1992 - 2002 Kai Makisara / 2000 - 2006 Willem Riede
Linus Torvalds1da177e2005-04-16 15:20:36 -070017 email osst@riede.org
18
19 $Header: /cvsroot/osst/Driver/osst.c,v 1.73 2005/01/01 21:13:34 wriede Exp $
20
21 Microscopic alterations - Rik Ling, 2000/12/21
22 Last st.c sync: Tue Oct 15 22:01:04 2002 by makisara
23 Some small formal changes - aeb, 950809
24*/
25
26static const char * cvsid = "$Id: osst.c,v 1.73 2005/01/01 21:13:34 wriede Exp $";
Willem Riede5e6575c2006-02-11 14:46:56 -050027static const char * osst_version = "0.99.4";
Linus Torvalds1da177e2005-04-16 15:20:36 -070028
29/* The "failure to reconnect" firmware bug */
30#define OSST_FW_NEED_POLL_MIN 10601 /*(107A)*/
31#define OSST_FW_NEED_POLL_MAX 10704 /*(108D)*/
32#define OSST_FW_NEED_POLL(x,d) ((x) >= OSST_FW_NEED_POLL_MIN && (x) <= OSST_FW_NEED_POLL_MAX && d->host->this_id != 7)
33
34#include <linux/module.h>
35
36#include <linux/fs.h>
37#include <linux/kernel.h>
38#include <linux/sched.h>
39#include <linux/proc_fs.h>
40#include <linux/mm.h>
41#include <linux/init.h>
42#include <linux/string.h>
43#include <linux/errno.h>
44#include <linux/mtio.h>
45#include <linux/ioctl.h>
46#include <linux/fcntl.h>
47#include <linux/spinlock.h>
48#include <linux/vmalloc.h>
49#include <linux/blkdev.h>
50#include <linux/moduleparam.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070051#include <linux/delay.h>
Marcelo Feitoza Parisi60c904a2006-03-28 01:56:47 -080052#include <linux/jiffies.h>
Jonathan Corbet647d87b2008-05-15 12:23:19 -060053#include <linux/smp_lock.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070054#include <asm/uaccess.h>
55#include <asm/dma.h>
56#include <asm/system.h>
57
58/* The driver prints some debugging information on the console if DEBUG
59 is defined and non-zero. */
60#define DEBUG 0
61
62/* The message level for the debug messages is currently set to KERN_NOTICE
63 so that people can easily see the messages. Later when the debugging messages
64 in the drivers are more widely classified, this may be changed to KERN_DEBUG. */
65#define OSST_DEB_MSG KERN_NOTICE
66
67#include <scsi/scsi.h>
68#include <scsi/scsi_dbg.h>
69#include <scsi/scsi_device.h>
70#include <scsi/scsi_driver.h>
71#include <scsi/scsi_eh.h>
72#include <scsi/scsi_host.h>
73#include <scsi/scsi_ioctl.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070074
75#define ST_KILOBYTE 1024
76
77#include "st.h"
78#include "osst.h"
79#include "osst_options.h"
80#include "osst_detect.h"
81
82static int max_dev = 0;
83static int write_threshold_kbs = 0;
84static int max_sg_segs = 0;
85
86#ifdef MODULE
87MODULE_AUTHOR("Willem Riede");
88MODULE_DESCRIPTION("OnStream {DI-|FW-|SC-|USB}{30|50} Tape Driver");
89MODULE_LICENSE("GPL");
Rene Hermanf018fa52006-03-08 00:14:20 -080090MODULE_ALIAS_CHARDEV_MAJOR(OSST_MAJOR);
Michael Tokarevd7b8bcb02006-10-27 16:02:37 +040091MODULE_ALIAS_SCSI_DEVICE(TYPE_TAPE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070092
93module_param(max_dev, int, 0444);
94MODULE_PARM_DESC(max_dev, "Maximum number of OnStream Tape Drives to attach (4)");
95
96module_param(write_threshold_kbs, int, 0644);
97MODULE_PARM_DESC(write_threshold_kbs, "Asynchronous write threshold (KB; 32)");
98
99module_param(max_sg_segs, int, 0644);
100MODULE_PARM_DESC(max_sg_segs, "Maximum number of scatter/gather segments to use (9)");
101#else
102static struct osst_dev_parm {
103 char *name;
104 int *val;
105} parms[] __initdata = {
106 { "max_dev", &max_dev },
107 { "write_threshold_kbs", &write_threshold_kbs },
108 { "max_sg_segs", &max_sg_segs }
109};
110#endif
111
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112/* Some default definitions have been moved to osst_options.h */
113#define OSST_BUFFER_SIZE (OSST_BUFFER_BLOCKS * ST_KILOBYTE)
114#define OSST_WRITE_THRESHOLD (OSST_WRITE_THRESHOLD_BLOCKS * ST_KILOBYTE)
115
116/* The buffer size should fit into the 24 bits for length in the
117 6-byte SCSI read and write commands. */
118#if OSST_BUFFER_SIZE >= (2 << 24 - 1)
119#error "Buffer size should not exceed (2 << 24 - 1) bytes!"
120#endif
121
122#if DEBUG
123static int debugging = 1;
124/* uncomment define below to test error recovery */
125// #define OSST_INJECT_ERRORS 1
126#endif
127
128/* Do not retry! The drive firmware already retries when appropriate,
129 and when it tries to tell us something, we had better listen... */
130#define MAX_RETRIES 0
131
132#define NO_TAPE NOT_READY
133
134#define OSST_WAIT_POSITION_COMPLETE (HZ > 200 ? HZ / 200 : 1)
135#define OSST_WAIT_WRITE_COMPLETE (HZ / 12)
136#define OSST_WAIT_LONG_WRITE_COMPLETE (HZ / 2)
137
138#define OSST_TIMEOUT (200 * HZ)
139#define OSST_LONG_TIMEOUT (1800 * HZ)
140
141#define TAPE_NR(x) (iminor(x) & ~(-1 << ST_MODE_SHIFT))
142#define TAPE_MODE(x) ((iminor(x) & ST_MODE_MASK) >> ST_MODE_SHIFT)
143#define TAPE_REWIND(x) ((iminor(x) & 0x80) == 0)
144#define TAPE_IS_RAW(x) (TAPE_MODE(x) & (ST_NBR_MODES >> 1))
145
146/* Internal ioctl to set both density (uppermost 8 bits) and blocksize (lower
147 24 bits) */
148#define SET_DENS_AND_BLK 0x10001
149
150static int osst_buffer_size = OSST_BUFFER_SIZE;
151static int osst_write_threshold = OSST_WRITE_THRESHOLD;
152static int osst_max_sg_segs = OSST_MAX_SG;
153static int osst_max_dev = OSST_MAX_TAPES;
154static int osst_nr_dev;
155
156static struct osst_tape **os_scsi_tapes = NULL;
157static DEFINE_RWLOCK(os_scsi_tapes_lock);
158
159static int modes_defined = 0;
160
161static struct osst_buffer *new_tape_buffer(int, int, int);
162static int enlarge_buffer(struct osst_buffer *, int);
163static void normalize_buffer(struct osst_buffer *);
164static int append_to_buffer(const char __user *, struct osst_buffer *, int);
165static int from_buffer(struct osst_buffer *, char __user *, int);
166static int osst_zero_buffer_tail(struct osst_buffer *);
167static int osst_copy_to_buffer(struct osst_buffer *, unsigned char *);
168static int osst_copy_from_buffer(struct osst_buffer *, unsigned char *);
169
170static int osst_probe(struct device *);
171static int osst_remove(struct device *);
172
173static struct scsi_driver osst_template = {
174 .owner = THIS_MODULE,
175 .gendrv = {
176 .name = "osst",
177 .probe = osst_probe,
178 .remove = osst_remove,
179 }
180};
181
Willem Riede5e6575c2006-02-11 14:46:56 -0500182static int osst_int_ioctl(struct osst_tape *STp, struct osst_request ** aSRpnt,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183 unsigned int cmd_in, unsigned long arg);
184
Willem Riede5e6575c2006-02-11 14:46:56 -0500185static int osst_set_frame_position(struct osst_tape *STp, struct osst_request ** aSRpnt, int frame, int skip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186
Willem Riede5e6575c2006-02-11 14:46:56 -0500187static int osst_get_frame_position(struct osst_tape *STp, struct osst_request ** aSRpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188
Willem Riede5e6575c2006-02-11 14:46:56 -0500189static int osst_flush_write_buffer(struct osst_tape *STp, struct osst_request ** aSRpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190
Willem Riede5e6575c2006-02-11 14:46:56 -0500191static int osst_write_error_recovery(struct osst_tape * STp, struct osst_request ** aSRpnt, int pending);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192
193static inline char *tape_name(struct osst_tape *tape)
194{
195 return tape->drive->disk_name;
196}
197
198/* Routines that handle the interaction with mid-layer SCSI routines */
199
Willem Riede5e6575c2006-02-11 14:46:56 -0500200
201/* Normalize Sense */
202static void osst_analyze_sense(struct osst_request *SRpnt, struct st_cmdstatus *s)
203{
204 const u8 *ucp;
205 const u8 *sense = SRpnt->sense;
206
207 s->have_sense = scsi_normalize_sense(SRpnt->sense,
208 SCSI_SENSE_BUFFERSIZE, &s->sense_hdr);
209 s->flags = 0;
210
211 if (s->have_sense) {
212 s->deferred = 0;
213 s->remainder_valid =
214 scsi_get_sense_info_fld(sense, SCSI_SENSE_BUFFERSIZE, &s->uremainder64);
215 switch (sense[0] & 0x7f) {
216 case 0x71:
217 s->deferred = 1;
218 case 0x70:
219 s->fixed_format = 1;
220 s->flags = sense[2] & 0xe0;
221 break;
222 case 0x73:
223 s->deferred = 1;
224 case 0x72:
225 s->fixed_format = 0;
226 ucp = scsi_sense_desc_find(sense, SCSI_SENSE_BUFFERSIZE, 4);
227 s->flags = ucp ? (ucp[3] & 0xe0) : 0;
228 break;
229 }
230 }
231}
232
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233/* Convert the result to success code */
Willem Riede5e6575c2006-02-11 14:46:56 -0500234static int osst_chk_result(struct osst_tape * STp, struct osst_request * SRpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235{
236 char *name = tape_name(STp);
Willem Riede5e6575c2006-02-11 14:46:56 -0500237 int result = SRpnt->result;
238 u8 * sense = SRpnt->sense, scode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239#if DEBUG
240 const char *stp;
241#endif
Willem Riede5e6575c2006-02-11 14:46:56 -0500242 struct st_cmdstatus *cmdstatp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243
Willem Riede5e6575c2006-02-11 14:46:56 -0500244 if (!result)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245 return 0;
Willem Riede5e6575c2006-02-11 14:46:56 -0500246
247 cmdstatp = &STp->buffer->cmdstat;
248 osst_analyze_sense(SRpnt, cmdstatp);
249
250 if (cmdstatp->have_sense)
251 scode = STp->buffer->cmdstat.sense_hdr.sense_key;
252 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253 scode = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254#if DEBUG
255 if (debugging) {
Willem Riede5e6575c2006-02-11 14:46:56 -0500256 printk(OSST_DEB_MSG "%s:D: Error: %x, cmd: %x %x %x %x %x %x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257 name, result,
Willem Riede5e6575c2006-02-11 14:46:56 -0500258 SRpnt->cmd[0], SRpnt->cmd[1], SRpnt->cmd[2],
259 SRpnt->cmd[3], SRpnt->cmd[4], SRpnt->cmd[5]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260 if (scode) printk(OSST_DEB_MSG "%s:D: Sense: %02x, ASC: %02x, ASCQ: %02x\n",
261 name, scode, sense[12], sense[13]);
Willem Riede5e6575c2006-02-11 14:46:56 -0500262 if (cmdstatp->have_sense)
263 __scsi_print_sense("osst ", SRpnt->sense, SCSI_SENSE_BUFFERSIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264 }
265 else
266#endif
Willem Riede5e6575c2006-02-11 14:46:56 -0500267 if (cmdstatp->have_sense && (
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268 scode != NO_SENSE &&
269 scode != RECOVERED_ERROR &&
270/* scode != UNIT_ATTENTION && */
271 scode != BLANK_CHECK &&
272 scode != VOLUME_OVERFLOW &&
Willem Riede5e6575c2006-02-11 14:46:56 -0500273 SRpnt->cmd[0] != MODE_SENSE &&
274 SRpnt->cmd[0] != TEST_UNIT_READY)) { /* Abnormal conditions for tape */
275 if (cmdstatp->have_sense) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 printk(KERN_WARNING "%s:W: Command with sense data:\n", name);
Willem Riede5e6575c2006-02-11 14:46:56 -0500277 __scsi_print_sense("osst ", SRpnt->sense, SCSI_SENSE_BUFFERSIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278 }
279 else {
280 static int notyetprinted = 1;
281
282 printk(KERN_WARNING
283 "%s:W: Warning %x (sugg. bt 0x%x, driver bt 0x%x, host bt 0x%x).\n",
284 name, result, suggestion(result), driver_byte(result) & DRIVER_MASK,
285 host_byte(result));
286 if (notyetprinted) {
287 notyetprinted = 0;
288 printk(KERN_INFO
289 "%s:I: This warning may be caused by your scsi controller,\n", name);
290 printk(KERN_INFO
291 "%s:I: it has been reported with some Buslogic cards.\n", name);
292 }
293 }
294 }
295 STp->pos_unknown |= STp->device->was_reset;
296
Willem Riede5e6575c2006-02-11 14:46:56 -0500297 if (cmdstatp->have_sense && scode == RECOVERED_ERROR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298 STp->recover_count++;
299 STp->recover_erreg++;
300#if DEBUG
301 if (debugging) {
Willem Riede5e6575c2006-02-11 14:46:56 -0500302 if (SRpnt->cmd[0] == READ_6)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303 stp = "read";
Willem Riede5e6575c2006-02-11 14:46:56 -0500304 else if (SRpnt->cmd[0] == WRITE_6)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305 stp = "write";
306 else
307 stp = "ioctl";
308 printk(OSST_DEB_MSG "%s:D: Recovered %s error (%d).\n", name, stp,
309 STp->recover_count);
310 }
311#endif
312 if ((sense[2] & 0xe0) == 0)
313 return 0;
314 }
315 return (-EIO);
316}
317
318
319/* Wakeup from interrupt */
Willem Riede5e6575c2006-02-11 14:46:56 -0500320static void osst_sleep_done(void *data, char *sense, int result, int resid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321{
Willem Riede5e6575c2006-02-11 14:46:56 -0500322 struct osst_request *SRpnt = data;
323 struct osst_tape *STp = SRpnt->stp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324
Willem Riede5e6575c2006-02-11 14:46:56 -0500325 memcpy(SRpnt->sense, sense, SCSI_SENSE_BUFFERSIZE);
326 STp->buffer->cmdstat.midlevel_result = SRpnt->result = result;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327#if DEBUG
328 STp->write_pending = 0;
329#endif
Willem Riede5e6575c2006-02-11 14:46:56 -0500330 if (SRpnt->waiting)
331 complete(SRpnt->waiting);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332}
333
Willem Riede5e6575c2006-02-11 14:46:56 -0500334/* osst_request memory management */
335static struct osst_request *osst_allocate_request(void)
336{
337 return kzalloc(sizeof(struct osst_request), GFP_KERNEL);
338}
339
340static void osst_release_request(struct osst_request *streq)
341{
342 kfree(streq);
343}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344
345/* Do the scsi command. Waits until command performed if do_wait is true.
346 Otherwise osst_write_behind_check() is used to check that the command
347 has finished. */
Willem Riede5e6575c2006-02-11 14:46:56 -0500348static struct osst_request * osst_do_scsi(struct osst_request *SRpnt, struct osst_tape *STp,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 unsigned char *cmd, int bytes, int direction, int timeout, int retries, int do_wait)
350{
351 unsigned char *bp;
Willem Riede5e6575c2006-02-11 14:46:56 -0500352 unsigned short use_sg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353#ifdef OSST_INJECT_ERRORS
354 static int inject = 0;
355 static int repeat = 0;
356#endif
Willem Riede5e6575c2006-02-11 14:46:56 -0500357 struct completion *waiting;
358
359 /* if async, make sure there's no command outstanding */
360 if (!do_wait && ((STp->buffer)->last_SRpnt)) {
361 printk(KERN_ERR "%s: Async command already active.\n",
362 tape_name(STp));
363 if (signal_pending(current))
364 (STp->buffer)->syscall_result = (-EINTR);
365 else
366 (STp->buffer)->syscall_result = (-EBUSY);
367 return NULL;
368 }
369
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 if (SRpnt == NULL) {
Willem Riede5e6575c2006-02-11 14:46:56 -0500371 SRpnt = osst_allocate_request();
372 if (SRpnt == NULL) {
373 printk(KERN_ERR "%s: Can't allocate SCSI request.\n",
374 tape_name(STp));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 if (signal_pending(current))
376 (STp->buffer)->syscall_result = (-EINTR);
377 else
378 (STp->buffer)->syscall_result = (-EBUSY);
379 return NULL;
380 }
Willem Riede5e6575c2006-02-11 14:46:56 -0500381 SRpnt->stp = STp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 }
383
Willem Riede5e6575c2006-02-11 14:46:56 -0500384 /* If async IO, set last_SRpnt. This ptr tells write_behind_check
385 which IO is outstanding. It's nulled out when the IO completes. */
386 if (!do_wait)
387 (STp->buffer)->last_SRpnt = SRpnt;
388
389 waiting = &STp->wait;
390 init_completion(waiting);
391 SRpnt->waiting = waiting;
392
393 use_sg = (bytes > STp->buffer->sg[0].length) ? STp->buffer->use_sg : 0;
394 if (use_sg) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 bp = (char *)&(STp->buffer->sg[0]);
Willem Riede5e6575c2006-02-11 14:46:56 -0500396 if (STp->buffer->sg_segs < use_sg)
397 use_sg = STp->buffer->sg_segs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 }
399 else
400 bp = (STp->buffer)->b_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401
Willem Riede5e6575c2006-02-11 14:46:56 -0500402 memcpy(SRpnt->cmd, cmd, sizeof(SRpnt->cmd));
403 STp->buffer->cmdstat.have_sense = 0;
404 STp->buffer->syscall_result = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405
Willem Riede5e6575c2006-02-11 14:46:56 -0500406 if (scsi_execute_async(STp->device, cmd, COMMAND_SIZE(cmd[0]), direction, bp, bytes,
407 use_sg, timeout, retries, SRpnt, osst_sleep_done, GFP_KERNEL))
408 /* could not allocate the buffer or request was too large */
409 (STp->buffer)->syscall_result = (-EBUSY);
410 else if (do_wait) {
411 wait_for_completion(waiting);
412 SRpnt->waiting = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 STp->buffer->syscall_result = osst_chk_result(STp, SRpnt);
414#ifdef OSST_INJECT_ERRORS
415 if (STp->buffer->syscall_result == 0 &&
416 cmd[0] == READ_6 &&
417 cmd[4] &&
418 ( (++ inject % 83) == 29 ||
419 (STp->first_frame_position == 240
420 /* or STp->read_error_frame to fail again on the block calculated above */ &&
421 ++repeat < 3))) {
422 printk(OSST_DEB_MSG "%s:D: Injecting read error\n", tape_name(STp));
423 STp->buffer->last_result_fatal = 1;
424 }
425#endif
426 }
427 return SRpnt;
428}
429
430
431/* Handle the write-behind checking (downs the semaphore) */
432static void osst_write_behind_check(struct osst_tape *STp)
433{
434 struct osst_buffer * STbuffer;
435
436 STbuffer = STp->buffer;
437
438#if DEBUG
439 if (STp->write_pending)
440 STp->nbr_waits++;
441 else
442 STp->nbr_finished++;
443#endif
444 wait_for_completion(&(STp->wait));
Willem Riede5e6575c2006-02-11 14:46:56 -0500445 STp->buffer->last_SRpnt->waiting = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446
447 STp->buffer->syscall_result = osst_chk_result(STp, STp->buffer->last_SRpnt);
448
Willem Riede5e6575c2006-02-11 14:46:56 -0500449 if (STp->buffer->syscall_result)
450 STp->buffer->syscall_result =
451 osst_write_error_recovery(STp, &(STp->buffer->last_SRpnt), 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 else
453 STp->first_frame_position++;
454
Willem Riede5e6575c2006-02-11 14:46:56 -0500455 osst_release_request(STp->buffer->last_SRpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456
457 if (STbuffer->writing < STbuffer->buffer_bytes)
458 printk(KERN_WARNING "osst :A: write_behind_check: something left in buffer!\n");
459
Willem Riede5e6575c2006-02-11 14:46:56 -0500460 STbuffer->last_SRpnt = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 STbuffer->buffer_bytes -= STbuffer->writing;
462 STbuffer->writing = 0;
463
464 return;
465}
466
467
468
469/* Onstream specific Routines */
470/*
471 * Initialize the OnStream AUX
472 */
473static void osst_init_aux(struct osst_tape * STp, int frame_type, int frame_seq_number,
474 int logical_blk_num, int blk_sz, int blk_cnt)
475{
476 os_aux_t *aux = STp->buffer->aux;
477 os_partition_t *par = &aux->partition;
478 os_dat_t *dat = &aux->dat;
479
480 if (STp->raw) return;
481
482 memset(aux, 0, sizeof(*aux));
483 aux->format_id = htonl(0);
484 memcpy(aux->application_sig, "LIN4", 4);
485 aux->hdwr = htonl(0);
486 aux->frame_type = frame_type;
487
488 switch (frame_type) {
489 case OS_FRAME_TYPE_HEADER:
490 aux->update_frame_cntr = htonl(STp->update_frame_cntr);
491 par->partition_num = OS_CONFIG_PARTITION;
492 par->par_desc_ver = OS_PARTITION_VERSION;
493 par->wrt_pass_cntr = htons(0xffff);
494 /* 0-4 = reserved, 5-9 = header, 2990-2994 = header, 2995-2999 = reserved */
495 par->first_frame_ppos = htonl(0);
496 par->last_frame_ppos = htonl(0xbb7);
497 aux->frame_seq_num = htonl(0);
498 aux->logical_blk_num_high = htonl(0);
499 aux->logical_blk_num = htonl(0);
500 aux->next_mark_ppos = htonl(STp->first_mark_ppos);
501 break;
502 case OS_FRAME_TYPE_DATA:
503 case OS_FRAME_TYPE_MARKER:
504 dat->dat_sz = 8;
505 dat->reserved1 = 0;
506 dat->entry_cnt = 1;
507 dat->reserved3 = 0;
508 dat->dat_list[0].blk_sz = htonl(blk_sz);
509 dat->dat_list[0].blk_cnt = htons(blk_cnt);
510 dat->dat_list[0].flags = frame_type==OS_FRAME_TYPE_MARKER?
511 OS_DAT_FLAGS_MARK:OS_DAT_FLAGS_DATA;
512 dat->dat_list[0].reserved = 0;
513 case OS_FRAME_TYPE_EOD:
514 aux->update_frame_cntr = htonl(0);
515 par->partition_num = OS_DATA_PARTITION;
516 par->par_desc_ver = OS_PARTITION_VERSION;
517 par->wrt_pass_cntr = htons(STp->wrt_pass_cntr);
518 par->first_frame_ppos = htonl(STp->first_data_ppos);
519 par->last_frame_ppos = htonl(STp->capacity);
520 aux->frame_seq_num = htonl(frame_seq_number);
521 aux->logical_blk_num_high = htonl(0);
522 aux->logical_blk_num = htonl(logical_blk_num);
523 break;
524 default: ; /* probably FILL */
525 }
Al Viro95389b82007-02-09 16:39:45 +0000526 aux->filemark_cnt = htonl(STp->filemark_cnt);
527 aux->phys_fm = htonl(0xffffffff);
528 aux->last_mark_ppos = htonl(STp->last_mark_ppos);
529 aux->last_mark_lbn = htonl(STp->last_mark_lbn);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530}
531
532/*
533 * Verify that we have the correct tape frame
534 */
535static int osst_verify_frame(struct osst_tape * STp, int frame_seq_number, int quiet)
536{
537 char * name = tape_name(STp);
538 os_aux_t * aux = STp->buffer->aux;
539 os_partition_t * par = &(aux->partition);
540 struct st_partstat * STps = &(STp->ps[STp->partition]);
541 int blk_cnt, blk_sz, i;
542
543 if (STp->raw) {
544 if (STp->buffer->syscall_result) {
545 for (i=0; i < STp->buffer->sg_segs; i++)
Jens Axboe45711f12007-10-22 21:19:53 +0200546 memset(page_address(sg_page(&STp->buffer->sg[i])),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 0, STp->buffer->sg[i].length);
548 strcpy(STp->buffer->b_data, "READ ERROR ON FRAME");
549 } else
550 STp->buffer->buffer_bytes = OS_FRAME_SIZE;
551 return 1;
552 }
553 if (STp->buffer->syscall_result) {
554#if DEBUG
555 printk(OSST_DEB_MSG "%s:D: Skipping frame, read error\n", name);
556#endif
557 return 0;
558 }
559 if (ntohl(aux->format_id) != 0) {
560#if DEBUG
561 printk(OSST_DEB_MSG "%s:D: Skipping frame, format_id %u\n", name, ntohl(aux->format_id));
562#endif
563 goto err_out;
564 }
565 if (memcmp(aux->application_sig, STp->application_sig, 4) != 0 &&
566 (memcmp(aux->application_sig, "LIN3", 4) != 0 || STp->linux_media_version != 4)) {
567#if DEBUG
568 printk(OSST_DEB_MSG "%s:D: Skipping frame, incorrect application signature\n", name);
569#endif
570 goto err_out;
571 }
572 if (par->partition_num != OS_DATA_PARTITION) {
573 if (!STp->linux_media || STp->linux_media_version != 2) {
574#if DEBUG
575 printk(OSST_DEB_MSG "%s:D: Skipping frame, partition num %d\n",
576 name, par->partition_num);
577#endif
578 goto err_out;
579 }
580 }
581 if (par->par_desc_ver != OS_PARTITION_VERSION) {
582#if DEBUG
583 printk(OSST_DEB_MSG "%s:D: Skipping frame, partition version %d\n", name, par->par_desc_ver);
584#endif
585 goto err_out;
586 }
587 if (ntohs(par->wrt_pass_cntr) != STp->wrt_pass_cntr) {
588#if DEBUG
589 printk(OSST_DEB_MSG "%s:D: Skipping frame, wrt_pass_cntr %d (expected %d)\n",
590 name, ntohs(par->wrt_pass_cntr), STp->wrt_pass_cntr);
591#endif
592 goto err_out;
593 }
594 if (aux->frame_type != OS_FRAME_TYPE_DATA &&
595 aux->frame_type != OS_FRAME_TYPE_EOD &&
596 aux->frame_type != OS_FRAME_TYPE_MARKER) {
Ilpo Järvinenccd14432007-10-23 13:42:04 -0700597 if (!quiet) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598#if DEBUG
599 printk(OSST_DEB_MSG "%s:D: Skipping frame, frame type %x\n", name, aux->frame_type);
600#endif
Ilpo Järvinenccd14432007-10-23 13:42:04 -0700601 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602 goto err_out;
603 }
604 if (aux->frame_type == OS_FRAME_TYPE_EOD &&
605 STp->first_frame_position < STp->eod_frame_ppos) {
606 printk(KERN_INFO "%s:I: Skipping premature EOD frame %d\n", name,
607 STp->first_frame_position);
608 goto err_out;
609 }
610 if (frame_seq_number != -1 && ntohl(aux->frame_seq_num) != frame_seq_number) {
Ilpo Järvinenccd14432007-10-23 13:42:04 -0700611 if (!quiet) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612#if DEBUG
613 printk(OSST_DEB_MSG "%s:D: Skipping frame, sequence number %u (expected %d)\n",
614 name, ntohl(aux->frame_seq_num), frame_seq_number);
615#endif
Ilpo Järvinenccd14432007-10-23 13:42:04 -0700616 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 goto err_out;
618 }
619 if (aux->frame_type == OS_FRAME_TYPE_MARKER) {
620 STps->eof = ST_FM_HIT;
621
622 i = ntohl(aux->filemark_cnt);
623 if (STp->header_cache != NULL && i < OS_FM_TAB_MAX && (i > STp->filemark_cnt ||
624 STp->first_frame_position - 1 != ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[i]))) {
625#if DEBUG
626 printk(OSST_DEB_MSG "%s:D: %s filemark %d at frame pos %d\n", name,
627 STp->header_cache->dat_fm_tab.fm_tab_ent[i] == 0?"Learned":"Corrected",
628 i, STp->first_frame_position - 1);
629#endif
630 STp->header_cache->dat_fm_tab.fm_tab_ent[i] = htonl(STp->first_frame_position - 1);
631 if (i >= STp->filemark_cnt)
632 STp->filemark_cnt = i+1;
633 }
634 }
635 if (aux->frame_type == OS_FRAME_TYPE_EOD) {
636 STps->eof = ST_EOD_1;
637 STp->frame_in_buffer = 1;
638 }
639 if (aux->frame_type == OS_FRAME_TYPE_DATA) {
640 blk_cnt = ntohs(aux->dat.dat_list[0].blk_cnt);
641 blk_sz = ntohl(aux->dat.dat_list[0].blk_sz);
642 STp->buffer->buffer_bytes = blk_cnt * blk_sz;
643 STp->buffer->read_pointer = 0;
644 STp->frame_in_buffer = 1;
645
646 /* See what block size was used to write file */
647 if (STp->block_size != blk_sz && blk_sz > 0) {
648 printk(KERN_INFO
649 "%s:I: File was written with block size %d%c, currently %d%c, adjusted to match.\n",
650 name, blk_sz<1024?blk_sz:blk_sz/1024,blk_sz<1024?'b':'k',
651 STp->block_size<1024?STp->block_size:STp->block_size/1024,
652 STp->block_size<1024?'b':'k');
653 STp->block_size = blk_sz;
654 STp->buffer->buffer_blocks = OS_DATA_SIZE / blk_sz;
655 }
656 STps->eof = ST_NOEOF;
657 }
658 STp->frame_seq_number = ntohl(aux->frame_seq_num);
659 STp->logical_blk_num = ntohl(aux->logical_blk_num);
660 return 1;
661
662err_out:
663 if (STp->read_error_frame == 0)
664 STp->read_error_frame = STp->first_frame_position - 1;
665 return 0;
666}
667
668/*
669 * Wait for the unit to become Ready
670 */
Willem Riede5e6575c2006-02-11 14:46:56 -0500671static int osst_wait_ready(struct osst_tape * STp, struct osst_request ** aSRpnt,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 unsigned timeout, int initial_delay)
673{
674 unsigned char cmd[MAX_COMMAND_SIZE];
Willem Riede5e6575c2006-02-11 14:46:56 -0500675 struct osst_request * SRpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 unsigned long startwait = jiffies;
677#if DEBUG
678 int dbg = debugging;
679 char * name = tape_name(STp);
680
681 printk(OSST_DEB_MSG "%s:D: Reached onstream wait ready\n", name);
682#endif
683
684 if (initial_delay > 0)
685 msleep(jiffies_to_msecs(initial_delay));
686
687 memset(cmd, 0, MAX_COMMAND_SIZE);
688 cmd[0] = TEST_UNIT_READY;
689
690 SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1);
691 *aSRpnt = SRpnt;
692 if (!SRpnt) return (-EBUSY);
693
694 while ( STp->buffer->syscall_result && time_before(jiffies, startwait + timeout*HZ) &&
Willem Riede5e6575c2006-02-11 14:46:56 -0500695 (( SRpnt->sense[2] == 2 && SRpnt->sense[12] == 4 &&
696 (SRpnt->sense[13] == 1 || SRpnt->sense[13] == 8) ) ||
697 ( SRpnt->sense[2] == 6 && SRpnt->sense[12] == 0x28 &&
698 SRpnt->sense[13] == 0 ) )) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699#if DEBUG
700 if (debugging) {
701 printk(OSST_DEB_MSG "%s:D: Sleeping in onstream wait ready\n", name);
702 printk(OSST_DEB_MSG "%s:D: Turning off debugging for a while\n", name);
703 debugging = 0;
704 }
705#endif
706 msleep(100);
707
708 memset(cmd, 0, MAX_COMMAND_SIZE);
709 cmd[0] = TEST_UNIT_READY;
710
711 SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1);
712 }
713 *aSRpnt = SRpnt;
714#if DEBUG
715 debugging = dbg;
716#endif
717 if ( STp->buffer->syscall_result &&
718 osst_write_error_recovery(STp, aSRpnt, 0) ) {
719#if DEBUG
720 printk(OSST_DEB_MSG "%s:D: Abnormal exit from onstream wait ready\n", name);
721 printk(OSST_DEB_MSG "%s:D: Result = %d, Sense: 0=%02x, 2=%02x, 12=%02x, 13=%02x\n", name,
Willem Riede5e6575c2006-02-11 14:46:56 -0500722 STp->buffer->syscall_result, SRpnt->sense[0], SRpnt->sense[2],
723 SRpnt->sense[12], SRpnt->sense[13]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724#endif
725 return (-EIO);
726 }
727#if DEBUG
728 printk(OSST_DEB_MSG "%s:D: Normal exit from onstream wait ready\n", name);
729#endif
730 return 0;
731}
732
733/*
734 * Wait for a tape to be inserted in the unit
735 */
Willem Riede5e6575c2006-02-11 14:46:56 -0500736static int osst_wait_for_medium(struct osst_tape * STp, struct osst_request ** aSRpnt, unsigned timeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737{
738 unsigned char cmd[MAX_COMMAND_SIZE];
Willem Riede5e6575c2006-02-11 14:46:56 -0500739 struct osst_request * SRpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 unsigned long startwait = jiffies;
741#if DEBUG
742 int dbg = debugging;
743 char * name = tape_name(STp);
744
745 printk(OSST_DEB_MSG "%s:D: Reached onstream wait for medium\n", name);
746#endif
747
748 memset(cmd, 0, MAX_COMMAND_SIZE);
749 cmd[0] = TEST_UNIT_READY;
750
751 SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1);
752 *aSRpnt = SRpnt;
753 if (!SRpnt) return (-EBUSY);
754
755 while ( STp->buffer->syscall_result && time_before(jiffies, startwait + timeout*HZ) &&
Willem Riede5e6575c2006-02-11 14:46:56 -0500756 SRpnt->sense[2] == 2 && SRpnt->sense[12] == 0x3a && SRpnt->sense[13] == 0 ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757#if DEBUG
758 if (debugging) {
759 printk(OSST_DEB_MSG "%s:D: Sleeping in onstream wait medium\n", name);
760 printk(OSST_DEB_MSG "%s:D: Turning off debugging for a while\n", name);
761 debugging = 0;
762 }
763#endif
764 msleep(100);
765
766 memset(cmd, 0, MAX_COMMAND_SIZE);
767 cmd[0] = TEST_UNIT_READY;
768
769 SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1);
770 }
771 *aSRpnt = SRpnt;
772#if DEBUG
773 debugging = dbg;
774#endif
Willem Riede5e6575c2006-02-11 14:46:56 -0500775 if ( STp->buffer->syscall_result && SRpnt->sense[2] != 2 &&
776 SRpnt->sense[12] != 4 && SRpnt->sense[13] == 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777#if DEBUG
778 printk(OSST_DEB_MSG "%s:D: Abnormal exit from onstream wait medium\n", name);
779 printk(OSST_DEB_MSG "%s:D: Result = %d, Sense: 0=%02x, 2=%02x, 12=%02x, 13=%02x\n", name,
Willem Riede5e6575c2006-02-11 14:46:56 -0500780 STp->buffer->syscall_result, SRpnt->sense[0], SRpnt->sense[2],
781 SRpnt->sense[12], SRpnt->sense[13]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782#endif
783 return 0;
784 }
785#if DEBUG
786 printk(OSST_DEB_MSG "%s:D: Normal exit from onstream wait medium\n", name);
787#endif
788 return 1;
789}
790
Willem Riede5e6575c2006-02-11 14:46:56 -0500791static int osst_position_tape_and_confirm(struct osst_tape * STp, struct osst_request ** aSRpnt, int frame)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792{
793 int retval;
794
795 osst_wait_ready(STp, aSRpnt, 15 * 60, 0); /* TODO - can this catch a write error? */
796 retval = osst_set_frame_position(STp, aSRpnt, frame, 0);
797 if (retval) return (retval);
798 osst_wait_ready(STp, aSRpnt, 15 * 60, OSST_WAIT_POSITION_COMPLETE);
799 return (osst_get_frame_position(STp, aSRpnt));
800}
801
802/*
803 * Wait for write(s) to complete
804 */
Willem Riede5e6575c2006-02-11 14:46:56 -0500805static int osst_flush_drive_buffer(struct osst_tape * STp, struct osst_request ** aSRpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806{
807 unsigned char cmd[MAX_COMMAND_SIZE];
Willem Riede5e6575c2006-02-11 14:46:56 -0500808 struct osst_request * SRpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 int result = 0;
810 int delay = OSST_WAIT_WRITE_COMPLETE;
811#if DEBUG
812 char * name = tape_name(STp);
813
814 printk(OSST_DEB_MSG "%s:D: Reached onstream flush drive buffer (write filemark)\n", name);
815#endif
816
817 memset(cmd, 0, MAX_COMMAND_SIZE);
818 cmd[0] = WRITE_FILEMARKS;
819 cmd[1] = 1;
820
821 SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1);
822 *aSRpnt = SRpnt;
823 if (!SRpnt) return (-EBUSY);
824 if (STp->buffer->syscall_result) {
Willem Riede5e6575c2006-02-11 14:46:56 -0500825 if ((SRpnt->sense[2] & 0x0f) == 2 && SRpnt->sense[12] == 4) {
826 if (SRpnt->sense[13] == 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 delay = OSST_WAIT_LONG_WRITE_COMPLETE;
828 }
829 } else
830 result = osst_write_error_recovery(STp, aSRpnt, 0);
831 }
832 result |= osst_wait_ready(STp, aSRpnt, 5 * 60, delay);
833 STp->ps[STp->partition].rw = OS_WRITING_COMPLETE;
834
835 return (result);
836}
837
838#define OSST_POLL_PER_SEC 10
Willem Riede5e6575c2006-02-11 14:46:56 -0500839static int osst_wait_frame(struct osst_tape * STp, struct osst_request ** aSRpnt, int curr, int minlast, int to)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840{
841 unsigned long startwait = jiffies;
842 char * name = tape_name(STp);
843#if DEBUG
844 char notyetprinted = 1;
845#endif
846 if (minlast >= 0 && STp->ps[STp->partition].rw != ST_READING)
847 printk(KERN_ERR "%s:A: Waiting for frame without having initialized read!\n", name);
848
849 while (time_before (jiffies, startwait + to*HZ))
850 {
851 int result;
852 result = osst_get_frame_position(STp, aSRpnt);
853 if (result == -EIO)
854 if ((result = osst_write_error_recovery(STp, aSRpnt, 0)) == 0)
855 return 0; /* successful recovery leaves drive ready for frame */
856 if (result < 0) break;
857 if (STp->first_frame_position == curr &&
858 ((minlast < 0 &&
859 (signed)STp->last_frame_position > (signed)curr + minlast) ||
860 (minlast >= 0 && STp->cur_frames > minlast)
861 ) && result >= 0)
862 {
863#if DEBUG
Marcelo Feitoza Parisi60c904a2006-03-28 01:56:47 -0800864 if (debugging || time_after_eq(jiffies, startwait + 2*HZ/OSST_POLL_PER_SEC))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865 printk (OSST_DEB_MSG
866 "%s:D: Succ wait f fr %i (>%i): %i-%i %i (%i): %3li.%li s\n",
867 name, curr, curr+minlast, STp->first_frame_position,
868 STp->last_frame_position, STp->cur_frames,
869 result, (jiffies-startwait)/HZ,
870 (((jiffies-startwait)%HZ)*10)/HZ);
871#endif
872 return 0;
873 }
874#if DEBUG
Marcelo Feitoza Parisi60c904a2006-03-28 01:56:47 -0800875 if (time_after_eq(jiffies, startwait + 2*HZ/OSST_POLL_PER_SEC) && notyetprinted)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876 {
877 printk (OSST_DEB_MSG "%s:D: Wait for frame %i (>%i): %i-%i %i (%i)\n",
878 name, curr, curr+minlast, STp->first_frame_position,
879 STp->last_frame_position, STp->cur_frames, result);
880 notyetprinted--;
881 }
882#endif
883 msleep(1000 / OSST_POLL_PER_SEC);
884 }
885#if DEBUG
886 printk (OSST_DEB_MSG "%s:D: Fail wait f fr %i (>%i): %i-%i %i: %3li.%li s\n",
887 name, curr, curr+minlast, STp->first_frame_position,
888 STp->last_frame_position, STp->cur_frames,
889 (jiffies-startwait)/HZ, (((jiffies-startwait)%HZ)*10)/HZ);
890#endif
891 return -EBUSY;
892}
893
Willem Riede5e6575c2006-02-11 14:46:56 -0500894static int osst_recover_wait_frame(struct osst_tape * STp, struct osst_request ** aSRpnt, int writing)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895{
Willem Riede5e6575c2006-02-11 14:46:56 -0500896 struct osst_request * SRpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 unsigned char cmd[MAX_COMMAND_SIZE];
898 unsigned long startwait = jiffies;
899 int retval = 1;
900 char * name = tape_name(STp);
901
902 if (writing) {
903 char mybuf[24];
904 char * olddata = STp->buffer->b_data;
905 int oldsize = STp->buffer->buffer_size;
906
907 /* write zero fm then read pos - if shows write error, try to recover - if no progress, wait */
908
909 memset(cmd, 0, MAX_COMMAND_SIZE);
910 cmd[0] = WRITE_FILEMARKS;
911 cmd[1] = 1;
912 SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, DMA_NONE, STp->timeout,
913 MAX_RETRIES, 1);
914
915 while (retval && time_before (jiffies, startwait + 5*60*HZ)) {
916
Willem Riede5e6575c2006-02-11 14:46:56 -0500917 if (STp->buffer->syscall_result && (SRpnt->sense[2] & 0x0f) != 2) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918
919 /* some failure - not just not-ready */
920 retval = osst_write_error_recovery(STp, aSRpnt, 0);
921 break;
922 }
Nishanth Aravamudana9a30472005-11-07 01:01:20 -0800923 schedule_timeout_interruptible(HZ / OSST_POLL_PER_SEC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924
925 STp->buffer->b_data = mybuf; STp->buffer->buffer_size = 24;
926 memset(cmd, 0, MAX_COMMAND_SIZE);
927 cmd[0] = READ_POSITION;
928
929 SRpnt = osst_do_scsi(SRpnt, STp, cmd, 20, DMA_FROM_DEVICE, STp->timeout,
930 MAX_RETRIES, 1);
931
932 retval = ( STp->buffer->syscall_result || (STp->buffer)->b_data[15] > 25 );
933 STp->buffer->b_data = olddata; STp->buffer->buffer_size = oldsize;
934 }
935 if (retval)
936 printk(KERN_ERR "%s:E: Device did not succeed to write buffered data\n", name);
937 } else
938 /* TODO - figure out which error conditions can be handled */
939 if (STp->buffer->syscall_result)
940 printk(KERN_WARNING
941 "%s:W: Recover_wait_frame(read) cannot handle %02x:%02x:%02x\n", name,
Willem Riede5e6575c2006-02-11 14:46:56 -0500942 (*aSRpnt)->sense[ 2] & 0x0f,
943 (*aSRpnt)->sense[12],
944 (*aSRpnt)->sense[13]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945
946 return retval;
947}
948
949/*
950 * Read the next OnStream tape frame at the current location
951 */
Willem Riede5e6575c2006-02-11 14:46:56 -0500952static int osst_read_frame(struct osst_tape * STp, struct osst_request ** aSRpnt, int timeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953{
954 unsigned char cmd[MAX_COMMAND_SIZE];
Willem Riede5e6575c2006-02-11 14:46:56 -0500955 struct osst_request * SRpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956 int retval = 0;
957#if DEBUG
958 os_aux_t * aux = STp->buffer->aux;
959 char * name = tape_name(STp);
960#endif
961
962 if (STp->poll)
963 if (osst_wait_frame (STp, aSRpnt, STp->first_frame_position, 0, timeout))
964 retval = osst_recover_wait_frame(STp, aSRpnt, 0);
965
966 memset(cmd, 0, MAX_COMMAND_SIZE);
967 cmd[0] = READ_6;
968 cmd[1] = 1;
969 cmd[4] = 1;
970
971#if DEBUG
972 if (debugging)
973 printk(OSST_DEB_MSG "%s:D: Reading frame from OnStream tape\n", name);
974#endif
975 SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, OS_FRAME_SIZE, DMA_FROM_DEVICE,
976 STp->timeout, MAX_RETRIES, 1);
977 *aSRpnt = SRpnt;
978 if (!SRpnt)
979 return (-EBUSY);
980
981 if ((STp->buffer)->syscall_result) {
982 retval = 1;
983 if (STp->read_error_frame == 0) {
984 STp->read_error_frame = STp->first_frame_position;
985#if DEBUG
986 printk(OSST_DEB_MSG "%s:D: Recording read error at %d\n", name, STp->read_error_frame);
987#endif
988 }
989#if DEBUG
990 if (debugging)
991 printk(OSST_DEB_MSG "%s:D: Sense: %2x %2x %2x %2x %2x %2x %2x %2x\n",
992 name,
Willem Riede5e6575c2006-02-11 14:46:56 -0500993 SRpnt->sense[0], SRpnt->sense[1],
994 SRpnt->sense[2], SRpnt->sense[3],
995 SRpnt->sense[4], SRpnt->sense[5],
996 SRpnt->sense[6], SRpnt->sense[7]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997#endif
998 }
999 else
1000 STp->first_frame_position++;
1001#if DEBUG
1002 if (debugging) {
1003 char sig[8]; int i;
1004 for (i=0;i<4;i++)
1005 sig[i] = aux->application_sig[i]<32?'^':aux->application_sig[i];
1006 sig[4] = '\0';
1007 printk(OSST_DEB_MSG
1008 "%s:D: AUX: %s UpdFrCt#%d Wpass#%d %s FrSeq#%d LogBlk#%d Qty=%d Sz=%d\n", name, sig,
1009 ntohl(aux->update_frame_cntr), ntohs(aux->partition.wrt_pass_cntr),
1010 aux->frame_type==1?"EOD":aux->frame_type==2?"MARK":
1011 aux->frame_type==8?"HEADR":aux->frame_type==0x80?"DATA":"FILL",
1012 ntohl(aux->frame_seq_num), ntohl(aux->logical_blk_num),
1013 ntohs(aux->dat.dat_list[0].blk_cnt), ntohl(aux->dat.dat_list[0].blk_sz) );
1014 if (aux->frame_type==2)
1015 printk(OSST_DEB_MSG "%s:D: mark_cnt=%d, last_mark_ppos=%d, last_mark_lbn=%d\n", name,
1016 ntohl(aux->filemark_cnt), ntohl(aux->last_mark_ppos), ntohl(aux->last_mark_lbn));
1017 printk(OSST_DEB_MSG "%s:D: Exit read frame from OnStream tape with code %d\n", name, retval);
1018 }
1019#endif
1020 return (retval);
1021}
1022
Willem Riede5e6575c2006-02-11 14:46:56 -05001023static int osst_initiate_read(struct osst_tape * STp, struct osst_request ** aSRpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024{
1025 struct st_partstat * STps = &(STp->ps[STp->partition]);
Willem Riede5e6575c2006-02-11 14:46:56 -05001026 struct osst_request * SRpnt ;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027 unsigned char cmd[MAX_COMMAND_SIZE];
1028 int retval = 0;
1029 char * name = tape_name(STp);
1030
1031 if (STps->rw != ST_READING) { /* Initialize read operation */
1032 if (STps->rw == ST_WRITING || STp->dirty) {
1033 STp->write_type = OS_WRITE_DATA;
1034 osst_flush_write_buffer(STp, aSRpnt);
1035 osst_flush_drive_buffer(STp, aSRpnt);
1036 }
1037 STps->rw = ST_READING;
1038 STp->frame_in_buffer = 0;
1039
1040 /*
1041 * Issue a read 0 command to get the OnStream drive
1042 * read frames into its buffer.
1043 */
1044 memset(cmd, 0, MAX_COMMAND_SIZE);
1045 cmd[0] = READ_6;
1046 cmd[1] = 1;
1047
1048#if DEBUG
1049 printk(OSST_DEB_MSG "%s:D: Start Read Ahead on OnStream tape\n", name);
1050#endif
1051 SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1);
1052 *aSRpnt = SRpnt;
1053 if ((retval = STp->buffer->syscall_result))
1054 printk(KERN_WARNING "%s:W: Error starting read ahead\n", name);
1055 }
1056
1057 return retval;
1058}
1059
Willem Riede5e6575c2006-02-11 14:46:56 -05001060static int osst_get_logical_frame(struct osst_tape * STp, struct osst_request ** aSRpnt,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061 int frame_seq_number, int quiet)
1062{
1063 struct st_partstat * STps = &(STp->ps[STp->partition]);
1064 char * name = tape_name(STp);
1065 int cnt = 0,
1066 bad = 0,
1067 past = 0,
1068 x,
1069 position;
1070
1071 /*
1072 * If we want just any frame (-1) and there is a frame in the buffer, return it
1073 */
1074 if (frame_seq_number == -1 && STp->frame_in_buffer) {
1075#if DEBUG
1076 printk(OSST_DEB_MSG "%s:D: Frame %d still in buffer\n", name, STp->frame_seq_number);
1077#endif
1078 return (STps->eof);
1079 }
1080 /*
1081 * Search and wait for the next logical tape frame
1082 */
1083 while (1) {
1084 if (cnt++ > 400) {
1085 printk(KERN_ERR "%s:E: Couldn't find logical frame %d, aborting\n",
1086 name, frame_seq_number);
1087 if (STp->read_error_frame) {
1088 osst_set_frame_position(STp, aSRpnt, STp->read_error_frame, 0);
1089#if DEBUG
1090 printk(OSST_DEB_MSG "%s:D: Repositioning tape to bad frame %d\n",
1091 name, STp->read_error_frame);
1092#endif
1093 STp->read_error_frame = 0;
1094 STp->abort_count++;
1095 }
1096 return (-EIO);
1097 }
1098#if DEBUG
1099 if (debugging)
1100 printk(OSST_DEB_MSG "%s:D: Looking for frame %d, attempt %d\n",
1101 name, frame_seq_number, cnt);
1102#endif
1103 if ( osst_initiate_read(STp, aSRpnt)
1104 || ( (!STp->frame_in_buffer) && osst_read_frame(STp, aSRpnt, 30) ) ) {
1105 if (STp->raw)
1106 return (-EIO);
1107 position = osst_get_frame_position(STp, aSRpnt);
1108 if (position >= 0xbae && position < 0xbb8)
1109 position = 0xbb8;
1110 else if (position > STp->eod_frame_ppos || ++bad == 10) {
1111 position = STp->read_error_frame - 1;
1112 bad = 0;
1113 }
1114 else {
1115 position += 29;
1116 cnt += 19;
1117 }
1118#if DEBUG
1119 printk(OSST_DEB_MSG "%s:D: Bad frame detected, positioning tape to block %d\n",
1120 name, position);
1121#endif
1122 osst_set_frame_position(STp, aSRpnt, position, 0);
1123 continue;
1124 }
1125 if (osst_verify_frame(STp, frame_seq_number, quiet))
1126 break;
1127 if (osst_verify_frame(STp, -1, quiet)) {
1128 x = ntohl(STp->buffer->aux->frame_seq_num);
1129 if (STp->fast_open) {
1130 printk(KERN_WARNING
1131 "%s:W: Found logical frame %d instead of %d after fast open\n",
1132 name, x, frame_seq_number);
1133 STp->header_ok = 0;
1134 STp->read_error_frame = 0;
1135 return (-EIO);
1136 }
1137 if (x > frame_seq_number) {
1138 if (++past > 3) {
1139 /* positioning backwards did not bring us to the desired frame */
1140 position = STp->read_error_frame - 1;
1141 }
1142 else {
1143 position = osst_get_frame_position(STp, aSRpnt)
1144 + frame_seq_number - x - 1;
1145
1146 if (STp->first_frame_position >= 3000 && position < 3000)
1147 position -= 10;
1148 }
1149#if DEBUG
1150 printk(OSST_DEB_MSG
1151 "%s:D: Found logical frame %d while looking for %d: back up %d\n",
1152 name, x, frame_seq_number,
1153 STp->first_frame_position - position);
1154#endif
1155 osst_set_frame_position(STp, aSRpnt, position, 0);
1156 cnt += 10;
1157 }
1158 else
1159 past = 0;
1160 }
1161 if (osst_get_frame_position(STp, aSRpnt) == 0xbaf) {
1162#if DEBUG
1163 printk(OSST_DEB_MSG "%s:D: Skipping config partition\n", name);
1164#endif
1165 osst_set_frame_position(STp, aSRpnt, 0xbb8, 0);
1166 cnt--;
1167 }
1168 STp->frame_in_buffer = 0;
1169 }
1170 if (cnt > 1) {
1171 STp->recover_count++;
1172 STp->recover_erreg++;
1173 printk(KERN_WARNING "%s:I: Don't worry, Read error at position %d recovered\n",
1174 name, STp->read_error_frame);
1175 }
1176 STp->read_count++;
1177
1178#if DEBUG
1179 if (debugging || STps->eof)
1180 printk(OSST_DEB_MSG
1181 "%s:D: Exit get logical frame (%d=>%d) from OnStream tape with code %d\n",
1182 name, frame_seq_number, STp->frame_seq_number, STps->eof);
1183#endif
1184 STp->fast_open = 0;
1185 STp->read_error_frame = 0;
1186 return (STps->eof);
1187}
1188
Willem Riede5e6575c2006-02-11 14:46:56 -05001189static int osst_seek_logical_blk(struct osst_tape * STp, struct osst_request ** aSRpnt, int logical_blk_num)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190{
1191 struct st_partstat * STps = &(STp->ps[STp->partition]);
1192 char * name = tape_name(STp);
1193 int retries = 0;
1194 int frame_seq_estimate, ppos_estimate, move;
1195
1196 if (logical_blk_num < 0) logical_blk_num = 0;
1197#if DEBUG
1198 printk(OSST_DEB_MSG "%s:D: Seeking logical block %d (now at %d, size %d%c)\n",
1199 name, logical_blk_num, STp->logical_blk_num,
1200 STp->block_size<1024?STp->block_size:STp->block_size/1024,
1201 STp->block_size<1024?'b':'k');
1202#endif
1203 /* Do we know where we are? */
1204 if (STps->drv_block >= 0) {
1205 move = logical_blk_num - STp->logical_blk_num;
1206 if (move < 0) move -= (OS_DATA_SIZE / STp->block_size) - 1;
1207 move /= (OS_DATA_SIZE / STp->block_size);
1208 frame_seq_estimate = STp->frame_seq_number + move;
1209 } else
1210 frame_seq_estimate = logical_blk_num * STp->block_size / OS_DATA_SIZE;
1211
1212 if (frame_seq_estimate < 2980) ppos_estimate = frame_seq_estimate + 10;
1213 else ppos_estimate = frame_seq_estimate + 20;
1214 while (++retries < 10) {
1215 if (ppos_estimate > STp->eod_frame_ppos-2) {
1216 frame_seq_estimate += STp->eod_frame_ppos - 2 - ppos_estimate;
1217 ppos_estimate = STp->eod_frame_ppos - 2;
1218 }
1219 if (frame_seq_estimate < 0) {
1220 frame_seq_estimate = 0;
1221 ppos_estimate = 10;
1222 }
1223 osst_set_frame_position(STp, aSRpnt, ppos_estimate, 0);
1224 if (osst_get_logical_frame(STp, aSRpnt, frame_seq_estimate, 1) >= 0) {
1225 /* we've located the estimated frame, now does it have our block? */
1226 if (logical_blk_num < STp->logical_blk_num ||
1227 logical_blk_num >= STp->logical_blk_num + ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt)) {
1228 if (STps->eof == ST_FM_HIT)
1229 move = logical_blk_num < STp->logical_blk_num? -2 : 1;
1230 else {
1231 move = logical_blk_num - STp->logical_blk_num;
1232 if (move < 0) move -= (OS_DATA_SIZE / STp->block_size) - 1;
1233 move /= (OS_DATA_SIZE / STp->block_size);
1234 }
1235 if (!move) move = logical_blk_num > STp->logical_blk_num ? 1 : -1;
1236#if DEBUG
1237 printk(OSST_DEB_MSG
1238 "%s:D: Seek retry %d at ppos %d fsq %d (est %d) lbn %d (need %d) move %d\n",
1239 name, retries, ppos_estimate, STp->frame_seq_number, frame_seq_estimate,
1240 STp->logical_blk_num, logical_blk_num, move);
1241#endif
1242 frame_seq_estimate += move;
1243 ppos_estimate += move;
1244 continue;
1245 } else {
1246 STp->buffer->read_pointer = (logical_blk_num - STp->logical_blk_num) * STp->block_size;
1247 STp->buffer->buffer_bytes -= STp->buffer->read_pointer;
1248 STp->logical_blk_num = logical_blk_num;
1249#if DEBUG
1250 printk(OSST_DEB_MSG
1251 "%s:D: Seek success at ppos %d fsq %d in_buf %d, bytes %d, ptr %d*%d\n",
1252 name, ppos_estimate, STp->frame_seq_number, STp->frame_in_buffer,
1253 STp->buffer->buffer_bytes, STp->buffer->read_pointer / STp->block_size,
1254 STp->block_size);
1255#endif
1256 STps->drv_file = ntohl(STp->buffer->aux->filemark_cnt);
1257 if (STps->eof == ST_FM_HIT) {
1258 STps->drv_file++;
1259 STps->drv_block = 0;
1260 } else {
1261 STps->drv_block = ntohl(STp->buffer->aux->last_mark_lbn)?
1262 STp->logical_blk_num -
1263 (STps->drv_file ? ntohl(STp->buffer->aux->last_mark_lbn) + 1 : 0):
1264 -1;
1265 }
1266 STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD:ST_NOEOF;
1267 return 0;
1268 }
1269 }
1270 if (osst_get_logical_frame(STp, aSRpnt, -1, 1) < 0)
1271 goto error;
1272 /* we are not yet at the estimated frame, adjust our estimate of its physical position */
1273#if DEBUG
1274 printk(OSST_DEB_MSG "%s:D: Seek retry %d at ppos %d fsq %d (est %d) lbn %d (need %d)\n",
1275 name, retries, ppos_estimate, STp->frame_seq_number, frame_seq_estimate,
1276 STp->logical_blk_num, logical_blk_num);
1277#endif
1278 if (frame_seq_estimate != STp->frame_seq_number)
1279 ppos_estimate += frame_seq_estimate - STp->frame_seq_number;
1280 else
1281 break;
1282 }
1283error:
1284 printk(KERN_ERR "%s:E: Couldn't seek to logical block %d (at %d), %d retries\n",
1285 name, logical_blk_num, STp->logical_blk_num, retries);
1286 return (-EIO);
1287}
1288
1289/* The values below are based on the OnStream frame payload size of 32K == 2**15,
1290 * that is, OSST_FRAME_SHIFT + OSST_SECTOR_SHIFT must be 15. With a minimum block
1291 * size of 512 bytes, we need to be able to resolve 32K/512 == 64 == 2**6 positions
1292 * inside each frame. Finaly, OSST_SECTOR_MASK == 2**OSST_FRAME_SHIFT - 1.
1293 */
1294#define OSST_FRAME_SHIFT 6
1295#define OSST_SECTOR_SHIFT 9
1296#define OSST_SECTOR_MASK 0x03F
1297
Willem Riede5e6575c2006-02-11 14:46:56 -05001298static int osst_get_sector(struct osst_tape * STp, struct osst_request ** aSRpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299{
1300 int sector;
1301#if DEBUG
1302 char * name = tape_name(STp);
1303
1304 printk(OSST_DEB_MSG
1305 "%s:D: Positioned at ppos %d, frame %d, lbn %d, file %d, blk %d, %cptr %d, eof %d\n",
1306 name, STp->first_frame_position, STp->frame_seq_number, STp->logical_blk_num,
1307 STp->ps[STp->partition].drv_file, STp->ps[STp->partition].drv_block,
1308 STp->ps[STp->partition].rw == ST_WRITING?'w':'r',
1309 STp->ps[STp->partition].rw == ST_WRITING?STp->buffer->buffer_bytes:
1310 STp->buffer->read_pointer, STp->ps[STp->partition].eof);
1311#endif
1312 /* do we know where we are inside a file? */
1313 if (STp->ps[STp->partition].drv_block >= 0) {
1314 sector = (STp->frame_in_buffer ? STp->first_frame_position-1 :
1315 STp->first_frame_position) << OSST_FRAME_SHIFT;
1316 if (STp->ps[STp->partition].rw == ST_WRITING)
1317 sector |= (STp->buffer->buffer_bytes >> OSST_SECTOR_SHIFT) & OSST_SECTOR_MASK;
1318 else
1319 sector |= (STp->buffer->read_pointer >> OSST_SECTOR_SHIFT) & OSST_SECTOR_MASK;
1320 } else {
1321 sector = osst_get_frame_position(STp, aSRpnt);
1322 if (sector > 0)
1323 sector <<= OSST_FRAME_SHIFT;
1324 }
1325 return sector;
1326}
1327
Willem Riede5e6575c2006-02-11 14:46:56 -05001328static int osst_seek_sector(struct osst_tape * STp, struct osst_request ** aSRpnt, int sector)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329{
1330 struct st_partstat * STps = &(STp->ps[STp->partition]);
1331 int frame = sector >> OSST_FRAME_SHIFT,
1332 offset = (sector & OSST_SECTOR_MASK) << OSST_SECTOR_SHIFT,
1333 r;
1334#if DEBUG
1335 char * name = tape_name(STp);
1336
1337 printk(OSST_DEB_MSG "%s:D: Seeking sector %d in frame %d at offset %d\n",
1338 name, sector, frame, offset);
1339#endif
1340 if (frame < 0 || frame >= STp->capacity) return (-ENXIO);
1341
1342 if (frame <= STp->first_data_ppos) {
1343 STp->frame_seq_number = STp->logical_blk_num = STps->drv_file = STps->drv_block = 0;
1344 return (osst_set_frame_position(STp, aSRpnt, frame, 0));
1345 }
1346 r = osst_set_frame_position(STp, aSRpnt, offset?frame:frame-1, 0);
1347 if (r < 0) return r;
1348
1349 r = osst_get_logical_frame(STp, aSRpnt, -1, 1);
1350 if (r < 0) return r;
1351
1352 if (osst_get_frame_position(STp, aSRpnt) != (offset?frame+1:frame)) return (-EIO);
1353
1354 if (offset) {
1355 STp->logical_blk_num += offset / STp->block_size;
1356 STp->buffer->read_pointer = offset;
1357 STp->buffer->buffer_bytes -= offset;
1358 } else {
1359 STp->frame_seq_number++;
1360 STp->frame_in_buffer = 0;
1361 STp->logical_blk_num += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
1362 STp->buffer->buffer_bytes = STp->buffer->read_pointer = 0;
1363 }
1364 STps->drv_file = ntohl(STp->buffer->aux->filemark_cnt);
1365 if (STps->eof == ST_FM_HIT) {
1366 STps->drv_file++;
1367 STps->drv_block = 0;
1368 } else {
1369 STps->drv_block = ntohl(STp->buffer->aux->last_mark_lbn)?
1370 STp->logical_blk_num -
1371 (STps->drv_file ? ntohl(STp->buffer->aux->last_mark_lbn) + 1 : 0):
1372 -1;
1373 }
1374 STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD:ST_NOEOF;
1375#if DEBUG
1376 printk(OSST_DEB_MSG
1377 "%s:D: Now positioned at ppos %d, frame %d, lbn %d, file %d, blk %d, rptr %d, eof %d\n",
1378 name, STp->first_frame_position, STp->frame_seq_number, STp->logical_blk_num,
1379 STps->drv_file, STps->drv_block, STp->buffer->read_pointer, STps->eof);
1380#endif
1381 return 0;
1382}
1383
1384/*
1385 * Read back the drive's internal buffer contents, as a part
1386 * of the write error recovery mechanism for old OnStream
1387 * firmware revisions.
1388 * Precondition for this function to work: all frames in the
1389 * drive's buffer must be of one type (DATA, MARK or EOD)!
1390 */
Willem Riede5e6575c2006-02-11 14:46:56 -05001391static int osst_read_back_buffer_and_rewrite(struct osst_tape * STp, struct osst_request ** aSRpnt,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392 unsigned int frame, unsigned int skip, int pending)
1393{
Willem Riede5e6575c2006-02-11 14:46:56 -05001394 struct osst_request * SRpnt = * aSRpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395 unsigned char * buffer, * p;
1396 unsigned char cmd[MAX_COMMAND_SIZE];
1397 int flag, new_frame, i;
1398 int nframes = STp->cur_frames;
1399 int blks_per_frame = ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
1400 int frame_seq_number = ntohl(STp->buffer->aux->frame_seq_num)
1401 - (nframes + pending - 1);
1402 int logical_blk_num = ntohl(STp->buffer->aux->logical_blk_num)
1403 - (nframes + pending - 1) * blks_per_frame;
1404 char * name = tape_name(STp);
1405 unsigned long startwait = jiffies;
1406#if DEBUG
1407 int dbg = debugging;
1408#endif
1409
1410 if ((buffer = (unsigned char *)vmalloc((nframes + 1) * OS_DATA_SIZE)) == NULL)
1411 return (-EIO);
1412
1413 printk(KERN_INFO "%s:I: Reading back %d frames from drive buffer%s\n",
1414 name, nframes, pending?" and one that was pending":"");
1415
1416 osst_copy_from_buffer(STp->buffer, (p = &buffer[nframes * OS_DATA_SIZE]));
1417#if DEBUG
1418 if (pending && debugging)
1419 printk(OSST_DEB_MSG "%s:D: Pending frame %d (lblk %d), data %02x %02x %02x %02x\n",
1420 name, frame_seq_number + nframes,
1421 logical_blk_num + nframes * blks_per_frame,
1422 p[0], p[1], p[2], p[3]);
1423#endif
1424 for (i = 0, p = buffer; i < nframes; i++, p += OS_DATA_SIZE) {
1425
1426 memset(cmd, 0, MAX_COMMAND_SIZE);
1427 cmd[0] = 0x3C; /* Buffer Read */
1428 cmd[1] = 6; /* Retrieve Faulty Block */
1429 cmd[7] = 32768 >> 8;
1430 cmd[8] = 32768 & 0xff;
1431
1432 SRpnt = osst_do_scsi(SRpnt, STp, cmd, OS_FRAME_SIZE, DMA_FROM_DEVICE,
1433 STp->timeout, MAX_RETRIES, 1);
1434
1435 if ((STp->buffer)->syscall_result || !SRpnt) {
1436 printk(KERN_ERR "%s:E: Failed to read frame back from OnStream buffer\n", name);
Jesper Juhlf91012102005-09-10 00:26:54 -07001437 vfree(buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438 *aSRpnt = SRpnt;
1439 return (-EIO);
1440 }
1441 osst_copy_from_buffer(STp->buffer, p);
1442#if DEBUG
1443 if (debugging)
1444 printk(OSST_DEB_MSG "%s:D: Read back logical frame %d, data %02x %02x %02x %02x\n",
1445 name, frame_seq_number + i, p[0], p[1], p[2], p[3]);
1446#endif
1447 }
1448 *aSRpnt = SRpnt;
1449 osst_get_frame_position(STp, aSRpnt);
1450
1451#if DEBUG
1452 printk(OSST_DEB_MSG "%s:D: Frames left in buffer: %d\n", name, STp->cur_frames);
1453#endif
1454 /* Write synchronously so we can be sure we're OK again and don't have to recover recursively */
1455 /* In the header we don't actually re-write the frames that fail, just the ones after them */
1456
1457 for (flag=1, new_frame=frame, p=buffer, i=0; i < nframes + pending; ) {
1458
1459 if (flag) {
1460 if (STp->write_type == OS_WRITE_HEADER) {
1461 i += skip;
1462 p += skip * OS_DATA_SIZE;
1463 }
1464 else if (new_frame < 2990 && new_frame+skip+nframes+pending >= 2990)
1465 new_frame = 3000-i;
1466 else
1467 new_frame += skip;
1468#if DEBUG
1469 printk(OSST_DEB_MSG "%s:D: Position to frame %d, write fseq %d\n",
1470 name, new_frame+i, frame_seq_number+i);
1471#endif
1472 osst_set_frame_position(STp, aSRpnt, new_frame + i, 0);
1473 osst_wait_ready(STp, aSRpnt, 60, OSST_WAIT_POSITION_COMPLETE);
1474 osst_get_frame_position(STp, aSRpnt);
1475 SRpnt = * aSRpnt;
1476
1477 if (new_frame > frame + 1000) {
1478 printk(KERN_ERR "%s:E: Failed to find writable tape media\n", name);
Jesper Juhlf91012102005-09-10 00:26:54 -07001479 vfree(buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480 return (-EIO);
1481 }
1482 if ( i >= nframes + pending ) break;
1483 flag = 0;
1484 }
1485 osst_copy_to_buffer(STp->buffer, p);
1486 /*
1487 * IMPORTANT: for error recovery to work, _never_ queue frames with mixed frame type!
1488 */
1489 osst_init_aux(STp, STp->buffer->aux->frame_type, frame_seq_number+i,
1490 logical_blk_num + i*blks_per_frame,
1491 ntohl(STp->buffer->aux->dat.dat_list[0].blk_sz), blks_per_frame);
1492 memset(cmd, 0, MAX_COMMAND_SIZE);
1493 cmd[0] = WRITE_6;
1494 cmd[1] = 1;
1495 cmd[4] = 1;
1496
1497#if DEBUG
1498 if (debugging)
1499 printk(OSST_DEB_MSG
1500 "%s:D: About to write frame %d, seq %d, lbn %d, data %02x %02x %02x %02x\n",
1501 name, new_frame+i, frame_seq_number+i, logical_blk_num + i*blks_per_frame,
1502 p[0], p[1], p[2], p[3]);
1503#endif
1504 SRpnt = osst_do_scsi(SRpnt, STp, cmd, OS_FRAME_SIZE, DMA_TO_DEVICE,
1505 STp->timeout, MAX_RETRIES, 1);
1506
1507 if (STp->buffer->syscall_result)
1508 flag = 1;
1509 else {
1510 p += OS_DATA_SIZE; i++;
1511
1512 /* if we just sent the last frame, wait till all successfully written */
1513 if ( i == nframes + pending ) {
1514#if DEBUG
1515 printk(OSST_DEB_MSG "%s:D: Check re-write successful\n", name);
1516#endif
1517 memset(cmd, 0, MAX_COMMAND_SIZE);
1518 cmd[0] = WRITE_FILEMARKS;
1519 cmd[1] = 1;
1520 SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE,
1521 STp->timeout, MAX_RETRIES, 1);
1522#if DEBUG
1523 if (debugging) {
1524 printk(OSST_DEB_MSG "%s:D: Sleeping in re-write wait ready\n", name);
1525 printk(OSST_DEB_MSG "%s:D: Turning off debugging for a while\n", name);
1526 debugging = 0;
1527 }
1528#endif
1529 flag = STp->buffer->syscall_result;
1530 while ( !flag && time_before(jiffies, startwait + 60*HZ) ) {
1531
1532 memset(cmd, 0, MAX_COMMAND_SIZE);
1533 cmd[0] = TEST_UNIT_READY;
1534
1535 SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE, STp->timeout,
1536 MAX_RETRIES, 1);
1537
Willem Riede5e6575c2006-02-11 14:46:56 -05001538 if (SRpnt->sense[2] == 2 && SRpnt->sense[12] == 4 &&
1539 (SRpnt->sense[13] == 1 || SRpnt->sense[13] == 8)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540 /* in the process of becoming ready */
1541 msleep(100);
1542 continue;
1543 }
1544 if (STp->buffer->syscall_result)
1545 flag = 1;
1546 break;
1547 }
1548#if DEBUG
1549 debugging = dbg;
1550 printk(OSST_DEB_MSG "%s:D: Wait re-write finished\n", name);
1551#endif
1552 }
1553 }
1554 *aSRpnt = SRpnt;
1555 if (flag) {
Willem Riede5e6575c2006-02-11 14:46:56 -05001556 if ((SRpnt->sense[ 2] & 0x0f) == 13 &&
1557 SRpnt->sense[12] == 0 &&
1558 SRpnt->sense[13] == 2) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559 printk(KERN_ERR "%s:E: Volume overflow in write error recovery\n", name);
Jesper Juhlf91012102005-09-10 00:26:54 -07001560 vfree(buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561 return (-EIO); /* hit end of tape = fail */
1562 }
Willem Riede5e6575c2006-02-11 14:46:56 -05001563 i = ((SRpnt->sense[3] << 24) |
1564 (SRpnt->sense[4] << 16) |
1565 (SRpnt->sense[5] << 8) |
1566 SRpnt->sense[6] ) - new_frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567 p = &buffer[i * OS_DATA_SIZE];
1568#if DEBUG
1569 printk(OSST_DEB_MSG "%s:D: Additional write error at %d\n", name, new_frame+i);
1570#endif
1571 osst_get_frame_position(STp, aSRpnt);
1572#if DEBUG
1573 printk(OSST_DEB_MSG "%s:D: reported frame positions: host = %d, tape = %d, buffer = %d\n",
1574 name, STp->first_frame_position, STp->last_frame_position, STp->cur_frames);
1575#endif
1576 }
1577 }
1578 if (flag) {
1579 /* error recovery did not successfully complete */
1580 printk(KERN_ERR "%s:D: Write error recovery failed in %s\n", name,
1581 STp->write_type == OS_WRITE_HEADER?"header":"body");
1582 }
1583 if (!pending)
1584 osst_copy_to_buffer(STp->buffer, p); /* so buffer content == at entry in all cases */
Jesper Juhlf91012102005-09-10 00:26:54 -07001585 vfree(buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586 return 0;
1587}
1588
Willem Riede5e6575c2006-02-11 14:46:56 -05001589static int osst_reposition_and_retry(struct osst_tape * STp, struct osst_request ** aSRpnt,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590 unsigned int frame, unsigned int skip, int pending)
1591{
1592 unsigned char cmd[MAX_COMMAND_SIZE];
Willem Riede5e6575c2006-02-11 14:46:56 -05001593 struct osst_request * SRpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594 char * name = tape_name(STp);
1595 int expected = 0;
1596 int attempts = 1000 / skip;
1597 int flag = 1;
1598 unsigned long startwait = jiffies;
1599#if DEBUG
1600 int dbg = debugging;
1601#endif
1602
1603 while (attempts && time_before(jiffies, startwait + 60*HZ)) {
1604 if (flag) {
1605#if DEBUG
1606 debugging = dbg;
1607#endif
1608 if (frame < 2990 && frame+skip+STp->cur_frames+pending >= 2990)
1609 frame = 3000-skip;
1610 expected = frame+skip+STp->cur_frames+pending;
1611#if DEBUG
1612 printk(OSST_DEB_MSG "%s:D: Position to fppos %d, re-write from fseq %d\n",
1613 name, frame+skip, STp->frame_seq_number-STp->cur_frames-pending);
1614#endif
1615 osst_set_frame_position(STp, aSRpnt, frame + skip, 1);
1616 flag = 0;
1617 attempts--;
Nishanth Aravamudana9a30472005-11-07 01:01:20 -08001618 schedule_timeout_interruptible(msecs_to_jiffies(100));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619 }
1620 if (osst_get_frame_position(STp, aSRpnt) < 0) { /* additional write error */
1621#if DEBUG
1622 printk(OSST_DEB_MSG "%s:D: Addl error, host %d, tape %d, buffer %d\n",
1623 name, STp->first_frame_position,
1624 STp->last_frame_position, STp->cur_frames);
1625#endif
1626 frame = STp->last_frame_position;
1627 flag = 1;
1628 continue;
1629 }
1630 if (pending && STp->cur_frames < 50) {
1631
1632 memset(cmd, 0, MAX_COMMAND_SIZE);
1633 cmd[0] = WRITE_6;
1634 cmd[1] = 1;
1635 cmd[4] = 1;
1636#if DEBUG
1637 printk(OSST_DEB_MSG "%s:D: About to write pending fseq %d at fppos %d\n",
1638 name, STp->frame_seq_number-1, STp->first_frame_position);
1639#endif
1640 SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, OS_FRAME_SIZE, DMA_TO_DEVICE,
1641 STp->timeout, MAX_RETRIES, 1);
1642 *aSRpnt = SRpnt;
1643
1644 if (STp->buffer->syscall_result) { /* additional write error */
Willem Riede5e6575c2006-02-11 14:46:56 -05001645 if ((SRpnt->sense[ 2] & 0x0f) == 13 &&
1646 SRpnt->sense[12] == 0 &&
1647 SRpnt->sense[13] == 2) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001648 printk(KERN_ERR
1649 "%s:E: Volume overflow in write error recovery\n",
1650 name);
1651 break; /* hit end of tape = fail */
1652 }
1653 flag = 1;
1654 }
1655 else
1656 pending = 0;
1657
1658 continue;
1659 }
1660 if (STp->cur_frames == 0) {
1661#if DEBUG
1662 debugging = dbg;
1663 printk(OSST_DEB_MSG "%s:D: Wait re-write finished\n", name);
1664#endif
1665 if (STp->first_frame_position != expected) {
1666 printk(KERN_ERR "%s:A: Actual position %d - expected %d\n",
1667 name, STp->first_frame_position, expected);
1668 return (-EIO);
1669 }
1670 return 0;
1671 }
1672#if DEBUG
1673 if (debugging) {
1674 printk(OSST_DEB_MSG "%s:D: Sleeping in re-write wait ready\n", name);
1675 printk(OSST_DEB_MSG "%s:D: Turning off debugging for a while\n", name);
1676 debugging = 0;
1677 }
1678#endif
Nishanth Aravamudana9a30472005-11-07 01:01:20 -08001679 schedule_timeout_interruptible(msecs_to_jiffies(100));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680 }
1681 printk(KERN_ERR "%s:E: Failed to find valid tape media\n", name);
1682#if DEBUG
1683 debugging = dbg;
1684#endif
1685 return (-EIO);
1686}
1687
1688/*
1689 * Error recovery algorithm for the OnStream tape.
1690 */
1691
Willem Riede5e6575c2006-02-11 14:46:56 -05001692static int osst_write_error_recovery(struct osst_tape * STp, struct osst_request ** aSRpnt, int pending)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693{
Willem Riede5e6575c2006-02-11 14:46:56 -05001694 struct osst_request * SRpnt = * aSRpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695 struct st_partstat * STps = & STp->ps[STp->partition];
1696 char * name = tape_name(STp);
1697 int retval = 0;
1698 int rw_state;
1699 unsigned int frame, skip;
1700
1701 rw_state = STps->rw;
1702
Willem Riede5e6575c2006-02-11 14:46:56 -05001703 if ((SRpnt->sense[ 2] & 0x0f) != 3
1704 || SRpnt->sense[12] != 12
1705 || SRpnt->sense[13] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001706#if DEBUG
1707 printk(OSST_DEB_MSG "%s:D: Write error recovery cannot handle %02x:%02x:%02x\n", name,
Willem Riede5e6575c2006-02-11 14:46:56 -05001708 SRpnt->sense[2], SRpnt->sense[12], SRpnt->sense[13]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709#endif
1710 return (-EIO);
1711 }
Willem Riede5e6575c2006-02-11 14:46:56 -05001712 frame = (SRpnt->sense[3] << 24) |
1713 (SRpnt->sense[4] << 16) |
1714 (SRpnt->sense[5] << 8) |
1715 SRpnt->sense[6];
1716 skip = SRpnt->sense[9];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717
1718#if DEBUG
1719 printk(OSST_DEB_MSG "%s:D: Detected physical bad frame at %u, advised to skip %d\n", name, frame, skip);
1720#endif
1721 osst_get_frame_position(STp, aSRpnt);
1722#if DEBUG
1723 printk(OSST_DEB_MSG "%s:D: reported frame positions: host = %d, tape = %d\n",
1724 name, STp->first_frame_position, STp->last_frame_position);
1725#endif
1726 switch (STp->write_type) {
1727 case OS_WRITE_DATA:
1728 case OS_WRITE_EOD:
1729 case OS_WRITE_NEW_MARK:
1730 printk(KERN_WARNING
1731 "%s:I: Relocating %d buffered logical frames from position %u to %u\n",
1732 name, STp->cur_frames, frame, (frame + skip > 3000 && frame < 3000)?3000:frame + skip);
1733 if (STp->os_fw_rev >= 10600)
1734 retval = osst_reposition_and_retry(STp, aSRpnt, frame, skip, pending);
1735 else
1736 retval = osst_read_back_buffer_and_rewrite(STp, aSRpnt, frame, skip, pending);
1737 printk(KERN_WARNING "%s:%s: %sWrite error%srecovered\n", name,
1738 retval?"E" :"I",
1739 retval?"" :"Don't worry, ",
1740 retval?" not ":" ");
1741 break;
1742 case OS_WRITE_LAST_MARK:
1743 printk(KERN_ERR "%s:E: Bad frame in update last marker, fatal\n", name);
1744 osst_set_frame_position(STp, aSRpnt, frame + STp->cur_frames + pending, 0);
1745 retval = -EIO;
1746 break;
1747 case OS_WRITE_HEADER:
1748 printk(KERN_WARNING "%s:I: Bad frame in header partition, skipped\n", name);
1749 retval = osst_read_back_buffer_and_rewrite(STp, aSRpnt, frame, 1, pending);
1750 break;
1751 default:
1752 printk(KERN_INFO "%s:I: Bad frame in filler, ignored\n", name);
1753 osst_set_frame_position(STp, aSRpnt, frame + STp->cur_frames + pending, 0);
1754 }
1755 osst_get_frame_position(STp, aSRpnt);
1756#if DEBUG
1757 printk(OSST_DEB_MSG "%s:D: Positioning complete, cur_frames %d, pos %d, tape pos %d\n",
1758 name, STp->cur_frames, STp->first_frame_position, STp->last_frame_position);
1759 printk(OSST_DEB_MSG "%s:D: next logical frame to write: %d\n", name, STp->logical_blk_num);
1760#endif
1761 if (retval == 0) {
1762 STp->recover_count++;
1763 STp->recover_erreg++;
1764 } else
1765 STp->abort_count++;
1766
1767 STps->rw = rw_state;
1768 return retval;
1769}
1770
Willem Riede5e6575c2006-02-11 14:46:56 -05001771static int osst_space_over_filemarks_backward(struct osst_tape * STp, struct osst_request ** aSRpnt,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772 int mt_op, int mt_count)
1773{
1774 char * name = tape_name(STp);
1775 int cnt;
1776 int last_mark_ppos = -1;
1777
1778#if DEBUG
1779 printk(OSST_DEB_MSG "%s:D: Reached space_over_filemarks_backwards %d %d\n", name, mt_op, mt_count);
1780#endif
1781 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
1782#if DEBUG
1783 printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks_bwd\n", name);
1784#endif
1785 return -EIO;
1786 }
1787 if (STp->linux_media_version >= 4) {
1788 /*
1789 * direct lookup in header filemark list
1790 */
1791 cnt = ntohl(STp->buffer->aux->filemark_cnt);
1792 if (STp->header_ok &&
1793 STp->header_cache != NULL &&
1794 (cnt - mt_count) >= 0 &&
1795 (cnt - mt_count) < OS_FM_TAB_MAX &&
1796 (cnt - mt_count) < STp->filemark_cnt &&
1797 STp->header_cache->dat_fm_tab.fm_tab_ent[cnt-1] == STp->buffer->aux->last_mark_ppos)
1798
1799 last_mark_ppos = ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[cnt - mt_count]);
1800#if DEBUG
1801 if (STp->header_cache == NULL || (cnt - mt_count) < 0 || (cnt - mt_count) >= OS_FM_TAB_MAX)
1802 printk(OSST_DEB_MSG "%s:D: Filemark lookup fail due to %s\n", name,
1803 STp->header_cache == NULL?"lack of header cache":"count out of range");
1804 else
1805 printk(OSST_DEB_MSG "%s:D: Filemark lookup: prev mark %d (%s), skip %d to %d\n",
1806 name, cnt,
1807 ((cnt == -1 && ntohl(STp->buffer->aux->last_mark_ppos) == -1) ||
1808 (STp->header_cache->dat_fm_tab.fm_tab_ent[cnt-1] ==
1809 STp->buffer->aux->last_mark_ppos))?"match":"error",
1810 mt_count, last_mark_ppos);
1811#endif
1812 if (last_mark_ppos > 10 && last_mark_ppos < STp->eod_frame_ppos) {
1813 osst_position_tape_and_confirm(STp, aSRpnt, last_mark_ppos);
1814 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
1815#if DEBUG
1816 printk(OSST_DEB_MSG
1817 "%s:D: Couldn't get logical blk num in space_filemarks\n", name);
1818#endif
1819 return (-EIO);
1820 }
1821 if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
1822 printk(KERN_WARNING "%s:W: Expected to find marker at ppos %d, not found\n",
1823 name, last_mark_ppos);
1824 return (-EIO);
1825 }
1826 goto found;
1827 }
1828#if DEBUG
1829 printk(OSST_DEB_MSG "%s:D: Reverting to scan filemark backwards\n", name);
1830#endif
1831 }
1832 cnt = 0;
1833 while (cnt != mt_count) {
1834 last_mark_ppos = ntohl(STp->buffer->aux->last_mark_ppos);
1835 if (last_mark_ppos == -1)
1836 return (-EIO);
1837#if DEBUG
1838 printk(OSST_DEB_MSG "%s:D: Positioning to last mark at %d\n", name, last_mark_ppos);
1839#endif
1840 osst_position_tape_and_confirm(STp, aSRpnt, last_mark_ppos);
1841 cnt++;
1842 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
1843#if DEBUG
1844 printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks\n", name);
1845#endif
1846 return (-EIO);
1847 }
1848 if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
1849 printk(KERN_WARNING "%s:W: Expected to find marker at ppos %d, not found\n",
1850 name, last_mark_ppos);
1851 return (-EIO);
1852 }
1853 }
1854found:
1855 if (mt_op == MTBSFM) {
1856 STp->frame_seq_number++;
1857 STp->frame_in_buffer = 0;
1858 STp->buffer->buffer_bytes = 0;
1859 STp->buffer->read_pointer = 0;
1860 STp->logical_blk_num += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
1861 }
1862 return 0;
1863}
1864
1865/*
1866 * ADRL 1.1 compatible "slow" space filemarks fwd version
1867 *
1868 * Just scans for the filemark sequentially.
1869 */
Willem Riede5e6575c2006-02-11 14:46:56 -05001870static int osst_space_over_filemarks_forward_slow(struct osst_tape * STp, struct osst_request ** aSRpnt,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871 int mt_op, int mt_count)
1872{
1873 int cnt = 0;
1874#if DEBUG
1875 char * name = tape_name(STp);
1876
1877 printk(OSST_DEB_MSG "%s:D: Reached space_over_filemarks_forward_slow %d %d\n", name, mt_op, mt_count);
1878#endif
1879 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
1880#if DEBUG
1881 printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks_fwd\n", name);
1882#endif
1883 return (-EIO);
1884 }
1885 while (1) {
1886 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
1887#if DEBUG
1888 printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks\n", name);
1889#endif
1890 return (-EIO);
1891 }
1892 if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_MARKER)
1893 cnt++;
1894 if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_EOD) {
1895#if DEBUG
1896 printk(OSST_DEB_MSG "%s:D: space_fwd: EOD reached\n", name);
1897#endif
1898 if (STp->first_frame_position > STp->eod_frame_ppos+1) {
1899#if DEBUG
1900 printk(OSST_DEB_MSG "%s:D: EOD position corrected (%d=>%d)\n",
1901 name, STp->eod_frame_ppos, STp->first_frame_position-1);
1902#endif
1903 STp->eod_frame_ppos = STp->first_frame_position-1;
1904 }
1905 return (-EIO);
1906 }
1907 if (cnt == mt_count)
1908 break;
1909 STp->frame_in_buffer = 0;
1910 }
1911 if (mt_op == MTFSF) {
1912 STp->frame_seq_number++;
1913 STp->frame_in_buffer = 0;
1914 STp->buffer->buffer_bytes = 0;
1915 STp->buffer->read_pointer = 0;
1916 STp->logical_blk_num += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
1917 }
1918 return 0;
1919}
1920
1921/*
1922 * Fast linux specific version of OnStream FSF
1923 */
Willem Riede5e6575c2006-02-11 14:46:56 -05001924static int osst_space_over_filemarks_forward_fast(struct osst_tape * STp, struct osst_request ** aSRpnt,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925 int mt_op, int mt_count)
1926{
1927 char * name = tape_name(STp);
1928 int cnt = 0,
1929 next_mark_ppos = -1;
1930
1931#if DEBUG
1932 printk(OSST_DEB_MSG "%s:D: Reached space_over_filemarks_forward_fast %d %d\n", name, mt_op, mt_count);
1933#endif
1934 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
1935#if DEBUG
1936 printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks_fwd\n", name);
1937#endif
1938 return (-EIO);
1939 }
1940
1941 if (STp->linux_media_version >= 4) {
1942 /*
1943 * direct lookup in header filemark list
1944 */
1945 cnt = ntohl(STp->buffer->aux->filemark_cnt) - 1;
1946 if (STp->header_ok &&
1947 STp->header_cache != NULL &&
1948 (cnt + mt_count) < OS_FM_TAB_MAX &&
1949 (cnt + mt_count) < STp->filemark_cnt &&
1950 ((cnt == -1 && ntohl(STp->buffer->aux->last_mark_ppos) == -1) ||
1951 (STp->header_cache->dat_fm_tab.fm_tab_ent[cnt] == STp->buffer->aux->last_mark_ppos)))
1952
1953 next_mark_ppos = ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[cnt + mt_count]);
1954#if DEBUG
1955 if (STp->header_cache == NULL || (cnt + mt_count) >= OS_FM_TAB_MAX)
1956 printk(OSST_DEB_MSG "%s:D: Filemark lookup fail due to %s\n", name,
1957 STp->header_cache == NULL?"lack of header cache":"count out of range");
1958 else
1959 printk(OSST_DEB_MSG "%s:D: Filemark lookup: prev mark %d (%s), skip %d to %d\n",
1960 name, cnt,
1961 ((cnt == -1 && ntohl(STp->buffer->aux->last_mark_ppos) == -1) ||
1962 (STp->header_cache->dat_fm_tab.fm_tab_ent[cnt] ==
1963 STp->buffer->aux->last_mark_ppos))?"match":"error",
1964 mt_count, next_mark_ppos);
1965#endif
1966 if (next_mark_ppos <= 10 || next_mark_ppos > STp->eod_frame_ppos) {
1967#if DEBUG
1968 printk(OSST_DEB_MSG "%s:D: Reverting to slow filemark space\n", name);
1969#endif
1970 return osst_space_over_filemarks_forward_slow(STp, aSRpnt, mt_op, mt_count);
1971 } else {
1972 osst_position_tape_and_confirm(STp, aSRpnt, next_mark_ppos);
1973 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
1974#if DEBUG
1975 printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks\n",
1976 name);
1977#endif
1978 return (-EIO);
1979 }
1980 if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
1981 printk(KERN_WARNING "%s:W: Expected to find marker at ppos %d, not found\n",
1982 name, next_mark_ppos);
1983 return (-EIO);
1984 }
1985 if (ntohl(STp->buffer->aux->filemark_cnt) != cnt + mt_count) {
1986 printk(KERN_WARNING "%s:W: Expected to find marker %d at ppos %d, not %d\n",
1987 name, cnt+mt_count, next_mark_ppos,
1988 ntohl(STp->buffer->aux->filemark_cnt));
1989 return (-EIO);
1990 }
1991 }
1992 } else {
1993 /*
1994 * Find nearest (usually previous) marker, then jump from marker to marker
1995 */
1996 while (1) {
1997 if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_MARKER)
1998 break;
1999 if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_EOD) {
2000#if DEBUG
2001 printk(OSST_DEB_MSG "%s:D: space_fwd: EOD reached\n", name);
2002#endif
2003 return (-EIO);
2004 }
2005 if (ntohl(STp->buffer->aux->filemark_cnt) == 0) {
2006 if (STp->first_mark_ppos == -1) {
2007#if DEBUG
2008 printk(OSST_DEB_MSG "%s:D: Reverting to slow filemark space\n", name);
2009#endif
2010 return osst_space_over_filemarks_forward_slow(STp, aSRpnt, mt_op, mt_count);
2011 }
2012 osst_position_tape_and_confirm(STp, aSRpnt, STp->first_mark_ppos);
2013 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
2014#if DEBUG
2015 printk(OSST_DEB_MSG
2016 "%s:D: Couldn't get logical blk num in space_filemarks_fwd_fast\n",
2017 name);
2018#endif
2019 return (-EIO);
2020 }
2021 if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
2022 printk(KERN_WARNING "%s:W: Expected to find filemark at %d\n",
2023 name, STp->first_mark_ppos);
2024 return (-EIO);
2025 }
2026 } else {
2027 if (osst_space_over_filemarks_backward(STp, aSRpnt, MTBSF, 1) < 0)
2028 return (-EIO);
2029 mt_count++;
2030 }
2031 }
2032 cnt++;
2033 while (cnt != mt_count) {
2034 next_mark_ppos = ntohl(STp->buffer->aux->next_mark_ppos);
2035 if (!next_mark_ppos || next_mark_ppos > STp->eod_frame_ppos) {
2036#if DEBUG
2037 printk(OSST_DEB_MSG "%s:D: Reverting to slow filemark space\n", name);
2038#endif
2039 return osst_space_over_filemarks_forward_slow(STp, aSRpnt, mt_op, mt_count - cnt);
2040 }
2041#if DEBUG
2042 else printk(OSST_DEB_MSG "%s:D: Positioning to next mark at %d\n", name, next_mark_ppos);
2043#endif
2044 osst_position_tape_and_confirm(STp, aSRpnt, next_mark_ppos);
2045 cnt++;
2046 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
2047#if DEBUG
2048 printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks\n",
2049 name);
2050#endif
2051 return (-EIO);
2052 }
2053 if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
2054 printk(KERN_WARNING "%s:W: Expected to find marker at ppos %d, not found\n",
2055 name, next_mark_ppos);
2056 return (-EIO);
2057 }
2058 }
2059 }
2060 if (mt_op == MTFSF) {
2061 STp->frame_seq_number++;
2062 STp->frame_in_buffer = 0;
2063 STp->buffer->buffer_bytes = 0;
2064 STp->buffer->read_pointer = 0;
2065 STp->logical_blk_num += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
2066 }
2067 return 0;
2068}
2069
2070/*
2071 * In debug mode, we want to see as many errors as possible
2072 * to test the error recovery mechanism.
2073 */
2074#if DEBUG
Willem Riede5e6575c2006-02-11 14:46:56 -05002075static void osst_set_retries(struct osst_tape * STp, struct osst_request ** aSRpnt, int retries)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002076{
2077 unsigned char cmd[MAX_COMMAND_SIZE];
Willem Riede5e6575c2006-02-11 14:46:56 -05002078 struct osst_request * SRpnt = * aSRpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002079 char * name = tape_name(STp);
2080
2081 memset(cmd, 0, MAX_COMMAND_SIZE);
2082 cmd[0] = MODE_SELECT;
2083 cmd[1] = 0x10;
2084 cmd[4] = NUMBER_RETRIES_PAGE_LENGTH + MODE_HEADER_LENGTH;
2085
2086 (STp->buffer)->b_data[0] = cmd[4] - 1;
2087 (STp->buffer)->b_data[1] = 0; /* Medium Type - ignoring */
2088 (STp->buffer)->b_data[2] = 0; /* Reserved */
2089 (STp->buffer)->b_data[3] = 0; /* Block Descriptor Length */
2090 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 0] = NUMBER_RETRIES_PAGE | (1 << 7);
2091 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 1] = 2;
2092 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] = 4;
2093 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] = retries;
2094
2095 if (debugging)
2096 printk(OSST_DEB_MSG "%s:D: Setting number of retries on OnStream tape to %d\n", name, retries);
2097
2098 SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_TO_DEVICE, STp->timeout, 0, 1);
2099 *aSRpnt = SRpnt;
2100
2101 if ((STp->buffer)->syscall_result)
2102 printk (KERN_ERR "%s:D: Couldn't set retries to %d\n", name, retries);
2103}
2104#endif
2105
2106
Willem Riede5e6575c2006-02-11 14:46:56 -05002107static int osst_write_filemark(struct osst_tape * STp, struct osst_request ** aSRpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108{
2109 int result;
2110 int this_mark_ppos = STp->first_frame_position;
2111 int this_mark_lbn = STp->logical_blk_num;
2112#if DEBUG
2113 char * name = tape_name(STp);
2114#endif
2115
2116 if (STp->raw) return 0;
2117
2118 STp->write_type = OS_WRITE_NEW_MARK;
2119#if DEBUG
2120 printk(OSST_DEB_MSG "%s:D: Writing Filemark %i at fppos %d (fseq %d, lblk %d)\n",
2121 name, STp->filemark_cnt, this_mark_ppos, STp->frame_seq_number, this_mark_lbn);
2122#endif
2123 STp->dirty = 1;
2124 result = osst_flush_write_buffer(STp, aSRpnt);
2125 result |= osst_flush_drive_buffer(STp, aSRpnt);
2126 STp->last_mark_ppos = this_mark_ppos;
2127 STp->last_mark_lbn = this_mark_lbn;
2128 if (STp->header_cache != NULL && STp->filemark_cnt < OS_FM_TAB_MAX)
2129 STp->header_cache->dat_fm_tab.fm_tab_ent[STp->filemark_cnt] = htonl(this_mark_ppos);
2130 if (STp->filemark_cnt++ == 0)
2131 STp->first_mark_ppos = this_mark_ppos;
2132 return result;
2133}
2134
Willem Riede5e6575c2006-02-11 14:46:56 -05002135static int osst_write_eod(struct osst_tape * STp, struct osst_request ** aSRpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002136{
2137 int result;
2138#if DEBUG
2139 char * name = tape_name(STp);
2140#endif
2141
2142 if (STp->raw) return 0;
2143
2144 STp->write_type = OS_WRITE_EOD;
2145 STp->eod_frame_ppos = STp->first_frame_position;
2146#if DEBUG
2147 printk(OSST_DEB_MSG "%s:D: Writing EOD at fppos %d (fseq %d, lblk %d)\n", name,
2148 STp->eod_frame_ppos, STp->frame_seq_number, STp->logical_blk_num);
2149#endif
2150 STp->dirty = 1;
2151
2152 result = osst_flush_write_buffer(STp, aSRpnt);
2153 result |= osst_flush_drive_buffer(STp, aSRpnt);
2154 STp->eod_frame_lfa = --(STp->frame_seq_number);
2155 return result;
2156}
2157
Willem Riede5e6575c2006-02-11 14:46:56 -05002158static int osst_write_filler(struct osst_tape * STp, struct osst_request ** aSRpnt, int where, int count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002159{
2160 char * name = tape_name(STp);
2161
2162#if DEBUG
2163 printk(OSST_DEB_MSG "%s:D: Reached onstream write filler group %d\n", name, where);
2164#endif
2165 osst_wait_ready(STp, aSRpnt, 60 * 5, 0);
2166 osst_set_frame_position(STp, aSRpnt, where, 0);
2167 STp->write_type = OS_WRITE_FILLER;
2168 while (count--) {
2169 memcpy(STp->buffer->b_data, "Filler", 6);
2170 STp->buffer->buffer_bytes = 6;
2171 STp->dirty = 1;
2172 if (osst_flush_write_buffer(STp, aSRpnt)) {
2173 printk(KERN_INFO "%s:I: Couldn't write filler frame\n", name);
2174 return (-EIO);
2175 }
2176 }
2177#if DEBUG
2178 printk(OSST_DEB_MSG "%s:D: Exiting onstream write filler group\n", name);
2179#endif
2180 return osst_flush_drive_buffer(STp, aSRpnt);
2181}
2182
Willem Riede5e6575c2006-02-11 14:46:56 -05002183static int __osst_write_header(struct osst_tape * STp, struct osst_request ** aSRpnt, int where, int count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002184{
2185 char * name = tape_name(STp);
2186 int result;
2187
2188#if DEBUG
2189 printk(OSST_DEB_MSG "%s:D: Reached onstream write header group %d\n", name, where);
2190#endif
2191 osst_wait_ready(STp, aSRpnt, 60 * 5, 0);
2192 osst_set_frame_position(STp, aSRpnt, where, 0);
2193 STp->write_type = OS_WRITE_HEADER;
2194 while (count--) {
2195 osst_copy_to_buffer(STp->buffer, (unsigned char *)STp->header_cache);
2196 STp->buffer->buffer_bytes = sizeof(os_header_t);
2197 STp->dirty = 1;
2198 if (osst_flush_write_buffer(STp, aSRpnt)) {
2199 printk(KERN_INFO "%s:I: Couldn't write header frame\n", name);
2200 return (-EIO);
2201 }
2202 }
2203 result = osst_flush_drive_buffer(STp, aSRpnt);
2204#if DEBUG
2205 printk(OSST_DEB_MSG "%s:D: Write onstream header group %s\n", name, result?"failed":"done");
2206#endif
2207 return result;
2208}
2209
Willem Riede5e6575c2006-02-11 14:46:56 -05002210static int osst_write_header(struct osst_tape * STp, struct osst_request ** aSRpnt, int locate_eod)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002211{
2212 os_header_t * header;
2213 int result;
2214 char * name = tape_name(STp);
2215
2216#if DEBUG
2217 printk(OSST_DEB_MSG "%s:D: Writing tape header\n", name);
2218#endif
2219 if (STp->raw) return 0;
2220
2221 if (STp->header_cache == NULL) {
2222 if ((STp->header_cache = (os_header_t *)vmalloc(sizeof(os_header_t))) == NULL) {
2223 printk(KERN_ERR "%s:E: Failed to allocate header cache\n", name);
2224 return (-ENOMEM);
2225 }
2226 memset(STp->header_cache, 0, sizeof(os_header_t));
2227#if DEBUG
2228 printk(OSST_DEB_MSG "%s:D: Allocated and cleared memory for header cache\n", name);
2229#endif
2230 }
2231 if (STp->header_ok) STp->update_frame_cntr++;
2232 else STp->update_frame_cntr = 0;
2233
2234 header = STp->header_cache;
2235 strcpy(header->ident_str, "ADR_SEQ");
2236 header->major_rev = 1;
2237 header->minor_rev = 4;
2238 header->ext_trk_tb_off = htons(17192);
2239 header->pt_par_num = 1;
2240 header->partition[0].partition_num = OS_DATA_PARTITION;
2241 header->partition[0].par_desc_ver = OS_PARTITION_VERSION;
2242 header->partition[0].wrt_pass_cntr = htons(STp->wrt_pass_cntr);
2243 header->partition[0].first_frame_ppos = htonl(STp->first_data_ppos);
2244 header->partition[0].last_frame_ppos = htonl(STp->capacity);
2245 header->partition[0].eod_frame_ppos = htonl(STp->eod_frame_ppos);
2246 header->cfg_col_width = htonl(20);
2247 header->dat_col_width = htonl(1500);
2248 header->qfa_col_width = htonl(0);
2249 header->ext_track_tb.nr_stream_part = 1;
2250 header->ext_track_tb.et_ent_sz = 32;
2251 header->ext_track_tb.dat_ext_trk_ey.et_part_num = 0;
2252 header->ext_track_tb.dat_ext_trk_ey.fmt = 1;
2253 header->ext_track_tb.dat_ext_trk_ey.fm_tab_off = htons(17736);
2254 header->ext_track_tb.dat_ext_trk_ey.last_hlb_hi = 0;
2255 header->ext_track_tb.dat_ext_trk_ey.last_hlb = htonl(STp->eod_frame_lfa);
2256 header->ext_track_tb.dat_ext_trk_ey.last_pp = htonl(STp->eod_frame_ppos);
2257 header->dat_fm_tab.fm_part_num = 0;
2258 header->dat_fm_tab.fm_tab_ent_sz = 4;
2259 header->dat_fm_tab.fm_tab_ent_cnt = htons(STp->filemark_cnt<OS_FM_TAB_MAX?
2260 STp->filemark_cnt:OS_FM_TAB_MAX);
2261
2262 result = __osst_write_header(STp, aSRpnt, 0xbae, 5);
2263 if (STp->update_frame_cntr == 0)
2264 osst_write_filler(STp, aSRpnt, 0xbb3, 5);
2265 result &= __osst_write_header(STp, aSRpnt, 5, 5);
2266
2267 if (locate_eod) {
2268#if DEBUG
2269 printk(OSST_DEB_MSG "%s:D: Locating back to eod frame addr %d\n", name, STp->eod_frame_ppos);
2270#endif
2271 osst_set_frame_position(STp, aSRpnt, STp->eod_frame_ppos, 0);
2272 }
2273 if (result)
2274 printk(KERN_ERR "%s:E: Write header failed\n", name);
2275 else {
2276 memcpy(STp->application_sig, "LIN4", 4);
2277 STp->linux_media = 1;
2278 STp->linux_media_version = 4;
2279 STp->header_ok = 1;
2280 }
2281 return result;
2282}
2283
Willem Riede5e6575c2006-02-11 14:46:56 -05002284static int osst_reset_header(struct osst_tape * STp, struct osst_request ** aSRpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002285{
2286 if (STp->header_cache != NULL)
2287 memset(STp->header_cache, 0, sizeof(os_header_t));
2288
2289 STp->logical_blk_num = STp->frame_seq_number = 0;
2290 STp->frame_in_buffer = 0;
2291 STp->eod_frame_ppos = STp->first_data_ppos = 0x0000000A;
2292 STp->filemark_cnt = 0;
2293 STp->first_mark_ppos = STp->last_mark_ppos = STp->last_mark_lbn = -1;
2294 return osst_write_header(STp, aSRpnt, 1);
2295}
2296
Willem Riede5e6575c2006-02-11 14:46:56 -05002297static int __osst_analyze_headers(struct osst_tape * STp, struct osst_request ** aSRpnt, int ppos)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002298{
2299 char * name = tape_name(STp);
2300 os_header_t * header;
2301 os_aux_t * aux;
2302 char id_string[8];
2303 int linux_media_version,
2304 update_frame_cntr;
2305
2306 if (STp->raw)
2307 return 1;
2308
2309 if (ppos == 5 || ppos == 0xbae || STp->buffer->syscall_result) {
2310 if (osst_set_frame_position(STp, aSRpnt, ppos, 0))
2311 printk(KERN_WARNING "%s:W: Couldn't position tape\n", name);
2312 osst_wait_ready(STp, aSRpnt, 60 * 15, 0);
2313 if (osst_initiate_read (STp, aSRpnt)) {
2314 printk(KERN_WARNING "%s:W: Couldn't initiate read\n", name);
2315 return 0;
2316 }
2317 }
2318 if (osst_read_frame(STp, aSRpnt, 180)) {
2319#if DEBUG
2320 printk(OSST_DEB_MSG "%s:D: Couldn't read header frame\n", name);
2321#endif
2322 return 0;
2323 }
2324 header = (os_header_t *) STp->buffer->b_data; /* warning: only first segment addressable */
2325 aux = STp->buffer->aux;
2326 if (aux->frame_type != OS_FRAME_TYPE_HEADER) {
2327#if DEBUG
2328 printk(OSST_DEB_MSG "%s:D: Skipping non-header frame (%d)\n", name, ppos);
2329#endif
2330 return 0;
2331 }
2332 if (ntohl(aux->frame_seq_num) != 0 ||
2333 ntohl(aux->logical_blk_num) != 0 ||
2334 aux->partition.partition_num != OS_CONFIG_PARTITION ||
2335 ntohl(aux->partition.first_frame_ppos) != 0 ||
2336 ntohl(aux->partition.last_frame_ppos) != 0xbb7 ) {
2337#if DEBUG
2338 printk(OSST_DEB_MSG "%s:D: Invalid header frame (%d,%d,%d,%d,%d)\n", name,
2339 ntohl(aux->frame_seq_num), ntohl(aux->logical_blk_num),
2340 aux->partition.partition_num, ntohl(aux->partition.first_frame_ppos),
2341 ntohl(aux->partition.last_frame_ppos));
2342#endif
2343 return 0;
2344 }
2345 if (strncmp(header->ident_str, "ADR_SEQ", 7) != 0 &&
2346 strncmp(header->ident_str, "ADR-SEQ", 7) != 0) {
2347 strlcpy(id_string, header->ident_str, 8);
2348#if DEBUG
2349 printk(OSST_DEB_MSG "%s:D: Invalid header identification string %s\n", name, id_string);
2350#endif
2351 return 0;
2352 }
2353 update_frame_cntr = ntohl(aux->update_frame_cntr);
2354 if (update_frame_cntr < STp->update_frame_cntr) {
2355#if DEBUG
2356 printk(OSST_DEB_MSG "%s:D: Skipping frame %d with update_frame_counter %d<%d\n",
2357 name, ppos, update_frame_cntr, STp->update_frame_cntr);
2358#endif
2359 return 0;
2360 }
2361 if (header->major_rev != 1 || header->minor_rev != 4 ) {
2362#if DEBUG
2363 printk(OSST_DEB_MSG "%s:D: %s revision %d.%d detected (1.4 supported)\n",
2364 name, (header->major_rev != 1 || header->minor_rev < 2 ||
2365 header->minor_rev > 4 )? "Invalid" : "Warning:",
2366 header->major_rev, header->minor_rev);
2367#endif
2368 if (header->major_rev != 1 || header->minor_rev < 2 || header->minor_rev > 4)
2369 return 0;
2370 }
2371#if DEBUG
2372 if (header->pt_par_num != 1)
2373 printk(KERN_INFO "%s:W: %d partitions defined, only one supported\n",
2374 name, header->pt_par_num);
2375#endif
2376 memcpy(id_string, aux->application_sig, 4);
2377 id_string[4] = 0;
2378 if (memcmp(id_string, "LIN", 3) == 0) {
2379 STp->linux_media = 1;
2380 linux_media_version = id_string[3] - '0';
2381 if (linux_media_version != 4)
2382 printk(KERN_INFO "%s:I: Linux media version %d detected (current 4)\n",
2383 name, linux_media_version);
2384 } else {
2385 printk(KERN_WARNING "%s:W: Non Linux media detected (%s)\n", name, id_string);
2386 return 0;
2387 }
2388 if (linux_media_version < STp->linux_media_version) {
2389#if DEBUG
2390 printk(OSST_DEB_MSG "%s:D: Skipping frame %d with linux_media_version %d\n",
2391 name, ppos, linux_media_version);
2392#endif
2393 return 0;
2394 }
2395 if (linux_media_version > STp->linux_media_version) {
2396#if DEBUG
2397 printk(OSST_DEB_MSG "%s:D: Frame %d sets linux_media_version to %d\n",
2398 name, ppos, linux_media_version);
2399#endif
2400 memcpy(STp->application_sig, id_string, 5);
2401 STp->linux_media_version = linux_media_version;
2402 STp->update_frame_cntr = -1;
2403 }
2404 if (update_frame_cntr > STp->update_frame_cntr) {
2405#if DEBUG
2406 printk(OSST_DEB_MSG "%s:D: Frame %d sets update_frame_counter to %d\n",
2407 name, ppos, update_frame_cntr);
2408#endif
2409 if (STp->header_cache == NULL) {
2410 if ((STp->header_cache = (os_header_t *)vmalloc(sizeof(os_header_t))) == NULL) {
2411 printk(KERN_ERR "%s:E: Failed to allocate header cache\n", name);
2412 return 0;
2413 }
2414#if DEBUG
2415 printk(OSST_DEB_MSG "%s:D: Allocated memory for header cache\n", name);
2416#endif
2417 }
2418 osst_copy_from_buffer(STp->buffer, (unsigned char *)STp->header_cache);
2419 header = STp->header_cache; /* further accesses from cached (full) copy */
2420
2421 STp->wrt_pass_cntr = ntohs(header->partition[0].wrt_pass_cntr);
2422 STp->first_data_ppos = ntohl(header->partition[0].first_frame_ppos);
2423 STp->eod_frame_ppos = ntohl(header->partition[0].eod_frame_ppos);
2424 STp->eod_frame_lfa = ntohl(header->ext_track_tb.dat_ext_trk_ey.last_hlb);
2425 STp->filemark_cnt = ntohl(aux->filemark_cnt);
2426 STp->first_mark_ppos = ntohl(aux->next_mark_ppos);
2427 STp->last_mark_ppos = ntohl(aux->last_mark_ppos);
2428 STp->last_mark_lbn = ntohl(aux->last_mark_lbn);
2429 STp->update_frame_cntr = update_frame_cntr;
2430#if DEBUG
2431 printk(OSST_DEB_MSG "%s:D: Detected write pass %d, update frame counter %d, filemark counter %d\n",
2432 name, STp->wrt_pass_cntr, STp->update_frame_cntr, STp->filemark_cnt);
2433 printk(OSST_DEB_MSG "%s:D: first data frame on tape = %d, last = %d, eod frame = %d\n", name,
2434 STp->first_data_ppos,
2435 ntohl(header->partition[0].last_frame_ppos),
2436 ntohl(header->partition[0].eod_frame_ppos));
2437 printk(OSST_DEB_MSG "%s:D: first mark on tape = %d, last = %d, eod frame = %d\n",
2438 name, STp->first_mark_ppos, STp->last_mark_ppos, STp->eod_frame_ppos);
2439#endif
2440 if (header->minor_rev < 4 && STp->linux_media_version == 4) {
2441#if DEBUG
2442 printk(OSST_DEB_MSG "%s:D: Moving filemark list to ADR 1.4 location\n", name);
2443#endif
2444 memcpy((void *)header->dat_fm_tab.fm_tab_ent,
2445 (void *)header->old_filemark_list, sizeof(header->dat_fm_tab.fm_tab_ent));
2446 memset((void *)header->old_filemark_list, 0, sizeof(header->old_filemark_list));
2447 }
2448 if (header->minor_rev == 4 &&
2449 (header->ext_trk_tb_off != htons(17192) ||
2450 header->partition[0].partition_num != OS_DATA_PARTITION ||
2451 header->partition[0].par_desc_ver != OS_PARTITION_VERSION ||
2452 header->partition[0].last_frame_ppos != htonl(STp->capacity) ||
2453 header->cfg_col_width != htonl(20) ||
2454 header->dat_col_width != htonl(1500) ||
2455 header->qfa_col_width != htonl(0) ||
2456 header->ext_track_tb.nr_stream_part != 1 ||
2457 header->ext_track_tb.et_ent_sz != 32 ||
2458 header->ext_track_tb.dat_ext_trk_ey.et_part_num != OS_DATA_PARTITION ||
2459 header->ext_track_tb.dat_ext_trk_ey.fmt != 1 ||
2460 header->ext_track_tb.dat_ext_trk_ey.fm_tab_off != htons(17736) ||
2461 header->ext_track_tb.dat_ext_trk_ey.last_hlb_hi != 0 ||
2462 header->ext_track_tb.dat_ext_trk_ey.last_pp != htonl(STp->eod_frame_ppos) ||
2463 header->dat_fm_tab.fm_part_num != OS_DATA_PARTITION ||
2464 header->dat_fm_tab.fm_tab_ent_sz != 4 ||
2465 header->dat_fm_tab.fm_tab_ent_cnt !=
2466 htons(STp->filemark_cnt<OS_FM_TAB_MAX?STp->filemark_cnt:OS_FM_TAB_MAX)))
2467 printk(KERN_WARNING "%s:W: Failed consistency check ADR 1.4 format\n", name);
2468
2469 }
2470
2471 return 1;
2472}
2473
Willem Riede5e6575c2006-02-11 14:46:56 -05002474static int osst_analyze_headers(struct osst_tape * STp, struct osst_request ** aSRpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002475{
2476 int position, ppos;
2477 int first, last;
2478 int valid = 0;
2479 char * name = tape_name(STp);
2480
2481 position = osst_get_frame_position(STp, aSRpnt);
2482
2483 if (STp->raw) {
2484 STp->header_ok = STp->linux_media = 1;
2485 STp->linux_media_version = 0;
2486 return 1;
2487 }
2488 STp->header_ok = STp->linux_media = STp->linux_media_version = 0;
2489 STp->wrt_pass_cntr = STp->update_frame_cntr = -1;
2490 STp->eod_frame_ppos = STp->first_data_ppos = -1;
2491 STp->first_mark_ppos = STp->last_mark_ppos = STp->last_mark_lbn = -1;
2492#if DEBUG
2493 printk(OSST_DEB_MSG "%s:D: Reading header\n", name);
2494#endif
2495
2496 /* optimization for speed - if we are positioned at ppos 10, read second group first */
2497 /* TODO try the ADR 1.1 locations for the second group if we have no valid one yet... */
2498
2499 first = position==10?0xbae: 5;
2500 last = position==10?0xbb3:10;
2501
2502 for (ppos = first; ppos < last; ppos++)
2503 if (__osst_analyze_headers(STp, aSRpnt, ppos))
2504 valid = 1;
2505
2506 first = position==10? 5:0xbae;
2507 last = position==10?10:0xbb3;
2508
2509 for (ppos = first; ppos < last; ppos++)
2510 if (__osst_analyze_headers(STp, aSRpnt, ppos))
2511 valid = 1;
2512
2513 if (!valid) {
2514 printk(KERN_ERR "%s:E: Failed to find valid ADRL header, new media?\n", name);
2515 STp->eod_frame_ppos = STp->first_data_ppos = 0;
2516 osst_set_frame_position(STp, aSRpnt, 10, 0);
2517 return 0;
2518 }
2519 if (position <= STp->first_data_ppos) {
2520 position = STp->first_data_ppos;
2521 STp->ps[0].drv_file = STp->ps[0].drv_block = STp->frame_seq_number = STp->logical_blk_num = 0;
2522 }
2523 osst_set_frame_position(STp, aSRpnt, position, 0);
2524 STp->header_ok = 1;
2525
2526 return 1;
2527}
2528
Willem Riede5e6575c2006-02-11 14:46:56 -05002529static int osst_verify_position(struct osst_tape * STp, struct osst_request ** aSRpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002530{
2531 int frame_position = STp->first_frame_position;
2532 int frame_seq_numbr = STp->frame_seq_number;
2533 int logical_blk_num = STp->logical_blk_num;
2534 int halfway_frame = STp->frame_in_buffer;
2535 int read_pointer = STp->buffer->read_pointer;
2536 int prev_mark_ppos = -1;
2537 int actual_mark_ppos, i, n;
2538#if DEBUG
2539 char * name = tape_name(STp);
2540
2541 printk(OSST_DEB_MSG "%s:D: Verify that the tape is really the one we think before writing\n", name);
2542#endif
2543 osst_set_frame_position(STp, aSRpnt, frame_position - 1, 0);
2544 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
2545#if DEBUG
2546 printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in verify_position\n", name);
2547#endif
2548 return (-EIO);
2549 }
2550 if (STp->linux_media_version >= 4) {
2551 for (i=0; i<STp->filemark_cnt; i++)
2552 if ((n=ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[i])) < frame_position)
2553 prev_mark_ppos = n;
2554 } else
2555 prev_mark_ppos = frame_position - 1; /* usually - we don't really know */
2556 actual_mark_ppos = STp->buffer->aux->frame_type == OS_FRAME_TYPE_MARKER ?
2557 frame_position - 1 : ntohl(STp->buffer->aux->last_mark_ppos);
2558 if (frame_position != STp->first_frame_position ||
2559 frame_seq_numbr != STp->frame_seq_number + (halfway_frame?0:1) ||
2560 prev_mark_ppos != actual_mark_ppos ) {
2561#if DEBUG
2562 printk(OSST_DEB_MSG "%s:D: Block mismatch: fppos %d-%d, fseq %d-%d, mark %d-%d\n", name,
2563 STp->first_frame_position, frame_position,
2564 STp->frame_seq_number + (halfway_frame?0:1),
2565 frame_seq_numbr, actual_mark_ppos, prev_mark_ppos);
2566#endif
2567 return (-EIO);
2568 }
2569 if (halfway_frame) {
2570 /* prepare buffer for append and rewrite on top of original */
2571 osst_set_frame_position(STp, aSRpnt, frame_position - 1, 0);
2572 STp->buffer->buffer_bytes = read_pointer;
2573 STp->ps[STp->partition].rw = ST_WRITING;
2574 STp->dirty = 1;
2575 }
2576 STp->frame_in_buffer = halfway_frame;
2577 STp->frame_seq_number = frame_seq_numbr;
2578 STp->logical_blk_num = logical_blk_num;
2579 return 0;
2580}
2581
2582/* Acc. to OnStream, the vers. numbering is the following:
2583 * X.XX for released versions (X=digit),
2584 * XXXY for unreleased versions (Y=letter)
2585 * Ordering 1.05 < 106A < 106B < ... < 106a < ... < 1.06
2586 * This fn makes monoton numbers out of this scheme ...
2587 */
2588static unsigned int osst_parse_firmware_rev (const char * str)
2589{
2590 if (str[1] == '.') {
2591 return (str[0]-'0')*10000
2592 +(str[2]-'0')*1000
2593 +(str[3]-'0')*100;
2594 } else {
2595 return (str[0]-'0')*10000
2596 +(str[1]-'0')*1000
2597 +(str[2]-'0')*100 - 100
2598 +(str[3]-'@');
2599 }
2600}
2601
2602/*
2603 * Configure the OnStream SCII tape drive for default operation
2604 */
Willem Riede5e6575c2006-02-11 14:46:56 -05002605static int osst_configure_onstream(struct osst_tape *STp, struct osst_request ** aSRpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002606{
2607 unsigned char cmd[MAX_COMMAND_SIZE];
2608 char * name = tape_name(STp);
Willem Riede5e6575c2006-02-11 14:46:56 -05002609 struct osst_request * SRpnt = * aSRpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002610 osst_mode_parameter_header_t * header;
2611 osst_block_size_page_t * bs;
2612 osst_capabilities_page_t * cp;
2613 osst_tape_paramtr_page_t * prm;
2614 int drive_buffer_size;
2615
2616 if (STp->ready != ST_READY) {
2617#if DEBUG
2618 printk(OSST_DEB_MSG "%s:D: Not Ready\n", name);
2619#endif
2620 return (-EIO);
2621 }
2622
2623 if (STp->os_fw_rev < 10600) {
2624 printk(KERN_INFO "%s:I: Old OnStream firmware revision detected (%s),\n", name, STp->device->rev);
2625 printk(KERN_INFO "%s:I: an upgrade to version 1.06 or above is recommended\n", name);
2626 }
2627
2628 /*
2629 * Configure 32.5KB (data+aux) frame size.
2630 * Get the current frame size from the block size mode page
2631 */
2632 memset(cmd, 0, MAX_COMMAND_SIZE);
2633 cmd[0] = MODE_SENSE;
2634 cmd[1] = 8;
2635 cmd[2] = BLOCK_SIZE_PAGE;
2636 cmd[4] = BLOCK_SIZE_PAGE_LENGTH + MODE_HEADER_LENGTH;
2637
2638 SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_FROM_DEVICE, STp->timeout, 0, 1);
2639 if (SRpnt == NULL) {
2640#if DEBUG
2641 printk(OSST_DEB_MSG "osst :D: Busy\n");
2642#endif
2643 return (-EBUSY);
2644 }
2645 *aSRpnt = SRpnt;
2646 if ((STp->buffer)->syscall_result != 0) {
2647 printk (KERN_ERR "%s:E: Can't get tape block size mode page\n", name);
2648 return (-EIO);
2649 }
2650
2651 header = (osst_mode_parameter_header_t *) (STp->buffer)->b_data;
2652 bs = (osst_block_size_page_t *) ((STp->buffer)->b_data + sizeof(osst_mode_parameter_header_t) + header->bdl);
2653
2654#if DEBUG
2655 printk(OSST_DEB_MSG "%s:D: 32KB play back: %s\n", name, bs->play32 ? "Yes" : "No");
2656 printk(OSST_DEB_MSG "%s:D: 32.5KB play back: %s\n", name, bs->play32_5 ? "Yes" : "No");
2657 printk(OSST_DEB_MSG "%s:D: 32KB record: %s\n", name, bs->record32 ? "Yes" : "No");
2658 printk(OSST_DEB_MSG "%s:D: 32.5KB record: %s\n", name, bs->record32_5 ? "Yes" : "No");
2659#endif
2660
2661 /*
2662 * Configure default auto columns mode, 32.5KB transfer mode
2663 */
2664 bs->one = 1;
2665 bs->play32 = 0;
2666 bs->play32_5 = 1;
2667 bs->record32 = 0;
2668 bs->record32_5 = 1;
2669
2670 memset(cmd, 0, MAX_COMMAND_SIZE);
2671 cmd[0] = MODE_SELECT;
2672 cmd[1] = 0x10;
2673 cmd[4] = BLOCK_SIZE_PAGE_LENGTH + MODE_HEADER_LENGTH;
2674
2675 SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_TO_DEVICE, STp->timeout, 0, 1);
2676 *aSRpnt = SRpnt;
2677 if ((STp->buffer)->syscall_result != 0) {
2678 printk (KERN_ERR "%s:E: Couldn't set tape block size mode page\n", name);
2679 return (-EIO);
2680 }
2681
2682#if DEBUG
2683 printk(KERN_INFO "%s:D: Drive Block Size changed to 32.5K\n", name);
2684 /*
2685 * In debug mode, we want to see as many errors as possible
2686 * to test the error recovery mechanism.
2687 */
2688 osst_set_retries(STp, aSRpnt, 0);
2689 SRpnt = * aSRpnt;
2690#endif
2691
2692 /*
2693 * Set vendor name to 'LIN4' for "Linux support version 4".
2694 */
2695
2696 memset(cmd, 0, MAX_COMMAND_SIZE);
2697 cmd[0] = MODE_SELECT;
2698 cmd[1] = 0x10;
2699 cmd[4] = VENDOR_IDENT_PAGE_LENGTH + MODE_HEADER_LENGTH;
2700
2701 header->mode_data_length = VENDOR_IDENT_PAGE_LENGTH + MODE_HEADER_LENGTH - 1;
2702 header->medium_type = 0; /* Medium Type - ignoring */
2703 header->dsp = 0; /* Reserved */
2704 header->bdl = 0; /* Block Descriptor Length */
2705
2706 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 0] = VENDOR_IDENT_PAGE | (1 << 7);
2707 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 1] = 6;
2708 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] = 'L';
2709 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] = 'I';
2710 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 4] = 'N';
2711 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 5] = '4';
2712 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 6] = 0;
2713 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 7] = 0;
2714
2715 SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_TO_DEVICE, STp->timeout, 0, 1);
2716 *aSRpnt = SRpnt;
2717
2718 if ((STp->buffer)->syscall_result != 0) {
2719 printk (KERN_ERR "%s:E: Couldn't set vendor name to %s\n", name,
2720 (char *) ((STp->buffer)->b_data + MODE_HEADER_LENGTH + 2));
2721 return (-EIO);
2722 }
2723
2724 memset(cmd, 0, MAX_COMMAND_SIZE);
2725 cmd[0] = MODE_SENSE;
2726 cmd[1] = 8;
2727 cmd[2] = CAPABILITIES_PAGE;
2728 cmd[4] = CAPABILITIES_PAGE_LENGTH + MODE_HEADER_LENGTH;
2729
2730 SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_FROM_DEVICE, STp->timeout, 0, 1);
2731 *aSRpnt = SRpnt;
2732
2733 if ((STp->buffer)->syscall_result != 0) {
2734 printk (KERN_ERR "%s:E: Can't get capabilities page\n", name);
2735 return (-EIO);
2736 }
2737
2738 header = (osst_mode_parameter_header_t *) (STp->buffer)->b_data;
2739 cp = (osst_capabilities_page_t *) ((STp->buffer)->b_data +
2740 sizeof(osst_mode_parameter_header_t) + header->bdl);
2741
2742 drive_buffer_size = ntohs(cp->buffer_size) / 2;
2743
2744 memset(cmd, 0, MAX_COMMAND_SIZE);
2745 cmd[0] = MODE_SENSE;
2746 cmd[1] = 8;
2747 cmd[2] = TAPE_PARAMTR_PAGE;
2748 cmd[4] = TAPE_PARAMTR_PAGE_LENGTH + MODE_HEADER_LENGTH;
2749
2750 SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_FROM_DEVICE, STp->timeout, 0, 1);
2751 *aSRpnt = SRpnt;
2752
2753 if ((STp->buffer)->syscall_result != 0) {
2754 printk (KERN_ERR "%s:E: Can't get tape parameter page\n", name);
2755 return (-EIO);
2756 }
2757
2758 header = (osst_mode_parameter_header_t *) (STp->buffer)->b_data;
2759 prm = (osst_tape_paramtr_page_t *) ((STp->buffer)->b_data +
2760 sizeof(osst_mode_parameter_header_t) + header->bdl);
2761
2762 STp->density = prm->density;
2763 STp->capacity = ntohs(prm->segtrk) * ntohs(prm->trks);
2764#if DEBUG
2765 printk(OSST_DEB_MSG "%s:D: Density %d, tape length: %dMB, drive buffer size: %dKB\n",
2766 name, STp->density, STp->capacity / 32, drive_buffer_size);
2767#endif
2768
2769 return 0;
2770
2771}
2772
2773
2774/* Step over EOF if it has been inadvertently crossed (ioctl not used because
2775 it messes up the block number). */
Willem Riede5e6575c2006-02-11 14:46:56 -05002776static int cross_eof(struct osst_tape *STp, struct osst_request ** aSRpnt, int forward)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002777{
2778 int result;
2779 char * name = tape_name(STp);
2780
2781#if DEBUG
2782 if (debugging)
2783 printk(OSST_DEB_MSG "%s:D: Stepping over filemark %s.\n",
2784 name, forward ? "forward" : "backward");
2785#endif
2786
2787 if (forward) {
2788 /* assumes that the filemark is already read by the drive, so this is low cost */
2789 result = osst_space_over_filemarks_forward_slow(STp, aSRpnt, MTFSF, 1);
2790 }
2791 else
2792 /* assumes this is only called if we just read the filemark! */
2793 result = osst_seek_logical_blk(STp, aSRpnt, STp->logical_blk_num - 1);
2794
2795 if (result < 0)
2796 printk(KERN_WARNING "%s:W: Stepping over filemark %s failed.\n",
2797 name, forward ? "forward" : "backward");
2798
2799 return result;
2800}
2801
2802
2803/* Get the tape position. */
2804
Willem Riede5e6575c2006-02-11 14:46:56 -05002805static int osst_get_frame_position(struct osst_tape *STp, struct osst_request ** aSRpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002806{
2807 unsigned char scmd[MAX_COMMAND_SIZE];
Willem Riede5e6575c2006-02-11 14:46:56 -05002808 struct osst_request * SRpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002809 int result = 0;
2810 char * name = tape_name(STp);
2811
2812 /* KG: We want to be able to use it for checking Write Buffer availability
2813 * and thus don't want to risk to overwrite anything. Exchange buffers ... */
2814 char mybuf[24];
2815 char * olddata = STp->buffer->b_data;
2816 int oldsize = STp->buffer->buffer_size;
2817
2818 if (STp->ready != ST_READY) return (-EIO);
2819
2820 memset (scmd, 0, MAX_COMMAND_SIZE);
2821 scmd[0] = READ_POSITION;
2822
2823 STp->buffer->b_data = mybuf; STp->buffer->buffer_size = 24;
2824 SRpnt = osst_do_scsi(*aSRpnt, STp, scmd, 20, DMA_FROM_DEVICE,
2825 STp->timeout, MAX_RETRIES, 1);
2826 if (!SRpnt) {
2827 STp->buffer->b_data = olddata; STp->buffer->buffer_size = oldsize;
2828 return (-EBUSY);
2829 }
2830 *aSRpnt = SRpnt;
2831
2832 if (STp->buffer->syscall_result)
Willem Riede5e6575c2006-02-11 14:46:56 -05002833 result = ((SRpnt->sense[2] & 0x0f) == 3) ? -EIO : -EINVAL; /* 3: Write Error */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002834
2835 if (result == -EINVAL)
2836 printk(KERN_ERR "%s:E: Can't read tape position.\n", name);
2837 else {
2838 if (result == -EIO) { /* re-read position - this needs to preserve media errors */
2839 unsigned char mysense[16];
Willem Riede5e6575c2006-02-11 14:46:56 -05002840 memcpy (mysense, SRpnt->sense, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002841 memset (scmd, 0, MAX_COMMAND_SIZE);
2842 scmd[0] = READ_POSITION;
2843 STp->buffer->b_data = mybuf; STp->buffer->buffer_size = 24;
2844 SRpnt = osst_do_scsi(SRpnt, STp, scmd, 20, DMA_FROM_DEVICE,
2845 STp->timeout, MAX_RETRIES, 1);
2846#if DEBUG
2847 printk(OSST_DEB_MSG "%s:D: Reread position, reason=[%02x:%02x:%02x], result=[%s%02x:%02x:%02x]\n",
2848 name, mysense[2], mysense[12], mysense[13], STp->buffer->syscall_result?"":"ok:",
Willem Riede5e6575c2006-02-11 14:46:56 -05002849 SRpnt->sense[2],SRpnt->sense[12],SRpnt->sense[13]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002850#endif
2851 if (!STp->buffer->syscall_result)
Willem Riede5e6575c2006-02-11 14:46:56 -05002852 memcpy (SRpnt->sense, mysense, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002853 else
2854 printk(KERN_WARNING "%s:W: Double error in get position\n", name);
2855 }
2856 STp->first_frame_position = ((STp->buffer)->b_data[4] << 24)
2857 + ((STp->buffer)->b_data[5] << 16)
2858 + ((STp->buffer)->b_data[6] << 8)
2859 + (STp->buffer)->b_data[7];
2860 STp->last_frame_position = ((STp->buffer)->b_data[ 8] << 24)
2861 + ((STp->buffer)->b_data[ 9] << 16)
2862 + ((STp->buffer)->b_data[10] << 8)
2863 + (STp->buffer)->b_data[11];
2864 STp->cur_frames = (STp->buffer)->b_data[15];
2865#if DEBUG
2866 if (debugging) {
2867 printk(OSST_DEB_MSG "%s:D: Drive Positions: host %d, tape %d%s, buffer %d\n", name,
2868 STp->first_frame_position, STp->last_frame_position,
2869 ((STp->buffer)->b_data[0]&0x80)?" (BOP)":
2870 ((STp->buffer)->b_data[0]&0x40)?" (EOP)":"",
2871 STp->cur_frames);
2872 }
2873#endif
2874 if (STp->cur_frames == 0 && STp->first_frame_position != STp->last_frame_position) {
2875#if DEBUG
2876 printk(OSST_DEB_MSG "%s:D: Correcting read position %d, %d, %d\n", name,
2877 STp->first_frame_position, STp->last_frame_position, STp->cur_frames);
2878#endif
2879 STp->first_frame_position = STp->last_frame_position;
2880 }
2881 }
2882 STp->buffer->b_data = olddata; STp->buffer->buffer_size = oldsize;
2883
2884 return (result == 0 ? STp->first_frame_position : result);
2885}
2886
2887
2888/* Set the tape block */
Willem Riede5e6575c2006-02-11 14:46:56 -05002889static int osst_set_frame_position(struct osst_tape *STp, struct osst_request ** aSRpnt, int ppos, int skip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002890{
2891 unsigned char scmd[MAX_COMMAND_SIZE];
Willem Riede5e6575c2006-02-11 14:46:56 -05002892 struct osst_request * SRpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002893 struct st_partstat * STps;
2894 int result = 0;
2895 int pp = (ppos == 3000 && !skip)? 0 : ppos;
2896 char * name = tape_name(STp);
2897
2898 if (STp->ready != ST_READY) return (-EIO);
2899
2900 STps = &(STp->ps[STp->partition]);
2901
2902 if (ppos < 0 || ppos > STp->capacity) {
2903 printk(KERN_WARNING "%s:W: Reposition request %d out of range\n", name, ppos);
2904 pp = ppos = ppos < 0 ? 0 : (STp->capacity - 1);
2905 result = (-EINVAL);
2906 }
2907
2908 do {
2909#if DEBUG
2910 if (debugging)
2911 printk(OSST_DEB_MSG "%s:D: Setting ppos to %d.\n", name, pp);
2912#endif
2913 memset (scmd, 0, MAX_COMMAND_SIZE);
2914 scmd[0] = SEEK_10;
2915 scmd[1] = 1;
2916 scmd[3] = (pp >> 24);
2917 scmd[4] = (pp >> 16);
2918 scmd[5] = (pp >> 8);
2919 scmd[6] = pp;
2920 if (skip)
2921 scmd[9] = 0x80;
2922
2923 SRpnt = osst_do_scsi(*aSRpnt, STp, scmd, 0, DMA_NONE, STp->long_timeout,
2924 MAX_RETRIES, 1);
2925 if (!SRpnt)
2926 return (-EBUSY);
2927 *aSRpnt = SRpnt;
2928
2929 if ((STp->buffer)->syscall_result != 0) {
2930#if DEBUG
2931 printk(OSST_DEB_MSG "%s:D: SEEK command from %d to %d failed.\n",
2932 name, STp->first_frame_position, pp);
2933#endif
2934 result = (-EIO);
2935 }
2936 if (pp != ppos)
2937 osst_wait_ready(STp, aSRpnt, 5 * 60, OSST_WAIT_POSITION_COMPLETE);
2938 } while ((pp != ppos) && (pp = ppos));
2939 STp->first_frame_position = STp->last_frame_position = ppos;
2940 STps->eof = ST_NOEOF;
2941 STps->at_sm = 0;
2942 STps->rw = ST_IDLE;
2943 STp->frame_in_buffer = 0;
2944 return result;
2945}
2946
Willem Riede5e6575c2006-02-11 14:46:56 -05002947static int osst_write_trailer(struct osst_tape *STp, struct osst_request ** aSRpnt, int leave_at_EOT)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002948{
2949 struct st_partstat * STps = &(STp->ps[STp->partition]);
2950 int result = 0;
2951
2952 if (STp->write_type != OS_WRITE_NEW_MARK) {
2953 /* true unless the user wrote the filemark for us */
2954 result = osst_flush_drive_buffer(STp, aSRpnt);
2955 if (result < 0) goto out;
2956 result = osst_write_filemark(STp, aSRpnt);
2957 if (result < 0) goto out;
2958
2959 if (STps->drv_file >= 0)
2960 STps->drv_file++ ;
2961 STps->drv_block = 0;
2962 }
2963 result = osst_write_eod(STp, aSRpnt);
2964 osst_write_header(STp, aSRpnt, leave_at_EOT);
2965
2966 STps->eof = ST_FM;
2967out:
2968 return result;
2969}
2970
2971/* osst versions of st functions - augmented and stripped to suit OnStream only */
2972
2973/* Flush the write buffer (never need to write if variable blocksize). */
Willem Riede5e6575c2006-02-11 14:46:56 -05002974static int osst_flush_write_buffer(struct osst_tape *STp, struct osst_request ** aSRpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002975{
2976 int offset, transfer, blks = 0;
2977 int result = 0;
2978 unsigned char cmd[MAX_COMMAND_SIZE];
Willem Riede5e6575c2006-02-11 14:46:56 -05002979 struct osst_request * SRpnt = *aSRpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002980 struct st_partstat * STps;
2981 char * name = tape_name(STp);
2982
2983 if ((STp->buffer)->writing) {
2984 if (SRpnt == (STp->buffer)->last_SRpnt)
2985#if DEBUG
2986 { printk(OSST_DEB_MSG
Willem Riede5e6575c2006-02-11 14:46:56 -05002987 "%s:D: aSRpnt points to osst_request that write_behind_check will release -- cleared\n", name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002988#endif
2989 *aSRpnt = SRpnt = NULL;
2990#if DEBUG
2991 } else if (SRpnt)
2992 printk(OSST_DEB_MSG
Willem Riede5e6575c2006-02-11 14:46:56 -05002993 "%s:D: aSRpnt does not point to osst_request that write_behind_check will release -- strange\n", name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002994#endif
2995 osst_write_behind_check(STp);
2996 if ((STp->buffer)->syscall_result) {
2997#if DEBUG
2998 if (debugging)
2999 printk(OSST_DEB_MSG "%s:D: Async write error (flush) %x.\n",
3000 name, (STp->buffer)->midlevel_result);
3001#endif
3002 if ((STp->buffer)->midlevel_result == INT_MAX)
3003 return (-ENOSPC);
3004 return (-EIO);
3005 }
3006 }
3007
3008 result = 0;
3009 if (STp->dirty == 1) {
3010
3011 STp->write_count++;
3012 STps = &(STp->ps[STp->partition]);
3013 STps->rw = ST_WRITING;
3014 offset = STp->buffer->buffer_bytes;
3015 blks = (offset + STp->block_size - 1) / STp->block_size;
3016 transfer = OS_FRAME_SIZE;
3017
3018 if (offset < OS_DATA_SIZE)
3019 osst_zero_buffer_tail(STp->buffer);
3020
3021 if (STp->poll)
3022 if (osst_wait_frame (STp, aSRpnt, STp->first_frame_position, -50, 120))
3023 result = osst_recover_wait_frame(STp, aSRpnt, 1);
3024
3025 memset(cmd, 0, MAX_COMMAND_SIZE);
3026 cmd[0] = WRITE_6;
3027 cmd[1] = 1;
3028 cmd[4] = 1;
3029
3030 switch (STp->write_type) {
3031 case OS_WRITE_DATA:
3032#if DEBUG
3033 if (debugging)
3034 printk(OSST_DEB_MSG "%s:D: Writing %d blocks to frame %d, lblks %d-%d\n",
3035 name, blks, STp->frame_seq_number,
3036 STp->logical_blk_num - blks, STp->logical_blk_num - 1);
3037#endif
3038 osst_init_aux(STp, OS_FRAME_TYPE_DATA, STp->frame_seq_number++,
3039 STp->logical_blk_num - blks, STp->block_size, blks);
3040 break;
3041 case OS_WRITE_EOD:
3042 osst_init_aux(STp, OS_FRAME_TYPE_EOD, STp->frame_seq_number++,
3043 STp->logical_blk_num, 0, 0);
3044 break;
3045 case OS_WRITE_NEW_MARK:
3046 osst_init_aux(STp, OS_FRAME_TYPE_MARKER, STp->frame_seq_number++,
3047 STp->logical_blk_num++, 0, blks=1);
3048 break;
3049 case OS_WRITE_HEADER:
3050 osst_init_aux(STp, OS_FRAME_TYPE_HEADER, 0, 0, 0, blks=0);
3051 break;
3052 default: /* probably FILLER */
3053 osst_init_aux(STp, OS_FRAME_TYPE_FILL, 0, 0, 0, 0);
3054 }
3055#if DEBUG
3056 if (debugging)
3057 printk(OSST_DEB_MSG "%s:D: Flushing %d bytes, Transfering %d bytes in %d lblocks.\n",
3058 name, offset, transfer, blks);
3059#endif
3060
3061 SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, transfer, DMA_TO_DEVICE,
3062 STp->timeout, MAX_RETRIES, 1);
3063 *aSRpnt = SRpnt;
3064 if (!SRpnt)
3065 return (-EBUSY);
3066
3067 if ((STp->buffer)->syscall_result != 0) {
3068#if DEBUG
3069 printk(OSST_DEB_MSG
3070 "%s:D: write sense [0]=0x%02x [2]=%02x [12]=%02x [13]=%02x\n",
Willem Riede5e6575c2006-02-11 14:46:56 -05003071 name, SRpnt->sense[0], SRpnt->sense[2],
3072 SRpnt->sense[12], SRpnt->sense[13]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003073#endif
Willem Riede5e6575c2006-02-11 14:46:56 -05003074 if ((SRpnt->sense[0] & 0x70) == 0x70 &&
3075 (SRpnt->sense[2] & 0x40) && /* FIXME - SC-30 drive doesn't assert EOM bit */
3076 (SRpnt->sense[2] & 0x0f) == NO_SENSE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003077 STp->dirty = 0;
3078 (STp->buffer)->buffer_bytes = 0;
3079 result = (-ENOSPC);
3080 }
3081 else {
3082 if (osst_write_error_recovery(STp, aSRpnt, 1)) {
3083 printk(KERN_ERR "%s:E: Error on flush write.\n", name);
3084 result = (-EIO);
3085 }
3086 }
3087 STps->drv_block = (-1); /* FIXME - even if write recovery succeeds? */
3088 }
3089 else {
3090 STp->first_frame_position++;
3091 STp->dirty = 0;
3092 (STp->buffer)->buffer_bytes = 0;
3093 }
3094 }
3095#if DEBUG
3096 printk(OSST_DEB_MSG "%s:D: Exit flush write buffer with code %d\n", name, result);
3097#endif
3098 return result;
3099}
3100
3101
3102/* Flush the tape buffer. The tape will be positioned correctly unless
3103 seek_next is true. */
Willem Riede5e6575c2006-02-11 14:46:56 -05003104static int osst_flush_buffer(struct osst_tape * STp, struct osst_request ** aSRpnt, int seek_next)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003105{
3106 struct st_partstat * STps;
3107 int backspace = 0, result = 0;
3108#if DEBUG
3109 char * name = tape_name(STp);
3110#endif
3111
3112 /*
3113 * If there was a bus reset, block further access
3114 * to this device.
3115 */
3116 if( STp->pos_unknown)
3117 return (-EIO);
3118
3119 if (STp->ready != ST_READY)
3120 return 0;
3121
3122 STps = &(STp->ps[STp->partition]);
3123 if (STps->rw == ST_WRITING || STp->dirty) { /* Writing */
3124 STp->write_type = OS_WRITE_DATA;
3125 return osst_flush_write_buffer(STp, aSRpnt);
3126 }
3127 if (STp->block_size == 0)
3128 return 0;
3129
3130#if DEBUG
3131 printk(OSST_DEB_MSG "%s:D: Reached flush (read) buffer\n", name);
3132#endif
3133
3134 if (!STp->can_bsr) {
3135 backspace = ((STp->buffer)->buffer_bytes + (STp->buffer)->read_pointer) / STp->block_size -
3136 ((STp->buffer)->read_pointer + STp->block_size - 1 ) / STp->block_size ;
3137 (STp->buffer)->buffer_bytes = 0;
3138 (STp->buffer)->read_pointer = 0;
3139 STp->frame_in_buffer = 0; /* FIXME is this relevant w. OSST? */
3140 }
3141
3142 if (!seek_next) {
3143 if (STps->eof == ST_FM_HIT) {
3144 result = cross_eof(STp, aSRpnt, 0); /* Back over the EOF hit */
3145 if (!result)
3146 STps->eof = ST_NOEOF;
3147 else {
3148 if (STps->drv_file >= 0)
3149 STps->drv_file++;
3150 STps->drv_block = 0;
3151 }
3152 }
3153 if (!result && backspace > 0) /* TODO -- design and run a test case for this */
3154 result = osst_seek_logical_blk(STp, aSRpnt, STp->logical_blk_num - backspace);
3155 }
3156 else if (STps->eof == ST_FM_HIT) {
3157 if (STps->drv_file >= 0)
3158 STps->drv_file++;
3159 STps->drv_block = 0;
3160 STps->eof = ST_NOEOF;
3161 }
3162
3163 return result;
3164}
3165
Willem Riede5e6575c2006-02-11 14:46:56 -05003166static int osst_write_frame(struct osst_tape * STp, struct osst_request ** aSRpnt, int synchronous)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003167{
3168 unsigned char cmd[MAX_COMMAND_SIZE];
Willem Riede5e6575c2006-02-11 14:46:56 -05003169 struct osst_request * SRpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003170 int blks;
3171#if DEBUG
3172 char * name = tape_name(STp);
3173#endif
3174
3175 if ((!STp-> raw) && (STp->first_frame_position == 0xbae)) { /* _must_ preserve buffer! */
3176#if DEBUG
3177 printk(OSST_DEB_MSG "%s:D: Reaching config partition.\n", name);
3178#endif
3179 if (osst_flush_drive_buffer(STp, aSRpnt) < 0) {
3180 return (-EIO);
3181 }
3182 /* error recovery may have bumped us past the header partition */
3183 if (osst_get_frame_position(STp, aSRpnt) < 0xbb8) {
3184#if DEBUG
3185 printk(OSST_DEB_MSG "%s:D: Skipping over config partition.\n", name);
3186#endif
3187 osst_position_tape_and_confirm(STp, aSRpnt, 0xbb8);
3188 }
3189 }
3190
3191 if (STp->poll)
3192 if (osst_wait_frame (STp, aSRpnt, STp->first_frame_position, -48, 120))
3193 if (osst_recover_wait_frame(STp, aSRpnt, 1))
3194 return (-EIO);
3195
3196// osst_build_stats(STp, &SRpnt);
3197
3198 STp->ps[STp->partition].rw = ST_WRITING;
3199 STp->write_type = OS_WRITE_DATA;
3200
3201 memset(cmd, 0, MAX_COMMAND_SIZE);
3202 cmd[0] = WRITE_6;
3203 cmd[1] = 1;
3204 cmd[4] = 1; /* one frame at a time... */
3205 blks = STp->buffer->buffer_bytes / STp->block_size;
3206#if DEBUG
3207 if (debugging)
3208 printk(OSST_DEB_MSG "%s:D: Writing %d blocks to frame %d, lblks %d-%d\n", name, blks,
3209 STp->frame_seq_number, STp->logical_blk_num - blks, STp->logical_blk_num - 1);
3210#endif
3211 osst_init_aux(STp, OS_FRAME_TYPE_DATA, STp->frame_seq_number++,
3212 STp->logical_blk_num - blks, STp->block_size, blks);
3213
3214#if DEBUG
3215 if (!synchronous)
3216 STp->write_pending = 1;
3217#endif
3218 SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, OS_FRAME_SIZE, DMA_TO_DEVICE, STp->timeout,
3219 MAX_RETRIES, synchronous);
3220 if (!SRpnt)
3221 return (-EBUSY);
3222 *aSRpnt = SRpnt;
3223
3224 if (synchronous) {
3225 if (STp->buffer->syscall_result != 0) {
3226#if DEBUG
3227 if (debugging)
3228 printk(OSST_DEB_MSG "%s:D: Error on write:\n", name);
3229#endif
Willem Riede5e6575c2006-02-11 14:46:56 -05003230 if ((SRpnt->sense[0] & 0x70) == 0x70 &&
3231 (SRpnt->sense[2] & 0x40)) {
3232 if ((SRpnt->sense[2] & 0x0f) == VOLUME_OVERFLOW)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003233 return (-ENOSPC);
3234 }
3235 else {
3236 if (osst_write_error_recovery(STp, aSRpnt, 1))
3237 return (-EIO);
3238 }
3239 }
3240 else
3241 STp->first_frame_position++;
3242 }
3243
3244 STp->write_count++;
3245
3246 return 0;
3247}
3248
Willem Riede5e6575c2006-02-11 14:46:56 -05003249/* Lock or unlock the drive door. Don't use when struct osst_request allocated. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003250static int do_door_lock(struct osst_tape * STp, int do_lock)
3251{
3252 int retval, cmd;
3253
3254 cmd = do_lock ? SCSI_IOCTL_DOORLOCK : SCSI_IOCTL_DOORUNLOCK;
3255#if DEBUG
3256 printk(OSST_DEB_MSG "%s:D: %socking drive door.\n", tape_name(STp), do_lock ? "L" : "Unl");
3257#endif
3258 retval = scsi_ioctl(STp->device, cmd, NULL);
3259 if (!retval) {
3260 STp->door_locked = do_lock ? ST_LOCKED_EXPLICIT : ST_UNLOCKED;
3261 }
3262 else {
3263 STp->door_locked = ST_LOCK_FAILS;
3264 }
3265 return retval;
3266}
3267
3268/* Set the internal state after reset */
3269static void reset_state(struct osst_tape *STp)
3270{
3271 int i;
3272 struct st_partstat *STps;
3273
3274 STp->pos_unknown = 0;
3275 for (i = 0; i < ST_NBR_PARTITIONS; i++) {
3276 STps = &(STp->ps[i]);
3277 STps->rw = ST_IDLE;
3278 STps->eof = ST_NOEOF;
3279 STps->at_sm = 0;
3280 STps->last_block_valid = 0;
3281 STps->drv_block = -1;
3282 STps->drv_file = -1;
3283 }
3284}
3285
3286
3287/* Entry points to osst */
3288
3289/* Write command */
3290static ssize_t osst_write(struct file * filp, const char __user * buf, size_t count, loff_t *ppos)
3291{
3292 ssize_t total, retval = 0;
3293 ssize_t i, do_count, blks, transfer;
3294 int write_threshold;
3295 int doing_write = 0;
3296 const char __user * b_point;
Willem Riede5e6575c2006-02-11 14:46:56 -05003297 struct osst_request * SRpnt = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003298 struct st_modedef * STm;
3299 struct st_partstat * STps;
3300 struct osst_tape * STp = filp->private_data;
3301 char * name = tape_name(STp);
3302
3303
Matthias Kaehlcke4390e602007-08-10 14:50:44 -07003304 if (mutex_lock_interruptible(&STp->lock))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003305 return (-ERESTARTSYS);
3306
3307 /*
3308 * If we are in the middle of error recovery, don't let anyone
3309 * else try and use this device. Also, if error recovery fails, it
3310 * may try and take the device offline, in which case all further
3311 * access to the device is prohibited.
3312 */
3313 if( !scsi_block_when_processing_errors(STp->device) ) {
3314 retval = (-ENXIO);
3315 goto out;
3316 }
3317
3318 if (STp->ready != ST_READY) {
3319 if (STp->ready == ST_NO_TAPE)
3320 retval = (-ENOMEDIUM);
3321 else
3322 retval = (-EIO);
3323 goto out;
3324 }
3325 STm = &(STp->modes[STp->current_mode]);
3326 if (!STm->defined) {
3327 retval = (-ENXIO);
3328 goto out;
3329 }
3330 if (count == 0)
3331 goto out;
3332
3333 /*
3334 * If there was a bus reset, block further access
3335 * to this device.
3336 */
3337 if (STp->pos_unknown) {
3338 retval = (-EIO);
3339 goto out;
3340 }
3341
3342#if DEBUG
3343 if (!STp->in_use) {
3344 printk(OSST_DEB_MSG "%s:D: Incorrect device.\n", name);
3345 retval = (-EIO);
3346 goto out;
3347 }
3348#endif
3349
3350 if (STp->write_prot) {
3351 retval = (-EACCES);
3352 goto out;
3353 }
3354
3355 /* Write must be integral number of blocks */
3356 if (STp->block_size != 0 && (count % STp->block_size) != 0) {
3357 printk(KERN_ERR "%s:E: Write (%Zd bytes) not multiple of tape block size (%d%c).\n",
3358 name, count, STp->block_size<1024?
3359 STp->block_size:STp->block_size/1024, STp->block_size<1024?'b':'k');
3360 retval = (-EINVAL);
3361 goto out;
3362 }
3363
3364 if (STp->first_frame_position >= STp->capacity - OSST_EOM_RESERVE) {
3365 printk(KERN_ERR "%s:E: Write truncated at EOM early warning (frame %d).\n",
3366 name, STp->first_frame_position);
3367 retval = (-ENOSPC);
3368 goto out;
3369 }
3370
3371 if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED && !do_door_lock(STp, 1))
3372 STp->door_locked = ST_LOCKED_AUTO;
3373
3374 STps = &(STp->ps[STp->partition]);
3375
3376 if (STps->rw == ST_READING) {
3377#if DEBUG
3378 printk(OSST_DEB_MSG "%s:D: Switching from read to write at file %d, block %d\n", name,
3379 STps->drv_file, STps->drv_block);
3380#endif
3381 retval = osst_flush_buffer(STp, &SRpnt, 0);
3382 if (retval)
3383 goto out;
3384 STps->rw = ST_IDLE;
3385 }
3386 if (STps->rw != ST_WRITING) {
3387 /* Are we totally rewriting this tape? */
3388 if (!STp->header_ok ||
3389 (STp->first_frame_position == STp->first_data_ppos && STps->drv_block < 0) ||
3390 (STps->drv_file == 0 && STps->drv_block == 0)) {
3391 STp->wrt_pass_cntr++;
3392#if DEBUG
3393 printk(OSST_DEB_MSG "%s:D: Allocating next write pass counter: %d\n",
3394 name, STp->wrt_pass_cntr);
3395#endif
3396 osst_reset_header(STp, &SRpnt);
3397 STps->drv_file = STps->drv_block = 0;
3398 }
3399 /* Do we know where we'll be writing on the tape? */
3400 else {
3401 if ((STp->fast_open && osst_verify_position(STp, &SRpnt)) ||
3402 STps->drv_file < 0 || STps->drv_block < 0) {
3403 if (STp->first_frame_position == STp->eod_frame_ppos) { /* at EOD */
3404 STps->drv_file = STp->filemark_cnt;
3405 STps->drv_block = 0;
3406 }
3407 else {
3408 /* We have no idea where the tape is positioned - give up */
3409#if DEBUG
3410 printk(OSST_DEB_MSG
3411 "%s:D: Cannot write at indeterminate position.\n", name);
3412#endif
3413 retval = (-EIO);
3414 goto out;
3415 }
3416 }
3417 if ((STps->drv_file + STps->drv_block) > 0 && STps->drv_file < STp->filemark_cnt) {
3418 STp->filemark_cnt = STps->drv_file;
3419 STp->last_mark_ppos =
3420 ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[STp->filemark_cnt-1]);
3421 printk(KERN_WARNING
3422 "%s:W: Overwriting file %d with old write pass counter %d\n",
3423 name, STps->drv_file, STp->wrt_pass_cntr);
3424 printk(KERN_WARNING
3425 "%s:W: may lead to stale data being accepted on reading back!\n",
3426 name);
3427#if DEBUG
3428 printk(OSST_DEB_MSG
3429 "%s:D: resetting filemark count to %d and last mark ppos,lbn to %d,%d\n",
3430 name, STp->filemark_cnt, STp->last_mark_ppos, STp->last_mark_lbn);
3431#endif
3432 }
3433 }
3434 STp->fast_open = 0;
3435 }
3436 if (!STp->header_ok) {
3437#if DEBUG
3438 printk(OSST_DEB_MSG "%s:D: Write cannot proceed without valid headers\n", name);
3439#endif
3440 retval = (-EIO);
3441 goto out;
3442 }
3443
3444 if ((STp->buffer)->writing) {
3445if (SRpnt) printk(KERN_ERR "%s:A: Not supposed to have SRpnt at line %d\n", name, __LINE__);
3446 osst_write_behind_check(STp);
3447 if ((STp->buffer)->syscall_result) {
3448#if DEBUG
3449 if (debugging)
3450 printk(OSST_DEB_MSG "%s:D: Async write error (write) %x.\n", name,
3451 (STp->buffer)->midlevel_result);
3452#endif
3453 if ((STp->buffer)->midlevel_result == INT_MAX)
3454 STps->eof = ST_EOM_OK;
3455 else
3456 STps->eof = ST_EOM_ERROR;
3457 }
3458 }
3459 if (STps->eof == ST_EOM_OK) {
3460 retval = (-ENOSPC);
3461 goto out;
3462 }
3463 else if (STps->eof == ST_EOM_ERROR) {
3464 retval = (-EIO);
3465 goto out;
3466 }
3467
3468 /* Check the buffer readability in cases where copy_user might catch
3469 the problems after some tape movement. */
3470 if ((copy_from_user(&i, buf, 1) != 0 ||
3471 copy_from_user(&i, buf + count - 1, 1) != 0)) {
3472 retval = (-EFAULT);
3473 goto out;
3474 }
3475
3476 if (!STm->do_buffer_writes) {
3477 write_threshold = 1;
3478 }
3479 else
3480 write_threshold = (STp->buffer)->buffer_blocks * STp->block_size;
3481 if (!STm->do_async_writes)
3482 write_threshold--;
3483
3484 total = count;
3485#if DEBUG
3486 if (debugging)
3487 printk(OSST_DEB_MSG "%s:D: Writing %d bytes to file %d block %d lblk %d fseq %d fppos %d\n",
Willem Riede5e6575c2006-02-11 14:46:56 -05003488 name, (int) count, STps->drv_file, STps->drv_block,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003489 STp->logical_blk_num, STp->frame_seq_number, STp->first_frame_position);
3490#endif
3491 b_point = buf;
3492 while ((STp->buffer)->buffer_bytes + count > write_threshold)
3493 {
3494 doing_write = 1;
3495 do_count = (STp->buffer)->buffer_blocks * STp->block_size -
3496 (STp->buffer)->buffer_bytes;
3497 if (do_count > count)
3498 do_count = count;
3499
3500 i = append_to_buffer(b_point, STp->buffer, do_count);
3501 if (i) {
3502 retval = i;
3503 goto out;
3504 }
3505
3506 blks = do_count / STp->block_size;
3507 STp->logical_blk_num += blks; /* logical_blk_num is incremented as data is moved from user */
3508
3509 i = osst_write_frame(STp, &SRpnt, 1);
3510
3511 if (i == (-ENOSPC)) {
3512 transfer = STp->buffer->writing; /* FIXME -- check this logic */
3513 if (transfer <= do_count) {
3514 filp->f_pos += do_count - transfer;
3515 count -= do_count - transfer;
3516 if (STps->drv_block >= 0) {
3517 STps->drv_block += (do_count - transfer) / STp->block_size;
3518 }
3519 STps->eof = ST_EOM_OK;
3520 retval = (-ENOSPC); /* EOM within current request */
3521#if DEBUG
3522 if (debugging)
3523 printk(OSST_DEB_MSG "%s:D: EOM with %d bytes unwritten.\n",
Willem Riede5e6575c2006-02-11 14:46:56 -05003524 name, (int) transfer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003525#endif
3526 }
3527 else {
3528 STps->eof = ST_EOM_ERROR;
3529 STps->drv_block = (-1); /* Too cautious? */
3530 retval = (-EIO); /* EOM for old data */
3531#if DEBUG
3532 if (debugging)
3533 printk(OSST_DEB_MSG "%s:D: EOM with lost data.\n", name);
3534#endif
3535 }
3536 }
3537 else
3538 retval = i;
3539
3540 if (retval < 0) {
3541 if (SRpnt != NULL) {
Willem Riede5e6575c2006-02-11 14:46:56 -05003542 osst_release_request(SRpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003543 SRpnt = NULL;
3544 }
3545 STp->buffer->buffer_bytes = 0;
3546 STp->dirty = 0;
3547 if (count < total)
3548 retval = total - count;
3549 goto out;
3550 }
3551
3552 filp->f_pos += do_count;
3553 b_point += do_count;
3554 count -= do_count;
3555 if (STps->drv_block >= 0) {
3556 STps->drv_block += blks;
3557 }
3558 STp->buffer->buffer_bytes = 0;
3559 STp->dirty = 0;
3560 } /* end while write threshold exceeded */
3561
3562 if (count != 0) {
3563 STp->dirty = 1;
3564 i = append_to_buffer(b_point, STp->buffer, count);
3565 if (i) {
3566 retval = i;
3567 goto out;
3568 }
3569 blks = count / STp->block_size;
3570 STp->logical_blk_num += blks;
3571 if (STps->drv_block >= 0) {
3572 STps->drv_block += blks;
3573 }
3574 filp->f_pos += count;
3575 count = 0;
3576 }
3577
3578 if (doing_write && (STp->buffer)->syscall_result != 0) {
3579 retval = (STp->buffer)->syscall_result;
3580 goto out;
3581 }
3582
3583 if (STm->do_async_writes && ((STp->buffer)->buffer_bytes >= STp->write_threshold)) {
3584 /* Schedule an asynchronous write */
3585 (STp->buffer)->writing = ((STp->buffer)->buffer_bytes /
3586 STp->block_size) * STp->block_size;
3587 STp->dirty = !((STp->buffer)->writing ==
3588 (STp->buffer)->buffer_bytes);
3589
3590 i = osst_write_frame(STp, &SRpnt, 0);
3591 if (i < 0) {
3592 retval = (-EIO);
3593 goto out;
3594 }
3595 SRpnt = NULL; /* Prevent releasing this request! */
3596 }
3597 STps->at_sm &= (total == 0);
3598 if (total > 0)
3599 STps->eof = ST_NOEOF;
3600
3601 retval = total;
3602
3603out:
Willem Riede5e6575c2006-02-11 14:46:56 -05003604 if (SRpnt != NULL) osst_release_request(SRpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003605
Matthias Kaehlcke4390e602007-08-10 14:50:44 -07003606 mutex_unlock(&STp->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003607
3608 return retval;
3609}
3610
3611
3612/* Read command */
3613static ssize_t osst_read(struct file * filp, char __user * buf, size_t count, loff_t *ppos)
3614{
3615 ssize_t total, retval = 0;
3616 ssize_t i, transfer;
3617 int special;
3618 struct st_modedef * STm;
3619 struct st_partstat * STps;
Willem Riede5e6575c2006-02-11 14:46:56 -05003620 struct osst_request * SRpnt = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003621 struct osst_tape * STp = filp->private_data;
3622 char * name = tape_name(STp);
3623
3624
Matthias Kaehlcke4390e602007-08-10 14:50:44 -07003625 if (mutex_lock_interruptible(&STp->lock))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003626 return (-ERESTARTSYS);
3627
3628 /*
3629 * If we are in the middle of error recovery, don't let anyone
3630 * else try and use this device. Also, if error recovery fails, it
3631 * may try and take the device offline, in which case all further
3632 * access to the device is prohibited.
3633 */
3634 if( !scsi_block_when_processing_errors(STp->device) ) {
3635 retval = (-ENXIO);
3636 goto out;
3637 }
3638
3639 if (STp->ready != ST_READY) {
3640 if (STp->ready == ST_NO_TAPE)
3641 retval = (-ENOMEDIUM);
3642 else
3643 retval = (-EIO);
3644 goto out;
3645 }
3646 STm = &(STp->modes[STp->current_mode]);
3647 if (!STm->defined) {
3648 retval = (-ENXIO);
3649 goto out;
3650 }
3651#if DEBUG
3652 if (!STp->in_use) {
3653 printk(OSST_DEB_MSG "%s:D: Incorrect device.\n", name);
3654 retval = (-EIO);
3655 goto out;
3656 }
3657#endif
3658 /* Must have initialized medium */
3659 if (!STp->header_ok) {
3660 retval = (-EIO);
3661 goto out;
3662 }
3663
3664 if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED && !do_door_lock(STp, 1))
3665 STp->door_locked = ST_LOCKED_AUTO;
3666
3667 STps = &(STp->ps[STp->partition]);
3668 if (STps->rw == ST_WRITING) {
3669 retval = osst_flush_buffer(STp, &SRpnt, 0);
3670 if (retval)
3671 goto out;
3672 STps->rw = ST_IDLE;
3673 /* FIXME -- this may leave the tape without EOD and up2date headers */
3674 }
3675
3676 if ((count % STp->block_size) != 0) {
3677 printk(KERN_WARNING
3678 "%s:W: Read (%Zd bytes) not multiple of tape block size (%d%c).\n", name, count,
3679 STp->block_size<1024?STp->block_size:STp->block_size/1024, STp->block_size<1024?'b':'k');
3680 }
3681
3682#if DEBUG
3683 if (debugging && STps->eof != ST_NOEOF)
3684 printk(OSST_DEB_MSG "%s:D: EOF/EOM flag up (%d). Bytes %d\n", name,
3685 STps->eof, (STp->buffer)->buffer_bytes);
3686#endif
3687 if ((STp->buffer)->buffer_bytes == 0 &&
3688 STps->eof >= ST_EOD_1) {
3689 if (STps->eof < ST_EOD) {
3690 STps->eof += 1;
3691 retval = 0;
3692 goto out;
3693 }
3694 retval = (-EIO); /* EOM or Blank Check */
3695 goto out;
3696 }
3697
3698 /* Check the buffer writability before any tape movement. Don't alter
3699 buffer data. */
3700 if (copy_from_user(&i, buf, 1) != 0 ||
3701 copy_to_user (buf, &i, 1) != 0 ||
3702 copy_from_user(&i, buf + count - 1, 1) != 0 ||
3703 copy_to_user (buf + count - 1, &i, 1) != 0) {
3704 retval = (-EFAULT);
3705 goto out;
3706 }
3707
3708 /* Loop until enough data in buffer or a special condition found */
3709 for (total = 0, special = 0; total < count - STp->block_size + 1 && !special; ) {
3710
3711 /* Get new data if the buffer is empty */
3712 if ((STp->buffer)->buffer_bytes == 0) {
3713 if (STps->eof == ST_FM_HIT)
3714 break;
3715 special = osst_get_logical_frame(STp, &SRpnt, STp->frame_seq_number, 0);
3716 if (special < 0) { /* No need to continue read */
3717 STp->frame_in_buffer = 0;
3718 retval = special;
3719 goto out;
3720 }
3721 }
3722
3723 /* Move the data from driver buffer to user buffer */
3724 if ((STp->buffer)->buffer_bytes > 0) {
3725#if DEBUG
3726 if (debugging && STps->eof != ST_NOEOF)
3727 printk(OSST_DEB_MSG "%s:D: EOF up (%d). Left %d, needed %d.\n", name,
Willem Riede5e6575c2006-02-11 14:46:56 -05003728 STps->eof, (STp->buffer)->buffer_bytes, (int) (count - total));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003729#endif
3730 /* force multiple of block size, note block_size may have been adjusted */
3731 transfer = (((STp->buffer)->buffer_bytes < count - total ?
3732 (STp->buffer)->buffer_bytes : count - total)/
3733 STp->block_size) * STp->block_size;
3734
3735 if (transfer == 0) {
3736 printk(KERN_WARNING
3737 "%s:W: Nothing can be transfered, requested %Zd, tape block size (%d%c).\n",
3738 name, count, STp->block_size < 1024?
3739 STp->block_size:STp->block_size/1024,
3740 STp->block_size<1024?'b':'k');
3741 break;
3742 }
3743 i = from_buffer(STp->buffer, buf, transfer);
3744 if (i) {
3745 retval = i;
3746 goto out;
3747 }
3748 STp->logical_blk_num += transfer / STp->block_size;
3749 STps->drv_block += transfer / STp->block_size;
3750 filp->f_pos += transfer;
3751 buf += transfer;
3752 total += transfer;
3753 }
3754
3755 if ((STp->buffer)->buffer_bytes == 0) {
3756#if DEBUG
3757 if (debugging)
3758 printk(OSST_DEB_MSG "%s:D: Finished with frame %d\n",
3759 name, STp->frame_seq_number);
3760#endif
3761 STp->frame_in_buffer = 0;
3762 STp->frame_seq_number++; /* frame to look for next time */
3763 }
3764 } /* for (total = 0, special = 0; total < count && !special; ) */
3765
3766 /* Change the eof state if no data from tape or buffer */
3767 if (total == 0) {
3768 if (STps->eof == ST_FM_HIT) {
3769 STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD_2:ST_FM;
3770 STps->drv_block = 0;
3771 if (STps->drv_file >= 0)
3772 STps->drv_file++;
3773 }
3774 else if (STps->eof == ST_EOD_1) {
3775 STps->eof = ST_EOD_2;
3776 if (STps->drv_block > 0 && STps->drv_file >= 0)
3777 STps->drv_file++;
3778 STps->drv_block = 0;
3779 }
3780 else if (STps->eof == ST_EOD_2)
3781 STps->eof = ST_EOD;
3782 }
3783 else if (STps->eof == ST_FM)
3784 STps->eof = ST_NOEOF;
3785
3786 retval = total;
3787
3788out:
Willem Riede5e6575c2006-02-11 14:46:56 -05003789 if (SRpnt != NULL) osst_release_request(SRpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003790
Matthias Kaehlcke4390e602007-08-10 14:50:44 -07003791 mutex_unlock(&STp->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003792
3793 return retval;
3794}
3795
3796
3797/* Set the driver options */
3798static void osst_log_options(struct osst_tape *STp, struct st_modedef *STm, char *name)
3799{
3800 printk(KERN_INFO
3801"%s:I: Mode %d options: buffer writes: %d, async writes: %d, read ahead: %d\n",
3802 name, STp->current_mode, STm->do_buffer_writes, STm->do_async_writes,
3803 STm->do_read_ahead);
3804 printk(KERN_INFO
3805"%s:I: can bsr: %d, two FMs: %d, fast mteom: %d, auto lock: %d,\n",
3806 name, STp->can_bsr, STp->two_fm, STp->fast_mteom, STp->do_auto_lock);
3807 printk(KERN_INFO
3808"%s:I: defs for wr: %d, no block limits: %d, partitions: %d, s2 log: %d\n",
3809 name, STm->defaults_for_writes, STp->omit_blklims, STp->can_partitions,
3810 STp->scsi2_logical);
3811 printk(KERN_INFO
3812"%s:I: sysv: %d\n", name, STm->sysv);
3813#if DEBUG
3814 printk(KERN_INFO
3815 "%s:D: debugging: %d\n",
3816 name, debugging);
3817#endif
3818}
3819
3820
3821static int osst_set_options(struct osst_tape *STp, long options)
3822{
3823 int value;
3824 long code;
3825 struct st_modedef * STm;
3826 char * name = tape_name(STp);
3827
3828 STm = &(STp->modes[STp->current_mode]);
3829 if (!STm->defined) {
3830 memcpy(STm, &(STp->modes[0]), sizeof(*STm));
3831 modes_defined = 1;
3832#if DEBUG
3833 if (debugging)
3834 printk(OSST_DEB_MSG "%s:D: Initialized mode %d definition from mode 0\n",
3835 name, STp->current_mode);
3836#endif
3837 }
3838
3839 code = options & MT_ST_OPTIONS;
3840 if (code == MT_ST_BOOLEANS) {
3841 STm->do_buffer_writes = (options & MT_ST_BUFFER_WRITES) != 0;
3842 STm->do_async_writes = (options & MT_ST_ASYNC_WRITES) != 0;
3843 STm->defaults_for_writes = (options & MT_ST_DEF_WRITES) != 0;
3844 STm->do_read_ahead = (options & MT_ST_READ_AHEAD) != 0;
3845 STp->two_fm = (options & MT_ST_TWO_FM) != 0;
3846 STp->fast_mteom = (options & MT_ST_FAST_MTEOM) != 0;
3847 STp->do_auto_lock = (options & MT_ST_AUTO_LOCK) != 0;
3848 STp->can_bsr = (options & MT_ST_CAN_BSR) != 0;
3849 STp->omit_blklims = (options & MT_ST_NO_BLKLIMS) != 0;
3850 if ((STp->device)->scsi_level >= SCSI_2)
3851 STp->can_partitions = (options & MT_ST_CAN_PARTITIONS) != 0;
3852 STp->scsi2_logical = (options & MT_ST_SCSI2LOGICAL) != 0;
3853 STm->sysv = (options & MT_ST_SYSV) != 0;
3854#if DEBUG
3855 debugging = (options & MT_ST_DEBUGGING) != 0;
3856#endif
3857 osst_log_options(STp, STm, name);
3858 }
3859 else if (code == MT_ST_SETBOOLEANS || code == MT_ST_CLEARBOOLEANS) {
3860 value = (code == MT_ST_SETBOOLEANS);
3861 if ((options & MT_ST_BUFFER_WRITES) != 0)
3862 STm->do_buffer_writes = value;
3863 if ((options & MT_ST_ASYNC_WRITES) != 0)
3864 STm->do_async_writes = value;
3865 if ((options & MT_ST_DEF_WRITES) != 0)
3866 STm->defaults_for_writes = value;
3867 if ((options & MT_ST_READ_AHEAD) != 0)
3868 STm->do_read_ahead = value;
3869 if ((options & MT_ST_TWO_FM) != 0)
3870 STp->two_fm = value;
3871 if ((options & MT_ST_FAST_MTEOM) != 0)
3872 STp->fast_mteom = value;
3873 if ((options & MT_ST_AUTO_LOCK) != 0)
3874 STp->do_auto_lock = value;
3875 if ((options & MT_ST_CAN_BSR) != 0)
3876 STp->can_bsr = value;
3877 if ((options & MT_ST_NO_BLKLIMS) != 0)
3878 STp->omit_blklims = value;
3879 if ((STp->device)->scsi_level >= SCSI_2 &&
3880 (options & MT_ST_CAN_PARTITIONS) != 0)
3881 STp->can_partitions = value;
3882 if ((options & MT_ST_SCSI2LOGICAL) != 0)
3883 STp->scsi2_logical = value;
3884 if ((options & MT_ST_SYSV) != 0)
3885 STm->sysv = value;
3886#if DEBUG
3887 if ((options & MT_ST_DEBUGGING) != 0)
3888 debugging = value;
3889#endif
3890 osst_log_options(STp, STm, name);
3891 }
3892 else if (code == MT_ST_WRITE_THRESHOLD) {
3893 value = (options & ~MT_ST_OPTIONS) * ST_KILOBYTE;
3894 if (value < 1 || value > osst_buffer_size) {
3895 printk(KERN_WARNING "%s:W: Write threshold %d too small or too large.\n",
3896 name, value);
3897 return (-EIO);
3898 }
3899 STp->write_threshold = value;
3900 printk(KERN_INFO "%s:I: Write threshold set to %d bytes.\n",
3901 name, value);
3902 }
3903 else if (code == MT_ST_DEF_BLKSIZE) {
3904 value = (options & ~MT_ST_OPTIONS);
3905 if (value == ~MT_ST_OPTIONS) {
3906 STm->default_blksize = (-1);
3907 printk(KERN_INFO "%s:I: Default block size disabled.\n", name);
3908 }
3909 else {
3910 if (value < 512 || value > OS_DATA_SIZE || OS_DATA_SIZE % value) {
3911 printk(KERN_WARNING "%s:W: Default block size cannot be set to %d.\n",
3912 name, value);
3913 return (-EINVAL);
3914 }
3915 STm->default_blksize = value;
3916 printk(KERN_INFO "%s:I: Default block size set to %d bytes.\n",
3917 name, STm->default_blksize);
3918 }
3919 }
3920 else if (code == MT_ST_TIMEOUTS) {
3921 value = (options & ~MT_ST_OPTIONS);
3922 if ((value & MT_ST_SET_LONG_TIMEOUT) != 0) {
3923 STp->long_timeout = (value & ~MT_ST_SET_LONG_TIMEOUT) * HZ;
3924 printk(KERN_INFO "%s:I: Long timeout set to %d seconds.\n", name,
3925 (value & ~MT_ST_SET_LONG_TIMEOUT));
3926 }
3927 else {
3928 STp->timeout = value * HZ;
3929 printk(KERN_INFO "%s:I: Normal timeout set to %d seconds.\n", name, value);
3930 }
3931 }
3932 else if (code == MT_ST_DEF_OPTIONS) {
3933 code = (options & ~MT_ST_CLEAR_DEFAULT);
3934 value = (options & MT_ST_CLEAR_DEFAULT);
3935 if (code == MT_ST_DEF_DENSITY) {
3936 if (value == MT_ST_CLEAR_DEFAULT) {
3937 STm->default_density = (-1);
3938 printk(KERN_INFO "%s:I: Density default disabled.\n", name);
3939 }
3940 else {
3941 STm->default_density = value & 0xff;
3942 printk(KERN_INFO "%s:I: Density default set to %x\n",
3943 name, STm->default_density);
3944 }
3945 }
3946 else if (code == MT_ST_DEF_DRVBUFFER) {
3947 if (value == MT_ST_CLEAR_DEFAULT) {
3948 STp->default_drvbuffer = 0xff;
3949 printk(KERN_INFO "%s:I: Drive buffer default disabled.\n", name);
3950 }
3951 else {
3952 STp->default_drvbuffer = value & 7;
3953 printk(KERN_INFO "%s:I: Drive buffer default set to %x\n",
3954 name, STp->default_drvbuffer);
3955 }
3956 }
3957 else if (code == MT_ST_DEF_COMPRESSION) {
3958 if (value == MT_ST_CLEAR_DEFAULT) {
3959 STm->default_compression = ST_DONT_TOUCH;
3960 printk(KERN_INFO "%s:I: Compression default disabled.\n", name);
3961 }
3962 else {
3963 STm->default_compression = (value & 1 ? ST_YES : ST_NO);
3964 printk(KERN_INFO "%s:I: Compression default set to %x\n",
3965 name, (value & 1));
3966 }
3967 }
3968 }
3969 else
3970 return (-EIO);
3971
3972 return 0;
3973}
3974
3975
3976/* Internal ioctl function */
Willem Riede5e6575c2006-02-11 14:46:56 -05003977static int osst_int_ioctl(struct osst_tape * STp, struct osst_request ** aSRpnt,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003978 unsigned int cmd_in, unsigned long arg)
3979{
3980 int timeout;
3981 long ltmp;
3982 int i, ioctl_result;
3983 int chg_eof = 1;
3984 unsigned char cmd[MAX_COMMAND_SIZE];
Willem Riede5e6575c2006-02-11 14:46:56 -05003985 struct osst_request * SRpnt = * aSRpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003986 struct st_partstat * STps;
3987 int fileno, blkno, at_sm, frame_seq_numbr, logical_blk_num;
3988 int datalen = 0, direction = DMA_NONE;
3989 char * name = tape_name(STp);
3990
3991 if (STp->ready != ST_READY && cmd_in != MTLOAD) {
3992 if (STp->ready == ST_NO_TAPE)
3993 return (-ENOMEDIUM);
3994 else
3995 return (-EIO);
3996 }
3997 timeout = STp->long_timeout;
3998 STps = &(STp->ps[STp->partition]);
3999 fileno = STps->drv_file;
4000 blkno = STps->drv_block;
4001 at_sm = STps->at_sm;
4002 frame_seq_numbr = STp->frame_seq_number;
4003 logical_blk_num = STp->logical_blk_num;
4004
4005 memset(cmd, 0, MAX_COMMAND_SIZE);
4006 switch (cmd_in) {
4007 case MTFSFM:
4008 chg_eof = 0; /* Changed from the FSF after this */
4009 case MTFSF:
4010 if (STp->raw)
4011 return (-EIO);
4012 if (STp->linux_media)
4013 ioctl_result = osst_space_over_filemarks_forward_fast(STp, &SRpnt, cmd_in, arg);
4014 else
4015 ioctl_result = osst_space_over_filemarks_forward_slow(STp, &SRpnt, cmd_in, arg);
4016 if (fileno >= 0)
4017 fileno += arg;
4018 blkno = 0;
4019 at_sm &= (arg == 0);
4020 goto os_bypass;
4021
4022 case MTBSF:
4023 chg_eof = 0; /* Changed from the FSF after this */
4024 case MTBSFM:
4025 if (STp->raw)
4026 return (-EIO);
4027 ioctl_result = osst_space_over_filemarks_backward(STp, &SRpnt, cmd_in, arg);
4028 if (fileno >= 0)
4029 fileno -= arg;
4030 blkno = (-1); /* We can't know the block number */
4031 at_sm &= (arg == 0);
4032 goto os_bypass;
4033
4034 case MTFSR:
4035 case MTBSR:
4036#if DEBUG
4037 if (debugging)
4038 printk(OSST_DEB_MSG "%s:D: Skipping %lu blocks %s from logical block %d\n",
4039 name, arg, cmd_in==MTFSR?"forward":"backward", logical_blk_num);
4040#endif
4041 if (cmd_in == MTFSR) {
4042 logical_blk_num += arg;
4043 if (blkno >= 0) blkno += arg;
4044 }
4045 else {
4046 logical_blk_num -= arg;
4047 if (blkno >= 0) blkno -= arg;
4048 }
4049 ioctl_result = osst_seek_logical_blk(STp, &SRpnt, logical_blk_num);
4050 fileno = STps->drv_file;
4051 blkno = STps->drv_block;
4052 at_sm &= (arg == 0);
4053 goto os_bypass;
4054
4055 case MTFSS:
4056 cmd[0] = SPACE;
4057 cmd[1] = 0x04; /* Space Setmarks */ /* FIXME -- OS can't do this? */
4058 cmd[2] = (arg >> 16);
4059 cmd[3] = (arg >> 8);
4060 cmd[4] = arg;
4061#if DEBUG
4062 if (debugging)
4063 printk(OSST_DEB_MSG "%s:D: Spacing tape forward %d setmarks.\n", name,
4064 cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
4065#endif
4066 if (arg != 0) {
4067 blkno = fileno = (-1);
4068 at_sm = 1;
4069 }
4070 break;
4071 case MTBSS:
4072 cmd[0] = SPACE;
4073 cmd[1] = 0x04; /* Space Setmarks */ /* FIXME -- OS can't do this? */
4074 ltmp = (-arg);
4075 cmd[2] = (ltmp >> 16);
4076 cmd[3] = (ltmp >> 8);
4077 cmd[4] = ltmp;
4078#if DEBUG
4079 if (debugging) {
4080 if (cmd[2] & 0x80)
4081 ltmp = 0xff000000;
4082 ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4];
4083 printk(OSST_DEB_MSG "%s:D: Spacing tape backward %ld setmarks.\n",
4084 name, (-ltmp));
4085 }
4086#endif
4087 if (arg != 0) {
4088 blkno = fileno = (-1);
4089 at_sm = 1;
4090 }
4091 break;
4092 case MTWEOF:
4093 if ((STps->rw == ST_WRITING || STp->dirty) && !STp->pos_unknown) {
4094 STp->write_type = OS_WRITE_DATA;
4095 ioctl_result = osst_flush_write_buffer(STp, &SRpnt);
4096 } else
4097 ioctl_result = 0;
4098#if DEBUG
4099 if (debugging)
4100 printk(OSST_DEB_MSG "%s:D: Writing %ld filemark(s).\n", name, arg);
4101#endif
4102 for (i=0; i<arg; i++)
4103 ioctl_result |= osst_write_filemark(STp, &SRpnt);
4104 if (fileno >= 0) fileno += arg;
4105 if (blkno >= 0) blkno = 0;
4106 goto os_bypass;
4107
4108 case MTWSM:
4109 if (STp->write_prot)
4110 return (-EACCES);
4111 if (!STp->raw)
4112 return 0;
4113 cmd[0] = WRITE_FILEMARKS; /* FIXME -- need OS version */
4114 if (cmd_in == MTWSM)
4115 cmd[1] = 2;
4116 cmd[2] = (arg >> 16);
4117 cmd[3] = (arg >> 8);
4118 cmd[4] = arg;
4119 timeout = STp->timeout;
4120#if DEBUG
4121 if (debugging)
4122 printk(OSST_DEB_MSG "%s:D: Writing %d setmark(s).\n", name,
4123 cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
4124#endif
4125 if (fileno >= 0)
4126 fileno += arg;
4127 blkno = 0;
4128 at_sm = (cmd_in == MTWSM);
4129 break;
4130 case MTOFFL:
4131 case MTLOAD:
4132 case MTUNLOAD:
4133 case MTRETEN:
4134 cmd[0] = START_STOP;
4135 cmd[1] = 1; /* Don't wait for completion */
4136 if (cmd_in == MTLOAD) {
4137 if (STp->ready == ST_NO_TAPE)
4138 cmd[4] = 4; /* open tray */
4139 else
4140 cmd[4] = 1; /* load */
4141 }
4142 if (cmd_in == MTRETEN)
4143 cmd[4] = 3; /* retension then mount */
4144 if (cmd_in == MTOFFL)
4145 cmd[4] = 4; /* rewind then eject */
4146 timeout = STp->timeout;
4147#if DEBUG
4148 if (debugging) {
4149 switch (cmd_in) {
4150 case MTUNLOAD:
4151 printk(OSST_DEB_MSG "%s:D: Unloading tape.\n", name);
4152 break;
4153 case MTLOAD:
4154 printk(OSST_DEB_MSG "%s:D: Loading tape.\n", name);
4155 break;
4156 case MTRETEN:
4157 printk(OSST_DEB_MSG "%s:D: Retensioning tape.\n", name);
4158 break;
4159 case MTOFFL:
4160 printk(OSST_DEB_MSG "%s:D: Ejecting tape.\n", name);
4161 break;
4162 }
4163 }
4164#endif
4165 fileno = blkno = at_sm = frame_seq_numbr = logical_blk_num = 0 ;
4166 break;
4167 case MTNOP:
4168#if DEBUG
4169 if (debugging)
4170 printk(OSST_DEB_MSG "%s:D: No-op on tape.\n", name);
4171#endif
4172 return 0; /* Should do something ? */
4173 break;
4174 case MTEOM:
4175#if DEBUG
4176 if (debugging)
4177 printk(OSST_DEB_MSG "%s:D: Spacing to end of recorded medium.\n", name);
4178#endif
4179 if ((osst_position_tape_and_confirm(STp, &SRpnt, STp->eod_frame_ppos) < 0) ||
4180 (osst_get_logical_frame(STp, &SRpnt, -1, 0) < 0)) {
4181 ioctl_result = -EIO;
4182 goto os_bypass;
4183 }
4184 if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_EOD) {
4185#if DEBUG
4186 printk(OSST_DEB_MSG "%s:D: No EOD frame found where expected.\n", name);
4187#endif
4188 ioctl_result = -EIO;
4189 goto os_bypass;
4190 }
4191 ioctl_result = osst_set_frame_position(STp, &SRpnt, STp->eod_frame_ppos, 0);
4192 fileno = STp->filemark_cnt;
4193 blkno = at_sm = 0;
4194 goto os_bypass;
4195
4196 case MTERASE:
4197 if (STp->write_prot)
4198 return (-EACCES);
4199 ioctl_result = osst_reset_header(STp, &SRpnt);
4200 i = osst_write_eod(STp, &SRpnt);
4201 if (i < ioctl_result) ioctl_result = i;
4202 i = osst_position_tape_and_confirm(STp, &SRpnt, STp->eod_frame_ppos);
4203 if (i < ioctl_result) ioctl_result = i;
4204 fileno = blkno = at_sm = 0 ;
4205 goto os_bypass;
4206
4207 case MTREW:
4208 cmd[0] = REZERO_UNIT; /* rewind */
4209 cmd[1] = 1;
4210#if DEBUG
4211 if (debugging)
4212 printk(OSST_DEB_MSG "%s:D: Rewinding tape, Immed=%d.\n", name, cmd[1]);
4213#endif
4214 fileno = blkno = at_sm = frame_seq_numbr = logical_blk_num = 0 ;
4215 break;
4216
4217 case MTSETBLK: /* Set block length */
4218 if ((STps->drv_block == 0 ) &&
4219 !STp->dirty &&
4220 ((STp->buffer)->buffer_bytes == 0) &&
4221 ((arg & MT_ST_BLKSIZE_MASK) >= 512 ) &&
4222 ((arg & MT_ST_BLKSIZE_MASK) <= OS_DATA_SIZE) &&
4223 !(OS_DATA_SIZE % (arg & MT_ST_BLKSIZE_MASK)) ) {
4224 /*
4225 * Only allowed to change the block size if you opened the
4226 * device at the beginning of a file before writing anything.
4227 * Note, that when reading, changing block_size is futile,
4228 * as the size used when writing overrides it.
4229 */
4230 STp->block_size = (arg & MT_ST_BLKSIZE_MASK);
4231 printk(KERN_INFO "%s:I: Block size set to %d bytes.\n",
4232 name, STp->block_size);
4233 return 0;
4234 }
4235 case MTSETDENSITY: /* Set tape density */
4236 case MTSETDRVBUFFER: /* Set drive buffering */
4237 case SET_DENS_AND_BLK: /* Set density and block size */
4238 chg_eof = 0;
4239 if (STp->dirty || (STp->buffer)->buffer_bytes != 0)
4240 return (-EIO); /* Not allowed if data in buffer */
4241 if ((cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) &&
4242 (arg & MT_ST_BLKSIZE_MASK) != 0 &&
4243 (arg & MT_ST_BLKSIZE_MASK) != STp->block_size ) {
4244 printk(KERN_WARNING "%s:W: Illegal to set block size to %d%s.\n",
4245 name, (int)(arg & MT_ST_BLKSIZE_MASK),
4246 (OS_DATA_SIZE % (arg & MT_ST_BLKSIZE_MASK))?"":" now");
4247 return (-EINVAL);
4248 }
4249 return 0; /* FIXME silently ignore if block size didn't change */
4250
4251 default:
4252 return (-ENOSYS);
4253 }
4254
4255 SRpnt = osst_do_scsi(SRpnt, STp, cmd, datalen, direction, timeout, MAX_RETRIES, 1);
4256
4257 ioctl_result = (STp->buffer)->syscall_result;
4258
4259 if (!SRpnt) {
4260#if DEBUG
4261 printk(OSST_DEB_MSG "%s:D: Couldn't exec scsi cmd for IOCTL\n", name);
4262#endif
4263 return ioctl_result;
4264 }
4265
4266 if (!ioctl_result) { /* SCSI command successful */
4267 STp->frame_seq_number = frame_seq_numbr;
4268 STp->logical_blk_num = logical_blk_num;
4269 }
4270
4271os_bypass:
4272#if DEBUG
4273 if (debugging)
4274 printk(OSST_DEB_MSG "%s:D: IOCTL (%d) Result=%d\n", name, cmd_in, ioctl_result);
4275#endif
4276
4277 if (!ioctl_result) { /* success */
4278
4279 if (cmd_in == MTFSFM) {
4280 fileno--;
4281 blkno--;
4282 }
4283 if (cmd_in == MTBSFM) {
4284 fileno++;
4285 blkno++;
4286 }
4287 STps->drv_block = blkno;
4288 STps->drv_file = fileno;
4289 STps->at_sm = at_sm;
4290
4291 if (cmd_in == MTEOM)
4292 STps->eof = ST_EOD;
4293 else if ((cmd_in == MTFSFM || cmd_in == MTBSF) && STps->eof == ST_FM_HIT) {
4294 ioctl_result = osst_seek_logical_blk(STp, &SRpnt, STp->logical_blk_num-1);
4295 STps->drv_block++;
4296 STp->logical_blk_num++;
4297 STp->frame_seq_number++;
4298 STp->frame_in_buffer = 0;
4299 STp->buffer->read_pointer = 0;
4300 }
4301 else if (cmd_in == MTFSF)
4302 STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD:ST_FM;
4303 else if (chg_eof)
4304 STps->eof = ST_NOEOF;
4305
4306 if (cmd_in == MTOFFL || cmd_in == MTUNLOAD)
4307 STp->rew_at_close = 0;
4308 else if (cmd_in == MTLOAD) {
4309 for (i=0; i < ST_NBR_PARTITIONS; i++) {
4310 STp->ps[i].rw = ST_IDLE;
4311 STp->ps[i].last_block_valid = 0;/* FIXME - where else is this field maintained? */
4312 }
4313 STp->partition = 0;
4314 }
4315
4316 if (cmd_in == MTREW) {
4317 ioctl_result = osst_position_tape_and_confirm(STp, &SRpnt, STp->first_data_ppos);
4318 if (ioctl_result > 0)
4319 ioctl_result = 0;
4320 }
4321
4322 } else if (cmd_in == MTBSF || cmd_in == MTBSFM ) {
4323 if (osst_position_tape_and_confirm(STp, &SRpnt, STp->first_data_ppos) < 0)
4324 STps->drv_file = STps->drv_block = -1;
4325 else
4326 STps->drv_file = STps->drv_block = 0;
4327 STps->eof = ST_NOEOF;
4328 } else if (cmd_in == MTFSF || cmd_in == MTFSFM) {
4329 if (osst_position_tape_and_confirm(STp, &SRpnt, STp->eod_frame_ppos) < 0)
4330 STps->drv_file = STps->drv_block = -1;
4331 else {
4332 STps->drv_file = STp->filemark_cnt;
4333 STps->drv_block = 0;
4334 }
4335 STps->eof = ST_EOD;
4336 } else if (cmd_in == MTBSR || cmd_in == MTFSR || cmd_in == MTWEOF || cmd_in == MTEOM) {
4337 STps->drv_file = STps->drv_block = (-1);
4338 STps->eof = ST_NOEOF;
4339 STp->header_ok = 0;
4340 } else if (cmd_in == MTERASE) {
4341 STp->header_ok = 0;
4342 } else if (SRpnt) { /* SCSI command was not completely successful. */
Willem Riede5e6575c2006-02-11 14:46:56 -05004343 if (SRpnt->sense[2] & 0x40) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004344 STps->eof = ST_EOM_OK;
4345 STps->drv_block = 0;
4346 }
4347 if (chg_eof)
4348 STps->eof = ST_NOEOF;
4349
Willem Riede5e6575c2006-02-11 14:46:56 -05004350 if ((SRpnt->sense[2] & 0x0f) == BLANK_CHECK)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004351 STps->eof = ST_EOD;
4352
4353 if (cmd_in == MTLOAD && osst_wait_for_medium(STp, &SRpnt, 60))
4354 ioctl_result = osst_wait_ready(STp, &SRpnt, 5 * 60, OSST_WAIT_POSITION_COMPLETE);
4355 }
4356 *aSRpnt = SRpnt;
4357
4358 return ioctl_result;
4359}
4360
4361
4362/* Open the device */
Jonathan Corbet647d87b2008-05-15 12:23:19 -06004363static int __os_scsi_tape_open(struct inode * inode, struct file * filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004364{
4365 unsigned short flags;
4366 int i, b_size, new_session = 0, retval = 0;
4367 unsigned char cmd[MAX_COMMAND_SIZE];
Willem Riede5e6575c2006-02-11 14:46:56 -05004368 struct osst_request * SRpnt = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004369 struct osst_tape * STp;
4370 struct st_modedef * STm;
4371 struct st_partstat * STps;
4372 char * name;
4373 int dev = TAPE_NR(inode);
4374 int mode = TAPE_MODE(inode);
4375
4376 /*
4377 * We really want to do nonseekable_open(inode, filp); here, but some
4378 * versions of tar incorrectly call lseek on tapes and bail out if that
4379 * fails. So we disallow pread() and pwrite(), but permit lseeks.
4380 */
4381 filp->f_mode &= ~(FMODE_PREAD | FMODE_PWRITE);
4382
4383 write_lock(&os_scsi_tapes_lock);
4384 if (dev >= osst_max_dev || os_scsi_tapes == NULL ||
4385 (STp = os_scsi_tapes[dev]) == NULL || !STp->device) {
4386 write_unlock(&os_scsi_tapes_lock);
4387 return (-ENXIO);
4388 }
4389
4390 name = tape_name(STp);
4391
4392 if (STp->in_use) {
4393 write_unlock(&os_scsi_tapes_lock);
4394#if DEBUG
4395 printk(OSST_DEB_MSG "%s:D: Device already in use.\n", name);
4396#endif
4397 return (-EBUSY);
4398 }
4399 if (scsi_device_get(STp->device)) {
4400 write_unlock(&os_scsi_tapes_lock);
4401#if DEBUG
4402 printk(OSST_DEB_MSG "%s:D: Failed scsi_device_get.\n", name);
4403#endif
4404 return (-ENXIO);
4405 }
4406 filp->private_data = STp;
4407 STp->in_use = 1;
4408 write_unlock(&os_scsi_tapes_lock);
4409 STp->rew_at_close = TAPE_REWIND(inode);
4410
4411 if( !scsi_block_when_processing_errors(STp->device) ) {
4412 return -ENXIO;
4413 }
4414
4415 if (mode != STp->current_mode) {
4416#if DEBUG
4417 if (debugging)
4418 printk(OSST_DEB_MSG "%s:D: Mode change from %d to %d.\n",
4419 name, STp->current_mode, mode);
4420#endif
4421 new_session = 1;
4422 STp->current_mode = mode;
4423 }
4424 STm = &(STp->modes[STp->current_mode]);
4425
4426 flags = filp->f_flags;
4427 STp->write_prot = ((flags & O_ACCMODE) == O_RDONLY);
4428
4429 STp->raw = TAPE_IS_RAW(inode);
4430 if (STp->raw)
4431 STp->header_ok = 0;
4432
4433 /* Allocate data segments for this device's tape buffer */
4434 if (!enlarge_buffer(STp->buffer, STp->restr_dma)) {
4435 printk(KERN_ERR "%s:E: Unable to allocate memory segments for tape buffer.\n", name);
4436 retval = (-EOVERFLOW);
4437 goto err_out;
4438 }
4439 if (STp->buffer->buffer_size >= OS_FRAME_SIZE) {
4440 for (i = 0, b_size = 0;
4441 (i < STp->buffer->sg_segs) && ((b_size + STp->buffer->sg[i].length) <= OS_DATA_SIZE);
4442 b_size += STp->buffer->sg[i++].length);
Jens Axboe45711f12007-10-22 21:19:53 +02004443 STp->buffer->aux = (os_aux_t *) (page_address(sg_page(&STp->buffer->sg[i])) + OS_DATA_SIZE - b_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004444#if DEBUG
4445 printk(OSST_DEB_MSG "%s:D: b_data points to %p in segment 0 at %p\n", name,
4446 STp->buffer->b_data, page_address(STp->buffer->sg[0].page));
4447 printk(OSST_DEB_MSG "%s:D: AUX points to %p in segment %d at %p\n", name,
4448 STp->buffer->aux, i, page_address(STp->buffer->sg[i].page));
4449#endif
4450 } else {
4451 STp->buffer->aux = NULL; /* this had better never happen! */
4452 printk(KERN_NOTICE "%s:A: Framesize %d too large for buffer.\n", name, OS_FRAME_SIZE);
4453 retval = (-EIO);
4454 goto err_out;
4455 }
4456 STp->buffer->writing = 0;
4457 STp->buffer->syscall_result = 0;
4458 STp->dirty = 0;
4459 for (i=0; i < ST_NBR_PARTITIONS; i++) {
4460 STps = &(STp->ps[i]);
4461 STps->rw = ST_IDLE;
4462 }
4463 STp->ready = ST_READY;
4464#if DEBUG
4465 STp->nbr_waits = STp->nbr_finished = 0;
4466#endif
4467
4468 memset (cmd, 0, MAX_COMMAND_SIZE);
4469 cmd[0] = TEST_UNIT_READY;
4470
4471 SRpnt = osst_do_scsi(NULL, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1);
4472 if (!SRpnt) {
4473 retval = (STp->buffer)->syscall_result; /* FIXME - valid? */
4474 goto err_out;
4475 }
Willem Riede5e6575c2006-02-11 14:46:56 -05004476 if ((SRpnt->sense[0] & 0x70) == 0x70 &&
4477 (SRpnt->sense[2] & 0x0f) == NOT_READY &&
4478 SRpnt->sense[12] == 4 ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004479#if DEBUG
Willem Riede5e6575c2006-02-11 14:46:56 -05004480 printk(OSST_DEB_MSG "%s:D: Unit not ready, cause %x\n", name, SRpnt->sense[13]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004481#endif
4482 if (filp->f_flags & O_NONBLOCK) {
4483 retval = -EAGAIN;
4484 goto err_out;
4485 }
Willem Riede5e6575c2006-02-11 14:46:56 -05004486 if (SRpnt->sense[13] == 2) { /* initialize command required (LOAD) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004487 memset (cmd, 0, MAX_COMMAND_SIZE);
4488 cmd[0] = START_STOP;
4489 cmd[1] = 1;
4490 cmd[4] = 1;
4491 SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE,
4492 STp->timeout, MAX_RETRIES, 1);
4493 }
Willem Riede5e6575c2006-02-11 14:46:56 -05004494 osst_wait_ready(STp, &SRpnt, (SRpnt->sense[13]==1?15:3) * 60, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004495 }
Willem Riede5e6575c2006-02-11 14:46:56 -05004496 if ((SRpnt->sense[0] & 0x70) == 0x70 &&
4497 (SRpnt->sense[2] & 0x0f) == UNIT_ATTENTION) { /* New media? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004498#if DEBUG
4499 printk(OSST_DEB_MSG "%s:D: Unit wants attention\n", name);
4500#endif
4501 STp->header_ok = 0;
4502
4503 for (i=0; i < 10; i++) {
4504
4505 memset (cmd, 0, MAX_COMMAND_SIZE);
4506 cmd[0] = TEST_UNIT_READY;
4507
4508 SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE,
4509 STp->timeout, MAX_RETRIES, 1);
Willem Riede5e6575c2006-02-11 14:46:56 -05004510 if ((SRpnt->sense[0] & 0x70) != 0x70 ||
4511 (SRpnt->sense[2] & 0x0f) != UNIT_ATTENTION)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004512 break;
4513 }
4514
4515 STp->pos_unknown = 0;
4516 STp->partition = STp->new_partition = 0;
4517 if (STp->can_partitions)
4518 STp->nbr_partitions = 1; /* This guess will be updated later if necessary */
4519 for (i=0; i < ST_NBR_PARTITIONS; i++) {
4520 STps = &(STp->ps[i]);
4521 STps->rw = ST_IDLE; /* FIXME - seems to be redundant... */
4522 STps->eof = ST_NOEOF;
4523 STps->at_sm = 0;
4524 STps->last_block_valid = 0;
4525 STps->drv_block = 0;
4526 STps->drv_file = 0 ;
4527 }
4528 new_session = 1;
4529 STp->recover_count = 0;
4530 STp->abort_count = 0;
4531 }
4532 /*
4533 * if we have valid headers from before, and the drive/tape seem untouched,
4534 * open without reconfiguring and re-reading the headers
4535 */
4536 if (!STp->buffer->syscall_result && STp->header_ok &&
Willem Riede5e6575c2006-02-11 14:46:56 -05004537 !SRpnt->result && SRpnt->sense[0] == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004538
4539 memset(cmd, 0, MAX_COMMAND_SIZE);
4540 cmd[0] = MODE_SENSE;
4541 cmd[1] = 8;
4542 cmd[2] = VENDOR_IDENT_PAGE;
4543 cmd[4] = VENDOR_IDENT_PAGE_LENGTH + MODE_HEADER_LENGTH;
4544
4545 SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_FROM_DEVICE, STp->timeout, 0, 1);
4546
4547 if (STp->buffer->syscall_result ||
4548 STp->buffer->b_data[MODE_HEADER_LENGTH + 2] != 'L' ||
4549 STp->buffer->b_data[MODE_HEADER_LENGTH + 3] != 'I' ||
4550 STp->buffer->b_data[MODE_HEADER_LENGTH + 4] != 'N' ||
4551 STp->buffer->b_data[MODE_HEADER_LENGTH + 5] != '4' ) {
4552#if DEBUG
4553 printk(OSST_DEB_MSG "%s:D: Signature was changed to %c%c%c%c\n", name,
4554 STp->buffer->b_data[MODE_HEADER_LENGTH + 2],
4555 STp->buffer->b_data[MODE_HEADER_LENGTH + 3],
4556 STp->buffer->b_data[MODE_HEADER_LENGTH + 4],
4557 STp->buffer->b_data[MODE_HEADER_LENGTH + 5]);
4558#endif
4559 STp->header_ok = 0;
4560 }
4561 i = STp->first_frame_position;
4562 if (STp->header_ok && i == osst_get_frame_position(STp, &SRpnt)) {
4563 if (STp->door_locked == ST_UNLOCKED) {
4564 if (do_door_lock(STp, 1))
4565 printk(KERN_INFO "%s:I: Can't lock drive door\n", name);
4566 else
4567 STp->door_locked = ST_LOCKED_AUTO;
4568 }
4569 if (!STp->frame_in_buffer) {
4570 STp->block_size = (STm->default_blksize > 0) ?
4571 STm->default_blksize : OS_DATA_SIZE;
4572 STp->buffer->buffer_bytes = STp->buffer->read_pointer = 0;
4573 }
4574 STp->buffer->buffer_blocks = OS_DATA_SIZE / STp->block_size;
4575 STp->fast_open = 1;
Willem Riede5e6575c2006-02-11 14:46:56 -05004576 osst_release_request(SRpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004577 return 0;
4578 }
4579#if DEBUG
4580 if (i != STp->first_frame_position)
4581 printk(OSST_DEB_MSG "%s:D: Tape position changed from %d to %d\n",
4582 name, i, STp->first_frame_position);
4583#endif
4584 STp->header_ok = 0;
4585 }
4586 STp->fast_open = 0;
4587
4588 if ((STp->buffer)->syscall_result != 0 && /* in all error conditions except no medium */
Willem Riede5e6575c2006-02-11 14:46:56 -05004589 (SRpnt->sense[2] != 2 || SRpnt->sense[12] != 0x3A) ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004590
4591 memset(cmd, 0, MAX_COMMAND_SIZE);
4592 cmd[0] = MODE_SELECT;
4593 cmd[1] = 0x10;
4594 cmd[4] = 4 + MODE_HEADER_LENGTH;
4595
4596 (STp->buffer)->b_data[0] = cmd[4] - 1;
4597 (STp->buffer)->b_data[1] = 0; /* Medium Type - ignoring */
4598 (STp->buffer)->b_data[2] = 0; /* Reserved */
4599 (STp->buffer)->b_data[3] = 0; /* Block Descriptor Length */
4600 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 0] = 0x3f;
4601 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 1] = 1;
4602 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] = 2;
4603 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] = 3;
4604
4605#if DEBUG
4606 printk(OSST_DEB_MSG "%s:D: Applying soft reset\n", name);
4607#endif
4608 SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_TO_DEVICE, STp->timeout, 0, 1);
4609
4610 STp->header_ok = 0;
4611
4612 for (i=0; i < 10; i++) {
4613
4614 memset (cmd, 0, MAX_COMMAND_SIZE);
4615 cmd[0] = TEST_UNIT_READY;
4616
4617 SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE,
4618 STp->timeout, MAX_RETRIES, 1);
Willem Riede5e6575c2006-02-11 14:46:56 -05004619 if ((SRpnt->sense[0] & 0x70) != 0x70 ||
4620 (SRpnt->sense[2] & 0x0f) == NOT_READY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004621 break;
4622
Willem Riede5e6575c2006-02-11 14:46:56 -05004623 if ((SRpnt->sense[2] & 0x0f) == UNIT_ATTENTION) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004624 STp->pos_unknown = 0;
4625 STp->partition = STp->new_partition = 0;
4626 if (STp->can_partitions)
4627 STp->nbr_partitions = 1; /* This guess will be updated later if necessary */
4628 for (i=0; i < ST_NBR_PARTITIONS; i++) {
4629 STps = &(STp->ps[i]);
4630 STps->rw = ST_IDLE;
4631 STps->eof = ST_NOEOF;
4632 STps->at_sm = 0;
4633 STps->last_block_valid = 0;
4634 STps->drv_block = 0;
4635 STps->drv_file = 0 ;
4636 }
4637 new_session = 1;
4638 }
4639 }
4640 }
4641
4642 if (osst_wait_ready(STp, &SRpnt, 15 * 60, 0)) /* FIXME - not allowed with NOBLOCK */
4643 printk(KERN_INFO "%s:I: Device did not become Ready in open\n", name);
4644
4645 if ((STp->buffer)->syscall_result != 0) {
4646 if ((STp->device)->scsi_level >= SCSI_2 &&
Willem Riede5e6575c2006-02-11 14:46:56 -05004647 (SRpnt->sense[0] & 0x70) == 0x70 &&
4648 (SRpnt->sense[2] & 0x0f) == NOT_READY &&
4649 SRpnt->sense[12] == 0x3a) { /* Check ASC */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004650 STp->ready = ST_NO_TAPE;
4651 } else
4652 STp->ready = ST_NOT_READY;
Willem Riede5e6575c2006-02-11 14:46:56 -05004653 osst_release_request(SRpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004654 SRpnt = NULL;
4655 STp->density = 0; /* Clear the erroneous "residue" */
4656 STp->write_prot = 0;
4657 STp->block_size = 0;
4658 STp->ps[0].drv_file = STp->ps[0].drv_block = (-1);
4659 STp->partition = STp->new_partition = 0;
4660 STp->door_locked = ST_UNLOCKED;
4661 return 0;
4662 }
4663
4664 osst_configure_onstream(STp, &SRpnt);
4665
4666 STp->block_size = STp->raw ? OS_FRAME_SIZE : (
4667 (STm->default_blksize > 0) ? STm->default_blksize : OS_DATA_SIZE);
4668 STp->buffer->buffer_blocks = STp->raw ? 1 : OS_DATA_SIZE / STp->block_size;
4669 STp->buffer->buffer_bytes =
4670 STp->buffer->read_pointer =
4671 STp->frame_in_buffer = 0;
4672
4673#if DEBUG
4674 if (debugging)
4675 printk(OSST_DEB_MSG "%s:D: Block size: %d, frame size: %d, buffer size: %d (%d blocks).\n",
4676 name, STp->block_size, OS_FRAME_SIZE, (STp->buffer)->buffer_size,
4677 (STp->buffer)->buffer_blocks);
4678#endif
4679
4680 if (STp->drv_write_prot) {
4681 STp->write_prot = 1;
4682#if DEBUG
4683 if (debugging)
4684 printk(OSST_DEB_MSG "%s:D: Write protected\n", name);
4685#endif
4686 if ((flags & O_ACCMODE) == O_WRONLY || (flags & O_ACCMODE) == O_RDWR) {
4687 retval = (-EROFS);
4688 goto err_out;
4689 }
4690 }
4691
4692 if (new_session) { /* Change the drive parameters for the new mode */
4693#if DEBUG
4694 if (debugging)
4695 printk(OSST_DEB_MSG "%s:D: New Session\n", name);
4696#endif
4697 STp->density_changed = STp->blksize_changed = 0;
4698 STp->compression_changed = 0;
4699 }
4700
4701 /*
4702 * properly position the tape and check the ADR headers
4703 */
4704 if (STp->door_locked == ST_UNLOCKED) {
4705 if (do_door_lock(STp, 1))
4706 printk(KERN_INFO "%s:I: Can't lock drive door\n", name);
4707 else
4708 STp->door_locked = ST_LOCKED_AUTO;
4709 }
4710
4711 osst_analyze_headers(STp, &SRpnt);
4712
Willem Riede5e6575c2006-02-11 14:46:56 -05004713 osst_release_request(SRpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004714 SRpnt = NULL;
4715
4716 return 0;
4717
4718err_out:
4719 if (SRpnt != NULL)
Willem Riede5e6575c2006-02-11 14:46:56 -05004720 osst_release_request(SRpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004721 normalize_buffer(STp->buffer);
4722 STp->header_ok = 0;
4723 STp->in_use = 0;
4724 scsi_device_put(STp->device);
4725
4726 return retval;
4727}
4728
Jonathan Corbet647d87b2008-05-15 12:23:19 -06004729/* BKL pushdown: spaghetti avoidance wrapper */
4730static int os_scsi_tape_open(struct inode * inode, struct file * filp)
4731{
4732 int ret;
4733
4734 lock_kernel();
4735 ret = __os_scsi_tape_open(inode, filp);
4736 unlock_kernel();
4737 return ret;
4738}
4739
4740
Linus Torvalds1da177e2005-04-16 15:20:36 -07004741
4742/* Flush the tape buffer before close */
Miklos Szeredi75e1fcc2006-06-23 02:05:12 -07004743static int os_scsi_tape_flush(struct file * filp, fl_owner_t id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004744{
4745 int result = 0, result2;
4746 struct osst_tape * STp = filp->private_data;
4747 struct st_modedef * STm = &(STp->modes[STp->current_mode]);
4748 struct st_partstat * STps = &(STp->ps[STp->partition]);
Willem Riede5e6575c2006-02-11 14:46:56 -05004749 struct osst_request * SRpnt = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004750 char * name = tape_name(STp);
4751
4752 if (file_count(filp) > 1)
4753 return 0;
4754
4755 if ((STps->rw == ST_WRITING || STp->dirty) && !STp->pos_unknown) {
4756 STp->write_type = OS_WRITE_DATA;
4757 result = osst_flush_write_buffer(STp, &SRpnt);
4758 if (result != 0 && result != (-ENOSPC))
4759 goto out;
4760 }
4761 if ( STps->rw >= ST_WRITING && !STp->pos_unknown) {
4762
4763#if DEBUG
4764 if (debugging) {
4765 printk(OSST_DEB_MSG "%s:D: File length %ld bytes.\n",
4766 name, (long)(filp->f_pos));
4767 printk(OSST_DEB_MSG "%s:D: Async write waits %d, finished %d.\n",
4768 name, STp->nbr_waits, STp->nbr_finished);
4769 }
4770#endif
4771 result = osst_write_trailer(STp, &SRpnt, !(STp->rew_at_close));
4772#if DEBUG
4773 if (debugging)
4774 printk(OSST_DEB_MSG "%s:D: Buffer flushed, %d EOF(s) written\n",
4775 name, 1+STp->two_fm);
4776#endif
4777 }
4778 else if (!STp->rew_at_close) {
4779 STps = &(STp->ps[STp->partition]);
4780 if (!STm->sysv || STps->rw != ST_READING) {
4781 if (STp->can_bsr)
4782 result = osst_flush_buffer(STp, &SRpnt, 0); /* this is the default path */
4783 else if (STps->eof == ST_FM_HIT) {
4784 result = cross_eof(STp, &SRpnt, 0);
4785 if (result) {
4786 if (STps->drv_file >= 0)
4787 STps->drv_file++;
4788 STps->drv_block = 0;
4789 STps->eof = ST_FM;
4790 }
4791 else
4792 STps->eof = ST_NOEOF;
4793 }
4794 }
4795 else if ((STps->eof == ST_NOEOF &&
4796 !(result = cross_eof(STp, &SRpnt, 1))) ||
4797 STps->eof == ST_FM_HIT) {
4798 if (STps->drv_file >= 0)
4799 STps->drv_file++;
4800 STps->drv_block = 0;
4801 STps->eof = ST_FM;
4802 }
4803 }
4804
4805out:
4806 if (STp->rew_at_close) {
4807 result2 = osst_position_tape_and_confirm(STp, &SRpnt, STp->first_data_ppos);
4808 STps->drv_file = STps->drv_block = STp->frame_seq_number = STp->logical_blk_num = 0;
4809 if (result == 0 && result2 < 0)
4810 result = result2;
4811 }
Willem Riede5e6575c2006-02-11 14:46:56 -05004812 if (SRpnt) osst_release_request(SRpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004813
4814 if (STp->abort_count || STp->recover_count) {
4815 printk(KERN_INFO "%s:I:", name);
4816 if (STp->abort_count)
4817 printk(" %d unrecovered errors", STp->abort_count);
4818 if (STp->recover_count)
4819 printk(" %d recovered errors", STp->recover_count);
4820 if (STp->write_count)
4821 printk(" in %d frames written", STp->write_count);
4822 if (STp->read_count)
4823 printk(" in %d frames read", STp->read_count);
4824 printk("\n");
4825 STp->recover_count = 0;
4826 STp->abort_count = 0;
4827 }
4828 STp->write_count = 0;
4829 STp->read_count = 0;
4830
4831 return result;
4832}
4833
4834
4835/* Close the device and release it */
4836static int os_scsi_tape_close(struct inode * inode, struct file * filp)
4837{
4838 int result = 0;
4839 struct osst_tape * STp = filp->private_data;
4840
4841 if (STp->door_locked == ST_LOCKED_AUTO)
4842 do_door_lock(STp, 0);
4843
4844 if (STp->raw)
4845 STp->header_ok = 0;
4846
4847 normalize_buffer(STp->buffer);
4848 write_lock(&os_scsi_tapes_lock);
4849 STp->in_use = 0;
4850 write_unlock(&os_scsi_tapes_lock);
4851
4852 scsi_device_put(STp->device);
4853
4854 return result;
4855}
4856
4857
4858/* The ioctl command */
4859static int osst_ioctl(struct inode * inode,struct file * file,
4860 unsigned int cmd_in, unsigned long arg)
4861{
Eric Sesterhenn45223fd2006-09-25 16:59:08 -07004862 int i, cmd_nr, cmd_type, blk, retval = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004863 struct st_modedef * STm;
4864 struct st_partstat * STps;
Willem Riede5e6575c2006-02-11 14:46:56 -05004865 struct osst_request * SRpnt = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004866 struct osst_tape * STp = file->private_data;
4867 char * name = tape_name(STp);
4868 void __user * p = (void __user *)arg;
4869
Matthias Kaehlcke4390e602007-08-10 14:50:44 -07004870 if (mutex_lock_interruptible(&STp->lock))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004871 return -ERESTARTSYS;
4872
4873#if DEBUG
4874 if (debugging && !STp->in_use) {
4875 printk(OSST_DEB_MSG "%s:D: Incorrect device.\n", name);
4876 retval = (-EIO);
4877 goto out;
4878 }
4879#endif
4880 STm = &(STp->modes[STp->current_mode]);
4881 STps = &(STp->ps[STp->partition]);
4882
4883 /*
4884 * If we are in the middle of error recovery, don't let anyone
4885 * else try and use this device. Also, if error recovery fails, it
4886 * may try and take the device offline, in which case all further
4887 * access to the device is prohibited.
4888 */
4889 if( !scsi_block_when_processing_errors(STp->device) ) {
4890 retval = (-ENXIO);
4891 goto out;
4892 }
4893
4894 cmd_type = _IOC_TYPE(cmd_in);
4895 cmd_nr = _IOC_NR(cmd_in);
4896#if DEBUG
4897 printk(OSST_DEB_MSG "%s:D: Ioctl %d,%d in %s mode\n", name,
4898 cmd_type, cmd_nr, STp->raw?"raw":"normal");
4899#endif
4900 if (cmd_type == _IOC_TYPE(MTIOCTOP) && cmd_nr == _IOC_NR(MTIOCTOP)) {
4901 struct mtop mtc;
4902 int auto_weof = 0;
4903
4904 if (_IOC_SIZE(cmd_in) != sizeof(mtc)) {
4905 retval = (-EINVAL);
4906 goto out;
4907 }
4908
4909 i = copy_from_user((char *) &mtc, p, sizeof(struct mtop));
4910 if (i) {
4911 retval = (-EFAULT);
4912 goto out;
4913 }
4914
4915 if (mtc.mt_op == MTSETDRVBUFFER && !capable(CAP_SYS_ADMIN)) {
4916 printk(KERN_WARNING "%s:W: MTSETDRVBUFFER only allowed for root.\n", name);
4917 retval = (-EPERM);
4918 goto out;
4919 }
4920
4921 if (!STm->defined && (mtc.mt_op != MTSETDRVBUFFER && (mtc.mt_count & MT_ST_OPTIONS) == 0)) {
4922 retval = (-ENXIO);
4923 goto out;
4924 }
4925
4926 if (!STp->pos_unknown) {
4927
4928 if (STps->eof == ST_FM_HIT) {
4929 if (mtc.mt_op == MTFSF || mtc.mt_op == MTFSFM|| mtc.mt_op == MTEOM) {
4930 mtc.mt_count -= 1;
4931 if (STps->drv_file >= 0)
4932 STps->drv_file += 1;
4933 }
4934 else if (mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM) {
4935 mtc.mt_count += 1;
4936 if (STps->drv_file >= 0)
4937 STps->drv_file += 1;
4938 }
4939 }
4940
4941 if (mtc.mt_op == MTSEEK) {
4942 /* Old position must be restored if partition will be changed */
4943 i = !STp->can_partitions || (STp->new_partition != STp->partition);
4944 }
4945 else {
4946 i = mtc.mt_op == MTREW || mtc.mt_op == MTOFFL ||
4947 mtc.mt_op == MTRETEN || mtc.mt_op == MTEOM ||
4948 mtc.mt_op == MTLOCK || mtc.mt_op == MTLOAD ||
4949 mtc.mt_op == MTFSF || mtc.mt_op == MTFSFM ||
4950 mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM ||
4951 mtc.mt_op == MTCOMPRESSION;
4952 }
4953 i = osst_flush_buffer(STp, &SRpnt, i);
4954 if (i < 0) {
4955 retval = i;
4956 goto out;
4957 }
4958 }
4959 else {
4960 /*
4961 * If there was a bus reset, block further access
4962 * to this device. If the user wants to rewind the tape,
4963 * then reset the flag and allow access again.
4964 */
4965 if(mtc.mt_op != MTREW &&
4966 mtc.mt_op != MTOFFL &&
4967 mtc.mt_op != MTRETEN &&
4968 mtc.mt_op != MTERASE &&
4969 mtc.mt_op != MTSEEK &&
4970 mtc.mt_op != MTEOM) {
4971 retval = (-EIO);
4972 goto out;
4973 }
4974 reset_state(STp);
4975 /* remove this when the midlevel properly clears was_reset */
4976 STp->device->was_reset = 0;
4977 }
4978
4979 if (mtc.mt_op != MTCOMPRESSION && mtc.mt_op != MTLOCK &&
4980 mtc.mt_op != MTNOP && mtc.mt_op != MTSETBLK &&
4981 mtc.mt_op != MTSETDENSITY && mtc.mt_op != MTSETDRVBUFFER &&
4982 mtc.mt_op != MTMKPART && mtc.mt_op != MTSETPART &&
4983 mtc.mt_op != MTWEOF && mtc.mt_op != MTWSM ) {
4984
4985 /*
4986 * The user tells us to move to another position on the tape.
4987 * If we were appending to the tape content, that would leave
4988 * the tape without proper end, in that case write EOD and
4989 * update the header to reflect its position.
4990 */
4991#if DEBUG
4992 printk(KERN_WARNING "%s:D: auto_weod %s at ffp=%d,efp=%d,fsn=%d,lbn=%d,fn=%d,bn=%d\n", name,
4993 STps->rw >= ST_WRITING ? "write" : STps->rw == ST_READING ? "read" : "idle",
4994 STp->first_frame_position, STp->eod_frame_ppos, STp->frame_seq_number,
4995 STp->logical_blk_num, STps->drv_file, STps->drv_block );
4996#endif
4997 if (STps->rw >= ST_WRITING && STp->first_frame_position >= STp->eod_frame_ppos) {
4998 auto_weof = ((STp->write_type != OS_WRITE_NEW_MARK) &&
4999 !(mtc.mt_op == MTREW || mtc.mt_op == MTOFFL));
5000 i = osst_write_trailer(STp, &SRpnt,
5001 !(mtc.mt_op == MTREW || mtc.mt_op == MTOFFL));
5002#if DEBUG
5003 printk(KERN_WARNING "%s:D: post trailer xeof=%d,ffp=%d,efp=%d,fsn=%d,lbn=%d,fn=%d,bn=%d\n",
5004 name, auto_weof, STp->first_frame_position, STp->eod_frame_ppos,
5005 STp->frame_seq_number, STp->logical_blk_num, STps->drv_file, STps->drv_block );
5006#endif
5007 if (i < 0) {
5008 retval = i;
5009 goto out;
5010 }
5011 }
5012 STps->rw = ST_IDLE;
5013 }
5014
5015 if (mtc.mt_op == MTOFFL && STp->door_locked != ST_UNLOCKED)
5016 do_door_lock(STp, 0); /* Ignore result! */
5017
5018 if (mtc.mt_op == MTSETDRVBUFFER &&
5019 (mtc.mt_count & MT_ST_OPTIONS) != 0) {
5020 retval = osst_set_options(STp, mtc.mt_count);
5021 goto out;
5022 }
5023
5024 if (mtc.mt_op == MTSETPART) {
5025 if (mtc.mt_count >= STp->nbr_partitions)
5026 retval = -EINVAL;
5027 else {
5028 STp->new_partition = mtc.mt_count;
5029 retval = 0;
5030 }
5031 goto out;
5032 }
5033
5034 if (mtc.mt_op == MTMKPART) {
5035 if (!STp->can_partitions) {
5036 retval = (-EINVAL);
5037 goto out;
5038 }
5039 if ((i = osst_int_ioctl(STp, &SRpnt, MTREW, 0)) < 0 /*||
5040 (i = partition_tape(inode, mtc.mt_count)) < 0*/) {
5041 retval = i;
5042 goto out;
5043 }
5044 for (i=0; i < ST_NBR_PARTITIONS; i++) {
5045 STp->ps[i].rw = ST_IDLE;
5046 STp->ps[i].at_sm = 0;
5047 STp->ps[i].last_block_valid = 0;
5048 }
5049 STp->partition = STp->new_partition = 0;
5050 STp->nbr_partitions = 1; /* Bad guess ?-) */
5051 STps->drv_block = STps->drv_file = 0;
5052 retval = 0;
5053 goto out;
5054 }
5055
5056 if (mtc.mt_op == MTSEEK) {
5057 if (STp->raw)
5058 i = osst_set_frame_position(STp, &SRpnt, mtc.mt_count, 0);
5059 else
5060 i = osst_seek_sector(STp, &SRpnt, mtc.mt_count);
5061 if (!STp->can_partitions)
5062 STp->ps[0].rw = ST_IDLE;
5063 retval = i;
5064 goto out;
5065 }
5066
5067 if (mtc.mt_op == MTLOCK || mtc.mt_op == MTUNLOCK) {
5068 retval = do_door_lock(STp, (mtc.mt_op == MTLOCK));
5069 goto out;
5070 }
5071
5072 if (auto_weof)
5073 cross_eof(STp, &SRpnt, 0);
5074
5075 if (mtc.mt_op == MTCOMPRESSION)
5076 retval = -EINVAL; /* OnStream drives don't have compression hardware */
5077 else
5078 /* MTBSF MTBSFM MTBSR MTBSS MTEOM MTERASE MTFSF MTFSFB MTFSR MTFSS
5079 * MTLOAD MTOFFL MTRESET MTRETEN MTREW MTUNLOAD MTWEOF MTWSM */
5080 retval = osst_int_ioctl(STp, &SRpnt, mtc.mt_op, mtc.mt_count);
5081 goto out;
5082 }
5083
5084 if (!STm->defined) {
5085 retval = (-ENXIO);
5086 goto out;
5087 }
5088
5089 if ((i = osst_flush_buffer(STp, &SRpnt, 0)) < 0) {
5090 retval = i;
5091 goto out;
5092 }
5093
5094 if (cmd_type == _IOC_TYPE(MTIOCGET) && cmd_nr == _IOC_NR(MTIOCGET)) {
5095 struct mtget mt_status;
5096
5097 if (_IOC_SIZE(cmd_in) != sizeof(struct mtget)) {
5098 retval = (-EINVAL);
5099 goto out;
5100 }
5101
5102 mt_status.mt_type = MT_ISONSTREAM_SC;
5103 mt_status.mt_erreg = STp->recover_erreg << MT_ST_SOFTERR_SHIFT;
5104 mt_status.mt_dsreg =
5105 ((STp->block_size << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK) |
5106 ((STp->density << MT_ST_DENSITY_SHIFT) & MT_ST_DENSITY_MASK);
5107 mt_status.mt_blkno = STps->drv_block;
5108 mt_status.mt_fileno = STps->drv_file;
5109 if (STp->block_size != 0) {
5110 if (STps->rw == ST_WRITING)
5111 mt_status.mt_blkno += (STp->buffer)->buffer_bytes / STp->block_size;
5112 else if (STps->rw == ST_READING)
5113 mt_status.mt_blkno -= ((STp->buffer)->buffer_bytes +
5114 STp->block_size - 1) / STp->block_size;
5115 }
5116
5117 mt_status.mt_gstat = 0;
5118 if (STp->drv_write_prot)
5119 mt_status.mt_gstat |= GMT_WR_PROT(0xffffffff);
5120 if (mt_status.mt_blkno == 0) {
5121 if (mt_status.mt_fileno == 0)
5122 mt_status.mt_gstat |= GMT_BOT(0xffffffff);
5123 else
5124 mt_status.mt_gstat |= GMT_EOF(0xffffffff);
5125 }
5126 mt_status.mt_resid = STp->partition;
5127 if (STps->eof == ST_EOM_OK || STps->eof == ST_EOM_ERROR)
5128 mt_status.mt_gstat |= GMT_EOT(0xffffffff);
5129 else if (STps->eof >= ST_EOM_OK)
5130 mt_status.mt_gstat |= GMT_EOD(0xffffffff);
5131 if (STp->density == 1)
5132 mt_status.mt_gstat |= GMT_D_800(0xffffffff);
5133 else if (STp->density == 2)
5134 mt_status.mt_gstat |= GMT_D_1600(0xffffffff);
5135 else if (STp->density == 3)
5136 mt_status.mt_gstat |= GMT_D_6250(0xffffffff);
5137 if (STp->ready == ST_READY)
5138 mt_status.mt_gstat |= GMT_ONLINE(0xffffffff);
5139 if (STp->ready == ST_NO_TAPE)
5140 mt_status.mt_gstat |= GMT_DR_OPEN(0xffffffff);
5141 if (STps->at_sm)
5142 mt_status.mt_gstat |= GMT_SM(0xffffffff);
5143 if (STm->do_async_writes || (STm->do_buffer_writes && STp->block_size != 0) ||
5144 STp->drv_buffer != 0)
5145 mt_status.mt_gstat |= GMT_IM_REP_EN(0xffffffff);
5146
5147 i = copy_to_user(p, &mt_status, sizeof(struct mtget));
5148 if (i) {
5149 retval = (-EFAULT);
5150 goto out;
5151 }
5152
5153 STp->recover_erreg = 0; /* Clear after read */
5154 retval = 0;
5155 goto out;
5156 } /* End of MTIOCGET */
5157
5158 if (cmd_type == _IOC_TYPE(MTIOCPOS) && cmd_nr == _IOC_NR(MTIOCPOS)) {
5159 struct mtpos mt_pos;
5160
5161 if (_IOC_SIZE(cmd_in) != sizeof(struct mtpos)) {
5162 retval = (-EINVAL);
5163 goto out;
5164 }
5165 if (STp->raw)
5166 blk = osst_get_frame_position(STp, &SRpnt);
5167 else
5168 blk = osst_get_sector(STp, &SRpnt);
5169 if (blk < 0) {
5170 retval = blk;
5171 goto out;
5172 }
5173 mt_pos.mt_blkno = blk;
5174 i = copy_to_user(p, &mt_pos, sizeof(struct mtpos));
5175 if (i)
5176 retval = -EFAULT;
5177 goto out;
5178 }
Willem Riede5e6575c2006-02-11 14:46:56 -05005179 if (SRpnt) osst_release_request(SRpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005180
Matthias Kaehlcke4390e602007-08-10 14:50:44 -07005181 mutex_unlock(&STp->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005182
5183 return scsi_ioctl(STp->device, cmd_in, p);
5184
5185out:
Willem Riede5e6575c2006-02-11 14:46:56 -05005186 if (SRpnt) osst_release_request(SRpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005187
Matthias Kaehlcke4390e602007-08-10 14:50:44 -07005188 mutex_unlock(&STp->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005189
5190 return retval;
5191}
5192
5193#ifdef CONFIG_COMPAT
5194static long osst_compat_ioctl(struct file * file, unsigned int cmd_in, unsigned long arg)
5195{
5196 struct osst_tape *STp = file->private_data;
5197 struct scsi_device *sdev = STp->device;
5198 int ret = -ENOIOCTLCMD;
5199 if (sdev->host->hostt->compat_ioctl) {
5200
5201 ret = sdev->host->hostt->compat_ioctl(sdev, cmd_in, (void __user *)arg);
5202
5203 }
5204 return ret;
5205}
5206#endif
5207
5208
5209
5210/* Memory handling routines */
5211
5212/* Try to allocate a new tape buffer skeleton. Caller must not hold os_scsi_tapes_lock */
5213static struct osst_buffer * new_tape_buffer( int from_initialization, int need_dma, int max_sg )
5214{
Al Viroc53033f2005-10-21 03:22:08 -04005215 int i;
5216 gfp_t priority;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005217 struct osst_buffer *tb;
5218
5219 if (from_initialization)
5220 priority = GFP_ATOMIC;
5221 else
5222 priority = GFP_KERNEL;
5223
5224 i = sizeof(struct osst_buffer) + (osst_max_sg_segs - 1) * sizeof(struct scatterlist);
Jeff Garzik37e03332006-10-04 05:23:04 -04005225 tb = kzalloc(i, priority);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005226 if (!tb) {
5227 printk(KERN_NOTICE "osst :I: Can't allocate new tape buffer.\n");
5228 return NULL;
5229 }
Jeff Garzik37e03332006-10-04 05:23:04 -04005230
Linus Torvalds1da177e2005-04-16 15:20:36 -07005231 tb->sg_segs = tb->orig_sg_segs = 0;
5232 tb->use_sg = max_sg;
5233 tb->in_use = 1;
5234 tb->dma = need_dma;
5235 tb->buffer_size = 0;
5236#if DEBUG
5237 if (debugging)
5238 printk(OSST_DEB_MSG
5239 "osst :D: Allocated tape buffer skeleton (%d bytes, %d segments, dma: %d).\n",
5240 i, max_sg, need_dma);
5241#endif
5242 return tb;
5243}
5244
5245/* Try to allocate a temporary (while a user has the device open) enlarged tape buffer */
5246static int enlarge_buffer(struct osst_buffer *STbuffer, int need_dma)
5247{
Al Viroc53033f2005-10-21 03:22:08 -04005248 int segs, nbr, max_segs, b_size, order, got;
5249 gfp_t priority;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005250
5251 if (STbuffer->buffer_size >= OS_FRAME_SIZE)
5252 return 1;
5253
5254 if (STbuffer->sg_segs) {
5255 printk(KERN_WARNING "osst :A: Buffer not previously normalized.\n");
5256 normalize_buffer(STbuffer);
5257 }
5258 /* See how many segments we can use -- need at least two */
5259 nbr = max_segs = STbuffer->use_sg;
5260 if (nbr <= 2)
5261 return 0;
5262
5263 priority = GFP_KERNEL /* | __GFP_NOWARN */;
5264 if (need_dma)
5265 priority |= GFP_DMA;
5266
5267 /* Try to allocate the first segment up to OS_DATA_SIZE and the others
5268 big enough to reach the goal (code assumes no segments in place) */
5269 for (b_size = OS_DATA_SIZE, order = OSST_FIRST_ORDER; b_size >= PAGE_SIZE; order--, b_size /= 2) {
Jens Axboe45711f12007-10-22 21:19:53 +02005270 struct page *page = alloc_pages(priority, order);
5271
Linus Torvalds1da177e2005-04-16 15:20:36 -07005272 STbuffer->sg[0].offset = 0;
Jens Axboe45711f12007-10-22 21:19:53 +02005273 if (page != NULL) {
Jens Axboe642f149032007-10-24 11:20:47 +02005274 sg_set_page(&STbuffer->sg[0], page, b_size, 0);
Jens Axboe45711f12007-10-22 21:19:53 +02005275 STbuffer->b_data = page_address(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005276 break;
5277 }
5278 }
Jens Axboe45711f12007-10-22 21:19:53 +02005279 if (sg_page(&STbuffer->sg[0]) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005280 printk(KERN_NOTICE "osst :I: Can't allocate tape buffer main segment.\n");
5281 return 0;
5282 }
5283 /* Got initial segment of 'bsize,order', continue with same size if possible, except for AUX */
5284 for (segs=STbuffer->sg_segs=1, got=b_size;
5285 segs < max_segs && got < OS_FRAME_SIZE; ) {
Jens Axboe45711f12007-10-22 21:19:53 +02005286 struct page *page = alloc_pages(priority, (OS_FRAME_SIZE - got <= PAGE_SIZE) ? 0 : order);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005287 STbuffer->sg[segs].offset = 0;
Jens Axboe45711f12007-10-22 21:19:53 +02005288 if (page == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005289 if (OS_FRAME_SIZE - got <= (max_segs - segs) * b_size / 2 && order) {
5290 b_size /= 2; /* Large enough for the rest of the buffers */
5291 order--;
5292 continue;
5293 }
5294 printk(KERN_WARNING "osst :W: Failed to enlarge buffer to %d bytes.\n",
5295 OS_FRAME_SIZE);
5296#if DEBUG
5297 STbuffer->buffer_size = got;
5298#endif
5299 normalize_buffer(STbuffer);
5300 return 0;
5301 }
Jens Axboe642f149032007-10-24 11:20:47 +02005302 sg_set_page(&STbuffer->sg[segs], page, (OS_FRAME_SIZE - got <= PAGE_SIZE / 2) ? (OS_FRAME_SIZE - got) : b_size, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005303 got += STbuffer->sg[segs].length;
5304 STbuffer->buffer_size = got;
5305 STbuffer->sg_segs = ++segs;
5306 }
5307#if DEBUG
5308 if (debugging) {
5309 printk(OSST_DEB_MSG
5310 "osst :D: Expanded tape buffer (%d bytes, %d->%d segments, dma: %d, at: %p).\n",
5311 got, STbuffer->orig_sg_segs, STbuffer->sg_segs, need_dma, STbuffer->b_data);
5312 printk(OSST_DEB_MSG
5313 "osst :D: segment sizes: first %d at %p, last %d bytes at %p.\n",
5314 STbuffer->sg[0].length, page_address(STbuffer->sg[0].page),
5315 STbuffer->sg[segs-1].length, page_address(STbuffer->sg[segs-1].page));
5316 }
5317#endif
5318
5319 return 1;
5320}
5321
5322
5323/* Release the segments */
5324static void normalize_buffer(struct osst_buffer *STbuffer)
5325{
5326 int i, order, b_size;
5327
5328 for (i=0; i < STbuffer->sg_segs; i++) {
5329
5330 for (b_size = PAGE_SIZE, order = 0;
5331 b_size < STbuffer->sg[i].length;
5332 b_size *= 2, order++);
5333
Jens Axboe45711f12007-10-22 21:19:53 +02005334 __free_pages(sg_page(&STbuffer->sg[i]), order);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005335 STbuffer->buffer_size -= STbuffer->sg[i].length;
5336 }
5337#if DEBUG
5338 if (debugging && STbuffer->orig_sg_segs < STbuffer->sg_segs)
5339 printk(OSST_DEB_MSG "osst :D: Buffer at %p normalized to %d bytes (segs %d).\n",
5340 STbuffer->b_data, STbuffer->buffer_size, STbuffer->sg_segs);
5341#endif
5342 STbuffer->sg_segs = STbuffer->orig_sg_segs = 0;
5343}
5344
5345
5346/* Move data from the user buffer to the tape buffer. Returns zero (success) or
5347 negative error code. */
5348static int append_to_buffer(const char __user *ubp, struct osst_buffer *st_bp, int do_count)
5349{
5350 int i, cnt, res, offset;
5351
5352 for (i=0, offset=st_bp->buffer_bytes;
5353 i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++)
5354 offset -= st_bp->sg[i].length;
5355 if (i == st_bp->sg_segs) { /* Should never happen */
5356 printk(KERN_WARNING "osst :A: Append_to_buffer offset overflow.\n");
5357 return (-EIO);
5358 }
5359 for ( ; i < st_bp->sg_segs && do_count > 0; i++) {
5360 cnt = st_bp->sg[i].length - offset < do_count ?
5361 st_bp->sg[i].length - offset : do_count;
Jens Axboe45711f12007-10-22 21:19:53 +02005362 res = copy_from_user(page_address(sg_page(&st_bp->sg[i])) + offset, ubp, cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005363 if (res)
5364 return (-EFAULT);
5365 do_count -= cnt;
5366 st_bp->buffer_bytes += cnt;
5367 ubp += cnt;
5368 offset = 0;
5369 }
5370 if (do_count) { /* Should never happen */
5371 printk(KERN_WARNING "osst :A: Append_to_buffer overflow (left %d).\n",
5372 do_count);
5373 return (-EIO);
5374 }
5375 return 0;
5376}
5377
5378
5379/* Move data from the tape buffer to the user buffer. Returns zero (success) or
5380 negative error code. */
5381static int from_buffer(struct osst_buffer *st_bp, char __user *ubp, int do_count)
5382{
5383 int i, cnt, res, offset;
5384
5385 for (i=0, offset=st_bp->read_pointer;
5386 i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++)
5387 offset -= st_bp->sg[i].length;
5388 if (i == st_bp->sg_segs) { /* Should never happen */
5389 printk(KERN_WARNING "osst :A: From_buffer offset overflow.\n");
5390 return (-EIO);
5391 }
5392 for ( ; i < st_bp->sg_segs && do_count > 0; i++) {
5393 cnt = st_bp->sg[i].length - offset < do_count ?
5394 st_bp->sg[i].length - offset : do_count;
Jens Axboe45711f12007-10-22 21:19:53 +02005395 res = copy_to_user(ubp, page_address(sg_page(&st_bp->sg[i])) + offset, cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005396 if (res)
5397 return (-EFAULT);
5398 do_count -= cnt;
5399 st_bp->buffer_bytes -= cnt;
5400 st_bp->read_pointer += cnt;
5401 ubp += cnt;
5402 offset = 0;
5403 }
5404 if (do_count) { /* Should never happen */
5405 printk(KERN_WARNING "osst :A: From_buffer overflow (left %d).\n", do_count);
5406 return (-EIO);
5407 }
5408 return 0;
5409}
5410
5411/* Sets the tail of the buffer after fill point to zero.
5412 Returns zero (success) or negative error code. */
5413static int osst_zero_buffer_tail(struct osst_buffer *st_bp)
5414{
5415 int i, offset, do_count, cnt;
5416
5417 for (i = 0, offset = st_bp->buffer_bytes;
5418 i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++)
5419 offset -= st_bp->sg[i].length;
5420 if (i == st_bp->sg_segs) { /* Should never happen */
5421 printk(KERN_WARNING "osst :A: Zero_buffer offset overflow.\n");
5422 return (-EIO);
5423 }
5424 for (do_count = OS_DATA_SIZE - st_bp->buffer_bytes;
5425 i < st_bp->sg_segs && do_count > 0; i++) {
5426 cnt = st_bp->sg[i].length - offset < do_count ?
5427 st_bp->sg[i].length - offset : do_count ;
Jens Axboe45711f12007-10-22 21:19:53 +02005428 memset(page_address(sg_page(&st_bp->sg[i])) + offset, 0, cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005429 do_count -= cnt;
5430 offset = 0;
5431 }
5432 if (do_count) { /* Should never happen */
5433 printk(KERN_WARNING "osst :A: Zero_buffer overflow (left %d).\n", do_count);
5434 return (-EIO);
5435 }
5436 return 0;
5437}
5438
5439/* Copy a osst 32K chunk of memory into the buffer.
5440 Returns zero (success) or negative error code. */
5441static int osst_copy_to_buffer(struct osst_buffer *st_bp, unsigned char *ptr)
5442{
5443 int i, cnt, do_count = OS_DATA_SIZE;
5444
5445 for (i = 0; i < st_bp->sg_segs && do_count > 0; i++) {
5446 cnt = st_bp->sg[i].length < do_count ?
5447 st_bp->sg[i].length : do_count ;
Jens Axboe45711f12007-10-22 21:19:53 +02005448 memcpy(page_address(sg_page(&st_bp->sg[i])), ptr, cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005449 do_count -= cnt;
5450 ptr += cnt;
5451 }
5452 if (do_count || i != st_bp->sg_segs-1) { /* Should never happen */
5453 printk(KERN_WARNING "osst :A: Copy_to_buffer overflow (left %d at sg %d).\n",
5454 do_count, i);
5455 return (-EIO);
5456 }
5457 return 0;
5458}
5459
5460/* Copy a osst 32K chunk of memory from the buffer.
5461 Returns zero (success) or negative error code. */
5462static int osst_copy_from_buffer(struct osst_buffer *st_bp, unsigned char *ptr)
5463{
5464 int i, cnt, do_count = OS_DATA_SIZE;
5465
5466 for (i = 0; i < st_bp->sg_segs && do_count > 0; i++) {
5467 cnt = st_bp->sg[i].length < do_count ?
5468 st_bp->sg[i].length : do_count ;
Jens Axboe45711f12007-10-22 21:19:53 +02005469 memcpy(ptr, page_address(sg_page(&st_bp->sg[i])), cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005470 do_count -= cnt;
5471 ptr += cnt;
5472 }
5473 if (do_count || i != st_bp->sg_segs-1) { /* Should never happen */
5474 printk(KERN_WARNING "osst :A: Copy_from_buffer overflow (left %d at sg %d).\n",
5475 do_count, i);
5476 return (-EIO);
5477 }
5478 return 0;
5479}
5480
5481
5482/* Module housekeeping */
5483
5484static void validate_options (void)
5485{
5486 if (max_dev > 0)
5487 osst_max_dev = max_dev;
5488 if (write_threshold_kbs > 0)
5489 osst_write_threshold = write_threshold_kbs * ST_KILOBYTE;
5490 if (osst_write_threshold > osst_buffer_size)
5491 osst_write_threshold = osst_buffer_size;
5492 if (max_sg_segs >= OSST_FIRST_SG)
5493 osst_max_sg_segs = max_sg_segs;
5494#if DEBUG
5495 printk(OSST_DEB_MSG "osst :D: max tapes %d, write threshold %d, max s/g segs %d.\n",
5496 osst_max_dev, osst_write_threshold, osst_max_sg_segs);
5497#endif
5498}
5499
5500#ifndef MODULE
5501/* Set the boot options. Syntax: osst=xxx,yyy,...
5502 where xxx is write threshold in 1024 byte blocks,
5503 and yyy is number of s/g segments to use. */
5504static int __init osst_setup (char *str)
5505{
5506 int i, ints[5];
5507 char *stp;
5508
5509 stp = get_options(str, ARRAY_SIZE(ints), ints);
Tobias Klauser6391a112006-06-08 22:23:48 -07005510
Linus Torvalds1da177e2005-04-16 15:20:36 -07005511 if (ints[0] > 0) {
5512 for (i = 0; i < ints[0] && i < ARRAY_SIZE(parms); i++)
5513 *parms[i].val = ints[i + 1];
5514 } else {
5515 while (stp != NULL) {
5516 for (i = 0; i < ARRAY_SIZE(parms); i++) {
5517 int len = strlen(parms[i].name);
5518 if (!strncmp(stp, parms[i].name, len) &&
5519 (*(stp + len) == ':' || *(stp + len) == '=')) {
5520 *parms[i].val =
5521 simple_strtoul(stp + len + 1, NULL, 0);
5522 break;
5523 }
5524 }
Tobias Klauser6391a112006-06-08 22:23:48 -07005525 if (i >= ARRAY_SIZE(parms))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005526 printk(KERN_INFO "osst :I: Illegal parameter in '%s'\n",
5527 stp);
5528 stp = strchr(stp, ',');
5529 if (stp)
5530 stp++;
5531 }
5532 }
5533
5534 return 1;
5535}
5536
5537__setup("osst=", osst_setup);
5538
5539#endif
5540
Arjan van de Ven00977a52007-02-12 00:55:34 -08005541static const struct file_operations osst_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005542 .owner = THIS_MODULE,
5543 .read = osst_read,
5544 .write = osst_write,
5545 .ioctl = osst_ioctl,
5546#ifdef CONFIG_COMPAT
5547 .compat_ioctl = osst_compat_ioctl,
5548#endif
5549 .open = os_scsi_tape_open,
5550 .flush = os_scsi_tape_flush,
5551 .release = os_scsi_tape_close,
5552};
5553
5554static int osst_supports(struct scsi_device * SDp)
5555{
5556 struct osst_support_data {
5557 char *vendor;
5558 char *model;
5559 char *rev;
5560 char *driver_hint; /* Name of the correct driver, NULL if unknown */
5561 };
5562
5563static struct osst_support_data support_list[] = {
5564 /* {"XXX", "Yy-", "", NULL}, example */
5565 SIGS_FROM_OSST,
5566 {NULL, }};
5567
5568 struct osst_support_data *rp;
5569
5570 /* We are willing to drive OnStream SC-x0 as well as the
5571 * * IDE, ParPort, FireWire, USB variants, if accessible by
5572 * * emulation layer (ide-scsi, usb-storage, ...) */
5573
5574 for (rp=&(support_list[0]); rp->vendor != NULL; rp++)
5575 if (!strncmp(rp->vendor, SDp->vendor, strlen(rp->vendor)) &&
5576 !strncmp(rp->model, SDp->model, strlen(rp->model)) &&
5577 !strncmp(rp->rev, SDp->rev, strlen(rp->rev)))
5578 return 1;
5579 return 0;
5580}
5581
5582/*
5583 * sysfs support for osst driver parameter information
5584 */
5585
5586static ssize_t osst_version_show(struct device_driver *ddd, char *buf)
5587{
5588 return snprintf(buf, PAGE_SIZE, "%s\n", osst_version);
5589}
5590
5591static DRIVER_ATTR(version, S_IRUGO, osst_version_show, NULL);
5592
Robert P. J. Day405ae7d2007-02-17 19:13:42 +01005593static int osst_create_sysfs_files(struct device_driver *sysfs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005594{
Robert P. J. Day405ae7d2007-02-17 19:13:42 +01005595 return driver_create_file(sysfs, &driver_attr_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005596}
5597
Robert P. J. Day405ae7d2007-02-17 19:13:42 +01005598static void osst_remove_sysfs_files(struct device_driver *sysfs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005599{
Robert P. J. Day405ae7d2007-02-17 19:13:42 +01005600 driver_remove_file(sysfs, &driver_attr_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005601}
5602
5603/*
5604 * sysfs support for accessing ADR header information
5605 */
5606
Tony Jonesee959b02008-02-22 00:13:36 +01005607static ssize_t osst_adr_rev_show(struct device *dev,
5608 struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005609{
Tony Jonesee959b02008-02-22 00:13:36 +01005610 struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005611 ssize_t l = 0;
5612
5613 if (STp && STp->header_ok && STp->linux_media)
5614 l = snprintf(buf, PAGE_SIZE, "%d.%d\n", STp->header_cache->major_rev, STp->header_cache->minor_rev);
5615 return l;
5616}
5617
Tony Jonesee959b02008-02-22 00:13:36 +01005618DEVICE_ATTR(ADR_rev, S_IRUGO, osst_adr_rev_show, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005619
Tony Jonesee959b02008-02-22 00:13:36 +01005620static ssize_t osst_linux_media_version_show(struct device *dev,
5621 struct device_attribute *attr,
5622 char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005623{
Tony Jonesee959b02008-02-22 00:13:36 +01005624 struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005625 ssize_t l = 0;
5626
5627 if (STp && STp->header_ok && STp->linux_media)
5628 l = snprintf(buf, PAGE_SIZE, "LIN%d\n", STp->linux_media_version);
5629 return l;
5630}
5631
Tony Jonesee959b02008-02-22 00:13:36 +01005632DEVICE_ATTR(media_version, S_IRUGO, osst_linux_media_version_show, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005633
Tony Jonesee959b02008-02-22 00:13:36 +01005634static ssize_t osst_capacity_show(struct device *dev,
5635 struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005636{
Tony Jonesee959b02008-02-22 00:13:36 +01005637 struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005638 ssize_t l = 0;
5639
5640 if (STp && STp->header_ok && STp->linux_media)
5641 l = snprintf(buf, PAGE_SIZE, "%d\n", STp->capacity);
5642 return l;
5643}
5644
Tony Jonesee959b02008-02-22 00:13:36 +01005645DEVICE_ATTR(capacity, S_IRUGO, osst_capacity_show, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005646
Tony Jonesee959b02008-02-22 00:13:36 +01005647static ssize_t osst_first_data_ppos_show(struct device *dev,
5648 struct device_attribute *attr,
5649 char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005650{
Tony Jonesee959b02008-02-22 00:13:36 +01005651 struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005652 ssize_t l = 0;
5653
5654 if (STp && STp->header_ok && STp->linux_media)
5655 l = snprintf(buf, PAGE_SIZE, "%d\n", STp->first_data_ppos);
5656 return l;
5657}
5658
Tony Jonesee959b02008-02-22 00:13:36 +01005659DEVICE_ATTR(BOT_frame, S_IRUGO, osst_first_data_ppos_show, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005660
Tony Jonesee959b02008-02-22 00:13:36 +01005661static ssize_t osst_eod_frame_ppos_show(struct device *dev,
5662 struct device_attribute *attr,
5663 char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005664{
Tony Jonesee959b02008-02-22 00:13:36 +01005665 struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005666 ssize_t l = 0;
5667
5668 if (STp && STp->header_ok && STp->linux_media)
5669 l = snprintf(buf, PAGE_SIZE, "%d\n", STp->eod_frame_ppos);
5670 return l;
5671}
5672
Tony Jonesee959b02008-02-22 00:13:36 +01005673DEVICE_ATTR(EOD_frame, S_IRUGO, osst_eod_frame_ppos_show, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005674
Tony Jonesee959b02008-02-22 00:13:36 +01005675static ssize_t osst_filemark_cnt_show(struct device *dev,
5676 struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005677{
Tony Jonesee959b02008-02-22 00:13:36 +01005678 struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005679 ssize_t l = 0;
5680
5681 if (STp && STp->header_ok && STp->linux_media)
5682 l = snprintf(buf, PAGE_SIZE, "%d\n", STp->filemark_cnt);
5683 return l;
5684}
5685
Tony Jonesee959b02008-02-22 00:13:36 +01005686DEVICE_ATTR(file_count, S_IRUGO, osst_filemark_cnt_show, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005687
gregkh@suse.ded2538782005-03-23 09:55:22 -08005688static struct class *osst_sysfs_class;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005689
Jeff Garzik37e03332006-10-04 05:23:04 -04005690static int osst_sysfs_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005691{
gregkh@suse.ded2538782005-03-23 09:55:22 -08005692 osst_sysfs_class = class_create(THIS_MODULE, "onstream_tape");
Jeff Garzik37e03332006-10-04 05:23:04 -04005693 if (IS_ERR(osst_sysfs_class)) {
5694 printk(KERN_ERR "osst :W: Unable to register sysfs class\n");
5695 return PTR_ERR(osst_sysfs_class);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005696 }
Jeff Garzik37e03332006-10-04 05:23:04 -04005697
5698 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005699}
5700
5701static void osst_sysfs_destroy(dev_t dev)
5702{
Tony Jonesee959b02008-02-22 00:13:36 +01005703 device_destroy(osst_sysfs_class, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005704}
5705
Jeff Garzik37e03332006-10-04 05:23:04 -04005706static int osst_sysfs_add(dev_t dev, struct device *device, struct osst_tape * STp, char * name)
5707{
Tony Jonesee959b02008-02-22 00:13:36 +01005708 struct device *osst_member;
Jeff Garzik37e03332006-10-04 05:23:04 -04005709 int err;
5710
Greg Kroah-Hartmand73a1a672008-07-21 20:03:34 -07005711 osst_member = device_create(osst_sysfs_class, device, dev, STp,
5712 "%s", name);
Tony Jonesee959b02008-02-22 00:13:36 +01005713 if (IS_ERR(osst_member)) {
Jeff Garzik37e03332006-10-04 05:23:04 -04005714 printk(KERN_WARNING "osst :W: Unable to add sysfs class member %s\n", name);
Tony Jonesee959b02008-02-22 00:13:36 +01005715 return PTR_ERR(osst_member);
Jeff Garzik37e03332006-10-04 05:23:04 -04005716 }
5717
Tony Jonesee959b02008-02-22 00:13:36 +01005718 err = device_create_file(osst_member, &dev_attr_ADR_rev);
Jeff Garzik37e03332006-10-04 05:23:04 -04005719 if (err)
5720 goto err_out;
Tony Jonesee959b02008-02-22 00:13:36 +01005721 err = device_create_file(osst_member, &dev_attr_media_version);
Jeff Garzik37e03332006-10-04 05:23:04 -04005722 if (err)
5723 goto err_out;
Tony Jonesee959b02008-02-22 00:13:36 +01005724 err = device_create_file(osst_member, &dev_attr_capacity);
Jeff Garzik37e03332006-10-04 05:23:04 -04005725 if (err)
5726 goto err_out;
Tony Jonesee959b02008-02-22 00:13:36 +01005727 err = device_create_file(osst_member, &dev_attr_BOT_frame);
Jeff Garzik37e03332006-10-04 05:23:04 -04005728 if (err)
5729 goto err_out;
Tony Jonesee959b02008-02-22 00:13:36 +01005730 err = device_create_file(osst_member, &dev_attr_EOD_frame);
Jeff Garzik37e03332006-10-04 05:23:04 -04005731 if (err)
5732 goto err_out;
Tony Jonesee959b02008-02-22 00:13:36 +01005733 err = device_create_file(osst_member, &dev_attr_file_count);
Jeff Garzik37e03332006-10-04 05:23:04 -04005734 if (err)
5735 goto err_out;
5736
5737 return 0;
5738
5739err_out:
5740 osst_sysfs_destroy(dev);
5741 return err;
5742}
5743
Linus Torvalds1da177e2005-04-16 15:20:36 -07005744static void osst_sysfs_cleanup(void)
5745{
Jeff Garzik37e03332006-10-04 05:23:04 -04005746 class_destroy(osst_sysfs_class);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005747}
5748
5749/*
5750 * osst startup / cleanup code
5751 */
5752
5753static int osst_probe(struct device *dev)
5754{
5755 struct scsi_device * SDp = to_scsi_device(dev);
5756 struct osst_tape * tpnt;
5757 struct st_modedef * STm;
5758 struct st_partstat * STps;
5759 struct osst_buffer * buffer;
5760 struct gendisk * drive;
Jeff Garzik37e03332006-10-04 05:23:04 -04005761 int i, dev_num, err = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005762
5763 if (SDp->type != TYPE_TAPE || !osst_supports(SDp))
5764 return -ENODEV;
5765
5766 drive = alloc_disk(1);
5767 if (!drive) {
5768 printk(KERN_ERR "osst :E: Out of memory. Device not attached.\n");
5769 return -ENODEV;
5770 }
5771
5772 /* if this is the first attach, build the infrastructure */
5773 write_lock(&os_scsi_tapes_lock);
5774 if (os_scsi_tapes == NULL) {
5775 os_scsi_tapes =
5776 (struct osst_tape **)kmalloc(osst_max_dev * sizeof(struct osst_tape *),
5777 GFP_ATOMIC);
5778 if (os_scsi_tapes == NULL) {
5779 write_unlock(&os_scsi_tapes_lock);
5780 printk(KERN_ERR "osst :E: Unable to allocate array for OnStream SCSI tapes.\n");
5781 goto out_put_disk;
5782 }
5783 for (i=0; i < osst_max_dev; ++i) os_scsi_tapes[i] = NULL;
5784 }
5785
5786 if (osst_nr_dev >= osst_max_dev) {
5787 write_unlock(&os_scsi_tapes_lock);
5788 printk(KERN_ERR "osst :E: Too many tape devices (max. %d).\n", osst_max_dev);
5789 goto out_put_disk;
5790 }
5791
5792 /* find a free minor number */
5793 for (i=0; os_scsi_tapes[i] && i<osst_max_dev; i++);
5794 if(i >= osst_max_dev) panic ("Scsi_devices corrupt (osst)");
5795 dev_num = i;
5796
5797 /* allocate a struct osst_tape for this device */
Mariusz Kozlowskibbfbbbc2007-08-11 10:13:24 +02005798 tpnt = kzalloc(sizeof(struct osst_tape), GFP_ATOMIC);
5799 if (!tpnt) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005800 write_unlock(&os_scsi_tapes_lock);
5801 printk(KERN_ERR "osst :E: Can't allocate device descriptor, device not attached.\n");
5802 goto out_put_disk;
5803 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005804
5805 /* allocate a buffer for this device */
5806 i = SDp->host->sg_tablesize;
5807 if (osst_max_sg_segs < i)
5808 i = osst_max_sg_segs;
5809 buffer = new_tape_buffer(1, SDp->host->unchecked_isa_dma, i);
5810 if (buffer == NULL) {
5811 write_unlock(&os_scsi_tapes_lock);
5812 printk(KERN_ERR "osst :E: Unable to allocate a tape buffer, device not attached.\n");
5813 kfree(tpnt);
5814 goto out_put_disk;
5815 }
5816 os_scsi_tapes[dev_num] = tpnt;
5817 tpnt->buffer = buffer;
5818 tpnt->device = SDp;
5819 drive->private_data = &tpnt->driver;
5820 sprintf(drive->disk_name, "osst%d", dev_num);
5821 tpnt->driver = &osst_template;
5822 tpnt->drive = drive;
5823 tpnt->in_use = 0;
5824 tpnt->capacity = 0xfffff;
5825 tpnt->dirty = 0;
5826 tpnt->drv_buffer = 1; /* Try buffering if no mode sense */
5827 tpnt->restr_dma = (SDp->host)->unchecked_isa_dma;
5828 tpnt->density = 0;
5829 tpnt->do_auto_lock = OSST_AUTO_LOCK;
5830 tpnt->can_bsr = OSST_IN_FILE_POS;
5831 tpnt->can_partitions = 0;
5832 tpnt->two_fm = OSST_TWO_FM;
5833 tpnt->fast_mteom = OSST_FAST_MTEOM;
5834 tpnt->scsi2_logical = OSST_SCSI2LOGICAL; /* FIXME */
5835 tpnt->write_threshold = osst_write_threshold;
5836 tpnt->default_drvbuffer = 0xff; /* No forced buffering */
5837 tpnt->partition = 0;
5838 tpnt->new_partition = 0;
5839 tpnt->nbr_partitions = 0;
5840 tpnt->min_block = 512;
5841 tpnt->max_block = OS_DATA_SIZE;
5842 tpnt->timeout = OSST_TIMEOUT;
5843 tpnt->long_timeout = OSST_LONG_TIMEOUT;
5844
5845 /* Recognize OnStream tapes */
5846 /* We don't need to test for OnStream, as this has been done in detect () */
5847 tpnt->os_fw_rev = osst_parse_firmware_rev (SDp->rev);
5848 tpnt->omit_blklims = 1;
5849
5850 tpnt->poll = (strncmp(SDp->model, "DI-", 3) == 0) ||
5851 (strncmp(SDp->model, "FW-", 3) == 0) || OSST_FW_NEED_POLL(tpnt->os_fw_rev,SDp);
5852 tpnt->frame_in_buffer = 0;
5853 tpnt->header_ok = 0;
5854 tpnt->linux_media = 0;
5855 tpnt->header_cache = NULL;
5856
5857 for (i=0; i < ST_NBR_MODES; i++) {
5858 STm = &(tpnt->modes[i]);
5859 STm->defined = 0;
5860 STm->sysv = OSST_SYSV;
5861 STm->defaults_for_writes = 0;
5862 STm->do_async_writes = OSST_ASYNC_WRITES;
5863 STm->do_buffer_writes = OSST_BUFFER_WRITES;
5864 STm->do_read_ahead = OSST_READ_AHEAD;
5865 STm->default_compression = ST_DONT_TOUCH;
5866 STm->default_blksize = 512;
5867 STm->default_density = (-1); /* No forced density */
5868 }
5869
5870 for (i=0; i < ST_NBR_PARTITIONS; i++) {
5871 STps = &(tpnt->ps[i]);
5872 STps->rw = ST_IDLE;
5873 STps->eof = ST_NOEOF;
5874 STps->at_sm = 0;
5875 STps->last_block_valid = 0;
5876 STps->drv_block = (-1);
5877 STps->drv_file = (-1);
5878 }
5879
5880 tpnt->current_mode = 0;
5881 tpnt->modes[0].defined = 1;
5882 tpnt->modes[2].defined = 1;
5883 tpnt->density_changed = tpnt->compression_changed = tpnt->blksize_changed = 0;
5884
Matthias Kaehlcke4390e602007-08-10 14:50:44 -07005885 mutex_init(&tpnt->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005886 osst_nr_dev++;
5887 write_unlock(&os_scsi_tapes_lock);
Jeff Garzik37e03332006-10-04 05:23:04 -04005888
Linus Torvalds1da177e2005-04-16 15:20:36 -07005889 {
5890 char name[8];
Jeff Garzik37e03332006-10-04 05:23:04 -04005891
Linus Torvalds1da177e2005-04-16 15:20:36 -07005892 /* Rewind entry */
Jeff Garzik37e03332006-10-04 05:23:04 -04005893 err = osst_sysfs_add(MKDEV(OSST_MAJOR, dev_num), dev, tpnt, tape_name(tpnt));
5894 if (err)
5895 goto out_free_buffer;
5896
Linus Torvalds1da177e2005-04-16 15:20:36 -07005897 /* No-rewind entry */
5898 snprintf(name, 8, "%s%s", "n", tape_name(tpnt));
Jeff Garzik37e03332006-10-04 05:23:04 -04005899 err = osst_sysfs_add(MKDEV(OSST_MAJOR, dev_num + 128), dev, tpnt, name);
5900 if (err)
5901 goto out_free_sysfs1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005902 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005903
James Bottomley80e23ba2005-10-29 09:42:17 -05005904 sdev_printk(KERN_INFO, SDp,
James Bottomley9ccfc752005-10-02 11:45:08 -05005905 "osst :I: Attached OnStream %.5s tape as %s\n",
5906 SDp->model, tape_name(tpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005907
5908 return 0;
5909
Jeff Garzik37e03332006-10-04 05:23:04 -04005910out_free_sysfs1:
5911 osst_sysfs_destroy(MKDEV(OSST_MAJOR, dev_num));
5912out_free_buffer:
5913 kfree(buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005914out_put_disk:
5915 put_disk(drive);
Jeff Garzik37e03332006-10-04 05:23:04 -04005916 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005917};
5918
5919static int osst_remove(struct device *dev)
5920{
5921 struct scsi_device * SDp = to_scsi_device(dev);
5922 struct osst_tape * tpnt;
Greg KH5e3c34c2006-01-18 16:17:46 -08005923 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005924
5925 if ((SDp->type != TYPE_TAPE) || (osst_nr_dev <= 0))
5926 return 0;
5927
5928 write_lock(&os_scsi_tapes_lock);
5929 for(i=0; i < osst_max_dev; i++) {
5930 if((tpnt = os_scsi_tapes[i]) && (tpnt->device == SDp)) {
5931 osst_sysfs_destroy(MKDEV(OSST_MAJOR, i));
5932 osst_sysfs_destroy(MKDEV(OSST_MAJOR, i+128));
5933 tpnt->device = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005934 put_disk(tpnt->drive);
5935 os_scsi_tapes[i] = NULL;
5936 osst_nr_dev--;
5937 write_unlock(&os_scsi_tapes_lock);
Jesper Juhlf91012102005-09-10 00:26:54 -07005938 vfree(tpnt->header_cache);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005939 if (tpnt->buffer) {
5940 normalize_buffer(tpnt->buffer);
5941 kfree(tpnt->buffer);
5942 }
5943 kfree(tpnt);
5944 return 0;
5945 }
5946 }
5947 write_unlock(&os_scsi_tapes_lock);
5948 return 0;
5949}
5950
5951static int __init init_osst(void)
5952{
Jeff Garzik37e03332006-10-04 05:23:04 -04005953 int err;
5954
Linus Torvalds1da177e2005-04-16 15:20:36 -07005955 printk(KERN_INFO "osst :I: Tape driver with OnStream support version %s\nosst :I: %s\n", osst_version, cvsid);
5956
5957 validate_options();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005958
Jeff Garzik37e03332006-10-04 05:23:04 -04005959 err = osst_sysfs_init();
5960 if (err)
5961 return err;
5962
5963 err = register_chrdev(OSST_MAJOR, "osst", &osst_fops);
5964 if (err < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005965 printk(KERN_ERR "osst :E: Unable to register major %d for OnStream tapes\n", OSST_MAJOR);
Jeff Garzik37e03332006-10-04 05:23:04 -04005966 goto err_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005967 }
Jeff Garzik37e03332006-10-04 05:23:04 -04005968
5969 err = scsi_register_driver(&osst_template.gendrv);
5970 if (err)
5971 goto err_out_chrdev;
5972
Robert P. J. Day405ae7d2007-02-17 19:13:42 +01005973 err = osst_create_sysfs_files(&osst_template.gendrv);
Jeff Garzik37e03332006-10-04 05:23:04 -04005974 if (err)
5975 goto err_out_scsidrv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005976
5977 return 0;
Jeff Garzik37e03332006-10-04 05:23:04 -04005978
5979err_out_scsidrv:
5980 scsi_unregister_driver(&osst_template.gendrv);
5981err_out_chrdev:
5982 unregister_chrdev(OSST_MAJOR, "osst");
5983err_out:
5984 osst_sysfs_cleanup();
5985 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005986}
5987
5988static void __exit exit_osst (void)
5989{
5990 int i;
5991 struct osst_tape * STp;
5992
Robert P. J. Day405ae7d2007-02-17 19:13:42 +01005993 osst_remove_sysfs_files(&osst_template.gendrv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005994 scsi_unregister_driver(&osst_template.gendrv);
5995 unregister_chrdev(OSST_MAJOR, "osst");
5996 osst_sysfs_cleanup();
5997
5998 if (os_scsi_tapes) {
5999 for (i=0; i < osst_max_dev; ++i) {
6000 if (!(STp = os_scsi_tapes[i])) continue;
6001 /* This is defensive, supposed to happen during detach */
Jesper Juhlf91012102005-09-10 00:26:54 -07006002 vfree(STp->header_cache);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006003 if (STp->buffer) {
6004 normalize_buffer(STp->buffer);
6005 kfree(STp->buffer);
6006 }
6007 put_disk(STp->drive);
6008 kfree(STp);
6009 }
6010 kfree(os_scsi_tapes);
6011 }
6012 printk(KERN_INFO "osst :I: Unloaded.\n");
6013}
6014
6015module_init(init_osst);
6016module_exit(exit_osst);