blob: 00f3edc2417f7fc129c0879b1ce1bf4563e7e3dc [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>
52#include <asm/uaccess.h>
53#include <asm/dma.h>
54#include <asm/system.h>
55
56/* The driver prints some debugging information on the console if DEBUG
57 is defined and non-zero. */
58#define DEBUG 0
59
60/* The message level for the debug messages is currently set to KERN_NOTICE
61 so that people can easily see the messages. Later when the debugging messages
62 in the drivers are more widely classified, this may be changed to KERN_DEBUG. */
63#define OSST_DEB_MSG KERN_NOTICE
64
65#include <scsi/scsi.h>
66#include <scsi/scsi_dbg.h>
67#include <scsi/scsi_device.h>
68#include <scsi/scsi_driver.h>
69#include <scsi/scsi_eh.h>
70#include <scsi/scsi_host.h>
71#include <scsi/scsi_ioctl.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070072
73#define ST_KILOBYTE 1024
74
75#include "st.h"
76#include "osst.h"
77#include "osst_options.h"
78#include "osst_detect.h"
79
80static int max_dev = 0;
81static int write_threshold_kbs = 0;
82static int max_sg_segs = 0;
83
84#ifdef MODULE
85MODULE_AUTHOR("Willem Riede");
86MODULE_DESCRIPTION("OnStream {DI-|FW-|SC-|USB}{30|50} Tape Driver");
87MODULE_LICENSE("GPL");
88
89module_param(max_dev, int, 0444);
90MODULE_PARM_DESC(max_dev, "Maximum number of OnStream Tape Drives to attach (4)");
91
92module_param(write_threshold_kbs, int, 0644);
93MODULE_PARM_DESC(write_threshold_kbs, "Asynchronous write threshold (KB; 32)");
94
95module_param(max_sg_segs, int, 0644);
96MODULE_PARM_DESC(max_sg_segs, "Maximum number of scatter/gather segments to use (9)");
97#else
98static struct osst_dev_parm {
99 char *name;
100 int *val;
101} parms[] __initdata = {
102 { "max_dev", &max_dev },
103 { "write_threshold_kbs", &write_threshold_kbs },
104 { "max_sg_segs", &max_sg_segs }
105};
106#endif
107
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108/* Some default definitions have been moved to osst_options.h */
109#define OSST_BUFFER_SIZE (OSST_BUFFER_BLOCKS * ST_KILOBYTE)
110#define OSST_WRITE_THRESHOLD (OSST_WRITE_THRESHOLD_BLOCKS * ST_KILOBYTE)
111
112/* The buffer size should fit into the 24 bits for length in the
113 6-byte SCSI read and write commands. */
114#if OSST_BUFFER_SIZE >= (2 << 24 - 1)
115#error "Buffer size should not exceed (2 << 24 - 1) bytes!"
116#endif
117
118#if DEBUG
119static int debugging = 1;
120/* uncomment define below to test error recovery */
121// #define OSST_INJECT_ERRORS 1
122#endif
123
124/* Do not retry! The drive firmware already retries when appropriate,
125 and when it tries to tell us something, we had better listen... */
126#define MAX_RETRIES 0
127
128#define NO_TAPE NOT_READY
129
130#define OSST_WAIT_POSITION_COMPLETE (HZ > 200 ? HZ / 200 : 1)
131#define OSST_WAIT_WRITE_COMPLETE (HZ / 12)
132#define OSST_WAIT_LONG_WRITE_COMPLETE (HZ / 2)
133
134#define OSST_TIMEOUT (200 * HZ)
135#define OSST_LONG_TIMEOUT (1800 * HZ)
136
137#define TAPE_NR(x) (iminor(x) & ~(-1 << ST_MODE_SHIFT))
138#define TAPE_MODE(x) ((iminor(x) & ST_MODE_MASK) >> ST_MODE_SHIFT)
139#define TAPE_REWIND(x) ((iminor(x) & 0x80) == 0)
140#define TAPE_IS_RAW(x) (TAPE_MODE(x) & (ST_NBR_MODES >> 1))
141
142/* Internal ioctl to set both density (uppermost 8 bits) and blocksize (lower
143 24 bits) */
144#define SET_DENS_AND_BLK 0x10001
145
146static int osst_buffer_size = OSST_BUFFER_SIZE;
147static int osst_write_threshold = OSST_WRITE_THRESHOLD;
148static int osst_max_sg_segs = OSST_MAX_SG;
149static int osst_max_dev = OSST_MAX_TAPES;
150static int osst_nr_dev;
151
152static struct osst_tape **os_scsi_tapes = NULL;
153static DEFINE_RWLOCK(os_scsi_tapes_lock);
154
155static int modes_defined = 0;
156
157static struct osst_buffer *new_tape_buffer(int, int, int);
158static int enlarge_buffer(struct osst_buffer *, int);
159static void normalize_buffer(struct osst_buffer *);
160static int append_to_buffer(const char __user *, struct osst_buffer *, int);
161static int from_buffer(struct osst_buffer *, char __user *, int);
162static int osst_zero_buffer_tail(struct osst_buffer *);
163static int osst_copy_to_buffer(struct osst_buffer *, unsigned char *);
164static int osst_copy_from_buffer(struct osst_buffer *, unsigned char *);
165
166static int osst_probe(struct device *);
167static int osst_remove(struct device *);
168
169static struct scsi_driver osst_template = {
170 .owner = THIS_MODULE,
171 .gendrv = {
172 .name = "osst",
173 .probe = osst_probe,
174 .remove = osst_remove,
175 }
176};
177
Willem Riede5e6575c2006-02-11 14:46:56 -0500178static int osst_int_ioctl(struct osst_tape *STp, struct osst_request ** aSRpnt,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179 unsigned int cmd_in, unsigned long arg);
180
Willem Riede5e6575c2006-02-11 14:46:56 -0500181static int osst_set_frame_position(struct osst_tape *STp, struct osst_request ** aSRpnt, int frame, int skip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182
Willem Riede5e6575c2006-02-11 14:46:56 -0500183static int osst_get_frame_position(struct osst_tape *STp, struct osst_request ** aSRpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184
Willem Riede5e6575c2006-02-11 14:46:56 -0500185static int osst_flush_write_buffer(struct osst_tape *STp, struct osst_request ** aSRpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186
Willem Riede5e6575c2006-02-11 14:46:56 -0500187static int osst_write_error_recovery(struct osst_tape * STp, struct osst_request ** aSRpnt, int pending);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188
189static inline char *tape_name(struct osst_tape *tape)
190{
191 return tape->drive->disk_name;
192}
193
194/* Routines that handle the interaction with mid-layer SCSI routines */
195
Willem Riede5e6575c2006-02-11 14:46:56 -0500196
197/* Normalize Sense */
198static void osst_analyze_sense(struct osst_request *SRpnt, struct st_cmdstatus *s)
199{
200 const u8 *ucp;
201 const u8 *sense = SRpnt->sense;
202
203 s->have_sense = scsi_normalize_sense(SRpnt->sense,
204 SCSI_SENSE_BUFFERSIZE, &s->sense_hdr);
205 s->flags = 0;
206
207 if (s->have_sense) {
208 s->deferred = 0;
209 s->remainder_valid =
210 scsi_get_sense_info_fld(sense, SCSI_SENSE_BUFFERSIZE, &s->uremainder64);
211 switch (sense[0] & 0x7f) {
212 case 0x71:
213 s->deferred = 1;
214 case 0x70:
215 s->fixed_format = 1;
216 s->flags = sense[2] & 0xe0;
217 break;
218 case 0x73:
219 s->deferred = 1;
220 case 0x72:
221 s->fixed_format = 0;
222 ucp = scsi_sense_desc_find(sense, SCSI_SENSE_BUFFERSIZE, 4);
223 s->flags = ucp ? (ucp[3] & 0xe0) : 0;
224 break;
225 }
226 }
227}
228
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229/* Convert the result to success code */
Willem Riede5e6575c2006-02-11 14:46:56 -0500230static int osst_chk_result(struct osst_tape * STp, struct osst_request * SRpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231{
232 char *name = tape_name(STp);
Willem Riede5e6575c2006-02-11 14:46:56 -0500233 int result = SRpnt->result;
234 u8 * sense = SRpnt->sense, scode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235#if DEBUG
236 const char *stp;
237#endif
Willem Riede5e6575c2006-02-11 14:46:56 -0500238 struct st_cmdstatus *cmdstatp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239
Willem Riede5e6575c2006-02-11 14:46:56 -0500240 if (!result)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241 return 0;
Willem Riede5e6575c2006-02-11 14:46:56 -0500242
243 cmdstatp = &STp->buffer->cmdstat;
244 osst_analyze_sense(SRpnt, cmdstatp);
245
246 if (cmdstatp->have_sense)
247 scode = STp->buffer->cmdstat.sense_hdr.sense_key;
248 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249 scode = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250#if DEBUG
251 if (debugging) {
Willem Riede5e6575c2006-02-11 14:46:56 -0500252 printk(OSST_DEB_MSG "%s:D: Error: %x, cmd: %x %x %x %x %x %x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253 name, result,
Willem Riede5e6575c2006-02-11 14:46:56 -0500254 SRpnt->cmd[0], SRpnt->cmd[1], SRpnt->cmd[2],
255 SRpnt->cmd[3], SRpnt->cmd[4], SRpnt->cmd[5]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 if (scode) printk(OSST_DEB_MSG "%s:D: Sense: %02x, ASC: %02x, ASCQ: %02x\n",
257 name, scode, sense[12], sense[13]);
Willem Riede5e6575c2006-02-11 14:46:56 -0500258 if (cmdstatp->have_sense)
259 __scsi_print_sense("osst ", SRpnt->sense, SCSI_SENSE_BUFFERSIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260 }
261 else
262#endif
Willem Riede5e6575c2006-02-11 14:46:56 -0500263 if (cmdstatp->have_sense && (
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264 scode != NO_SENSE &&
265 scode != RECOVERED_ERROR &&
266/* scode != UNIT_ATTENTION && */
267 scode != BLANK_CHECK &&
268 scode != VOLUME_OVERFLOW &&
Willem Riede5e6575c2006-02-11 14:46:56 -0500269 SRpnt->cmd[0] != MODE_SENSE &&
270 SRpnt->cmd[0] != TEST_UNIT_READY)) { /* Abnormal conditions for tape */
271 if (cmdstatp->have_sense) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 printk(KERN_WARNING "%s:W: Command with sense data:\n", name);
Willem Riede5e6575c2006-02-11 14:46:56 -0500273 __scsi_print_sense("osst ", SRpnt->sense, SCSI_SENSE_BUFFERSIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274 }
275 else {
276 static int notyetprinted = 1;
277
278 printk(KERN_WARNING
279 "%s:W: Warning %x (sugg. bt 0x%x, driver bt 0x%x, host bt 0x%x).\n",
280 name, result, suggestion(result), driver_byte(result) & DRIVER_MASK,
281 host_byte(result));
282 if (notyetprinted) {
283 notyetprinted = 0;
284 printk(KERN_INFO
285 "%s:I: This warning may be caused by your scsi controller,\n", name);
286 printk(KERN_INFO
287 "%s:I: it has been reported with some Buslogic cards.\n", name);
288 }
289 }
290 }
291 STp->pos_unknown |= STp->device->was_reset;
292
Willem Riede5e6575c2006-02-11 14:46:56 -0500293 if (cmdstatp->have_sense && scode == RECOVERED_ERROR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 STp->recover_count++;
295 STp->recover_erreg++;
296#if DEBUG
297 if (debugging) {
Willem Riede5e6575c2006-02-11 14:46:56 -0500298 if (SRpnt->cmd[0] == READ_6)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 stp = "read";
Willem Riede5e6575c2006-02-11 14:46:56 -0500300 else if (SRpnt->cmd[0] == WRITE_6)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 stp = "write";
302 else
303 stp = "ioctl";
304 printk(OSST_DEB_MSG "%s:D: Recovered %s error (%d).\n", name, stp,
305 STp->recover_count);
306 }
307#endif
308 if ((sense[2] & 0xe0) == 0)
309 return 0;
310 }
311 return (-EIO);
312}
313
314
315/* Wakeup from interrupt */
Willem Riede5e6575c2006-02-11 14:46:56 -0500316static void osst_sleep_done(void *data, char *sense, int result, int resid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317{
Willem Riede5e6575c2006-02-11 14:46:56 -0500318 struct osst_request *SRpnt = data;
319 struct osst_tape *STp = SRpnt->stp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320
Willem Riede5e6575c2006-02-11 14:46:56 -0500321 memcpy(SRpnt->sense, sense, SCSI_SENSE_BUFFERSIZE);
322 STp->buffer->cmdstat.midlevel_result = SRpnt->result = result;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323#if DEBUG
324 STp->write_pending = 0;
325#endif
Willem Riede5e6575c2006-02-11 14:46:56 -0500326 if (SRpnt->waiting)
327 complete(SRpnt->waiting);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328}
329
Willem Riede5e6575c2006-02-11 14:46:56 -0500330/* osst_request memory management */
331static struct osst_request *osst_allocate_request(void)
332{
333 return kzalloc(sizeof(struct osst_request), GFP_KERNEL);
334}
335
336static void osst_release_request(struct osst_request *streq)
337{
338 kfree(streq);
339}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340
341/* Do the scsi command. Waits until command performed if do_wait is true.
342 Otherwise osst_write_behind_check() is used to check that the command
343 has finished. */
Willem Riede5e6575c2006-02-11 14:46:56 -0500344static struct osst_request * osst_do_scsi(struct osst_request *SRpnt, struct osst_tape *STp,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345 unsigned char *cmd, int bytes, int direction, int timeout, int retries, int do_wait)
346{
347 unsigned char *bp;
Willem Riede5e6575c2006-02-11 14:46:56 -0500348 unsigned short use_sg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349#ifdef OSST_INJECT_ERRORS
350 static int inject = 0;
351 static int repeat = 0;
352#endif
Willem Riede5e6575c2006-02-11 14:46:56 -0500353 struct completion *waiting;
354
355 /* if async, make sure there's no command outstanding */
356 if (!do_wait && ((STp->buffer)->last_SRpnt)) {
357 printk(KERN_ERR "%s: Async command already active.\n",
358 tape_name(STp));
359 if (signal_pending(current))
360 (STp->buffer)->syscall_result = (-EINTR);
361 else
362 (STp->buffer)->syscall_result = (-EBUSY);
363 return NULL;
364 }
365
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 if (SRpnt == NULL) {
Willem Riede5e6575c2006-02-11 14:46:56 -0500367 SRpnt = osst_allocate_request();
368 if (SRpnt == NULL) {
369 printk(KERN_ERR "%s: Can't allocate SCSI request.\n",
370 tape_name(STp));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 if (signal_pending(current))
372 (STp->buffer)->syscall_result = (-EINTR);
373 else
374 (STp->buffer)->syscall_result = (-EBUSY);
375 return NULL;
376 }
Willem Riede5e6575c2006-02-11 14:46:56 -0500377 SRpnt->stp = STp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 }
379
Willem Riede5e6575c2006-02-11 14:46:56 -0500380 /* If async IO, set last_SRpnt. This ptr tells write_behind_check
381 which IO is outstanding. It's nulled out when the IO completes. */
382 if (!do_wait)
383 (STp->buffer)->last_SRpnt = SRpnt;
384
385 waiting = &STp->wait;
386 init_completion(waiting);
387 SRpnt->waiting = waiting;
388
389 use_sg = (bytes > STp->buffer->sg[0].length) ? STp->buffer->use_sg : 0;
390 if (use_sg) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 bp = (char *)&(STp->buffer->sg[0]);
Willem Riede5e6575c2006-02-11 14:46:56 -0500392 if (STp->buffer->sg_segs < use_sg)
393 use_sg = STp->buffer->sg_segs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 }
395 else
396 bp = (STp->buffer)->b_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397
Willem Riede5e6575c2006-02-11 14:46:56 -0500398 memcpy(SRpnt->cmd, cmd, sizeof(SRpnt->cmd));
399 STp->buffer->cmdstat.have_sense = 0;
400 STp->buffer->syscall_result = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401
Willem Riede5e6575c2006-02-11 14:46:56 -0500402 if (scsi_execute_async(STp->device, cmd, COMMAND_SIZE(cmd[0]), direction, bp, bytes,
403 use_sg, timeout, retries, SRpnt, osst_sleep_done, GFP_KERNEL))
404 /* could not allocate the buffer or request was too large */
405 (STp->buffer)->syscall_result = (-EBUSY);
406 else if (do_wait) {
407 wait_for_completion(waiting);
408 SRpnt->waiting = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409 STp->buffer->syscall_result = osst_chk_result(STp, SRpnt);
410#ifdef OSST_INJECT_ERRORS
411 if (STp->buffer->syscall_result == 0 &&
412 cmd[0] == READ_6 &&
413 cmd[4] &&
414 ( (++ inject % 83) == 29 ||
415 (STp->first_frame_position == 240
416 /* or STp->read_error_frame to fail again on the block calculated above */ &&
417 ++repeat < 3))) {
418 printk(OSST_DEB_MSG "%s:D: Injecting read error\n", tape_name(STp));
419 STp->buffer->last_result_fatal = 1;
420 }
421#endif
422 }
423 return SRpnt;
424}
425
426
427/* Handle the write-behind checking (downs the semaphore) */
428static void osst_write_behind_check(struct osst_tape *STp)
429{
430 struct osst_buffer * STbuffer;
431
432 STbuffer = STp->buffer;
433
434#if DEBUG
435 if (STp->write_pending)
436 STp->nbr_waits++;
437 else
438 STp->nbr_finished++;
439#endif
440 wait_for_completion(&(STp->wait));
Willem Riede5e6575c2006-02-11 14:46:56 -0500441 STp->buffer->last_SRpnt->waiting = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442
443 STp->buffer->syscall_result = osst_chk_result(STp, STp->buffer->last_SRpnt);
444
Willem Riede5e6575c2006-02-11 14:46:56 -0500445 if (STp->buffer->syscall_result)
446 STp->buffer->syscall_result =
447 osst_write_error_recovery(STp, &(STp->buffer->last_SRpnt), 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 else
449 STp->first_frame_position++;
450
Willem Riede5e6575c2006-02-11 14:46:56 -0500451 osst_release_request(STp->buffer->last_SRpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452
453 if (STbuffer->writing < STbuffer->buffer_bytes)
454 printk(KERN_WARNING "osst :A: write_behind_check: something left in buffer!\n");
455
Willem Riede5e6575c2006-02-11 14:46:56 -0500456 STbuffer->last_SRpnt = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 STbuffer->buffer_bytes -= STbuffer->writing;
458 STbuffer->writing = 0;
459
460 return;
461}
462
463
464
465/* Onstream specific Routines */
466/*
467 * Initialize the OnStream AUX
468 */
469static void osst_init_aux(struct osst_tape * STp, int frame_type, int frame_seq_number,
470 int logical_blk_num, int blk_sz, int blk_cnt)
471{
472 os_aux_t *aux = STp->buffer->aux;
473 os_partition_t *par = &aux->partition;
474 os_dat_t *dat = &aux->dat;
475
476 if (STp->raw) return;
477
478 memset(aux, 0, sizeof(*aux));
479 aux->format_id = htonl(0);
480 memcpy(aux->application_sig, "LIN4", 4);
481 aux->hdwr = htonl(0);
482 aux->frame_type = frame_type;
483
484 switch (frame_type) {
485 case OS_FRAME_TYPE_HEADER:
486 aux->update_frame_cntr = htonl(STp->update_frame_cntr);
487 par->partition_num = OS_CONFIG_PARTITION;
488 par->par_desc_ver = OS_PARTITION_VERSION;
489 par->wrt_pass_cntr = htons(0xffff);
490 /* 0-4 = reserved, 5-9 = header, 2990-2994 = header, 2995-2999 = reserved */
491 par->first_frame_ppos = htonl(0);
492 par->last_frame_ppos = htonl(0xbb7);
493 aux->frame_seq_num = htonl(0);
494 aux->logical_blk_num_high = htonl(0);
495 aux->logical_blk_num = htonl(0);
496 aux->next_mark_ppos = htonl(STp->first_mark_ppos);
497 break;
498 case OS_FRAME_TYPE_DATA:
499 case OS_FRAME_TYPE_MARKER:
500 dat->dat_sz = 8;
501 dat->reserved1 = 0;
502 dat->entry_cnt = 1;
503 dat->reserved3 = 0;
504 dat->dat_list[0].blk_sz = htonl(blk_sz);
505 dat->dat_list[0].blk_cnt = htons(blk_cnt);
506 dat->dat_list[0].flags = frame_type==OS_FRAME_TYPE_MARKER?
507 OS_DAT_FLAGS_MARK:OS_DAT_FLAGS_DATA;
508 dat->dat_list[0].reserved = 0;
509 case OS_FRAME_TYPE_EOD:
510 aux->update_frame_cntr = htonl(0);
511 par->partition_num = OS_DATA_PARTITION;
512 par->par_desc_ver = OS_PARTITION_VERSION;
513 par->wrt_pass_cntr = htons(STp->wrt_pass_cntr);
514 par->first_frame_ppos = htonl(STp->first_data_ppos);
515 par->last_frame_ppos = htonl(STp->capacity);
516 aux->frame_seq_num = htonl(frame_seq_number);
517 aux->logical_blk_num_high = htonl(0);
518 aux->logical_blk_num = htonl(logical_blk_num);
519 break;
520 default: ; /* probably FILL */
521 }
522 aux->filemark_cnt = ntohl(STp->filemark_cnt);
523 aux->phys_fm = ntohl(0xffffffff);
524 aux->last_mark_ppos = ntohl(STp->last_mark_ppos);
525 aux->last_mark_lbn = ntohl(STp->last_mark_lbn);
526}
527
528/*
529 * Verify that we have the correct tape frame
530 */
531static int osst_verify_frame(struct osst_tape * STp, int frame_seq_number, int quiet)
532{
533 char * name = tape_name(STp);
534 os_aux_t * aux = STp->buffer->aux;
535 os_partition_t * par = &(aux->partition);
536 struct st_partstat * STps = &(STp->ps[STp->partition]);
537 int blk_cnt, blk_sz, i;
538
539 if (STp->raw) {
540 if (STp->buffer->syscall_result) {
541 for (i=0; i < STp->buffer->sg_segs; i++)
542 memset(page_address(STp->buffer->sg[i].page),
543 0, STp->buffer->sg[i].length);
544 strcpy(STp->buffer->b_data, "READ ERROR ON FRAME");
545 } else
546 STp->buffer->buffer_bytes = OS_FRAME_SIZE;
547 return 1;
548 }
549 if (STp->buffer->syscall_result) {
550#if DEBUG
551 printk(OSST_DEB_MSG "%s:D: Skipping frame, read error\n", name);
552#endif
553 return 0;
554 }
555 if (ntohl(aux->format_id) != 0) {
556#if DEBUG
557 printk(OSST_DEB_MSG "%s:D: Skipping frame, format_id %u\n", name, ntohl(aux->format_id));
558#endif
559 goto err_out;
560 }
561 if (memcmp(aux->application_sig, STp->application_sig, 4) != 0 &&
562 (memcmp(aux->application_sig, "LIN3", 4) != 0 || STp->linux_media_version != 4)) {
563#if DEBUG
564 printk(OSST_DEB_MSG "%s:D: Skipping frame, incorrect application signature\n", name);
565#endif
566 goto err_out;
567 }
568 if (par->partition_num != OS_DATA_PARTITION) {
569 if (!STp->linux_media || STp->linux_media_version != 2) {
570#if DEBUG
571 printk(OSST_DEB_MSG "%s:D: Skipping frame, partition num %d\n",
572 name, par->partition_num);
573#endif
574 goto err_out;
575 }
576 }
577 if (par->par_desc_ver != OS_PARTITION_VERSION) {
578#if DEBUG
579 printk(OSST_DEB_MSG "%s:D: Skipping frame, partition version %d\n", name, par->par_desc_ver);
580#endif
581 goto err_out;
582 }
583 if (ntohs(par->wrt_pass_cntr) != STp->wrt_pass_cntr) {
584#if DEBUG
585 printk(OSST_DEB_MSG "%s:D: Skipping frame, wrt_pass_cntr %d (expected %d)\n",
586 name, ntohs(par->wrt_pass_cntr), STp->wrt_pass_cntr);
587#endif
588 goto err_out;
589 }
590 if (aux->frame_type != OS_FRAME_TYPE_DATA &&
591 aux->frame_type != OS_FRAME_TYPE_EOD &&
592 aux->frame_type != OS_FRAME_TYPE_MARKER) {
593 if (!quiet)
594#if DEBUG
595 printk(OSST_DEB_MSG "%s:D: Skipping frame, frame type %x\n", name, aux->frame_type);
596#endif
597 goto err_out;
598 }
599 if (aux->frame_type == OS_FRAME_TYPE_EOD &&
600 STp->first_frame_position < STp->eod_frame_ppos) {
601 printk(KERN_INFO "%s:I: Skipping premature EOD frame %d\n", name,
602 STp->first_frame_position);
603 goto err_out;
604 }
605 if (frame_seq_number != -1 && ntohl(aux->frame_seq_num) != frame_seq_number) {
606 if (!quiet)
607#if DEBUG
608 printk(OSST_DEB_MSG "%s:D: Skipping frame, sequence number %u (expected %d)\n",
609 name, ntohl(aux->frame_seq_num), frame_seq_number);
610#endif
611 goto err_out;
612 }
613 if (aux->frame_type == OS_FRAME_TYPE_MARKER) {
614 STps->eof = ST_FM_HIT;
615
616 i = ntohl(aux->filemark_cnt);
617 if (STp->header_cache != NULL && i < OS_FM_TAB_MAX && (i > STp->filemark_cnt ||
618 STp->first_frame_position - 1 != ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[i]))) {
619#if DEBUG
620 printk(OSST_DEB_MSG "%s:D: %s filemark %d at frame pos %d\n", name,
621 STp->header_cache->dat_fm_tab.fm_tab_ent[i] == 0?"Learned":"Corrected",
622 i, STp->first_frame_position - 1);
623#endif
624 STp->header_cache->dat_fm_tab.fm_tab_ent[i] = htonl(STp->first_frame_position - 1);
625 if (i >= STp->filemark_cnt)
626 STp->filemark_cnt = i+1;
627 }
628 }
629 if (aux->frame_type == OS_FRAME_TYPE_EOD) {
630 STps->eof = ST_EOD_1;
631 STp->frame_in_buffer = 1;
632 }
633 if (aux->frame_type == OS_FRAME_TYPE_DATA) {
634 blk_cnt = ntohs(aux->dat.dat_list[0].blk_cnt);
635 blk_sz = ntohl(aux->dat.dat_list[0].blk_sz);
636 STp->buffer->buffer_bytes = blk_cnt * blk_sz;
637 STp->buffer->read_pointer = 0;
638 STp->frame_in_buffer = 1;
639
640 /* See what block size was used to write file */
641 if (STp->block_size != blk_sz && blk_sz > 0) {
642 printk(KERN_INFO
643 "%s:I: File was written with block size %d%c, currently %d%c, adjusted to match.\n",
644 name, blk_sz<1024?blk_sz:blk_sz/1024,blk_sz<1024?'b':'k',
645 STp->block_size<1024?STp->block_size:STp->block_size/1024,
646 STp->block_size<1024?'b':'k');
647 STp->block_size = blk_sz;
648 STp->buffer->buffer_blocks = OS_DATA_SIZE / blk_sz;
649 }
650 STps->eof = ST_NOEOF;
651 }
652 STp->frame_seq_number = ntohl(aux->frame_seq_num);
653 STp->logical_blk_num = ntohl(aux->logical_blk_num);
654 return 1;
655
656err_out:
657 if (STp->read_error_frame == 0)
658 STp->read_error_frame = STp->first_frame_position - 1;
659 return 0;
660}
661
662/*
663 * Wait for the unit to become Ready
664 */
Willem Riede5e6575c2006-02-11 14:46:56 -0500665static int osst_wait_ready(struct osst_tape * STp, struct osst_request ** aSRpnt,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 unsigned timeout, int initial_delay)
667{
668 unsigned char cmd[MAX_COMMAND_SIZE];
Willem Riede5e6575c2006-02-11 14:46:56 -0500669 struct osst_request * SRpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 unsigned long startwait = jiffies;
671#if DEBUG
672 int dbg = debugging;
673 char * name = tape_name(STp);
674
675 printk(OSST_DEB_MSG "%s:D: Reached onstream wait ready\n", name);
676#endif
677
678 if (initial_delay > 0)
679 msleep(jiffies_to_msecs(initial_delay));
680
681 memset(cmd, 0, MAX_COMMAND_SIZE);
682 cmd[0] = TEST_UNIT_READY;
683
684 SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1);
685 *aSRpnt = SRpnt;
686 if (!SRpnt) return (-EBUSY);
687
688 while ( STp->buffer->syscall_result && time_before(jiffies, startwait + timeout*HZ) &&
Willem Riede5e6575c2006-02-11 14:46:56 -0500689 (( SRpnt->sense[2] == 2 && SRpnt->sense[12] == 4 &&
690 (SRpnt->sense[13] == 1 || SRpnt->sense[13] == 8) ) ||
691 ( SRpnt->sense[2] == 6 && SRpnt->sense[12] == 0x28 &&
692 SRpnt->sense[13] == 0 ) )) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693#if DEBUG
694 if (debugging) {
695 printk(OSST_DEB_MSG "%s:D: Sleeping in onstream wait ready\n", name);
696 printk(OSST_DEB_MSG "%s:D: Turning off debugging for a while\n", name);
697 debugging = 0;
698 }
699#endif
700 msleep(100);
701
702 memset(cmd, 0, MAX_COMMAND_SIZE);
703 cmd[0] = TEST_UNIT_READY;
704
705 SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1);
706 }
707 *aSRpnt = SRpnt;
708#if DEBUG
709 debugging = dbg;
710#endif
711 if ( STp->buffer->syscall_result &&
712 osst_write_error_recovery(STp, aSRpnt, 0) ) {
713#if DEBUG
714 printk(OSST_DEB_MSG "%s:D: Abnormal exit from onstream wait ready\n", name);
715 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 -0500716 STp->buffer->syscall_result, SRpnt->sense[0], SRpnt->sense[2],
717 SRpnt->sense[12], SRpnt->sense[13]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718#endif
719 return (-EIO);
720 }
721#if DEBUG
722 printk(OSST_DEB_MSG "%s:D: Normal exit from onstream wait ready\n", name);
723#endif
724 return 0;
725}
726
727/*
728 * Wait for a tape to be inserted in the unit
729 */
Willem Riede5e6575c2006-02-11 14:46:56 -0500730static int osst_wait_for_medium(struct osst_tape * STp, struct osst_request ** aSRpnt, unsigned timeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731{
732 unsigned char cmd[MAX_COMMAND_SIZE];
Willem Riede5e6575c2006-02-11 14:46:56 -0500733 struct osst_request * SRpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 unsigned long startwait = jiffies;
735#if DEBUG
736 int dbg = debugging;
737 char * name = tape_name(STp);
738
739 printk(OSST_DEB_MSG "%s:D: Reached onstream wait for medium\n", name);
740#endif
741
742 memset(cmd, 0, MAX_COMMAND_SIZE);
743 cmd[0] = TEST_UNIT_READY;
744
745 SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1);
746 *aSRpnt = SRpnt;
747 if (!SRpnt) return (-EBUSY);
748
749 while ( STp->buffer->syscall_result && time_before(jiffies, startwait + timeout*HZ) &&
Willem Riede5e6575c2006-02-11 14:46:56 -0500750 SRpnt->sense[2] == 2 && SRpnt->sense[12] == 0x3a && SRpnt->sense[13] == 0 ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751#if DEBUG
752 if (debugging) {
753 printk(OSST_DEB_MSG "%s:D: Sleeping in onstream wait medium\n", name);
754 printk(OSST_DEB_MSG "%s:D: Turning off debugging for a while\n", name);
755 debugging = 0;
756 }
757#endif
758 msleep(100);
759
760 memset(cmd, 0, MAX_COMMAND_SIZE);
761 cmd[0] = TEST_UNIT_READY;
762
763 SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1);
764 }
765 *aSRpnt = SRpnt;
766#if DEBUG
767 debugging = dbg;
768#endif
Willem Riede5e6575c2006-02-11 14:46:56 -0500769 if ( STp->buffer->syscall_result && SRpnt->sense[2] != 2 &&
770 SRpnt->sense[12] != 4 && SRpnt->sense[13] == 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771#if DEBUG
772 printk(OSST_DEB_MSG "%s:D: Abnormal exit from onstream wait medium\n", name);
773 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 -0500774 STp->buffer->syscall_result, SRpnt->sense[0], SRpnt->sense[2],
775 SRpnt->sense[12], SRpnt->sense[13]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776#endif
777 return 0;
778 }
779#if DEBUG
780 printk(OSST_DEB_MSG "%s:D: Normal exit from onstream wait medium\n", name);
781#endif
782 return 1;
783}
784
Willem Riede5e6575c2006-02-11 14:46:56 -0500785static int osst_position_tape_and_confirm(struct osst_tape * STp, struct osst_request ** aSRpnt, int frame)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786{
787 int retval;
788
789 osst_wait_ready(STp, aSRpnt, 15 * 60, 0); /* TODO - can this catch a write error? */
790 retval = osst_set_frame_position(STp, aSRpnt, frame, 0);
791 if (retval) return (retval);
792 osst_wait_ready(STp, aSRpnt, 15 * 60, OSST_WAIT_POSITION_COMPLETE);
793 return (osst_get_frame_position(STp, aSRpnt));
794}
795
796/*
797 * Wait for write(s) to complete
798 */
Willem Riede5e6575c2006-02-11 14:46:56 -0500799static int osst_flush_drive_buffer(struct osst_tape * STp, struct osst_request ** aSRpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800{
801 unsigned char cmd[MAX_COMMAND_SIZE];
Willem Riede5e6575c2006-02-11 14:46:56 -0500802 struct osst_request * SRpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 int result = 0;
804 int delay = OSST_WAIT_WRITE_COMPLETE;
805#if DEBUG
806 char * name = tape_name(STp);
807
808 printk(OSST_DEB_MSG "%s:D: Reached onstream flush drive buffer (write filemark)\n", name);
809#endif
810
811 memset(cmd, 0, MAX_COMMAND_SIZE);
812 cmd[0] = WRITE_FILEMARKS;
813 cmd[1] = 1;
814
815 SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1);
816 *aSRpnt = SRpnt;
817 if (!SRpnt) return (-EBUSY);
818 if (STp->buffer->syscall_result) {
Willem Riede5e6575c2006-02-11 14:46:56 -0500819 if ((SRpnt->sense[2] & 0x0f) == 2 && SRpnt->sense[12] == 4) {
820 if (SRpnt->sense[13] == 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 delay = OSST_WAIT_LONG_WRITE_COMPLETE;
822 }
823 } else
824 result = osst_write_error_recovery(STp, aSRpnt, 0);
825 }
826 result |= osst_wait_ready(STp, aSRpnt, 5 * 60, delay);
827 STp->ps[STp->partition].rw = OS_WRITING_COMPLETE;
828
829 return (result);
830}
831
832#define OSST_POLL_PER_SEC 10
Willem Riede5e6575c2006-02-11 14:46:56 -0500833static 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 -0700834{
835 unsigned long startwait = jiffies;
836 char * name = tape_name(STp);
837#if DEBUG
838 char notyetprinted = 1;
839#endif
840 if (minlast >= 0 && STp->ps[STp->partition].rw != ST_READING)
841 printk(KERN_ERR "%s:A: Waiting for frame without having initialized read!\n", name);
842
843 while (time_before (jiffies, startwait + to*HZ))
844 {
845 int result;
846 result = osst_get_frame_position(STp, aSRpnt);
847 if (result == -EIO)
848 if ((result = osst_write_error_recovery(STp, aSRpnt, 0)) == 0)
849 return 0; /* successful recovery leaves drive ready for frame */
850 if (result < 0) break;
851 if (STp->first_frame_position == curr &&
852 ((minlast < 0 &&
853 (signed)STp->last_frame_position > (signed)curr + minlast) ||
854 (minlast >= 0 && STp->cur_frames > minlast)
855 ) && result >= 0)
856 {
857#if DEBUG
858 if (debugging || jiffies - startwait >= 2*HZ/OSST_POLL_PER_SEC)
859 printk (OSST_DEB_MSG
860 "%s:D: Succ wait f fr %i (>%i): %i-%i %i (%i): %3li.%li s\n",
861 name, curr, curr+minlast, STp->first_frame_position,
862 STp->last_frame_position, STp->cur_frames,
863 result, (jiffies-startwait)/HZ,
864 (((jiffies-startwait)%HZ)*10)/HZ);
865#endif
866 return 0;
867 }
868#if DEBUG
869 if (jiffies - startwait >= 2*HZ/OSST_POLL_PER_SEC && notyetprinted)
870 {
871 printk (OSST_DEB_MSG "%s:D: Wait for frame %i (>%i): %i-%i %i (%i)\n",
872 name, curr, curr+minlast, STp->first_frame_position,
873 STp->last_frame_position, STp->cur_frames, result);
874 notyetprinted--;
875 }
876#endif
877 msleep(1000 / OSST_POLL_PER_SEC);
878 }
879#if DEBUG
880 printk (OSST_DEB_MSG "%s:D: Fail wait f fr %i (>%i): %i-%i %i: %3li.%li s\n",
881 name, curr, curr+minlast, STp->first_frame_position,
882 STp->last_frame_position, STp->cur_frames,
883 (jiffies-startwait)/HZ, (((jiffies-startwait)%HZ)*10)/HZ);
884#endif
885 return -EBUSY;
886}
887
Willem Riede5e6575c2006-02-11 14:46:56 -0500888static int osst_recover_wait_frame(struct osst_tape * STp, struct osst_request ** aSRpnt, int writing)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889{
Willem Riede5e6575c2006-02-11 14:46:56 -0500890 struct osst_request * SRpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 unsigned char cmd[MAX_COMMAND_SIZE];
892 unsigned long startwait = jiffies;
893 int retval = 1;
894 char * name = tape_name(STp);
895
896 if (writing) {
897 char mybuf[24];
898 char * olddata = STp->buffer->b_data;
899 int oldsize = STp->buffer->buffer_size;
900
901 /* write zero fm then read pos - if shows write error, try to recover - if no progress, wait */
902
903 memset(cmd, 0, MAX_COMMAND_SIZE);
904 cmd[0] = WRITE_FILEMARKS;
905 cmd[1] = 1;
906 SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, DMA_NONE, STp->timeout,
907 MAX_RETRIES, 1);
908
909 while (retval && time_before (jiffies, startwait + 5*60*HZ)) {
910
Willem Riede5e6575c2006-02-11 14:46:56 -0500911 if (STp->buffer->syscall_result && (SRpnt->sense[2] & 0x0f) != 2) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912
913 /* some failure - not just not-ready */
914 retval = osst_write_error_recovery(STp, aSRpnt, 0);
915 break;
916 }
Nishanth Aravamudana9a30472005-11-07 01:01:20 -0800917 schedule_timeout_interruptible(HZ / OSST_POLL_PER_SEC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918
919 STp->buffer->b_data = mybuf; STp->buffer->buffer_size = 24;
920 memset(cmd, 0, MAX_COMMAND_SIZE);
921 cmd[0] = READ_POSITION;
922
923 SRpnt = osst_do_scsi(SRpnt, STp, cmd, 20, DMA_FROM_DEVICE, STp->timeout,
924 MAX_RETRIES, 1);
925
926 retval = ( STp->buffer->syscall_result || (STp->buffer)->b_data[15] > 25 );
927 STp->buffer->b_data = olddata; STp->buffer->buffer_size = oldsize;
928 }
929 if (retval)
930 printk(KERN_ERR "%s:E: Device did not succeed to write buffered data\n", name);
931 } else
932 /* TODO - figure out which error conditions can be handled */
933 if (STp->buffer->syscall_result)
934 printk(KERN_WARNING
935 "%s:W: Recover_wait_frame(read) cannot handle %02x:%02x:%02x\n", name,
Willem Riede5e6575c2006-02-11 14:46:56 -0500936 (*aSRpnt)->sense[ 2] & 0x0f,
937 (*aSRpnt)->sense[12],
938 (*aSRpnt)->sense[13]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939
940 return retval;
941}
942
943/*
944 * Read the next OnStream tape frame at the current location
945 */
Willem Riede5e6575c2006-02-11 14:46:56 -0500946static int osst_read_frame(struct osst_tape * STp, struct osst_request ** aSRpnt, int timeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947{
948 unsigned char cmd[MAX_COMMAND_SIZE];
Willem Riede5e6575c2006-02-11 14:46:56 -0500949 struct osst_request * SRpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950 int retval = 0;
951#if DEBUG
952 os_aux_t * aux = STp->buffer->aux;
953 char * name = tape_name(STp);
954#endif
955
956 if (STp->poll)
957 if (osst_wait_frame (STp, aSRpnt, STp->first_frame_position, 0, timeout))
958 retval = osst_recover_wait_frame(STp, aSRpnt, 0);
959
960 memset(cmd, 0, MAX_COMMAND_SIZE);
961 cmd[0] = READ_6;
962 cmd[1] = 1;
963 cmd[4] = 1;
964
965#if DEBUG
966 if (debugging)
967 printk(OSST_DEB_MSG "%s:D: Reading frame from OnStream tape\n", name);
968#endif
969 SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, OS_FRAME_SIZE, DMA_FROM_DEVICE,
970 STp->timeout, MAX_RETRIES, 1);
971 *aSRpnt = SRpnt;
972 if (!SRpnt)
973 return (-EBUSY);
974
975 if ((STp->buffer)->syscall_result) {
976 retval = 1;
977 if (STp->read_error_frame == 0) {
978 STp->read_error_frame = STp->first_frame_position;
979#if DEBUG
980 printk(OSST_DEB_MSG "%s:D: Recording read error at %d\n", name, STp->read_error_frame);
981#endif
982 }
983#if DEBUG
984 if (debugging)
985 printk(OSST_DEB_MSG "%s:D: Sense: %2x %2x %2x %2x %2x %2x %2x %2x\n",
986 name,
Willem Riede5e6575c2006-02-11 14:46:56 -0500987 SRpnt->sense[0], SRpnt->sense[1],
988 SRpnt->sense[2], SRpnt->sense[3],
989 SRpnt->sense[4], SRpnt->sense[5],
990 SRpnt->sense[6], SRpnt->sense[7]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991#endif
992 }
993 else
994 STp->first_frame_position++;
995#if DEBUG
996 if (debugging) {
997 char sig[8]; int i;
998 for (i=0;i<4;i++)
999 sig[i] = aux->application_sig[i]<32?'^':aux->application_sig[i];
1000 sig[4] = '\0';
1001 printk(OSST_DEB_MSG
1002 "%s:D: AUX: %s UpdFrCt#%d Wpass#%d %s FrSeq#%d LogBlk#%d Qty=%d Sz=%d\n", name, sig,
1003 ntohl(aux->update_frame_cntr), ntohs(aux->partition.wrt_pass_cntr),
1004 aux->frame_type==1?"EOD":aux->frame_type==2?"MARK":
1005 aux->frame_type==8?"HEADR":aux->frame_type==0x80?"DATA":"FILL",
1006 ntohl(aux->frame_seq_num), ntohl(aux->logical_blk_num),
1007 ntohs(aux->dat.dat_list[0].blk_cnt), ntohl(aux->dat.dat_list[0].blk_sz) );
1008 if (aux->frame_type==2)
1009 printk(OSST_DEB_MSG "%s:D: mark_cnt=%d, last_mark_ppos=%d, last_mark_lbn=%d\n", name,
1010 ntohl(aux->filemark_cnt), ntohl(aux->last_mark_ppos), ntohl(aux->last_mark_lbn));
1011 printk(OSST_DEB_MSG "%s:D: Exit read frame from OnStream tape with code %d\n", name, retval);
1012 }
1013#endif
1014 return (retval);
1015}
1016
Willem Riede5e6575c2006-02-11 14:46:56 -05001017static int osst_initiate_read(struct osst_tape * STp, struct osst_request ** aSRpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018{
1019 struct st_partstat * STps = &(STp->ps[STp->partition]);
Willem Riede5e6575c2006-02-11 14:46:56 -05001020 struct osst_request * SRpnt ;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 unsigned char cmd[MAX_COMMAND_SIZE];
1022 int retval = 0;
1023 char * name = tape_name(STp);
1024
1025 if (STps->rw != ST_READING) { /* Initialize read operation */
1026 if (STps->rw == ST_WRITING || STp->dirty) {
1027 STp->write_type = OS_WRITE_DATA;
1028 osst_flush_write_buffer(STp, aSRpnt);
1029 osst_flush_drive_buffer(STp, aSRpnt);
1030 }
1031 STps->rw = ST_READING;
1032 STp->frame_in_buffer = 0;
1033
1034 /*
1035 * Issue a read 0 command to get the OnStream drive
1036 * read frames into its buffer.
1037 */
1038 memset(cmd, 0, MAX_COMMAND_SIZE);
1039 cmd[0] = READ_6;
1040 cmd[1] = 1;
1041
1042#if DEBUG
1043 printk(OSST_DEB_MSG "%s:D: Start Read Ahead on OnStream tape\n", name);
1044#endif
1045 SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1);
1046 *aSRpnt = SRpnt;
1047 if ((retval = STp->buffer->syscall_result))
1048 printk(KERN_WARNING "%s:W: Error starting read ahead\n", name);
1049 }
1050
1051 return retval;
1052}
1053
Willem Riede5e6575c2006-02-11 14:46:56 -05001054static int osst_get_logical_frame(struct osst_tape * STp, struct osst_request ** aSRpnt,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055 int frame_seq_number, int quiet)
1056{
1057 struct st_partstat * STps = &(STp->ps[STp->partition]);
1058 char * name = tape_name(STp);
1059 int cnt = 0,
1060 bad = 0,
1061 past = 0,
1062 x,
1063 position;
1064
1065 /*
1066 * If we want just any frame (-1) and there is a frame in the buffer, return it
1067 */
1068 if (frame_seq_number == -1 && STp->frame_in_buffer) {
1069#if DEBUG
1070 printk(OSST_DEB_MSG "%s:D: Frame %d still in buffer\n", name, STp->frame_seq_number);
1071#endif
1072 return (STps->eof);
1073 }
1074 /*
1075 * Search and wait for the next logical tape frame
1076 */
1077 while (1) {
1078 if (cnt++ > 400) {
1079 printk(KERN_ERR "%s:E: Couldn't find logical frame %d, aborting\n",
1080 name, frame_seq_number);
1081 if (STp->read_error_frame) {
1082 osst_set_frame_position(STp, aSRpnt, STp->read_error_frame, 0);
1083#if DEBUG
1084 printk(OSST_DEB_MSG "%s:D: Repositioning tape to bad frame %d\n",
1085 name, STp->read_error_frame);
1086#endif
1087 STp->read_error_frame = 0;
1088 STp->abort_count++;
1089 }
1090 return (-EIO);
1091 }
1092#if DEBUG
1093 if (debugging)
1094 printk(OSST_DEB_MSG "%s:D: Looking for frame %d, attempt %d\n",
1095 name, frame_seq_number, cnt);
1096#endif
1097 if ( osst_initiate_read(STp, aSRpnt)
1098 || ( (!STp->frame_in_buffer) && osst_read_frame(STp, aSRpnt, 30) ) ) {
1099 if (STp->raw)
1100 return (-EIO);
1101 position = osst_get_frame_position(STp, aSRpnt);
1102 if (position >= 0xbae && position < 0xbb8)
1103 position = 0xbb8;
1104 else if (position > STp->eod_frame_ppos || ++bad == 10) {
1105 position = STp->read_error_frame - 1;
1106 bad = 0;
1107 }
1108 else {
1109 position += 29;
1110 cnt += 19;
1111 }
1112#if DEBUG
1113 printk(OSST_DEB_MSG "%s:D: Bad frame detected, positioning tape to block %d\n",
1114 name, position);
1115#endif
1116 osst_set_frame_position(STp, aSRpnt, position, 0);
1117 continue;
1118 }
1119 if (osst_verify_frame(STp, frame_seq_number, quiet))
1120 break;
1121 if (osst_verify_frame(STp, -1, quiet)) {
1122 x = ntohl(STp->buffer->aux->frame_seq_num);
1123 if (STp->fast_open) {
1124 printk(KERN_WARNING
1125 "%s:W: Found logical frame %d instead of %d after fast open\n",
1126 name, x, frame_seq_number);
1127 STp->header_ok = 0;
1128 STp->read_error_frame = 0;
1129 return (-EIO);
1130 }
1131 if (x > frame_seq_number) {
1132 if (++past > 3) {
1133 /* positioning backwards did not bring us to the desired frame */
1134 position = STp->read_error_frame - 1;
1135 }
1136 else {
1137 position = osst_get_frame_position(STp, aSRpnt)
1138 + frame_seq_number - x - 1;
1139
1140 if (STp->first_frame_position >= 3000 && position < 3000)
1141 position -= 10;
1142 }
1143#if DEBUG
1144 printk(OSST_DEB_MSG
1145 "%s:D: Found logical frame %d while looking for %d: back up %d\n",
1146 name, x, frame_seq_number,
1147 STp->first_frame_position - position);
1148#endif
1149 osst_set_frame_position(STp, aSRpnt, position, 0);
1150 cnt += 10;
1151 }
1152 else
1153 past = 0;
1154 }
1155 if (osst_get_frame_position(STp, aSRpnt) == 0xbaf) {
1156#if DEBUG
1157 printk(OSST_DEB_MSG "%s:D: Skipping config partition\n", name);
1158#endif
1159 osst_set_frame_position(STp, aSRpnt, 0xbb8, 0);
1160 cnt--;
1161 }
1162 STp->frame_in_buffer = 0;
1163 }
1164 if (cnt > 1) {
1165 STp->recover_count++;
1166 STp->recover_erreg++;
1167 printk(KERN_WARNING "%s:I: Don't worry, Read error at position %d recovered\n",
1168 name, STp->read_error_frame);
1169 }
1170 STp->read_count++;
1171
1172#if DEBUG
1173 if (debugging || STps->eof)
1174 printk(OSST_DEB_MSG
1175 "%s:D: Exit get logical frame (%d=>%d) from OnStream tape with code %d\n",
1176 name, frame_seq_number, STp->frame_seq_number, STps->eof);
1177#endif
1178 STp->fast_open = 0;
1179 STp->read_error_frame = 0;
1180 return (STps->eof);
1181}
1182
Willem Riede5e6575c2006-02-11 14:46:56 -05001183static int osst_seek_logical_blk(struct osst_tape * STp, struct osst_request ** aSRpnt, int logical_blk_num)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184{
1185 struct st_partstat * STps = &(STp->ps[STp->partition]);
1186 char * name = tape_name(STp);
1187 int retries = 0;
1188 int frame_seq_estimate, ppos_estimate, move;
1189
1190 if (logical_blk_num < 0) logical_blk_num = 0;
1191#if DEBUG
1192 printk(OSST_DEB_MSG "%s:D: Seeking logical block %d (now at %d, size %d%c)\n",
1193 name, logical_blk_num, STp->logical_blk_num,
1194 STp->block_size<1024?STp->block_size:STp->block_size/1024,
1195 STp->block_size<1024?'b':'k');
1196#endif
1197 /* Do we know where we are? */
1198 if (STps->drv_block >= 0) {
1199 move = logical_blk_num - STp->logical_blk_num;
1200 if (move < 0) move -= (OS_DATA_SIZE / STp->block_size) - 1;
1201 move /= (OS_DATA_SIZE / STp->block_size);
1202 frame_seq_estimate = STp->frame_seq_number + move;
1203 } else
1204 frame_seq_estimate = logical_blk_num * STp->block_size / OS_DATA_SIZE;
1205
1206 if (frame_seq_estimate < 2980) ppos_estimate = frame_seq_estimate + 10;
1207 else ppos_estimate = frame_seq_estimate + 20;
1208 while (++retries < 10) {
1209 if (ppos_estimate > STp->eod_frame_ppos-2) {
1210 frame_seq_estimate += STp->eod_frame_ppos - 2 - ppos_estimate;
1211 ppos_estimate = STp->eod_frame_ppos - 2;
1212 }
1213 if (frame_seq_estimate < 0) {
1214 frame_seq_estimate = 0;
1215 ppos_estimate = 10;
1216 }
1217 osst_set_frame_position(STp, aSRpnt, ppos_estimate, 0);
1218 if (osst_get_logical_frame(STp, aSRpnt, frame_seq_estimate, 1) >= 0) {
1219 /* we've located the estimated frame, now does it have our block? */
1220 if (logical_blk_num < STp->logical_blk_num ||
1221 logical_blk_num >= STp->logical_blk_num + ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt)) {
1222 if (STps->eof == ST_FM_HIT)
1223 move = logical_blk_num < STp->logical_blk_num? -2 : 1;
1224 else {
1225 move = logical_blk_num - STp->logical_blk_num;
1226 if (move < 0) move -= (OS_DATA_SIZE / STp->block_size) - 1;
1227 move /= (OS_DATA_SIZE / STp->block_size);
1228 }
1229 if (!move) move = logical_blk_num > STp->logical_blk_num ? 1 : -1;
1230#if DEBUG
1231 printk(OSST_DEB_MSG
1232 "%s:D: Seek retry %d at ppos %d fsq %d (est %d) lbn %d (need %d) move %d\n",
1233 name, retries, ppos_estimate, STp->frame_seq_number, frame_seq_estimate,
1234 STp->logical_blk_num, logical_blk_num, move);
1235#endif
1236 frame_seq_estimate += move;
1237 ppos_estimate += move;
1238 continue;
1239 } else {
1240 STp->buffer->read_pointer = (logical_blk_num - STp->logical_blk_num) * STp->block_size;
1241 STp->buffer->buffer_bytes -= STp->buffer->read_pointer;
1242 STp->logical_blk_num = logical_blk_num;
1243#if DEBUG
1244 printk(OSST_DEB_MSG
1245 "%s:D: Seek success at ppos %d fsq %d in_buf %d, bytes %d, ptr %d*%d\n",
1246 name, ppos_estimate, STp->frame_seq_number, STp->frame_in_buffer,
1247 STp->buffer->buffer_bytes, STp->buffer->read_pointer / STp->block_size,
1248 STp->block_size);
1249#endif
1250 STps->drv_file = ntohl(STp->buffer->aux->filemark_cnt);
1251 if (STps->eof == ST_FM_HIT) {
1252 STps->drv_file++;
1253 STps->drv_block = 0;
1254 } else {
1255 STps->drv_block = ntohl(STp->buffer->aux->last_mark_lbn)?
1256 STp->logical_blk_num -
1257 (STps->drv_file ? ntohl(STp->buffer->aux->last_mark_lbn) + 1 : 0):
1258 -1;
1259 }
1260 STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD:ST_NOEOF;
1261 return 0;
1262 }
1263 }
1264 if (osst_get_logical_frame(STp, aSRpnt, -1, 1) < 0)
1265 goto error;
1266 /* we are not yet at the estimated frame, adjust our estimate of its physical position */
1267#if DEBUG
1268 printk(OSST_DEB_MSG "%s:D: Seek retry %d at ppos %d fsq %d (est %d) lbn %d (need %d)\n",
1269 name, retries, ppos_estimate, STp->frame_seq_number, frame_seq_estimate,
1270 STp->logical_blk_num, logical_blk_num);
1271#endif
1272 if (frame_seq_estimate != STp->frame_seq_number)
1273 ppos_estimate += frame_seq_estimate - STp->frame_seq_number;
1274 else
1275 break;
1276 }
1277error:
1278 printk(KERN_ERR "%s:E: Couldn't seek to logical block %d (at %d), %d retries\n",
1279 name, logical_blk_num, STp->logical_blk_num, retries);
1280 return (-EIO);
1281}
1282
1283/* The values below are based on the OnStream frame payload size of 32K == 2**15,
1284 * that is, OSST_FRAME_SHIFT + OSST_SECTOR_SHIFT must be 15. With a minimum block
1285 * size of 512 bytes, we need to be able to resolve 32K/512 == 64 == 2**6 positions
1286 * inside each frame. Finaly, OSST_SECTOR_MASK == 2**OSST_FRAME_SHIFT - 1.
1287 */
1288#define OSST_FRAME_SHIFT 6
1289#define OSST_SECTOR_SHIFT 9
1290#define OSST_SECTOR_MASK 0x03F
1291
Willem Riede5e6575c2006-02-11 14:46:56 -05001292static int osst_get_sector(struct osst_tape * STp, struct osst_request ** aSRpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293{
1294 int sector;
1295#if DEBUG
1296 char * name = tape_name(STp);
1297
1298 printk(OSST_DEB_MSG
1299 "%s:D: Positioned at ppos %d, frame %d, lbn %d, file %d, blk %d, %cptr %d, eof %d\n",
1300 name, STp->first_frame_position, STp->frame_seq_number, STp->logical_blk_num,
1301 STp->ps[STp->partition].drv_file, STp->ps[STp->partition].drv_block,
1302 STp->ps[STp->partition].rw == ST_WRITING?'w':'r',
1303 STp->ps[STp->partition].rw == ST_WRITING?STp->buffer->buffer_bytes:
1304 STp->buffer->read_pointer, STp->ps[STp->partition].eof);
1305#endif
1306 /* do we know where we are inside a file? */
1307 if (STp->ps[STp->partition].drv_block >= 0) {
1308 sector = (STp->frame_in_buffer ? STp->first_frame_position-1 :
1309 STp->first_frame_position) << OSST_FRAME_SHIFT;
1310 if (STp->ps[STp->partition].rw == ST_WRITING)
1311 sector |= (STp->buffer->buffer_bytes >> OSST_SECTOR_SHIFT) & OSST_SECTOR_MASK;
1312 else
1313 sector |= (STp->buffer->read_pointer >> OSST_SECTOR_SHIFT) & OSST_SECTOR_MASK;
1314 } else {
1315 sector = osst_get_frame_position(STp, aSRpnt);
1316 if (sector > 0)
1317 sector <<= OSST_FRAME_SHIFT;
1318 }
1319 return sector;
1320}
1321
Willem Riede5e6575c2006-02-11 14:46:56 -05001322static int osst_seek_sector(struct osst_tape * STp, struct osst_request ** aSRpnt, int sector)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323{
1324 struct st_partstat * STps = &(STp->ps[STp->partition]);
1325 int frame = sector >> OSST_FRAME_SHIFT,
1326 offset = (sector & OSST_SECTOR_MASK) << OSST_SECTOR_SHIFT,
1327 r;
1328#if DEBUG
1329 char * name = tape_name(STp);
1330
1331 printk(OSST_DEB_MSG "%s:D: Seeking sector %d in frame %d at offset %d\n",
1332 name, sector, frame, offset);
1333#endif
1334 if (frame < 0 || frame >= STp->capacity) return (-ENXIO);
1335
1336 if (frame <= STp->first_data_ppos) {
1337 STp->frame_seq_number = STp->logical_blk_num = STps->drv_file = STps->drv_block = 0;
1338 return (osst_set_frame_position(STp, aSRpnt, frame, 0));
1339 }
1340 r = osst_set_frame_position(STp, aSRpnt, offset?frame:frame-1, 0);
1341 if (r < 0) return r;
1342
1343 r = osst_get_logical_frame(STp, aSRpnt, -1, 1);
1344 if (r < 0) return r;
1345
1346 if (osst_get_frame_position(STp, aSRpnt) != (offset?frame+1:frame)) return (-EIO);
1347
1348 if (offset) {
1349 STp->logical_blk_num += offset / STp->block_size;
1350 STp->buffer->read_pointer = offset;
1351 STp->buffer->buffer_bytes -= offset;
1352 } else {
1353 STp->frame_seq_number++;
1354 STp->frame_in_buffer = 0;
1355 STp->logical_blk_num += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
1356 STp->buffer->buffer_bytes = STp->buffer->read_pointer = 0;
1357 }
1358 STps->drv_file = ntohl(STp->buffer->aux->filemark_cnt);
1359 if (STps->eof == ST_FM_HIT) {
1360 STps->drv_file++;
1361 STps->drv_block = 0;
1362 } else {
1363 STps->drv_block = ntohl(STp->buffer->aux->last_mark_lbn)?
1364 STp->logical_blk_num -
1365 (STps->drv_file ? ntohl(STp->buffer->aux->last_mark_lbn) + 1 : 0):
1366 -1;
1367 }
1368 STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD:ST_NOEOF;
1369#if DEBUG
1370 printk(OSST_DEB_MSG
1371 "%s:D: Now positioned at ppos %d, frame %d, lbn %d, file %d, blk %d, rptr %d, eof %d\n",
1372 name, STp->first_frame_position, STp->frame_seq_number, STp->logical_blk_num,
1373 STps->drv_file, STps->drv_block, STp->buffer->read_pointer, STps->eof);
1374#endif
1375 return 0;
1376}
1377
1378/*
1379 * Read back the drive's internal buffer contents, as a part
1380 * of the write error recovery mechanism for old OnStream
1381 * firmware revisions.
1382 * Precondition for this function to work: all frames in the
1383 * drive's buffer must be of one type (DATA, MARK or EOD)!
1384 */
Willem Riede5e6575c2006-02-11 14:46:56 -05001385static int osst_read_back_buffer_and_rewrite(struct osst_tape * STp, struct osst_request ** aSRpnt,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386 unsigned int frame, unsigned int skip, int pending)
1387{
Willem Riede5e6575c2006-02-11 14:46:56 -05001388 struct osst_request * SRpnt = * aSRpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389 unsigned char * buffer, * p;
1390 unsigned char cmd[MAX_COMMAND_SIZE];
1391 int flag, new_frame, i;
1392 int nframes = STp->cur_frames;
1393 int blks_per_frame = ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
1394 int frame_seq_number = ntohl(STp->buffer->aux->frame_seq_num)
1395 - (nframes + pending - 1);
1396 int logical_blk_num = ntohl(STp->buffer->aux->logical_blk_num)
1397 - (nframes + pending - 1) * blks_per_frame;
1398 char * name = tape_name(STp);
1399 unsigned long startwait = jiffies;
1400#if DEBUG
1401 int dbg = debugging;
1402#endif
1403
1404 if ((buffer = (unsigned char *)vmalloc((nframes + 1) * OS_DATA_SIZE)) == NULL)
1405 return (-EIO);
1406
1407 printk(KERN_INFO "%s:I: Reading back %d frames from drive buffer%s\n",
1408 name, nframes, pending?" and one that was pending":"");
1409
1410 osst_copy_from_buffer(STp->buffer, (p = &buffer[nframes * OS_DATA_SIZE]));
1411#if DEBUG
1412 if (pending && debugging)
1413 printk(OSST_DEB_MSG "%s:D: Pending frame %d (lblk %d), data %02x %02x %02x %02x\n",
1414 name, frame_seq_number + nframes,
1415 logical_blk_num + nframes * blks_per_frame,
1416 p[0], p[1], p[2], p[3]);
1417#endif
1418 for (i = 0, p = buffer; i < nframes; i++, p += OS_DATA_SIZE) {
1419
1420 memset(cmd, 0, MAX_COMMAND_SIZE);
1421 cmd[0] = 0x3C; /* Buffer Read */
1422 cmd[1] = 6; /* Retrieve Faulty Block */
1423 cmd[7] = 32768 >> 8;
1424 cmd[8] = 32768 & 0xff;
1425
1426 SRpnt = osst_do_scsi(SRpnt, STp, cmd, OS_FRAME_SIZE, DMA_FROM_DEVICE,
1427 STp->timeout, MAX_RETRIES, 1);
1428
1429 if ((STp->buffer)->syscall_result || !SRpnt) {
1430 printk(KERN_ERR "%s:E: Failed to read frame back from OnStream buffer\n", name);
Jesper Juhlf91012102005-09-10 00:26:54 -07001431 vfree(buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001432 *aSRpnt = SRpnt;
1433 return (-EIO);
1434 }
1435 osst_copy_from_buffer(STp->buffer, p);
1436#if DEBUG
1437 if (debugging)
1438 printk(OSST_DEB_MSG "%s:D: Read back logical frame %d, data %02x %02x %02x %02x\n",
1439 name, frame_seq_number + i, p[0], p[1], p[2], p[3]);
1440#endif
1441 }
1442 *aSRpnt = SRpnt;
1443 osst_get_frame_position(STp, aSRpnt);
1444
1445#if DEBUG
1446 printk(OSST_DEB_MSG "%s:D: Frames left in buffer: %d\n", name, STp->cur_frames);
1447#endif
1448 /* Write synchronously so we can be sure we're OK again and don't have to recover recursively */
1449 /* In the header we don't actually re-write the frames that fail, just the ones after them */
1450
1451 for (flag=1, new_frame=frame, p=buffer, i=0; i < nframes + pending; ) {
1452
1453 if (flag) {
1454 if (STp->write_type == OS_WRITE_HEADER) {
1455 i += skip;
1456 p += skip * OS_DATA_SIZE;
1457 }
1458 else if (new_frame < 2990 && new_frame+skip+nframes+pending >= 2990)
1459 new_frame = 3000-i;
1460 else
1461 new_frame += skip;
1462#if DEBUG
1463 printk(OSST_DEB_MSG "%s:D: Position to frame %d, write fseq %d\n",
1464 name, new_frame+i, frame_seq_number+i);
1465#endif
1466 osst_set_frame_position(STp, aSRpnt, new_frame + i, 0);
1467 osst_wait_ready(STp, aSRpnt, 60, OSST_WAIT_POSITION_COMPLETE);
1468 osst_get_frame_position(STp, aSRpnt);
1469 SRpnt = * aSRpnt;
1470
1471 if (new_frame > frame + 1000) {
1472 printk(KERN_ERR "%s:E: Failed to find writable tape media\n", name);
Jesper Juhlf91012102005-09-10 00:26:54 -07001473 vfree(buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474 return (-EIO);
1475 }
1476 if ( i >= nframes + pending ) break;
1477 flag = 0;
1478 }
1479 osst_copy_to_buffer(STp->buffer, p);
1480 /*
1481 * IMPORTANT: for error recovery to work, _never_ queue frames with mixed frame type!
1482 */
1483 osst_init_aux(STp, STp->buffer->aux->frame_type, frame_seq_number+i,
1484 logical_blk_num + i*blks_per_frame,
1485 ntohl(STp->buffer->aux->dat.dat_list[0].blk_sz), blks_per_frame);
1486 memset(cmd, 0, MAX_COMMAND_SIZE);
1487 cmd[0] = WRITE_6;
1488 cmd[1] = 1;
1489 cmd[4] = 1;
1490
1491#if DEBUG
1492 if (debugging)
1493 printk(OSST_DEB_MSG
1494 "%s:D: About to write frame %d, seq %d, lbn %d, data %02x %02x %02x %02x\n",
1495 name, new_frame+i, frame_seq_number+i, logical_blk_num + i*blks_per_frame,
1496 p[0], p[1], p[2], p[3]);
1497#endif
1498 SRpnt = osst_do_scsi(SRpnt, STp, cmd, OS_FRAME_SIZE, DMA_TO_DEVICE,
1499 STp->timeout, MAX_RETRIES, 1);
1500
1501 if (STp->buffer->syscall_result)
1502 flag = 1;
1503 else {
1504 p += OS_DATA_SIZE; i++;
1505
1506 /* if we just sent the last frame, wait till all successfully written */
1507 if ( i == nframes + pending ) {
1508#if DEBUG
1509 printk(OSST_DEB_MSG "%s:D: Check re-write successful\n", name);
1510#endif
1511 memset(cmd, 0, MAX_COMMAND_SIZE);
1512 cmd[0] = WRITE_FILEMARKS;
1513 cmd[1] = 1;
1514 SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE,
1515 STp->timeout, MAX_RETRIES, 1);
1516#if DEBUG
1517 if (debugging) {
1518 printk(OSST_DEB_MSG "%s:D: Sleeping in re-write wait ready\n", name);
1519 printk(OSST_DEB_MSG "%s:D: Turning off debugging for a while\n", name);
1520 debugging = 0;
1521 }
1522#endif
1523 flag = STp->buffer->syscall_result;
1524 while ( !flag && time_before(jiffies, startwait + 60*HZ) ) {
1525
1526 memset(cmd, 0, MAX_COMMAND_SIZE);
1527 cmd[0] = TEST_UNIT_READY;
1528
1529 SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE, STp->timeout,
1530 MAX_RETRIES, 1);
1531
Willem Riede5e6575c2006-02-11 14:46:56 -05001532 if (SRpnt->sense[2] == 2 && SRpnt->sense[12] == 4 &&
1533 (SRpnt->sense[13] == 1 || SRpnt->sense[13] == 8)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534 /* in the process of becoming ready */
1535 msleep(100);
1536 continue;
1537 }
1538 if (STp->buffer->syscall_result)
1539 flag = 1;
1540 break;
1541 }
1542#if DEBUG
1543 debugging = dbg;
1544 printk(OSST_DEB_MSG "%s:D: Wait re-write finished\n", name);
1545#endif
1546 }
1547 }
1548 *aSRpnt = SRpnt;
1549 if (flag) {
Willem Riede5e6575c2006-02-11 14:46:56 -05001550 if ((SRpnt->sense[ 2] & 0x0f) == 13 &&
1551 SRpnt->sense[12] == 0 &&
1552 SRpnt->sense[13] == 2) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553 printk(KERN_ERR "%s:E: Volume overflow in write error recovery\n", name);
Jesper Juhlf91012102005-09-10 00:26:54 -07001554 vfree(buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555 return (-EIO); /* hit end of tape = fail */
1556 }
Willem Riede5e6575c2006-02-11 14:46:56 -05001557 i = ((SRpnt->sense[3] << 24) |
1558 (SRpnt->sense[4] << 16) |
1559 (SRpnt->sense[5] << 8) |
1560 SRpnt->sense[6] ) - new_frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561 p = &buffer[i * OS_DATA_SIZE];
1562#if DEBUG
1563 printk(OSST_DEB_MSG "%s:D: Additional write error at %d\n", name, new_frame+i);
1564#endif
1565 osst_get_frame_position(STp, aSRpnt);
1566#if DEBUG
1567 printk(OSST_DEB_MSG "%s:D: reported frame positions: host = %d, tape = %d, buffer = %d\n",
1568 name, STp->first_frame_position, STp->last_frame_position, STp->cur_frames);
1569#endif
1570 }
1571 }
1572 if (flag) {
1573 /* error recovery did not successfully complete */
1574 printk(KERN_ERR "%s:D: Write error recovery failed in %s\n", name,
1575 STp->write_type == OS_WRITE_HEADER?"header":"body");
1576 }
1577 if (!pending)
1578 osst_copy_to_buffer(STp->buffer, p); /* so buffer content == at entry in all cases */
Jesper Juhlf91012102005-09-10 00:26:54 -07001579 vfree(buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580 return 0;
1581}
1582
Willem Riede5e6575c2006-02-11 14:46:56 -05001583static int osst_reposition_and_retry(struct osst_tape * STp, struct osst_request ** aSRpnt,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584 unsigned int frame, unsigned int skip, int pending)
1585{
1586 unsigned char cmd[MAX_COMMAND_SIZE];
Willem Riede5e6575c2006-02-11 14:46:56 -05001587 struct osst_request * SRpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588 char * name = tape_name(STp);
1589 int expected = 0;
1590 int attempts = 1000 / skip;
1591 int flag = 1;
1592 unsigned long startwait = jiffies;
1593#if DEBUG
1594 int dbg = debugging;
1595#endif
1596
1597 while (attempts && time_before(jiffies, startwait + 60*HZ)) {
1598 if (flag) {
1599#if DEBUG
1600 debugging = dbg;
1601#endif
1602 if (frame < 2990 && frame+skip+STp->cur_frames+pending >= 2990)
1603 frame = 3000-skip;
1604 expected = frame+skip+STp->cur_frames+pending;
1605#if DEBUG
1606 printk(OSST_DEB_MSG "%s:D: Position to fppos %d, re-write from fseq %d\n",
1607 name, frame+skip, STp->frame_seq_number-STp->cur_frames-pending);
1608#endif
1609 osst_set_frame_position(STp, aSRpnt, frame + skip, 1);
1610 flag = 0;
1611 attempts--;
Nishanth Aravamudana9a30472005-11-07 01:01:20 -08001612 schedule_timeout_interruptible(msecs_to_jiffies(100));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001613 }
1614 if (osst_get_frame_position(STp, aSRpnt) < 0) { /* additional write error */
1615#if DEBUG
1616 printk(OSST_DEB_MSG "%s:D: Addl error, host %d, tape %d, buffer %d\n",
1617 name, STp->first_frame_position,
1618 STp->last_frame_position, STp->cur_frames);
1619#endif
1620 frame = STp->last_frame_position;
1621 flag = 1;
1622 continue;
1623 }
1624 if (pending && STp->cur_frames < 50) {
1625
1626 memset(cmd, 0, MAX_COMMAND_SIZE);
1627 cmd[0] = WRITE_6;
1628 cmd[1] = 1;
1629 cmd[4] = 1;
1630#if DEBUG
1631 printk(OSST_DEB_MSG "%s:D: About to write pending fseq %d at fppos %d\n",
1632 name, STp->frame_seq_number-1, STp->first_frame_position);
1633#endif
1634 SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, OS_FRAME_SIZE, DMA_TO_DEVICE,
1635 STp->timeout, MAX_RETRIES, 1);
1636 *aSRpnt = SRpnt;
1637
1638 if (STp->buffer->syscall_result) { /* additional write error */
Willem Riede5e6575c2006-02-11 14:46:56 -05001639 if ((SRpnt->sense[ 2] & 0x0f) == 13 &&
1640 SRpnt->sense[12] == 0 &&
1641 SRpnt->sense[13] == 2) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642 printk(KERN_ERR
1643 "%s:E: Volume overflow in write error recovery\n",
1644 name);
1645 break; /* hit end of tape = fail */
1646 }
1647 flag = 1;
1648 }
1649 else
1650 pending = 0;
1651
1652 continue;
1653 }
1654 if (STp->cur_frames == 0) {
1655#if DEBUG
1656 debugging = dbg;
1657 printk(OSST_DEB_MSG "%s:D: Wait re-write finished\n", name);
1658#endif
1659 if (STp->first_frame_position != expected) {
1660 printk(KERN_ERR "%s:A: Actual position %d - expected %d\n",
1661 name, STp->first_frame_position, expected);
1662 return (-EIO);
1663 }
1664 return 0;
1665 }
1666#if DEBUG
1667 if (debugging) {
1668 printk(OSST_DEB_MSG "%s:D: Sleeping in re-write wait ready\n", name);
1669 printk(OSST_DEB_MSG "%s:D: Turning off debugging for a while\n", name);
1670 debugging = 0;
1671 }
1672#endif
Nishanth Aravamudana9a30472005-11-07 01:01:20 -08001673 schedule_timeout_interruptible(msecs_to_jiffies(100));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674 }
1675 printk(KERN_ERR "%s:E: Failed to find valid tape media\n", name);
1676#if DEBUG
1677 debugging = dbg;
1678#endif
1679 return (-EIO);
1680}
1681
1682/*
1683 * Error recovery algorithm for the OnStream tape.
1684 */
1685
Willem Riede5e6575c2006-02-11 14:46:56 -05001686static int osst_write_error_recovery(struct osst_tape * STp, struct osst_request ** aSRpnt, int pending)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687{
Willem Riede5e6575c2006-02-11 14:46:56 -05001688 struct osst_request * SRpnt = * aSRpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689 struct st_partstat * STps = & STp->ps[STp->partition];
1690 char * name = tape_name(STp);
1691 int retval = 0;
1692 int rw_state;
1693 unsigned int frame, skip;
1694
1695 rw_state = STps->rw;
1696
Willem Riede5e6575c2006-02-11 14:46:56 -05001697 if ((SRpnt->sense[ 2] & 0x0f) != 3
1698 || SRpnt->sense[12] != 12
1699 || SRpnt->sense[13] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700#if DEBUG
1701 printk(OSST_DEB_MSG "%s:D: Write error recovery cannot handle %02x:%02x:%02x\n", name,
Willem Riede5e6575c2006-02-11 14:46:56 -05001702 SRpnt->sense[2], SRpnt->sense[12], SRpnt->sense[13]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703#endif
1704 return (-EIO);
1705 }
Willem Riede5e6575c2006-02-11 14:46:56 -05001706 frame = (SRpnt->sense[3] << 24) |
1707 (SRpnt->sense[4] << 16) |
1708 (SRpnt->sense[5] << 8) |
1709 SRpnt->sense[6];
1710 skip = SRpnt->sense[9];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711
1712#if DEBUG
1713 printk(OSST_DEB_MSG "%s:D: Detected physical bad frame at %u, advised to skip %d\n", name, frame, skip);
1714#endif
1715 osst_get_frame_position(STp, aSRpnt);
1716#if DEBUG
1717 printk(OSST_DEB_MSG "%s:D: reported frame positions: host = %d, tape = %d\n",
1718 name, STp->first_frame_position, STp->last_frame_position);
1719#endif
1720 switch (STp->write_type) {
1721 case OS_WRITE_DATA:
1722 case OS_WRITE_EOD:
1723 case OS_WRITE_NEW_MARK:
1724 printk(KERN_WARNING
1725 "%s:I: Relocating %d buffered logical frames from position %u to %u\n",
1726 name, STp->cur_frames, frame, (frame + skip > 3000 && frame < 3000)?3000:frame + skip);
1727 if (STp->os_fw_rev >= 10600)
1728 retval = osst_reposition_and_retry(STp, aSRpnt, frame, skip, pending);
1729 else
1730 retval = osst_read_back_buffer_and_rewrite(STp, aSRpnt, frame, skip, pending);
1731 printk(KERN_WARNING "%s:%s: %sWrite error%srecovered\n", name,
1732 retval?"E" :"I",
1733 retval?"" :"Don't worry, ",
1734 retval?" not ":" ");
1735 break;
1736 case OS_WRITE_LAST_MARK:
1737 printk(KERN_ERR "%s:E: Bad frame in update last marker, fatal\n", name);
1738 osst_set_frame_position(STp, aSRpnt, frame + STp->cur_frames + pending, 0);
1739 retval = -EIO;
1740 break;
1741 case OS_WRITE_HEADER:
1742 printk(KERN_WARNING "%s:I: Bad frame in header partition, skipped\n", name);
1743 retval = osst_read_back_buffer_and_rewrite(STp, aSRpnt, frame, 1, pending);
1744 break;
1745 default:
1746 printk(KERN_INFO "%s:I: Bad frame in filler, ignored\n", name);
1747 osst_set_frame_position(STp, aSRpnt, frame + STp->cur_frames + pending, 0);
1748 }
1749 osst_get_frame_position(STp, aSRpnt);
1750#if DEBUG
1751 printk(OSST_DEB_MSG "%s:D: Positioning complete, cur_frames %d, pos %d, tape pos %d\n",
1752 name, STp->cur_frames, STp->first_frame_position, STp->last_frame_position);
1753 printk(OSST_DEB_MSG "%s:D: next logical frame to write: %d\n", name, STp->logical_blk_num);
1754#endif
1755 if (retval == 0) {
1756 STp->recover_count++;
1757 STp->recover_erreg++;
1758 } else
1759 STp->abort_count++;
1760
1761 STps->rw = rw_state;
1762 return retval;
1763}
1764
Willem Riede5e6575c2006-02-11 14:46:56 -05001765static int osst_space_over_filemarks_backward(struct osst_tape * STp, struct osst_request ** aSRpnt,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766 int mt_op, int mt_count)
1767{
1768 char * name = tape_name(STp);
1769 int cnt;
1770 int last_mark_ppos = -1;
1771
1772#if DEBUG
1773 printk(OSST_DEB_MSG "%s:D: Reached space_over_filemarks_backwards %d %d\n", name, mt_op, mt_count);
1774#endif
1775 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
1776#if DEBUG
1777 printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks_bwd\n", name);
1778#endif
1779 return -EIO;
1780 }
1781 if (STp->linux_media_version >= 4) {
1782 /*
1783 * direct lookup in header filemark list
1784 */
1785 cnt = ntohl(STp->buffer->aux->filemark_cnt);
1786 if (STp->header_ok &&
1787 STp->header_cache != NULL &&
1788 (cnt - mt_count) >= 0 &&
1789 (cnt - mt_count) < OS_FM_TAB_MAX &&
1790 (cnt - mt_count) < STp->filemark_cnt &&
1791 STp->header_cache->dat_fm_tab.fm_tab_ent[cnt-1] == STp->buffer->aux->last_mark_ppos)
1792
1793 last_mark_ppos = ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[cnt - mt_count]);
1794#if DEBUG
1795 if (STp->header_cache == NULL || (cnt - mt_count) < 0 || (cnt - mt_count) >= OS_FM_TAB_MAX)
1796 printk(OSST_DEB_MSG "%s:D: Filemark lookup fail due to %s\n", name,
1797 STp->header_cache == NULL?"lack of header cache":"count out of range");
1798 else
1799 printk(OSST_DEB_MSG "%s:D: Filemark lookup: prev mark %d (%s), skip %d to %d\n",
1800 name, cnt,
1801 ((cnt == -1 && ntohl(STp->buffer->aux->last_mark_ppos) == -1) ||
1802 (STp->header_cache->dat_fm_tab.fm_tab_ent[cnt-1] ==
1803 STp->buffer->aux->last_mark_ppos))?"match":"error",
1804 mt_count, last_mark_ppos);
1805#endif
1806 if (last_mark_ppos > 10 && last_mark_ppos < STp->eod_frame_ppos) {
1807 osst_position_tape_and_confirm(STp, aSRpnt, last_mark_ppos);
1808 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
1809#if DEBUG
1810 printk(OSST_DEB_MSG
1811 "%s:D: Couldn't get logical blk num in space_filemarks\n", name);
1812#endif
1813 return (-EIO);
1814 }
1815 if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
1816 printk(KERN_WARNING "%s:W: Expected to find marker at ppos %d, not found\n",
1817 name, last_mark_ppos);
1818 return (-EIO);
1819 }
1820 goto found;
1821 }
1822#if DEBUG
1823 printk(OSST_DEB_MSG "%s:D: Reverting to scan filemark backwards\n", name);
1824#endif
1825 }
1826 cnt = 0;
1827 while (cnt != mt_count) {
1828 last_mark_ppos = ntohl(STp->buffer->aux->last_mark_ppos);
1829 if (last_mark_ppos == -1)
1830 return (-EIO);
1831#if DEBUG
1832 printk(OSST_DEB_MSG "%s:D: Positioning to last mark at %d\n", name, last_mark_ppos);
1833#endif
1834 osst_position_tape_and_confirm(STp, aSRpnt, last_mark_ppos);
1835 cnt++;
1836 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
1837#if DEBUG
1838 printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks\n", name);
1839#endif
1840 return (-EIO);
1841 }
1842 if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
1843 printk(KERN_WARNING "%s:W: Expected to find marker at ppos %d, not found\n",
1844 name, last_mark_ppos);
1845 return (-EIO);
1846 }
1847 }
1848found:
1849 if (mt_op == MTBSFM) {
1850 STp->frame_seq_number++;
1851 STp->frame_in_buffer = 0;
1852 STp->buffer->buffer_bytes = 0;
1853 STp->buffer->read_pointer = 0;
1854 STp->logical_blk_num += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
1855 }
1856 return 0;
1857}
1858
1859/*
1860 * ADRL 1.1 compatible "slow" space filemarks fwd version
1861 *
1862 * Just scans for the filemark sequentially.
1863 */
Willem Riede5e6575c2006-02-11 14:46:56 -05001864static int osst_space_over_filemarks_forward_slow(struct osst_tape * STp, struct osst_request ** aSRpnt,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865 int mt_op, int mt_count)
1866{
1867 int cnt = 0;
1868#if DEBUG
1869 char * name = tape_name(STp);
1870
1871 printk(OSST_DEB_MSG "%s:D: Reached space_over_filemarks_forward_slow %d %d\n", name, mt_op, mt_count);
1872#endif
1873 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
1874#if DEBUG
1875 printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks_fwd\n", name);
1876#endif
1877 return (-EIO);
1878 }
1879 while (1) {
1880 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
1881#if DEBUG
1882 printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks\n", name);
1883#endif
1884 return (-EIO);
1885 }
1886 if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_MARKER)
1887 cnt++;
1888 if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_EOD) {
1889#if DEBUG
1890 printk(OSST_DEB_MSG "%s:D: space_fwd: EOD reached\n", name);
1891#endif
1892 if (STp->first_frame_position > STp->eod_frame_ppos+1) {
1893#if DEBUG
1894 printk(OSST_DEB_MSG "%s:D: EOD position corrected (%d=>%d)\n",
1895 name, STp->eod_frame_ppos, STp->first_frame_position-1);
1896#endif
1897 STp->eod_frame_ppos = STp->first_frame_position-1;
1898 }
1899 return (-EIO);
1900 }
1901 if (cnt == mt_count)
1902 break;
1903 STp->frame_in_buffer = 0;
1904 }
1905 if (mt_op == MTFSF) {
1906 STp->frame_seq_number++;
1907 STp->frame_in_buffer = 0;
1908 STp->buffer->buffer_bytes = 0;
1909 STp->buffer->read_pointer = 0;
1910 STp->logical_blk_num += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
1911 }
1912 return 0;
1913}
1914
1915/*
1916 * Fast linux specific version of OnStream FSF
1917 */
Willem Riede5e6575c2006-02-11 14:46:56 -05001918static int osst_space_over_filemarks_forward_fast(struct osst_tape * STp, struct osst_request ** aSRpnt,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919 int mt_op, int mt_count)
1920{
1921 char * name = tape_name(STp);
1922 int cnt = 0,
1923 next_mark_ppos = -1;
1924
1925#if DEBUG
1926 printk(OSST_DEB_MSG "%s:D: Reached space_over_filemarks_forward_fast %d %d\n", name, mt_op, mt_count);
1927#endif
1928 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
1929#if DEBUG
1930 printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks_fwd\n", name);
1931#endif
1932 return (-EIO);
1933 }
1934
1935 if (STp->linux_media_version >= 4) {
1936 /*
1937 * direct lookup in header filemark list
1938 */
1939 cnt = ntohl(STp->buffer->aux->filemark_cnt) - 1;
1940 if (STp->header_ok &&
1941 STp->header_cache != NULL &&
1942 (cnt + mt_count) < OS_FM_TAB_MAX &&
1943 (cnt + mt_count) < STp->filemark_cnt &&
1944 ((cnt == -1 && ntohl(STp->buffer->aux->last_mark_ppos) == -1) ||
1945 (STp->header_cache->dat_fm_tab.fm_tab_ent[cnt] == STp->buffer->aux->last_mark_ppos)))
1946
1947 next_mark_ppos = ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[cnt + mt_count]);
1948#if DEBUG
1949 if (STp->header_cache == NULL || (cnt + mt_count) >= OS_FM_TAB_MAX)
1950 printk(OSST_DEB_MSG "%s:D: Filemark lookup fail due to %s\n", name,
1951 STp->header_cache == NULL?"lack of header cache":"count out of range");
1952 else
1953 printk(OSST_DEB_MSG "%s:D: Filemark lookup: prev mark %d (%s), skip %d to %d\n",
1954 name, cnt,
1955 ((cnt == -1 && ntohl(STp->buffer->aux->last_mark_ppos) == -1) ||
1956 (STp->header_cache->dat_fm_tab.fm_tab_ent[cnt] ==
1957 STp->buffer->aux->last_mark_ppos))?"match":"error",
1958 mt_count, next_mark_ppos);
1959#endif
1960 if (next_mark_ppos <= 10 || next_mark_ppos > STp->eod_frame_ppos) {
1961#if DEBUG
1962 printk(OSST_DEB_MSG "%s:D: Reverting to slow filemark space\n", name);
1963#endif
1964 return osst_space_over_filemarks_forward_slow(STp, aSRpnt, mt_op, mt_count);
1965 } else {
1966 osst_position_tape_and_confirm(STp, aSRpnt, next_mark_ppos);
1967 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
1968#if DEBUG
1969 printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks\n",
1970 name);
1971#endif
1972 return (-EIO);
1973 }
1974 if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
1975 printk(KERN_WARNING "%s:W: Expected to find marker at ppos %d, not found\n",
1976 name, next_mark_ppos);
1977 return (-EIO);
1978 }
1979 if (ntohl(STp->buffer->aux->filemark_cnt) != cnt + mt_count) {
1980 printk(KERN_WARNING "%s:W: Expected to find marker %d at ppos %d, not %d\n",
1981 name, cnt+mt_count, next_mark_ppos,
1982 ntohl(STp->buffer->aux->filemark_cnt));
1983 return (-EIO);
1984 }
1985 }
1986 } else {
1987 /*
1988 * Find nearest (usually previous) marker, then jump from marker to marker
1989 */
1990 while (1) {
1991 if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_MARKER)
1992 break;
1993 if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_EOD) {
1994#if DEBUG
1995 printk(OSST_DEB_MSG "%s:D: space_fwd: EOD reached\n", name);
1996#endif
1997 return (-EIO);
1998 }
1999 if (ntohl(STp->buffer->aux->filemark_cnt) == 0) {
2000 if (STp->first_mark_ppos == -1) {
2001#if DEBUG
2002 printk(OSST_DEB_MSG "%s:D: Reverting to slow filemark space\n", name);
2003#endif
2004 return osst_space_over_filemarks_forward_slow(STp, aSRpnt, mt_op, mt_count);
2005 }
2006 osst_position_tape_and_confirm(STp, aSRpnt, STp->first_mark_ppos);
2007 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
2008#if DEBUG
2009 printk(OSST_DEB_MSG
2010 "%s:D: Couldn't get logical blk num in space_filemarks_fwd_fast\n",
2011 name);
2012#endif
2013 return (-EIO);
2014 }
2015 if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
2016 printk(KERN_WARNING "%s:W: Expected to find filemark at %d\n",
2017 name, STp->first_mark_ppos);
2018 return (-EIO);
2019 }
2020 } else {
2021 if (osst_space_over_filemarks_backward(STp, aSRpnt, MTBSF, 1) < 0)
2022 return (-EIO);
2023 mt_count++;
2024 }
2025 }
2026 cnt++;
2027 while (cnt != mt_count) {
2028 next_mark_ppos = ntohl(STp->buffer->aux->next_mark_ppos);
2029 if (!next_mark_ppos || next_mark_ppos > STp->eod_frame_ppos) {
2030#if DEBUG
2031 printk(OSST_DEB_MSG "%s:D: Reverting to slow filemark space\n", name);
2032#endif
2033 return osst_space_over_filemarks_forward_slow(STp, aSRpnt, mt_op, mt_count - cnt);
2034 }
2035#if DEBUG
2036 else printk(OSST_DEB_MSG "%s:D: Positioning to next mark at %d\n", name, next_mark_ppos);
2037#endif
2038 osst_position_tape_and_confirm(STp, aSRpnt, next_mark_ppos);
2039 cnt++;
2040 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
2041#if DEBUG
2042 printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks\n",
2043 name);
2044#endif
2045 return (-EIO);
2046 }
2047 if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
2048 printk(KERN_WARNING "%s:W: Expected to find marker at ppos %d, not found\n",
2049 name, next_mark_ppos);
2050 return (-EIO);
2051 }
2052 }
2053 }
2054 if (mt_op == MTFSF) {
2055 STp->frame_seq_number++;
2056 STp->frame_in_buffer = 0;
2057 STp->buffer->buffer_bytes = 0;
2058 STp->buffer->read_pointer = 0;
2059 STp->logical_blk_num += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
2060 }
2061 return 0;
2062}
2063
2064/*
2065 * In debug mode, we want to see as many errors as possible
2066 * to test the error recovery mechanism.
2067 */
2068#if DEBUG
Willem Riede5e6575c2006-02-11 14:46:56 -05002069static void osst_set_retries(struct osst_tape * STp, struct osst_request ** aSRpnt, int retries)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002070{
2071 unsigned char cmd[MAX_COMMAND_SIZE];
Willem Riede5e6575c2006-02-11 14:46:56 -05002072 struct osst_request * SRpnt = * aSRpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002073 char * name = tape_name(STp);
2074
2075 memset(cmd, 0, MAX_COMMAND_SIZE);
2076 cmd[0] = MODE_SELECT;
2077 cmd[1] = 0x10;
2078 cmd[4] = NUMBER_RETRIES_PAGE_LENGTH + MODE_HEADER_LENGTH;
2079
2080 (STp->buffer)->b_data[0] = cmd[4] - 1;
2081 (STp->buffer)->b_data[1] = 0; /* Medium Type - ignoring */
2082 (STp->buffer)->b_data[2] = 0; /* Reserved */
2083 (STp->buffer)->b_data[3] = 0; /* Block Descriptor Length */
2084 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 0] = NUMBER_RETRIES_PAGE | (1 << 7);
2085 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 1] = 2;
2086 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] = 4;
2087 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] = retries;
2088
2089 if (debugging)
2090 printk(OSST_DEB_MSG "%s:D: Setting number of retries on OnStream tape to %d\n", name, retries);
2091
2092 SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_TO_DEVICE, STp->timeout, 0, 1);
2093 *aSRpnt = SRpnt;
2094
2095 if ((STp->buffer)->syscall_result)
2096 printk (KERN_ERR "%s:D: Couldn't set retries to %d\n", name, retries);
2097}
2098#endif
2099
2100
Willem Riede5e6575c2006-02-11 14:46:56 -05002101static int osst_write_filemark(struct osst_tape * STp, struct osst_request ** aSRpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002102{
2103 int result;
2104 int this_mark_ppos = STp->first_frame_position;
2105 int this_mark_lbn = STp->logical_blk_num;
2106#if DEBUG
2107 char * name = tape_name(STp);
2108#endif
2109
2110 if (STp->raw) return 0;
2111
2112 STp->write_type = OS_WRITE_NEW_MARK;
2113#if DEBUG
2114 printk(OSST_DEB_MSG "%s:D: Writing Filemark %i at fppos %d (fseq %d, lblk %d)\n",
2115 name, STp->filemark_cnt, this_mark_ppos, STp->frame_seq_number, this_mark_lbn);
2116#endif
2117 STp->dirty = 1;
2118 result = osst_flush_write_buffer(STp, aSRpnt);
2119 result |= osst_flush_drive_buffer(STp, aSRpnt);
2120 STp->last_mark_ppos = this_mark_ppos;
2121 STp->last_mark_lbn = this_mark_lbn;
2122 if (STp->header_cache != NULL && STp->filemark_cnt < OS_FM_TAB_MAX)
2123 STp->header_cache->dat_fm_tab.fm_tab_ent[STp->filemark_cnt] = htonl(this_mark_ppos);
2124 if (STp->filemark_cnt++ == 0)
2125 STp->first_mark_ppos = this_mark_ppos;
2126 return result;
2127}
2128
Willem Riede5e6575c2006-02-11 14:46:56 -05002129static int osst_write_eod(struct osst_tape * STp, struct osst_request ** aSRpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002130{
2131 int result;
2132#if DEBUG
2133 char * name = tape_name(STp);
2134#endif
2135
2136 if (STp->raw) return 0;
2137
2138 STp->write_type = OS_WRITE_EOD;
2139 STp->eod_frame_ppos = STp->first_frame_position;
2140#if DEBUG
2141 printk(OSST_DEB_MSG "%s:D: Writing EOD at fppos %d (fseq %d, lblk %d)\n", name,
2142 STp->eod_frame_ppos, STp->frame_seq_number, STp->logical_blk_num);
2143#endif
2144 STp->dirty = 1;
2145
2146 result = osst_flush_write_buffer(STp, aSRpnt);
2147 result |= osst_flush_drive_buffer(STp, aSRpnt);
2148 STp->eod_frame_lfa = --(STp->frame_seq_number);
2149 return result;
2150}
2151
Willem Riede5e6575c2006-02-11 14:46:56 -05002152static int osst_write_filler(struct osst_tape * STp, struct osst_request ** aSRpnt, int where, int count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002153{
2154 char * name = tape_name(STp);
2155
2156#if DEBUG
2157 printk(OSST_DEB_MSG "%s:D: Reached onstream write filler group %d\n", name, where);
2158#endif
2159 osst_wait_ready(STp, aSRpnt, 60 * 5, 0);
2160 osst_set_frame_position(STp, aSRpnt, where, 0);
2161 STp->write_type = OS_WRITE_FILLER;
2162 while (count--) {
2163 memcpy(STp->buffer->b_data, "Filler", 6);
2164 STp->buffer->buffer_bytes = 6;
2165 STp->dirty = 1;
2166 if (osst_flush_write_buffer(STp, aSRpnt)) {
2167 printk(KERN_INFO "%s:I: Couldn't write filler frame\n", name);
2168 return (-EIO);
2169 }
2170 }
2171#if DEBUG
2172 printk(OSST_DEB_MSG "%s:D: Exiting onstream write filler group\n", name);
2173#endif
2174 return osst_flush_drive_buffer(STp, aSRpnt);
2175}
2176
Willem Riede5e6575c2006-02-11 14:46:56 -05002177static int __osst_write_header(struct osst_tape * STp, struct osst_request ** aSRpnt, int where, int count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002178{
2179 char * name = tape_name(STp);
2180 int result;
2181
2182#if DEBUG
2183 printk(OSST_DEB_MSG "%s:D: Reached onstream write header group %d\n", name, where);
2184#endif
2185 osst_wait_ready(STp, aSRpnt, 60 * 5, 0);
2186 osst_set_frame_position(STp, aSRpnt, where, 0);
2187 STp->write_type = OS_WRITE_HEADER;
2188 while (count--) {
2189 osst_copy_to_buffer(STp->buffer, (unsigned char *)STp->header_cache);
2190 STp->buffer->buffer_bytes = sizeof(os_header_t);
2191 STp->dirty = 1;
2192 if (osst_flush_write_buffer(STp, aSRpnt)) {
2193 printk(KERN_INFO "%s:I: Couldn't write header frame\n", name);
2194 return (-EIO);
2195 }
2196 }
2197 result = osst_flush_drive_buffer(STp, aSRpnt);
2198#if DEBUG
2199 printk(OSST_DEB_MSG "%s:D: Write onstream header group %s\n", name, result?"failed":"done");
2200#endif
2201 return result;
2202}
2203
Willem Riede5e6575c2006-02-11 14:46:56 -05002204static int osst_write_header(struct osst_tape * STp, struct osst_request ** aSRpnt, int locate_eod)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002205{
2206 os_header_t * header;
2207 int result;
2208 char * name = tape_name(STp);
2209
2210#if DEBUG
2211 printk(OSST_DEB_MSG "%s:D: Writing tape header\n", name);
2212#endif
2213 if (STp->raw) return 0;
2214
2215 if (STp->header_cache == NULL) {
2216 if ((STp->header_cache = (os_header_t *)vmalloc(sizeof(os_header_t))) == NULL) {
2217 printk(KERN_ERR "%s:E: Failed to allocate header cache\n", name);
2218 return (-ENOMEM);
2219 }
2220 memset(STp->header_cache, 0, sizeof(os_header_t));
2221#if DEBUG
2222 printk(OSST_DEB_MSG "%s:D: Allocated and cleared memory for header cache\n", name);
2223#endif
2224 }
2225 if (STp->header_ok) STp->update_frame_cntr++;
2226 else STp->update_frame_cntr = 0;
2227
2228 header = STp->header_cache;
2229 strcpy(header->ident_str, "ADR_SEQ");
2230 header->major_rev = 1;
2231 header->minor_rev = 4;
2232 header->ext_trk_tb_off = htons(17192);
2233 header->pt_par_num = 1;
2234 header->partition[0].partition_num = OS_DATA_PARTITION;
2235 header->partition[0].par_desc_ver = OS_PARTITION_VERSION;
2236 header->partition[0].wrt_pass_cntr = htons(STp->wrt_pass_cntr);
2237 header->partition[0].first_frame_ppos = htonl(STp->first_data_ppos);
2238 header->partition[0].last_frame_ppos = htonl(STp->capacity);
2239 header->partition[0].eod_frame_ppos = htonl(STp->eod_frame_ppos);
2240 header->cfg_col_width = htonl(20);
2241 header->dat_col_width = htonl(1500);
2242 header->qfa_col_width = htonl(0);
2243 header->ext_track_tb.nr_stream_part = 1;
2244 header->ext_track_tb.et_ent_sz = 32;
2245 header->ext_track_tb.dat_ext_trk_ey.et_part_num = 0;
2246 header->ext_track_tb.dat_ext_trk_ey.fmt = 1;
2247 header->ext_track_tb.dat_ext_trk_ey.fm_tab_off = htons(17736);
2248 header->ext_track_tb.dat_ext_trk_ey.last_hlb_hi = 0;
2249 header->ext_track_tb.dat_ext_trk_ey.last_hlb = htonl(STp->eod_frame_lfa);
2250 header->ext_track_tb.dat_ext_trk_ey.last_pp = htonl(STp->eod_frame_ppos);
2251 header->dat_fm_tab.fm_part_num = 0;
2252 header->dat_fm_tab.fm_tab_ent_sz = 4;
2253 header->dat_fm_tab.fm_tab_ent_cnt = htons(STp->filemark_cnt<OS_FM_TAB_MAX?
2254 STp->filemark_cnt:OS_FM_TAB_MAX);
2255
2256 result = __osst_write_header(STp, aSRpnt, 0xbae, 5);
2257 if (STp->update_frame_cntr == 0)
2258 osst_write_filler(STp, aSRpnt, 0xbb3, 5);
2259 result &= __osst_write_header(STp, aSRpnt, 5, 5);
2260
2261 if (locate_eod) {
2262#if DEBUG
2263 printk(OSST_DEB_MSG "%s:D: Locating back to eod frame addr %d\n", name, STp->eod_frame_ppos);
2264#endif
2265 osst_set_frame_position(STp, aSRpnt, STp->eod_frame_ppos, 0);
2266 }
2267 if (result)
2268 printk(KERN_ERR "%s:E: Write header failed\n", name);
2269 else {
2270 memcpy(STp->application_sig, "LIN4", 4);
2271 STp->linux_media = 1;
2272 STp->linux_media_version = 4;
2273 STp->header_ok = 1;
2274 }
2275 return result;
2276}
2277
Willem Riede5e6575c2006-02-11 14:46:56 -05002278static int osst_reset_header(struct osst_tape * STp, struct osst_request ** aSRpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002279{
2280 if (STp->header_cache != NULL)
2281 memset(STp->header_cache, 0, sizeof(os_header_t));
2282
2283 STp->logical_blk_num = STp->frame_seq_number = 0;
2284 STp->frame_in_buffer = 0;
2285 STp->eod_frame_ppos = STp->first_data_ppos = 0x0000000A;
2286 STp->filemark_cnt = 0;
2287 STp->first_mark_ppos = STp->last_mark_ppos = STp->last_mark_lbn = -1;
2288 return osst_write_header(STp, aSRpnt, 1);
2289}
2290
Willem Riede5e6575c2006-02-11 14:46:56 -05002291static int __osst_analyze_headers(struct osst_tape * STp, struct osst_request ** aSRpnt, int ppos)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002292{
2293 char * name = tape_name(STp);
2294 os_header_t * header;
2295 os_aux_t * aux;
2296 char id_string[8];
2297 int linux_media_version,
2298 update_frame_cntr;
2299
2300 if (STp->raw)
2301 return 1;
2302
2303 if (ppos == 5 || ppos == 0xbae || STp->buffer->syscall_result) {
2304 if (osst_set_frame_position(STp, aSRpnt, ppos, 0))
2305 printk(KERN_WARNING "%s:W: Couldn't position tape\n", name);
2306 osst_wait_ready(STp, aSRpnt, 60 * 15, 0);
2307 if (osst_initiate_read (STp, aSRpnt)) {
2308 printk(KERN_WARNING "%s:W: Couldn't initiate read\n", name);
2309 return 0;
2310 }
2311 }
2312 if (osst_read_frame(STp, aSRpnt, 180)) {
2313#if DEBUG
2314 printk(OSST_DEB_MSG "%s:D: Couldn't read header frame\n", name);
2315#endif
2316 return 0;
2317 }
2318 header = (os_header_t *) STp->buffer->b_data; /* warning: only first segment addressable */
2319 aux = STp->buffer->aux;
2320 if (aux->frame_type != OS_FRAME_TYPE_HEADER) {
2321#if DEBUG
2322 printk(OSST_DEB_MSG "%s:D: Skipping non-header frame (%d)\n", name, ppos);
2323#endif
2324 return 0;
2325 }
2326 if (ntohl(aux->frame_seq_num) != 0 ||
2327 ntohl(aux->logical_blk_num) != 0 ||
2328 aux->partition.partition_num != OS_CONFIG_PARTITION ||
2329 ntohl(aux->partition.first_frame_ppos) != 0 ||
2330 ntohl(aux->partition.last_frame_ppos) != 0xbb7 ) {
2331#if DEBUG
2332 printk(OSST_DEB_MSG "%s:D: Invalid header frame (%d,%d,%d,%d,%d)\n", name,
2333 ntohl(aux->frame_seq_num), ntohl(aux->logical_blk_num),
2334 aux->partition.partition_num, ntohl(aux->partition.first_frame_ppos),
2335 ntohl(aux->partition.last_frame_ppos));
2336#endif
2337 return 0;
2338 }
2339 if (strncmp(header->ident_str, "ADR_SEQ", 7) != 0 &&
2340 strncmp(header->ident_str, "ADR-SEQ", 7) != 0) {
2341 strlcpy(id_string, header->ident_str, 8);
2342#if DEBUG
2343 printk(OSST_DEB_MSG "%s:D: Invalid header identification string %s\n", name, id_string);
2344#endif
2345 return 0;
2346 }
2347 update_frame_cntr = ntohl(aux->update_frame_cntr);
2348 if (update_frame_cntr < STp->update_frame_cntr) {
2349#if DEBUG
2350 printk(OSST_DEB_MSG "%s:D: Skipping frame %d with update_frame_counter %d<%d\n",
2351 name, ppos, update_frame_cntr, STp->update_frame_cntr);
2352#endif
2353 return 0;
2354 }
2355 if (header->major_rev != 1 || header->minor_rev != 4 ) {
2356#if DEBUG
2357 printk(OSST_DEB_MSG "%s:D: %s revision %d.%d detected (1.4 supported)\n",
2358 name, (header->major_rev != 1 || header->minor_rev < 2 ||
2359 header->minor_rev > 4 )? "Invalid" : "Warning:",
2360 header->major_rev, header->minor_rev);
2361#endif
2362 if (header->major_rev != 1 || header->minor_rev < 2 || header->minor_rev > 4)
2363 return 0;
2364 }
2365#if DEBUG
2366 if (header->pt_par_num != 1)
2367 printk(KERN_INFO "%s:W: %d partitions defined, only one supported\n",
2368 name, header->pt_par_num);
2369#endif
2370 memcpy(id_string, aux->application_sig, 4);
2371 id_string[4] = 0;
2372 if (memcmp(id_string, "LIN", 3) == 0) {
2373 STp->linux_media = 1;
2374 linux_media_version = id_string[3] - '0';
2375 if (linux_media_version != 4)
2376 printk(KERN_INFO "%s:I: Linux media version %d detected (current 4)\n",
2377 name, linux_media_version);
2378 } else {
2379 printk(KERN_WARNING "%s:W: Non Linux media detected (%s)\n", name, id_string);
2380 return 0;
2381 }
2382 if (linux_media_version < STp->linux_media_version) {
2383#if DEBUG
2384 printk(OSST_DEB_MSG "%s:D: Skipping frame %d with linux_media_version %d\n",
2385 name, ppos, linux_media_version);
2386#endif
2387 return 0;
2388 }
2389 if (linux_media_version > STp->linux_media_version) {
2390#if DEBUG
2391 printk(OSST_DEB_MSG "%s:D: Frame %d sets linux_media_version to %d\n",
2392 name, ppos, linux_media_version);
2393#endif
2394 memcpy(STp->application_sig, id_string, 5);
2395 STp->linux_media_version = linux_media_version;
2396 STp->update_frame_cntr = -1;
2397 }
2398 if (update_frame_cntr > STp->update_frame_cntr) {
2399#if DEBUG
2400 printk(OSST_DEB_MSG "%s:D: Frame %d sets update_frame_counter to %d\n",
2401 name, ppos, update_frame_cntr);
2402#endif
2403 if (STp->header_cache == NULL) {
2404 if ((STp->header_cache = (os_header_t *)vmalloc(sizeof(os_header_t))) == NULL) {
2405 printk(KERN_ERR "%s:E: Failed to allocate header cache\n", name);
2406 return 0;
2407 }
2408#if DEBUG
2409 printk(OSST_DEB_MSG "%s:D: Allocated memory for header cache\n", name);
2410#endif
2411 }
2412 osst_copy_from_buffer(STp->buffer, (unsigned char *)STp->header_cache);
2413 header = STp->header_cache; /* further accesses from cached (full) copy */
2414
2415 STp->wrt_pass_cntr = ntohs(header->partition[0].wrt_pass_cntr);
2416 STp->first_data_ppos = ntohl(header->partition[0].first_frame_ppos);
2417 STp->eod_frame_ppos = ntohl(header->partition[0].eod_frame_ppos);
2418 STp->eod_frame_lfa = ntohl(header->ext_track_tb.dat_ext_trk_ey.last_hlb);
2419 STp->filemark_cnt = ntohl(aux->filemark_cnt);
2420 STp->first_mark_ppos = ntohl(aux->next_mark_ppos);
2421 STp->last_mark_ppos = ntohl(aux->last_mark_ppos);
2422 STp->last_mark_lbn = ntohl(aux->last_mark_lbn);
2423 STp->update_frame_cntr = update_frame_cntr;
2424#if DEBUG
2425 printk(OSST_DEB_MSG "%s:D: Detected write pass %d, update frame counter %d, filemark counter %d\n",
2426 name, STp->wrt_pass_cntr, STp->update_frame_cntr, STp->filemark_cnt);
2427 printk(OSST_DEB_MSG "%s:D: first data frame on tape = %d, last = %d, eod frame = %d\n", name,
2428 STp->first_data_ppos,
2429 ntohl(header->partition[0].last_frame_ppos),
2430 ntohl(header->partition[0].eod_frame_ppos));
2431 printk(OSST_DEB_MSG "%s:D: first mark on tape = %d, last = %d, eod frame = %d\n",
2432 name, STp->first_mark_ppos, STp->last_mark_ppos, STp->eod_frame_ppos);
2433#endif
2434 if (header->minor_rev < 4 && STp->linux_media_version == 4) {
2435#if DEBUG
2436 printk(OSST_DEB_MSG "%s:D: Moving filemark list to ADR 1.4 location\n", name);
2437#endif
2438 memcpy((void *)header->dat_fm_tab.fm_tab_ent,
2439 (void *)header->old_filemark_list, sizeof(header->dat_fm_tab.fm_tab_ent));
2440 memset((void *)header->old_filemark_list, 0, sizeof(header->old_filemark_list));
2441 }
2442 if (header->minor_rev == 4 &&
2443 (header->ext_trk_tb_off != htons(17192) ||
2444 header->partition[0].partition_num != OS_DATA_PARTITION ||
2445 header->partition[0].par_desc_ver != OS_PARTITION_VERSION ||
2446 header->partition[0].last_frame_ppos != htonl(STp->capacity) ||
2447 header->cfg_col_width != htonl(20) ||
2448 header->dat_col_width != htonl(1500) ||
2449 header->qfa_col_width != htonl(0) ||
2450 header->ext_track_tb.nr_stream_part != 1 ||
2451 header->ext_track_tb.et_ent_sz != 32 ||
2452 header->ext_track_tb.dat_ext_trk_ey.et_part_num != OS_DATA_PARTITION ||
2453 header->ext_track_tb.dat_ext_trk_ey.fmt != 1 ||
2454 header->ext_track_tb.dat_ext_trk_ey.fm_tab_off != htons(17736) ||
2455 header->ext_track_tb.dat_ext_trk_ey.last_hlb_hi != 0 ||
2456 header->ext_track_tb.dat_ext_trk_ey.last_pp != htonl(STp->eod_frame_ppos) ||
2457 header->dat_fm_tab.fm_part_num != OS_DATA_PARTITION ||
2458 header->dat_fm_tab.fm_tab_ent_sz != 4 ||
2459 header->dat_fm_tab.fm_tab_ent_cnt !=
2460 htons(STp->filemark_cnt<OS_FM_TAB_MAX?STp->filemark_cnt:OS_FM_TAB_MAX)))
2461 printk(KERN_WARNING "%s:W: Failed consistency check ADR 1.4 format\n", name);
2462
2463 }
2464
2465 return 1;
2466}
2467
Willem Riede5e6575c2006-02-11 14:46:56 -05002468static int osst_analyze_headers(struct osst_tape * STp, struct osst_request ** aSRpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002469{
2470 int position, ppos;
2471 int first, last;
2472 int valid = 0;
2473 char * name = tape_name(STp);
2474
2475 position = osst_get_frame_position(STp, aSRpnt);
2476
2477 if (STp->raw) {
2478 STp->header_ok = STp->linux_media = 1;
2479 STp->linux_media_version = 0;
2480 return 1;
2481 }
2482 STp->header_ok = STp->linux_media = STp->linux_media_version = 0;
2483 STp->wrt_pass_cntr = STp->update_frame_cntr = -1;
2484 STp->eod_frame_ppos = STp->first_data_ppos = -1;
2485 STp->first_mark_ppos = STp->last_mark_ppos = STp->last_mark_lbn = -1;
2486#if DEBUG
2487 printk(OSST_DEB_MSG "%s:D: Reading header\n", name);
2488#endif
2489
2490 /* optimization for speed - if we are positioned at ppos 10, read second group first */
2491 /* TODO try the ADR 1.1 locations for the second group if we have no valid one yet... */
2492
2493 first = position==10?0xbae: 5;
2494 last = position==10?0xbb3:10;
2495
2496 for (ppos = first; ppos < last; ppos++)
2497 if (__osst_analyze_headers(STp, aSRpnt, ppos))
2498 valid = 1;
2499
2500 first = position==10? 5:0xbae;
2501 last = position==10?10:0xbb3;
2502
2503 for (ppos = first; ppos < last; ppos++)
2504 if (__osst_analyze_headers(STp, aSRpnt, ppos))
2505 valid = 1;
2506
2507 if (!valid) {
2508 printk(KERN_ERR "%s:E: Failed to find valid ADRL header, new media?\n", name);
2509 STp->eod_frame_ppos = STp->first_data_ppos = 0;
2510 osst_set_frame_position(STp, aSRpnt, 10, 0);
2511 return 0;
2512 }
2513 if (position <= STp->first_data_ppos) {
2514 position = STp->first_data_ppos;
2515 STp->ps[0].drv_file = STp->ps[0].drv_block = STp->frame_seq_number = STp->logical_blk_num = 0;
2516 }
2517 osst_set_frame_position(STp, aSRpnt, position, 0);
2518 STp->header_ok = 1;
2519
2520 return 1;
2521}
2522
Willem Riede5e6575c2006-02-11 14:46:56 -05002523static int osst_verify_position(struct osst_tape * STp, struct osst_request ** aSRpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002524{
2525 int frame_position = STp->first_frame_position;
2526 int frame_seq_numbr = STp->frame_seq_number;
2527 int logical_blk_num = STp->logical_blk_num;
2528 int halfway_frame = STp->frame_in_buffer;
2529 int read_pointer = STp->buffer->read_pointer;
2530 int prev_mark_ppos = -1;
2531 int actual_mark_ppos, i, n;
2532#if DEBUG
2533 char * name = tape_name(STp);
2534
2535 printk(OSST_DEB_MSG "%s:D: Verify that the tape is really the one we think before writing\n", name);
2536#endif
2537 osst_set_frame_position(STp, aSRpnt, frame_position - 1, 0);
2538 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
2539#if DEBUG
2540 printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in verify_position\n", name);
2541#endif
2542 return (-EIO);
2543 }
2544 if (STp->linux_media_version >= 4) {
2545 for (i=0; i<STp->filemark_cnt; i++)
2546 if ((n=ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[i])) < frame_position)
2547 prev_mark_ppos = n;
2548 } else
2549 prev_mark_ppos = frame_position - 1; /* usually - we don't really know */
2550 actual_mark_ppos = STp->buffer->aux->frame_type == OS_FRAME_TYPE_MARKER ?
2551 frame_position - 1 : ntohl(STp->buffer->aux->last_mark_ppos);
2552 if (frame_position != STp->first_frame_position ||
2553 frame_seq_numbr != STp->frame_seq_number + (halfway_frame?0:1) ||
2554 prev_mark_ppos != actual_mark_ppos ) {
2555#if DEBUG
2556 printk(OSST_DEB_MSG "%s:D: Block mismatch: fppos %d-%d, fseq %d-%d, mark %d-%d\n", name,
2557 STp->first_frame_position, frame_position,
2558 STp->frame_seq_number + (halfway_frame?0:1),
2559 frame_seq_numbr, actual_mark_ppos, prev_mark_ppos);
2560#endif
2561 return (-EIO);
2562 }
2563 if (halfway_frame) {
2564 /* prepare buffer for append and rewrite on top of original */
2565 osst_set_frame_position(STp, aSRpnt, frame_position - 1, 0);
2566 STp->buffer->buffer_bytes = read_pointer;
2567 STp->ps[STp->partition].rw = ST_WRITING;
2568 STp->dirty = 1;
2569 }
2570 STp->frame_in_buffer = halfway_frame;
2571 STp->frame_seq_number = frame_seq_numbr;
2572 STp->logical_blk_num = logical_blk_num;
2573 return 0;
2574}
2575
2576/* Acc. to OnStream, the vers. numbering is the following:
2577 * X.XX for released versions (X=digit),
2578 * XXXY for unreleased versions (Y=letter)
2579 * Ordering 1.05 < 106A < 106B < ... < 106a < ... < 1.06
2580 * This fn makes monoton numbers out of this scheme ...
2581 */
2582static unsigned int osst_parse_firmware_rev (const char * str)
2583{
2584 if (str[1] == '.') {
2585 return (str[0]-'0')*10000
2586 +(str[2]-'0')*1000
2587 +(str[3]-'0')*100;
2588 } else {
2589 return (str[0]-'0')*10000
2590 +(str[1]-'0')*1000
2591 +(str[2]-'0')*100 - 100
2592 +(str[3]-'@');
2593 }
2594}
2595
2596/*
2597 * Configure the OnStream SCII tape drive for default operation
2598 */
Willem Riede5e6575c2006-02-11 14:46:56 -05002599static int osst_configure_onstream(struct osst_tape *STp, struct osst_request ** aSRpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002600{
2601 unsigned char cmd[MAX_COMMAND_SIZE];
2602 char * name = tape_name(STp);
Willem Riede5e6575c2006-02-11 14:46:56 -05002603 struct osst_request * SRpnt = * aSRpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002604 osst_mode_parameter_header_t * header;
2605 osst_block_size_page_t * bs;
2606 osst_capabilities_page_t * cp;
2607 osst_tape_paramtr_page_t * prm;
2608 int drive_buffer_size;
2609
2610 if (STp->ready != ST_READY) {
2611#if DEBUG
2612 printk(OSST_DEB_MSG "%s:D: Not Ready\n", name);
2613#endif
2614 return (-EIO);
2615 }
2616
2617 if (STp->os_fw_rev < 10600) {
2618 printk(KERN_INFO "%s:I: Old OnStream firmware revision detected (%s),\n", name, STp->device->rev);
2619 printk(KERN_INFO "%s:I: an upgrade to version 1.06 or above is recommended\n", name);
2620 }
2621
2622 /*
2623 * Configure 32.5KB (data+aux) frame size.
2624 * Get the current frame size from the block size mode page
2625 */
2626 memset(cmd, 0, MAX_COMMAND_SIZE);
2627 cmd[0] = MODE_SENSE;
2628 cmd[1] = 8;
2629 cmd[2] = BLOCK_SIZE_PAGE;
2630 cmd[4] = BLOCK_SIZE_PAGE_LENGTH + MODE_HEADER_LENGTH;
2631
2632 SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_FROM_DEVICE, STp->timeout, 0, 1);
2633 if (SRpnt == NULL) {
2634#if DEBUG
2635 printk(OSST_DEB_MSG "osst :D: Busy\n");
2636#endif
2637 return (-EBUSY);
2638 }
2639 *aSRpnt = SRpnt;
2640 if ((STp->buffer)->syscall_result != 0) {
2641 printk (KERN_ERR "%s:E: Can't get tape block size mode page\n", name);
2642 return (-EIO);
2643 }
2644
2645 header = (osst_mode_parameter_header_t *) (STp->buffer)->b_data;
2646 bs = (osst_block_size_page_t *) ((STp->buffer)->b_data + sizeof(osst_mode_parameter_header_t) + header->bdl);
2647
2648#if DEBUG
2649 printk(OSST_DEB_MSG "%s:D: 32KB play back: %s\n", name, bs->play32 ? "Yes" : "No");
2650 printk(OSST_DEB_MSG "%s:D: 32.5KB play back: %s\n", name, bs->play32_5 ? "Yes" : "No");
2651 printk(OSST_DEB_MSG "%s:D: 32KB record: %s\n", name, bs->record32 ? "Yes" : "No");
2652 printk(OSST_DEB_MSG "%s:D: 32.5KB record: %s\n", name, bs->record32_5 ? "Yes" : "No");
2653#endif
2654
2655 /*
2656 * Configure default auto columns mode, 32.5KB transfer mode
2657 */
2658 bs->one = 1;
2659 bs->play32 = 0;
2660 bs->play32_5 = 1;
2661 bs->record32 = 0;
2662 bs->record32_5 = 1;
2663
2664 memset(cmd, 0, MAX_COMMAND_SIZE);
2665 cmd[0] = MODE_SELECT;
2666 cmd[1] = 0x10;
2667 cmd[4] = BLOCK_SIZE_PAGE_LENGTH + MODE_HEADER_LENGTH;
2668
2669 SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_TO_DEVICE, STp->timeout, 0, 1);
2670 *aSRpnt = SRpnt;
2671 if ((STp->buffer)->syscall_result != 0) {
2672 printk (KERN_ERR "%s:E: Couldn't set tape block size mode page\n", name);
2673 return (-EIO);
2674 }
2675
2676#if DEBUG
2677 printk(KERN_INFO "%s:D: Drive Block Size changed to 32.5K\n", name);
2678 /*
2679 * In debug mode, we want to see as many errors as possible
2680 * to test the error recovery mechanism.
2681 */
2682 osst_set_retries(STp, aSRpnt, 0);
2683 SRpnt = * aSRpnt;
2684#endif
2685
2686 /*
2687 * Set vendor name to 'LIN4' for "Linux support version 4".
2688 */
2689
2690 memset(cmd, 0, MAX_COMMAND_SIZE);
2691 cmd[0] = MODE_SELECT;
2692 cmd[1] = 0x10;
2693 cmd[4] = VENDOR_IDENT_PAGE_LENGTH + MODE_HEADER_LENGTH;
2694
2695 header->mode_data_length = VENDOR_IDENT_PAGE_LENGTH + MODE_HEADER_LENGTH - 1;
2696 header->medium_type = 0; /* Medium Type - ignoring */
2697 header->dsp = 0; /* Reserved */
2698 header->bdl = 0; /* Block Descriptor Length */
2699
2700 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 0] = VENDOR_IDENT_PAGE | (1 << 7);
2701 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 1] = 6;
2702 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] = 'L';
2703 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] = 'I';
2704 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 4] = 'N';
2705 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 5] = '4';
2706 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 6] = 0;
2707 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 7] = 0;
2708
2709 SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_TO_DEVICE, STp->timeout, 0, 1);
2710 *aSRpnt = SRpnt;
2711
2712 if ((STp->buffer)->syscall_result != 0) {
2713 printk (KERN_ERR "%s:E: Couldn't set vendor name to %s\n", name,
2714 (char *) ((STp->buffer)->b_data + MODE_HEADER_LENGTH + 2));
2715 return (-EIO);
2716 }
2717
2718 memset(cmd, 0, MAX_COMMAND_SIZE);
2719 cmd[0] = MODE_SENSE;
2720 cmd[1] = 8;
2721 cmd[2] = CAPABILITIES_PAGE;
2722 cmd[4] = CAPABILITIES_PAGE_LENGTH + MODE_HEADER_LENGTH;
2723
2724 SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_FROM_DEVICE, STp->timeout, 0, 1);
2725 *aSRpnt = SRpnt;
2726
2727 if ((STp->buffer)->syscall_result != 0) {
2728 printk (KERN_ERR "%s:E: Can't get capabilities page\n", name);
2729 return (-EIO);
2730 }
2731
2732 header = (osst_mode_parameter_header_t *) (STp->buffer)->b_data;
2733 cp = (osst_capabilities_page_t *) ((STp->buffer)->b_data +
2734 sizeof(osst_mode_parameter_header_t) + header->bdl);
2735
2736 drive_buffer_size = ntohs(cp->buffer_size) / 2;
2737
2738 memset(cmd, 0, MAX_COMMAND_SIZE);
2739 cmd[0] = MODE_SENSE;
2740 cmd[1] = 8;
2741 cmd[2] = TAPE_PARAMTR_PAGE;
2742 cmd[4] = TAPE_PARAMTR_PAGE_LENGTH + MODE_HEADER_LENGTH;
2743
2744 SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_FROM_DEVICE, STp->timeout, 0, 1);
2745 *aSRpnt = SRpnt;
2746
2747 if ((STp->buffer)->syscall_result != 0) {
2748 printk (KERN_ERR "%s:E: Can't get tape parameter page\n", name);
2749 return (-EIO);
2750 }
2751
2752 header = (osst_mode_parameter_header_t *) (STp->buffer)->b_data;
2753 prm = (osst_tape_paramtr_page_t *) ((STp->buffer)->b_data +
2754 sizeof(osst_mode_parameter_header_t) + header->bdl);
2755
2756 STp->density = prm->density;
2757 STp->capacity = ntohs(prm->segtrk) * ntohs(prm->trks);
2758#if DEBUG
2759 printk(OSST_DEB_MSG "%s:D: Density %d, tape length: %dMB, drive buffer size: %dKB\n",
2760 name, STp->density, STp->capacity / 32, drive_buffer_size);
2761#endif
2762
2763 return 0;
2764
2765}
2766
2767
2768/* Step over EOF if it has been inadvertently crossed (ioctl not used because
2769 it messes up the block number). */
Willem Riede5e6575c2006-02-11 14:46:56 -05002770static int cross_eof(struct osst_tape *STp, struct osst_request ** aSRpnt, int forward)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002771{
2772 int result;
2773 char * name = tape_name(STp);
2774
2775#if DEBUG
2776 if (debugging)
2777 printk(OSST_DEB_MSG "%s:D: Stepping over filemark %s.\n",
2778 name, forward ? "forward" : "backward");
2779#endif
2780
2781 if (forward) {
2782 /* assumes that the filemark is already read by the drive, so this is low cost */
2783 result = osst_space_over_filemarks_forward_slow(STp, aSRpnt, MTFSF, 1);
2784 }
2785 else
2786 /* assumes this is only called if we just read the filemark! */
2787 result = osst_seek_logical_blk(STp, aSRpnt, STp->logical_blk_num - 1);
2788
2789 if (result < 0)
2790 printk(KERN_WARNING "%s:W: Stepping over filemark %s failed.\n",
2791 name, forward ? "forward" : "backward");
2792
2793 return result;
2794}
2795
2796
2797/* Get the tape position. */
2798
Willem Riede5e6575c2006-02-11 14:46:56 -05002799static int osst_get_frame_position(struct osst_tape *STp, struct osst_request ** aSRpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002800{
2801 unsigned char scmd[MAX_COMMAND_SIZE];
Willem Riede5e6575c2006-02-11 14:46:56 -05002802 struct osst_request * SRpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002803 int result = 0;
2804 char * name = tape_name(STp);
2805
2806 /* KG: We want to be able to use it for checking Write Buffer availability
2807 * and thus don't want to risk to overwrite anything. Exchange buffers ... */
2808 char mybuf[24];
2809 char * olddata = STp->buffer->b_data;
2810 int oldsize = STp->buffer->buffer_size;
2811
2812 if (STp->ready != ST_READY) return (-EIO);
2813
2814 memset (scmd, 0, MAX_COMMAND_SIZE);
2815 scmd[0] = READ_POSITION;
2816
2817 STp->buffer->b_data = mybuf; STp->buffer->buffer_size = 24;
2818 SRpnt = osst_do_scsi(*aSRpnt, STp, scmd, 20, DMA_FROM_DEVICE,
2819 STp->timeout, MAX_RETRIES, 1);
2820 if (!SRpnt) {
2821 STp->buffer->b_data = olddata; STp->buffer->buffer_size = oldsize;
2822 return (-EBUSY);
2823 }
2824 *aSRpnt = SRpnt;
2825
2826 if (STp->buffer->syscall_result)
Willem Riede5e6575c2006-02-11 14:46:56 -05002827 result = ((SRpnt->sense[2] & 0x0f) == 3) ? -EIO : -EINVAL; /* 3: Write Error */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002828
2829 if (result == -EINVAL)
2830 printk(KERN_ERR "%s:E: Can't read tape position.\n", name);
2831 else {
2832 if (result == -EIO) { /* re-read position - this needs to preserve media errors */
2833 unsigned char mysense[16];
Willem Riede5e6575c2006-02-11 14:46:56 -05002834 memcpy (mysense, SRpnt->sense, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002835 memset (scmd, 0, MAX_COMMAND_SIZE);
2836 scmd[0] = READ_POSITION;
2837 STp->buffer->b_data = mybuf; STp->buffer->buffer_size = 24;
2838 SRpnt = osst_do_scsi(SRpnt, STp, scmd, 20, DMA_FROM_DEVICE,
2839 STp->timeout, MAX_RETRIES, 1);
2840#if DEBUG
2841 printk(OSST_DEB_MSG "%s:D: Reread position, reason=[%02x:%02x:%02x], result=[%s%02x:%02x:%02x]\n",
2842 name, mysense[2], mysense[12], mysense[13], STp->buffer->syscall_result?"":"ok:",
Willem Riede5e6575c2006-02-11 14:46:56 -05002843 SRpnt->sense[2],SRpnt->sense[12],SRpnt->sense[13]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002844#endif
2845 if (!STp->buffer->syscall_result)
Willem Riede5e6575c2006-02-11 14:46:56 -05002846 memcpy (SRpnt->sense, mysense, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002847 else
2848 printk(KERN_WARNING "%s:W: Double error in get position\n", name);
2849 }
2850 STp->first_frame_position = ((STp->buffer)->b_data[4] << 24)
2851 + ((STp->buffer)->b_data[5] << 16)
2852 + ((STp->buffer)->b_data[6] << 8)
2853 + (STp->buffer)->b_data[7];
2854 STp->last_frame_position = ((STp->buffer)->b_data[ 8] << 24)
2855 + ((STp->buffer)->b_data[ 9] << 16)
2856 + ((STp->buffer)->b_data[10] << 8)
2857 + (STp->buffer)->b_data[11];
2858 STp->cur_frames = (STp->buffer)->b_data[15];
2859#if DEBUG
2860 if (debugging) {
2861 printk(OSST_DEB_MSG "%s:D: Drive Positions: host %d, tape %d%s, buffer %d\n", name,
2862 STp->first_frame_position, STp->last_frame_position,
2863 ((STp->buffer)->b_data[0]&0x80)?" (BOP)":
2864 ((STp->buffer)->b_data[0]&0x40)?" (EOP)":"",
2865 STp->cur_frames);
2866 }
2867#endif
2868 if (STp->cur_frames == 0 && STp->first_frame_position != STp->last_frame_position) {
2869#if DEBUG
2870 printk(OSST_DEB_MSG "%s:D: Correcting read position %d, %d, %d\n", name,
2871 STp->first_frame_position, STp->last_frame_position, STp->cur_frames);
2872#endif
2873 STp->first_frame_position = STp->last_frame_position;
2874 }
2875 }
2876 STp->buffer->b_data = olddata; STp->buffer->buffer_size = oldsize;
2877
2878 return (result == 0 ? STp->first_frame_position : result);
2879}
2880
2881
2882/* Set the tape block */
Willem Riede5e6575c2006-02-11 14:46:56 -05002883static int osst_set_frame_position(struct osst_tape *STp, struct osst_request ** aSRpnt, int ppos, int skip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002884{
2885 unsigned char scmd[MAX_COMMAND_SIZE];
Willem Riede5e6575c2006-02-11 14:46:56 -05002886 struct osst_request * SRpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002887 struct st_partstat * STps;
2888 int result = 0;
2889 int pp = (ppos == 3000 && !skip)? 0 : ppos;
2890 char * name = tape_name(STp);
2891
2892 if (STp->ready != ST_READY) return (-EIO);
2893
2894 STps = &(STp->ps[STp->partition]);
2895
2896 if (ppos < 0 || ppos > STp->capacity) {
2897 printk(KERN_WARNING "%s:W: Reposition request %d out of range\n", name, ppos);
2898 pp = ppos = ppos < 0 ? 0 : (STp->capacity - 1);
2899 result = (-EINVAL);
2900 }
2901
2902 do {
2903#if DEBUG
2904 if (debugging)
2905 printk(OSST_DEB_MSG "%s:D: Setting ppos to %d.\n", name, pp);
2906#endif
2907 memset (scmd, 0, MAX_COMMAND_SIZE);
2908 scmd[0] = SEEK_10;
2909 scmd[1] = 1;
2910 scmd[3] = (pp >> 24);
2911 scmd[4] = (pp >> 16);
2912 scmd[5] = (pp >> 8);
2913 scmd[6] = pp;
2914 if (skip)
2915 scmd[9] = 0x80;
2916
2917 SRpnt = osst_do_scsi(*aSRpnt, STp, scmd, 0, DMA_NONE, STp->long_timeout,
2918 MAX_RETRIES, 1);
2919 if (!SRpnt)
2920 return (-EBUSY);
2921 *aSRpnt = SRpnt;
2922
2923 if ((STp->buffer)->syscall_result != 0) {
2924#if DEBUG
2925 printk(OSST_DEB_MSG "%s:D: SEEK command from %d to %d failed.\n",
2926 name, STp->first_frame_position, pp);
2927#endif
2928 result = (-EIO);
2929 }
2930 if (pp != ppos)
2931 osst_wait_ready(STp, aSRpnt, 5 * 60, OSST_WAIT_POSITION_COMPLETE);
2932 } while ((pp != ppos) && (pp = ppos));
2933 STp->first_frame_position = STp->last_frame_position = ppos;
2934 STps->eof = ST_NOEOF;
2935 STps->at_sm = 0;
2936 STps->rw = ST_IDLE;
2937 STp->frame_in_buffer = 0;
2938 return result;
2939}
2940
Willem Riede5e6575c2006-02-11 14:46:56 -05002941static int osst_write_trailer(struct osst_tape *STp, struct osst_request ** aSRpnt, int leave_at_EOT)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002942{
2943 struct st_partstat * STps = &(STp->ps[STp->partition]);
2944 int result = 0;
2945
2946 if (STp->write_type != OS_WRITE_NEW_MARK) {
2947 /* true unless the user wrote the filemark for us */
2948 result = osst_flush_drive_buffer(STp, aSRpnt);
2949 if (result < 0) goto out;
2950 result = osst_write_filemark(STp, aSRpnt);
2951 if (result < 0) goto out;
2952
2953 if (STps->drv_file >= 0)
2954 STps->drv_file++ ;
2955 STps->drv_block = 0;
2956 }
2957 result = osst_write_eod(STp, aSRpnt);
2958 osst_write_header(STp, aSRpnt, leave_at_EOT);
2959
2960 STps->eof = ST_FM;
2961out:
2962 return result;
2963}
2964
2965/* osst versions of st functions - augmented and stripped to suit OnStream only */
2966
2967/* Flush the write buffer (never need to write if variable blocksize). */
Willem Riede5e6575c2006-02-11 14:46:56 -05002968static int osst_flush_write_buffer(struct osst_tape *STp, struct osst_request ** aSRpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002969{
2970 int offset, transfer, blks = 0;
2971 int result = 0;
2972 unsigned char cmd[MAX_COMMAND_SIZE];
Willem Riede5e6575c2006-02-11 14:46:56 -05002973 struct osst_request * SRpnt = *aSRpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002974 struct st_partstat * STps;
2975 char * name = tape_name(STp);
2976
2977 if ((STp->buffer)->writing) {
2978 if (SRpnt == (STp->buffer)->last_SRpnt)
2979#if DEBUG
2980 { printk(OSST_DEB_MSG
Willem Riede5e6575c2006-02-11 14:46:56 -05002981 "%s:D: aSRpnt points to osst_request that write_behind_check will release -- cleared\n", name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002982#endif
2983 *aSRpnt = SRpnt = NULL;
2984#if DEBUG
2985 } else if (SRpnt)
2986 printk(OSST_DEB_MSG
Willem Riede5e6575c2006-02-11 14:46:56 -05002987 "%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 -07002988#endif
2989 osst_write_behind_check(STp);
2990 if ((STp->buffer)->syscall_result) {
2991#if DEBUG
2992 if (debugging)
2993 printk(OSST_DEB_MSG "%s:D: Async write error (flush) %x.\n",
2994 name, (STp->buffer)->midlevel_result);
2995#endif
2996 if ((STp->buffer)->midlevel_result == INT_MAX)
2997 return (-ENOSPC);
2998 return (-EIO);
2999 }
3000 }
3001
3002 result = 0;
3003 if (STp->dirty == 1) {
3004
3005 STp->write_count++;
3006 STps = &(STp->ps[STp->partition]);
3007 STps->rw = ST_WRITING;
3008 offset = STp->buffer->buffer_bytes;
3009 blks = (offset + STp->block_size - 1) / STp->block_size;
3010 transfer = OS_FRAME_SIZE;
3011
3012 if (offset < OS_DATA_SIZE)
3013 osst_zero_buffer_tail(STp->buffer);
3014
3015 if (STp->poll)
3016 if (osst_wait_frame (STp, aSRpnt, STp->first_frame_position, -50, 120))
3017 result = osst_recover_wait_frame(STp, aSRpnt, 1);
3018
3019 memset(cmd, 0, MAX_COMMAND_SIZE);
3020 cmd[0] = WRITE_6;
3021 cmd[1] = 1;
3022 cmd[4] = 1;
3023
3024 switch (STp->write_type) {
3025 case OS_WRITE_DATA:
3026#if DEBUG
3027 if (debugging)
3028 printk(OSST_DEB_MSG "%s:D: Writing %d blocks to frame %d, lblks %d-%d\n",
3029 name, blks, STp->frame_seq_number,
3030 STp->logical_blk_num - blks, STp->logical_blk_num - 1);
3031#endif
3032 osst_init_aux(STp, OS_FRAME_TYPE_DATA, STp->frame_seq_number++,
3033 STp->logical_blk_num - blks, STp->block_size, blks);
3034 break;
3035 case OS_WRITE_EOD:
3036 osst_init_aux(STp, OS_FRAME_TYPE_EOD, STp->frame_seq_number++,
3037 STp->logical_blk_num, 0, 0);
3038 break;
3039 case OS_WRITE_NEW_MARK:
3040 osst_init_aux(STp, OS_FRAME_TYPE_MARKER, STp->frame_seq_number++,
3041 STp->logical_blk_num++, 0, blks=1);
3042 break;
3043 case OS_WRITE_HEADER:
3044 osst_init_aux(STp, OS_FRAME_TYPE_HEADER, 0, 0, 0, blks=0);
3045 break;
3046 default: /* probably FILLER */
3047 osst_init_aux(STp, OS_FRAME_TYPE_FILL, 0, 0, 0, 0);
3048 }
3049#if DEBUG
3050 if (debugging)
3051 printk(OSST_DEB_MSG "%s:D: Flushing %d bytes, Transfering %d bytes in %d lblocks.\n",
3052 name, offset, transfer, blks);
3053#endif
3054
3055 SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, transfer, DMA_TO_DEVICE,
3056 STp->timeout, MAX_RETRIES, 1);
3057 *aSRpnt = SRpnt;
3058 if (!SRpnt)
3059 return (-EBUSY);
3060
3061 if ((STp->buffer)->syscall_result != 0) {
3062#if DEBUG
3063 printk(OSST_DEB_MSG
3064 "%s:D: write sense [0]=0x%02x [2]=%02x [12]=%02x [13]=%02x\n",
Willem Riede5e6575c2006-02-11 14:46:56 -05003065 name, SRpnt->sense[0], SRpnt->sense[2],
3066 SRpnt->sense[12], SRpnt->sense[13]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003067#endif
Willem Riede5e6575c2006-02-11 14:46:56 -05003068 if ((SRpnt->sense[0] & 0x70) == 0x70 &&
3069 (SRpnt->sense[2] & 0x40) && /* FIXME - SC-30 drive doesn't assert EOM bit */
3070 (SRpnt->sense[2] & 0x0f) == NO_SENSE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003071 STp->dirty = 0;
3072 (STp->buffer)->buffer_bytes = 0;
3073 result = (-ENOSPC);
3074 }
3075 else {
3076 if (osst_write_error_recovery(STp, aSRpnt, 1)) {
3077 printk(KERN_ERR "%s:E: Error on flush write.\n", name);
3078 result = (-EIO);
3079 }
3080 }
3081 STps->drv_block = (-1); /* FIXME - even if write recovery succeeds? */
3082 }
3083 else {
3084 STp->first_frame_position++;
3085 STp->dirty = 0;
3086 (STp->buffer)->buffer_bytes = 0;
3087 }
3088 }
3089#if DEBUG
3090 printk(OSST_DEB_MSG "%s:D: Exit flush write buffer with code %d\n", name, result);
3091#endif
3092 return result;
3093}
3094
3095
3096/* Flush the tape buffer. The tape will be positioned correctly unless
3097 seek_next is true. */
Willem Riede5e6575c2006-02-11 14:46:56 -05003098static int osst_flush_buffer(struct osst_tape * STp, struct osst_request ** aSRpnt, int seek_next)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003099{
3100 struct st_partstat * STps;
3101 int backspace = 0, result = 0;
3102#if DEBUG
3103 char * name = tape_name(STp);
3104#endif
3105
3106 /*
3107 * If there was a bus reset, block further access
3108 * to this device.
3109 */
3110 if( STp->pos_unknown)
3111 return (-EIO);
3112
3113 if (STp->ready != ST_READY)
3114 return 0;
3115
3116 STps = &(STp->ps[STp->partition]);
3117 if (STps->rw == ST_WRITING || STp->dirty) { /* Writing */
3118 STp->write_type = OS_WRITE_DATA;
3119 return osst_flush_write_buffer(STp, aSRpnt);
3120 }
3121 if (STp->block_size == 0)
3122 return 0;
3123
3124#if DEBUG
3125 printk(OSST_DEB_MSG "%s:D: Reached flush (read) buffer\n", name);
3126#endif
3127
3128 if (!STp->can_bsr) {
3129 backspace = ((STp->buffer)->buffer_bytes + (STp->buffer)->read_pointer) / STp->block_size -
3130 ((STp->buffer)->read_pointer + STp->block_size - 1 ) / STp->block_size ;
3131 (STp->buffer)->buffer_bytes = 0;
3132 (STp->buffer)->read_pointer = 0;
3133 STp->frame_in_buffer = 0; /* FIXME is this relevant w. OSST? */
3134 }
3135
3136 if (!seek_next) {
3137 if (STps->eof == ST_FM_HIT) {
3138 result = cross_eof(STp, aSRpnt, 0); /* Back over the EOF hit */
3139 if (!result)
3140 STps->eof = ST_NOEOF;
3141 else {
3142 if (STps->drv_file >= 0)
3143 STps->drv_file++;
3144 STps->drv_block = 0;
3145 }
3146 }
3147 if (!result && backspace > 0) /* TODO -- design and run a test case for this */
3148 result = osst_seek_logical_blk(STp, aSRpnt, STp->logical_blk_num - backspace);
3149 }
3150 else if (STps->eof == ST_FM_HIT) {
3151 if (STps->drv_file >= 0)
3152 STps->drv_file++;
3153 STps->drv_block = 0;
3154 STps->eof = ST_NOEOF;
3155 }
3156
3157 return result;
3158}
3159
Willem Riede5e6575c2006-02-11 14:46:56 -05003160static int osst_write_frame(struct osst_tape * STp, struct osst_request ** aSRpnt, int synchronous)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003161{
3162 unsigned char cmd[MAX_COMMAND_SIZE];
Willem Riede5e6575c2006-02-11 14:46:56 -05003163 struct osst_request * SRpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003164 int blks;
3165#if DEBUG
3166 char * name = tape_name(STp);
3167#endif
3168
3169 if ((!STp-> raw) && (STp->first_frame_position == 0xbae)) { /* _must_ preserve buffer! */
3170#if DEBUG
3171 printk(OSST_DEB_MSG "%s:D: Reaching config partition.\n", name);
3172#endif
3173 if (osst_flush_drive_buffer(STp, aSRpnt) < 0) {
3174 return (-EIO);
3175 }
3176 /* error recovery may have bumped us past the header partition */
3177 if (osst_get_frame_position(STp, aSRpnt) < 0xbb8) {
3178#if DEBUG
3179 printk(OSST_DEB_MSG "%s:D: Skipping over config partition.\n", name);
3180#endif
3181 osst_position_tape_and_confirm(STp, aSRpnt, 0xbb8);
3182 }
3183 }
3184
3185 if (STp->poll)
3186 if (osst_wait_frame (STp, aSRpnt, STp->first_frame_position, -48, 120))
3187 if (osst_recover_wait_frame(STp, aSRpnt, 1))
3188 return (-EIO);
3189
3190// osst_build_stats(STp, &SRpnt);
3191
3192 STp->ps[STp->partition].rw = ST_WRITING;
3193 STp->write_type = OS_WRITE_DATA;
3194
3195 memset(cmd, 0, MAX_COMMAND_SIZE);
3196 cmd[0] = WRITE_6;
3197 cmd[1] = 1;
3198 cmd[4] = 1; /* one frame at a time... */
3199 blks = STp->buffer->buffer_bytes / STp->block_size;
3200#if DEBUG
3201 if (debugging)
3202 printk(OSST_DEB_MSG "%s:D: Writing %d blocks to frame %d, lblks %d-%d\n", name, blks,
3203 STp->frame_seq_number, STp->logical_blk_num - blks, STp->logical_blk_num - 1);
3204#endif
3205 osst_init_aux(STp, OS_FRAME_TYPE_DATA, STp->frame_seq_number++,
3206 STp->logical_blk_num - blks, STp->block_size, blks);
3207
3208#if DEBUG
3209 if (!synchronous)
3210 STp->write_pending = 1;
3211#endif
3212 SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, OS_FRAME_SIZE, DMA_TO_DEVICE, STp->timeout,
3213 MAX_RETRIES, synchronous);
3214 if (!SRpnt)
3215 return (-EBUSY);
3216 *aSRpnt = SRpnt;
3217
3218 if (synchronous) {
3219 if (STp->buffer->syscall_result != 0) {
3220#if DEBUG
3221 if (debugging)
3222 printk(OSST_DEB_MSG "%s:D: Error on write:\n", name);
3223#endif
Willem Riede5e6575c2006-02-11 14:46:56 -05003224 if ((SRpnt->sense[0] & 0x70) == 0x70 &&
3225 (SRpnt->sense[2] & 0x40)) {
3226 if ((SRpnt->sense[2] & 0x0f) == VOLUME_OVERFLOW)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003227 return (-ENOSPC);
3228 }
3229 else {
3230 if (osst_write_error_recovery(STp, aSRpnt, 1))
3231 return (-EIO);
3232 }
3233 }
3234 else
3235 STp->first_frame_position++;
3236 }
3237
3238 STp->write_count++;
3239
3240 return 0;
3241}
3242
Willem Riede5e6575c2006-02-11 14:46:56 -05003243/* Lock or unlock the drive door. Don't use when struct osst_request allocated. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003244static int do_door_lock(struct osst_tape * STp, int do_lock)
3245{
3246 int retval, cmd;
3247
3248 cmd = do_lock ? SCSI_IOCTL_DOORLOCK : SCSI_IOCTL_DOORUNLOCK;
3249#if DEBUG
3250 printk(OSST_DEB_MSG "%s:D: %socking drive door.\n", tape_name(STp), do_lock ? "L" : "Unl");
3251#endif
3252 retval = scsi_ioctl(STp->device, cmd, NULL);
3253 if (!retval) {
3254 STp->door_locked = do_lock ? ST_LOCKED_EXPLICIT : ST_UNLOCKED;
3255 }
3256 else {
3257 STp->door_locked = ST_LOCK_FAILS;
3258 }
3259 return retval;
3260}
3261
3262/* Set the internal state after reset */
3263static void reset_state(struct osst_tape *STp)
3264{
3265 int i;
3266 struct st_partstat *STps;
3267
3268 STp->pos_unknown = 0;
3269 for (i = 0; i < ST_NBR_PARTITIONS; i++) {
3270 STps = &(STp->ps[i]);
3271 STps->rw = ST_IDLE;
3272 STps->eof = ST_NOEOF;
3273 STps->at_sm = 0;
3274 STps->last_block_valid = 0;
3275 STps->drv_block = -1;
3276 STps->drv_file = -1;
3277 }
3278}
3279
3280
3281/* Entry points to osst */
3282
3283/* Write command */
3284static ssize_t osst_write(struct file * filp, const char __user * buf, size_t count, loff_t *ppos)
3285{
3286 ssize_t total, retval = 0;
3287 ssize_t i, do_count, blks, transfer;
3288 int write_threshold;
3289 int doing_write = 0;
3290 const char __user * b_point;
Willem Riede5e6575c2006-02-11 14:46:56 -05003291 struct osst_request * SRpnt = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003292 struct st_modedef * STm;
3293 struct st_partstat * STps;
3294 struct osst_tape * STp = filp->private_data;
3295 char * name = tape_name(STp);
3296
3297
3298 if (down_interruptible(&STp->lock))
3299 return (-ERESTARTSYS);
3300
3301 /*
3302 * If we are in the middle of error recovery, don't let anyone
3303 * else try and use this device. Also, if error recovery fails, it
3304 * may try and take the device offline, in which case all further
3305 * access to the device is prohibited.
3306 */
3307 if( !scsi_block_when_processing_errors(STp->device) ) {
3308 retval = (-ENXIO);
3309 goto out;
3310 }
3311
3312 if (STp->ready != ST_READY) {
3313 if (STp->ready == ST_NO_TAPE)
3314 retval = (-ENOMEDIUM);
3315 else
3316 retval = (-EIO);
3317 goto out;
3318 }
3319 STm = &(STp->modes[STp->current_mode]);
3320 if (!STm->defined) {
3321 retval = (-ENXIO);
3322 goto out;
3323 }
3324 if (count == 0)
3325 goto out;
3326
3327 /*
3328 * If there was a bus reset, block further access
3329 * to this device.
3330 */
3331 if (STp->pos_unknown) {
3332 retval = (-EIO);
3333 goto out;
3334 }
3335
3336#if DEBUG
3337 if (!STp->in_use) {
3338 printk(OSST_DEB_MSG "%s:D: Incorrect device.\n", name);
3339 retval = (-EIO);
3340 goto out;
3341 }
3342#endif
3343
3344 if (STp->write_prot) {
3345 retval = (-EACCES);
3346 goto out;
3347 }
3348
3349 /* Write must be integral number of blocks */
3350 if (STp->block_size != 0 && (count % STp->block_size) != 0) {
3351 printk(KERN_ERR "%s:E: Write (%Zd bytes) not multiple of tape block size (%d%c).\n",
3352 name, count, STp->block_size<1024?
3353 STp->block_size:STp->block_size/1024, STp->block_size<1024?'b':'k');
3354 retval = (-EINVAL);
3355 goto out;
3356 }
3357
3358 if (STp->first_frame_position >= STp->capacity - OSST_EOM_RESERVE) {
3359 printk(KERN_ERR "%s:E: Write truncated at EOM early warning (frame %d).\n",
3360 name, STp->first_frame_position);
3361 retval = (-ENOSPC);
3362 goto out;
3363 }
3364
3365 if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED && !do_door_lock(STp, 1))
3366 STp->door_locked = ST_LOCKED_AUTO;
3367
3368 STps = &(STp->ps[STp->partition]);
3369
3370 if (STps->rw == ST_READING) {
3371#if DEBUG
3372 printk(OSST_DEB_MSG "%s:D: Switching from read to write at file %d, block %d\n", name,
3373 STps->drv_file, STps->drv_block);
3374#endif
3375 retval = osst_flush_buffer(STp, &SRpnt, 0);
3376 if (retval)
3377 goto out;
3378 STps->rw = ST_IDLE;
3379 }
3380 if (STps->rw != ST_WRITING) {
3381 /* Are we totally rewriting this tape? */
3382 if (!STp->header_ok ||
3383 (STp->first_frame_position == STp->first_data_ppos && STps->drv_block < 0) ||
3384 (STps->drv_file == 0 && STps->drv_block == 0)) {
3385 STp->wrt_pass_cntr++;
3386#if DEBUG
3387 printk(OSST_DEB_MSG "%s:D: Allocating next write pass counter: %d\n",
3388 name, STp->wrt_pass_cntr);
3389#endif
3390 osst_reset_header(STp, &SRpnt);
3391 STps->drv_file = STps->drv_block = 0;
3392 }
3393 /* Do we know where we'll be writing on the tape? */
3394 else {
3395 if ((STp->fast_open && osst_verify_position(STp, &SRpnt)) ||
3396 STps->drv_file < 0 || STps->drv_block < 0) {
3397 if (STp->first_frame_position == STp->eod_frame_ppos) { /* at EOD */
3398 STps->drv_file = STp->filemark_cnt;
3399 STps->drv_block = 0;
3400 }
3401 else {
3402 /* We have no idea where the tape is positioned - give up */
3403#if DEBUG
3404 printk(OSST_DEB_MSG
3405 "%s:D: Cannot write at indeterminate position.\n", name);
3406#endif
3407 retval = (-EIO);
3408 goto out;
3409 }
3410 }
3411 if ((STps->drv_file + STps->drv_block) > 0 && STps->drv_file < STp->filemark_cnt) {
3412 STp->filemark_cnt = STps->drv_file;
3413 STp->last_mark_ppos =
3414 ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[STp->filemark_cnt-1]);
3415 printk(KERN_WARNING
3416 "%s:W: Overwriting file %d with old write pass counter %d\n",
3417 name, STps->drv_file, STp->wrt_pass_cntr);
3418 printk(KERN_WARNING
3419 "%s:W: may lead to stale data being accepted on reading back!\n",
3420 name);
3421#if DEBUG
3422 printk(OSST_DEB_MSG
3423 "%s:D: resetting filemark count to %d and last mark ppos,lbn to %d,%d\n",
3424 name, STp->filemark_cnt, STp->last_mark_ppos, STp->last_mark_lbn);
3425#endif
3426 }
3427 }
3428 STp->fast_open = 0;
3429 }
3430 if (!STp->header_ok) {
3431#if DEBUG
3432 printk(OSST_DEB_MSG "%s:D: Write cannot proceed without valid headers\n", name);
3433#endif
3434 retval = (-EIO);
3435 goto out;
3436 }
3437
3438 if ((STp->buffer)->writing) {
3439if (SRpnt) printk(KERN_ERR "%s:A: Not supposed to have SRpnt at line %d\n", name, __LINE__);
3440 osst_write_behind_check(STp);
3441 if ((STp->buffer)->syscall_result) {
3442#if DEBUG
3443 if (debugging)
3444 printk(OSST_DEB_MSG "%s:D: Async write error (write) %x.\n", name,
3445 (STp->buffer)->midlevel_result);
3446#endif
3447 if ((STp->buffer)->midlevel_result == INT_MAX)
3448 STps->eof = ST_EOM_OK;
3449 else
3450 STps->eof = ST_EOM_ERROR;
3451 }
3452 }
3453 if (STps->eof == ST_EOM_OK) {
3454 retval = (-ENOSPC);
3455 goto out;
3456 }
3457 else if (STps->eof == ST_EOM_ERROR) {
3458 retval = (-EIO);
3459 goto out;
3460 }
3461
3462 /* Check the buffer readability in cases where copy_user might catch
3463 the problems after some tape movement. */
3464 if ((copy_from_user(&i, buf, 1) != 0 ||
3465 copy_from_user(&i, buf + count - 1, 1) != 0)) {
3466 retval = (-EFAULT);
3467 goto out;
3468 }
3469
3470 if (!STm->do_buffer_writes) {
3471 write_threshold = 1;
3472 }
3473 else
3474 write_threshold = (STp->buffer)->buffer_blocks * STp->block_size;
3475 if (!STm->do_async_writes)
3476 write_threshold--;
3477
3478 total = count;
3479#if DEBUG
3480 if (debugging)
3481 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 -05003482 name, (int) count, STps->drv_file, STps->drv_block,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003483 STp->logical_blk_num, STp->frame_seq_number, STp->first_frame_position);
3484#endif
3485 b_point = buf;
3486 while ((STp->buffer)->buffer_bytes + count > write_threshold)
3487 {
3488 doing_write = 1;
3489 do_count = (STp->buffer)->buffer_blocks * STp->block_size -
3490 (STp->buffer)->buffer_bytes;
3491 if (do_count > count)
3492 do_count = count;
3493
3494 i = append_to_buffer(b_point, STp->buffer, do_count);
3495 if (i) {
3496 retval = i;
3497 goto out;
3498 }
3499
3500 blks = do_count / STp->block_size;
3501 STp->logical_blk_num += blks; /* logical_blk_num is incremented as data is moved from user */
3502
3503 i = osst_write_frame(STp, &SRpnt, 1);
3504
3505 if (i == (-ENOSPC)) {
3506 transfer = STp->buffer->writing; /* FIXME -- check this logic */
3507 if (transfer <= do_count) {
3508 filp->f_pos += do_count - transfer;
3509 count -= do_count - transfer;
3510 if (STps->drv_block >= 0) {
3511 STps->drv_block += (do_count - transfer) / STp->block_size;
3512 }
3513 STps->eof = ST_EOM_OK;
3514 retval = (-ENOSPC); /* EOM within current request */
3515#if DEBUG
3516 if (debugging)
3517 printk(OSST_DEB_MSG "%s:D: EOM with %d bytes unwritten.\n",
Willem Riede5e6575c2006-02-11 14:46:56 -05003518 name, (int) transfer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003519#endif
3520 }
3521 else {
3522 STps->eof = ST_EOM_ERROR;
3523 STps->drv_block = (-1); /* Too cautious? */
3524 retval = (-EIO); /* EOM for old data */
3525#if DEBUG
3526 if (debugging)
3527 printk(OSST_DEB_MSG "%s:D: EOM with lost data.\n", name);
3528#endif
3529 }
3530 }
3531 else
3532 retval = i;
3533
3534 if (retval < 0) {
3535 if (SRpnt != NULL) {
Willem Riede5e6575c2006-02-11 14:46:56 -05003536 osst_release_request(SRpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003537 SRpnt = NULL;
3538 }
3539 STp->buffer->buffer_bytes = 0;
3540 STp->dirty = 0;
3541 if (count < total)
3542 retval = total - count;
3543 goto out;
3544 }
3545
3546 filp->f_pos += do_count;
3547 b_point += do_count;
3548 count -= do_count;
3549 if (STps->drv_block >= 0) {
3550 STps->drv_block += blks;
3551 }
3552 STp->buffer->buffer_bytes = 0;
3553 STp->dirty = 0;
3554 } /* end while write threshold exceeded */
3555
3556 if (count != 0) {
3557 STp->dirty = 1;
3558 i = append_to_buffer(b_point, STp->buffer, count);
3559 if (i) {
3560 retval = i;
3561 goto out;
3562 }
3563 blks = count / STp->block_size;
3564 STp->logical_blk_num += blks;
3565 if (STps->drv_block >= 0) {
3566 STps->drv_block += blks;
3567 }
3568 filp->f_pos += count;
3569 count = 0;
3570 }
3571
3572 if (doing_write && (STp->buffer)->syscall_result != 0) {
3573 retval = (STp->buffer)->syscall_result;
3574 goto out;
3575 }
3576
3577 if (STm->do_async_writes && ((STp->buffer)->buffer_bytes >= STp->write_threshold)) {
3578 /* Schedule an asynchronous write */
3579 (STp->buffer)->writing = ((STp->buffer)->buffer_bytes /
3580 STp->block_size) * STp->block_size;
3581 STp->dirty = !((STp->buffer)->writing ==
3582 (STp->buffer)->buffer_bytes);
3583
3584 i = osst_write_frame(STp, &SRpnt, 0);
3585 if (i < 0) {
3586 retval = (-EIO);
3587 goto out;
3588 }
3589 SRpnt = NULL; /* Prevent releasing this request! */
3590 }
3591 STps->at_sm &= (total == 0);
3592 if (total > 0)
3593 STps->eof = ST_NOEOF;
3594
3595 retval = total;
3596
3597out:
Willem Riede5e6575c2006-02-11 14:46:56 -05003598 if (SRpnt != NULL) osst_release_request(SRpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003599
3600 up(&STp->lock);
3601
3602 return retval;
3603}
3604
3605
3606/* Read command */
3607static ssize_t osst_read(struct file * filp, char __user * buf, size_t count, loff_t *ppos)
3608{
3609 ssize_t total, retval = 0;
3610 ssize_t i, transfer;
3611 int special;
3612 struct st_modedef * STm;
3613 struct st_partstat * STps;
Willem Riede5e6575c2006-02-11 14:46:56 -05003614 struct osst_request * SRpnt = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003615 struct osst_tape * STp = filp->private_data;
3616 char * name = tape_name(STp);
3617
3618
3619 if (down_interruptible(&STp->lock))
3620 return (-ERESTARTSYS);
3621
3622 /*
3623 * If we are in the middle of error recovery, don't let anyone
3624 * else try and use this device. Also, if error recovery fails, it
3625 * may try and take the device offline, in which case all further
3626 * access to the device is prohibited.
3627 */
3628 if( !scsi_block_when_processing_errors(STp->device) ) {
3629 retval = (-ENXIO);
3630 goto out;
3631 }
3632
3633 if (STp->ready != ST_READY) {
3634 if (STp->ready == ST_NO_TAPE)
3635 retval = (-ENOMEDIUM);
3636 else
3637 retval = (-EIO);
3638 goto out;
3639 }
3640 STm = &(STp->modes[STp->current_mode]);
3641 if (!STm->defined) {
3642 retval = (-ENXIO);
3643 goto out;
3644 }
3645#if DEBUG
3646 if (!STp->in_use) {
3647 printk(OSST_DEB_MSG "%s:D: Incorrect device.\n", name);
3648 retval = (-EIO);
3649 goto out;
3650 }
3651#endif
3652 /* Must have initialized medium */
3653 if (!STp->header_ok) {
3654 retval = (-EIO);
3655 goto out;
3656 }
3657
3658 if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED && !do_door_lock(STp, 1))
3659 STp->door_locked = ST_LOCKED_AUTO;
3660
3661 STps = &(STp->ps[STp->partition]);
3662 if (STps->rw == ST_WRITING) {
3663 retval = osst_flush_buffer(STp, &SRpnt, 0);
3664 if (retval)
3665 goto out;
3666 STps->rw = ST_IDLE;
3667 /* FIXME -- this may leave the tape without EOD and up2date headers */
3668 }
3669
3670 if ((count % STp->block_size) != 0) {
3671 printk(KERN_WARNING
3672 "%s:W: Read (%Zd bytes) not multiple of tape block size (%d%c).\n", name, count,
3673 STp->block_size<1024?STp->block_size:STp->block_size/1024, STp->block_size<1024?'b':'k');
3674 }
3675
3676#if DEBUG
3677 if (debugging && STps->eof != ST_NOEOF)
3678 printk(OSST_DEB_MSG "%s:D: EOF/EOM flag up (%d). Bytes %d\n", name,
3679 STps->eof, (STp->buffer)->buffer_bytes);
3680#endif
3681 if ((STp->buffer)->buffer_bytes == 0 &&
3682 STps->eof >= ST_EOD_1) {
3683 if (STps->eof < ST_EOD) {
3684 STps->eof += 1;
3685 retval = 0;
3686 goto out;
3687 }
3688 retval = (-EIO); /* EOM or Blank Check */
3689 goto out;
3690 }
3691
3692 /* Check the buffer writability before any tape movement. Don't alter
3693 buffer data. */
3694 if (copy_from_user(&i, buf, 1) != 0 ||
3695 copy_to_user (buf, &i, 1) != 0 ||
3696 copy_from_user(&i, buf + count - 1, 1) != 0 ||
3697 copy_to_user (buf + count - 1, &i, 1) != 0) {
3698 retval = (-EFAULT);
3699 goto out;
3700 }
3701
3702 /* Loop until enough data in buffer or a special condition found */
3703 for (total = 0, special = 0; total < count - STp->block_size + 1 && !special; ) {
3704
3705 /* Get new data if the buffer is empty */
3706 if ((STp->buffer)->buffer_bytes == 0) {
3707 if (STps->eof == ST_FM_HIT)
3708 break;
3709 special = osst_get_logical_frame(STp, &SRpnt, STp->frame_seq_number, 0);
3710 if (special < 0) { /* No need to continue read */
3711 STp->frame_in_buffer = 0;
3712 retval = special;
3713 goto out;
3714 }
3715 }
3716
3717 /* Move the data from driver buffer to user buffer */
3718 if ((STp->buffer)->buffer_bytes > 0) {
3719#if DEBUG
3720 if (debugging && STps->eof != ST_NOEOF)
3721 printk(OSST_DEB_MSG "%s:D: EOF up (%d). Left %d, needed %d.\n", name,
Willem Riede5e6575c2006-02-11 14:46:56 -05003722 STps->eof, (STp->buffer)->buffer_bytes, (int) (count - total));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003723#endif
3724 /* force multiple of block size, note block_size may have been adjusted */
3725 transfer = (((STp->buffer)->buffer_bytes < count - total ?
3726 (STp->buffer)->buffer_bytes : count - total)/
3727 STp->block_size) * STp->block_size;
3728
3729 if (transfer == 0) {
3730 printk(KERN_WARNING
3731 "%s:W: Nothing can be transfered, requested %Zd, tape block size (%d%c).\n",
3732 name, count, STp->block_size < 1024?
3733 STp->block_size:STp->block_size/1024,
3734 STp->block_size<1024?'b':'k');
3735 break;
3736 }
3737 i = from_buffer(STp->buffer, buf, transfer);
3738 if (i) {
3739 retval = i;
3740 goto out;
3741 }
3742 STp->logical_blk_num += transfer / STp->block_size;
3743 STps->drv_block += transfer / STp->block_size;
3744 filp->f_pos += transfer;
3745 buf += transfer;
3746 total += transfer;
3747 }
3748
3749 if ((STp->buffer)->buffer_bytes == 0) {
3750#if DEBUG
3751 if (debugging)
3752 printk(OSST_DEB_MSG "%s:D: Finished with frame %d\n",
3753 name, STp->frame_seq_number);
3754#endif
3755 STp->frame_in_buffer = 0;
3756 STp->frame_seq_number++; /* frame to look for next time */
3757 }
3758 } /* for (total = 0, special = 0; total < count && !special; ) */
3759
3760 /* Change the eof state if no data from tape or buffer */
3761 if (total == 0) {
3762 if (STps->eof == ST_FM_HIT) {
3763 STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD_2:ST_FM;
3764 STps->drv_block = 0;
3765 if (STps->drv_file >= 0)
3766 STps->drv_file++;
3767 }
3768 else if (STps->eof == ST_EOD_1) {
3769 STps->eof = ST_EOD_2;
3770 if (STps->drv_block > 0 && STps->drv_file >= 0)
3771 STps->drv_file++;
3772 STps->drv_block = 0;
3773 }
3774 else if (STps->eof == ST_EOD_2)
3775 STps->eof = ST_EOD;
3776 }
3777 else if (STps->eof == ST_FM)
3778 STps->eof = ST_NOEOF;
3779
3780 retval = total;
3781
3782out:
Willem Riede5e6575c2006-02-11 14:46:56 -05003783 if (SRpnt != NULL) osst_release_request(SRpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003784
3785 up(&STp->lock);
3786
3787 return retval;
3788}
3789
3790
3791/* Set the driver options */
3792static void osst_log_options(struct osst_tape *STp, struct st_modedef *STm, char *name)
3793{
3794 printk(KERN_INFO
3795"%s:I: Mode %d options: buffer writes: %d, async writes: %d, read ahead: %d\n",
3796 name, STp->current_mode, STm->do_buffer_writes, STm->do_async_writes,
3797 STm->do_read_ahead);
3798 printk(KERN_INFO
3799"%s:I: can bsr: %d, two FMs: %d, fast mteom: %d, auto lock: %d,\n",
3800 name, STp->can_bsr, STp->two_fm, STp->fast_mteom, STp->do_auto_lock);
3801 printk(KERN_INFO
3802"%s:I: defs for wr: %d, no block limits: %d, partitions: %d, s2 log: %d\n",
3803 name, STm->defaults_for_writes, STp->omit_blklims, STp->can_partitions,
3804 STp->scsi2_logical);
3805 printk(KERN_INFO
3806"%s:I: sysv: %d\n", name, STm->sysv);
3807#if DEBUG
3808 printk(KERN_INFO
3809 "%s:D: debugging: %d\n",
3810 name, debugging);
3811#endif
3812}
3813
3814
3815static int osst_set_options(struct osst_tape *STp, long options)
3816{
3817 int value;
3818 long code;
3819 struct st_modedef * STm;
3820 char * name = tape_name(STp);
3821
3822 STm = &(STp->modes[STp->current_mode]);
3823 if (!STm->defined) {
3824 memcpy(STm, &(STp->modes[0]), sizeof(*STm));
3825 modes_defined = 1;
3826#if DEBUG
3827 if (debugging)
3828 printk(OSST_DEB_MSG "%s:D: Initialized mode %d definition from mode 0\n",
3829 name, STp->current_mode);
3830#endif
3831 }
3832
3833 code = options & MT_ST_OPTIONS;
3834 if (code == MT_ST_BOOLEANS) {
3835 STm->do_buffer_writes = (options & MT_ST_BUFFER_WRITES) != 0;
3836 STm->do_async_writes = (options & MT_ST_ASYNC_WRITES) != 0;
3837 STm->defaults_for_writes = (options & MT_ST_DEF_WRITES) != 0;
3838 STm->do_read_ahead = (options & MT_ST_READ_AHEAD) != 0;
3839 STp->two_fm = (options & MT_ST_TWO_FM) != 0;
3840 STp->fast_mteom = (options & MT_ST_FAST_MTEOM) != 0;
3841 STp->do_auto_lock = (options & MT_ST_AUTO_LOCK) != 0;
3842 STp->can_bsr = (options & MT_ST_CAN_BSR) != 0;
3843 STp->omit_blklims = (options & MT_ST_NO_BLKLIMS) != 0;
3844 if ((STp->device)->scsi_level >= SCSI_2)
3845 STp->can_partitions = (options & MT_ST_CAN_PARTITIONS) != 0;
3846 STp->scsi2_logical = (options & MT_ST_SCSI2LOGICAL) != 0;
3847 STm->sysv = (options & MT_ST_SYSV) != 0;
3848#if DEBUG
3849 debugging = (options & MT_ST_DEBUGGING) != 0;
3850#endif
3851 osst_log_options(STp, STm, name);
3852 }
3853 else if (code == MT_ST_SETBOOLEANS || code == MT_ST_CLEARBOOLEANS) {
3854 value = (code == MT_ST_SETBOOLEANS);
3855 if ((options & MT_ST_BUFFER_WRITES) != 0)
3856 STm->do_buffer_writes = value;
3857 if ((options & MT_ST_ASYNC_WRITES) != 0)
3858 STm->do_async_writes = value;
3859 if ((options & MT_ST_DEF_WRITES) != 0)
3860 STm->defaults_for_writes = value;
3861 if ((options & MT_ST_READ_AHEAD) != 0)
3862 STm->do_read_ahead = value;
3863 if ((options & MT_ST_TWO_FM) != 0)
3864 STp->two_fm = value;
3865 if ((options & MT_ST_FAST_MTEOM) != 0)
3866 STp->fast_mteom = value;
3867 if ((options & MT_ST_AUTO_LOCK) != 0)
3868 STp->do_auto_lock = value;
3869 if ((options & MT_ST_CAN_BSR) != 0)
3870 STp->can_bsr = value;
3871 if ((options & MT_ST_NO_BLKLIMS) != 0)
3872 STp->omit_blklims = value;
3873 if ((STp->device)->scsi_level >= SCSI_2 &&
3874 (options & MT_ST_CAN_PARTITIONS) != 0)
3875 STp->can_partitions = value;
3876 if ((options & MT_ST_SCSI2LOGICAL) != 0)
3877 STp->scsi2_logical = value;
3878 if ((options & MT_ST_SYSV) != 0)
3879 STm->sysv = value;
3880#if DEBUG
3881 if ((options & MT_ST_DEBUGGING) != 0)
3882 debugging = value;
3883#endif
3884 osst_log_options(STp, STm, name);
3885 }
3886 else if (code == MT_ST_WRITE_THRESHOLD) {
3887 value = (options & ~MT_ST_OPTIONS) * ST_KILOBYTE;
3888 if (value < 1 || value > osst_buffer_size) {
3889 printk(KERN_WARNING "%s:W: Write threshold %d too small or too large.\n",
3890 name, value);
3891 return (-EIO);
3892 }
3893 STp->write_threshold = value;
3894 printk(KERN_INFO "%s:I: Write threshold set to %d bytes.\n",
3895 name, value);
3896 }
3897 else if (code == MT_ST_DEF_BLKSIZE) {
3898 value = (options & ~MT_ST_OPTIONS);
3899 if (value == ~MT_ST_OPTIONS) {
3900 STm->default_blksize = (-1);
3901 printk(KERN_INFO "%s:I: Default block size disabled.\n", name);
3902 }
3903 else {
3904 if (value < 512 || value > OS_DATA_SIZE || OS_DATA_SIZE % value) {
3905 printk(KERN_WARNING "%s:W: Default block size cannot be set to %d.\n",
3906 name, value);
3907 return (-EINVAL);
3908 }
3909 STm->default_blksize = value;
3910 printk(KERN_INFO "%s:I: Default block size set to %d bytes.\n",
3911 name, STm->default_blksize);
3912 }
3913 }
3914 else if (code == MT_ST_TIMEOUTS) {
3915 value = (options & ~MT_ST_OPTIONS);
3916 if ((value & MT_ST_SET_LONG_TIMEOUT) != 0) {
3917 STp->long_timeout = (value & ~MT_ST_SET_LONG_TIMEOUT) * HZ;
3918 printk(KERN_INFO "%s:I: Long timeout set to %d seconds.\n", name,
3919 (value & ~MT_ST_SET_LONG_TIMEOUT));
3920 }
3921 else {
3922 STp->timeout = value * HZ;
3923 printk(KERN_INFO "%s:I: Normal timeout set to %d seconds.\n", name, value);
3924 }
3925 }
3926 else if (code == MT_ST_DEF_OPTIONS) {
3927 code = (options & ~MT_ST_CLEAR_DEFAULT);
3928 value = (options & MT_ST_CLEAR_DEFAULT);
3929 if (code == MT_ST_DEF_DENSITY) {
3930 if (value == MT_ST_CLEAR_DEFAULT) {
3931 STm->default_density = (-1);
3932 printk(KERN_INFO "%s:I: Density default disabled.\n", name);
3933 }
3934 else {
3935 STm->default_density = value & 0xff;
3936 printk(KERN_INFO "%s:I: Density default set to %x\n",
3937 name, STm->default_density);
3938 }
3939 }
3940 else if (code == MT_ST_DEF_DRVBUFFER) {
3941 if (value == MT_ST_CLEAR_DEFAULT) {
3942 STp->default_drvbuffer = 0xff;
3943 printk(KERN_INFO "%s:I: Drive buffer default disabled.\n", name);
3944 }
3945 else {
3946 STp->default_drvbuffer = value & 7;
3947 printk(KERN_INFO "%s:I: Drive buffer default set to %x\n",
3948 name, STp->default_drvbuffer);
3949 }
3950 }
3951 else if (code == MT_ST_DEF_COMPRESSION) {
3952 if (value == MT_ST_CLEAR_DEFAULT) {
3953 STm->default_compression = ST_DONT_TOUCH;
3954 printk(KERN_INFO "%s:I: Compression default disabled.\n", name);
3955 }
3956 else {
3957 STm->default_compression = (value & 1 ? ST_YES : ST_NO);
3958 printk(KERN_INFO "%s:I: Compression default set to %x\n",
3959 name, (value & 1));
3960 }
3961 }
3962 }
3963 else
3964 return (-EIO);
3965
3966 return 0;
3967}
3968
3969
3970/* Internal ioctl function */
Willem Riede5e6575c2006-02-11 14:46:56 -05003971static int osst_int_ioctl(struct osst_tape * STp, struct osst_request ** aSRpnt,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003972 unsigned int cmd_in, unsigned long arg)
3973{
3974 int timeout;
3975 long ltmp;
3976 int i, ioctl_result;
3977 int chg_eof = 1;
3978 unsigned char cmd[MAX_COMMAND_SIZE];
Willem Riede5e6575c2006-02-11 14:46:56 -05003979 struct osst_request * SRpnt = * aSRpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003980 struct st_partstat * STps;
3981 int fileno, blkno, at_sm, frame_seq_numbr, logical_blk_num;
3982 int datalen = 0, direction = DMA_NONE;
3983 char * name = tape_name(STp);
3984
3985 if (STp->ready != ST_READY && cmd_in != MTLOAD) {
3986 if (STp->ready == ST_NO_TAPE)
3987 return (-ENOMEDIUM);
3988 else
3989 return (-EIO);
3990 }
3991 timeout = STp->long_timeout;
3992 STps = &(STp->ps[STp->partition]);
3993 fileno = STps->drv_file;
3994 blkno = STps->drv_block;
3995 at_sm = STps->at_sm;
3996 frame_seq_numbr = STp->frame_seq_number;
3997 logical_blk_num = STp->logical_blk_num;
3998
3999 memset(cmd, 0, MAX_COMMAND_SIZE);
4000 switch (cmd_in) {
4001 case MTFSFM:
4002 chg_eof = 0; /* Changed from the FSF after this */
4003 case MTFSF:
4004 if (STp->raw)
4005 return (-EIO);
4006 if (STp->linux_media)
4007 ioctl_result = osst_space_over_filemarks_forward_fast(STp, &SRpnt, cmd_in, arg);
4008 else
4009 ioctl_result = osst_space_over_filemarks_forward_slow(STp, &SRpnt, cmd_in, arg);
4010 if (fileno >= 0)
4011 fileno += arg;
4012 blkno = 0;
4013 at_sm &= (arg == 0);
4014 goto os_bypass;
4015
4016 case MTBSF:
4017 chg_eof = 0; /* Changed from the FSF after this */
4018 case MTBSFM:
4019 if (STp->raw)
4020 return (-EIO);
4021 ioctl_result = osst_space_over_filemarks_backward(STp, &SRpnt, cmd_in, arg);
4022 if (fileno >= 0)
4023 fileno -= arg;
4024 blkno = (-1); /* We can't know the block number */
4025 at_sm &= (arg == 0);
4026 goto os_bypass;
4027
4028 case MTFSR:
4029 case MTBSR:
4030#if DEBUG
4031 if (debugging)
4032 printk(OSST_DEB_MSG "%s:D: Skipping %lu blocks %s from logical block %d\n",
4033 name, arg, cmd_in==MTFSR?"forward":"backward", logical_blk_num);
4034#endif
4035 if (cmd_in == MTFSR) {
4036 logical_blk_num += arg;
4037 if (blkno >= 0) blkno += arg;
4038 }
4039 else {
4040 logical_blk_num -= arg;
4041 if (blkno >= 0) blkno -= arg;
4042 }
4043 ioctl_result = osst_seek_logical_blk(STp, &SRpnt, logical_blk_num);
4044 fileno = STps->drv_file;
4045 blkno = STps->drv_block;
4046 at_sm &= (arg == 0);
4047 goto os_bypass;
4048
4049 case MTFSS:
4050 cmd[0] = SPACE;
4051 cmd[1] = 0x04; /* Space Setmarks */ /* FIXME -- OS can't do this? */
4052 cmd[2] = (arg >> 16);
4053 cmd[3] = (arg >> 8);
4054 cmd[4] = arg;
4055#if DEBUG
4056 if (debugging)
4057 printk(OSST_DEB_MSG "%s:D: Spacing tape forward %d setmarks.\n", name,
4058 cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
4059#endif
4060 if (arg != 0) {
4061 blkno = fileno = (-1);
4062 at_sm = 1;
4063 }
4064 break;
4065 case MTBSS:
4066 cmd[0] = SPACE;
4067 cmd[1] = 0x04; /* Space Setmarks */ /* FIXME -- OS can't do this? */
4068 ltmp = (-arg);
4069 cmd[2] = (ltmp >> 16);
4070 cmd[3] = (ltmp >> 8);
4071 cmd[4] = ltmp;
4072#if DEBUG
4073 if (debugging) {
4074 if (cmd[2] & 0x80)
4075 ltmp = 0xff000000;
4076 ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4];
4077 printk(OSST_DEB_MSG "%s:D: Spacing tape backward %ld setmarks.\n",
4078 name, (-ltmp));
4079 }
4080#endif
4081 if (arg != 0) {
4082 blkno = fileno = (-1);
4083 at_sm = 1;
4084 }
4085 break;
4086 case MTWEOF:
4087 if ((STps->rw == ST_WRITING || STp->dirty) && !STp->pos_unknown) {
4088 STp->write_type = OS_WRITE_DATA;
4089 ioctl_result = osst_flush_write_buffer(STp, &SRpnt);
4090 } else
4091 ioctl_result = 0;
4092#if DEBUG
4093 if (debugging)
4094 printk(OSST_DEB_MSG "%s:D: Writing %ld filemark(s).\n", name, arg);
4095#endif
4096 for (i=0; i<arg; i++)
4097 ioctl_result |= osst_write_filemark(STp, &SRpnt);
4098 if (fileno >= 0) fileno += arg;
4099 if (blkno >= 0) blkno = 0;
4100 goto os_bypass;
4101
4102 case MTWSM:
4103 if (STp->write_prot)
4104 return (-EACCES);
4105 if (!STp->raw)
4106 return 0;
4107 cmd[0] = WRITE_FILEMARKS; /* FIXME -- need OS version */
4108 if (cmd_in == MTWSM)
4109 cmd[1] = 2;
4110 cmd[2] = (arg >> 16);
4111 cmd[3] = (arg >> 8);
4112 cmd[4] = arg;
4113 timeout = STp->timeout;
4114#if DEBUG
4115 if (debugging)
4116 printk(OSST_DEB_MSG "%s:D: Writing %d setmark(s).\n", name,
4117 cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
4118#endif
4119 if (fileno >= 0)
4120 fileno += arg;
4121 blkno = 0;
4122 at_sm = (cmd_in == MTWSM);
4123 break;
4124 case MTOFFL:
4125 case MTLOAD:
4126 case MTUNLOAD:
4127 case MTRETEN:
4128 cmd[0] = START_STOP;
4129 cmd[1] = 1; /* Don't wait for completion */
4130 if (cmd_in == MTLOAD) {
4131 if (STp->ready == ST_NO_TAPE)
4132 cmd[4] = 4; /* open tray */
4133 else
4134 cmd[4] = 1; /* load */
4135 }
4136 if (cmd_in == MTRETEN)
4137 cmd[4] = 3; /* retension then mount */
4138 if (cmd_in == MTOFFL)
4139 cmd[4] = 4; /* rewind then eject */
4140 timeout = STp->timeout;
4141#if DEBUG
4142 if (debugging) {
4143 switch (cmd_in) {
4144 case MTUNLOAD:
4145 printk(OSST_DEB_MSG "%s:D: Unloading tape.\n", name);
4146 break;
4147 case MTLOAD:
4148 printk(OSST_DEB_MSG "%s:D: Loading tape.\n", name);
4149 break;
4150 case MTRETEN:
4151 printk(OSST_DEB_MSG "%s:D: Retensioning tape.\n", name);
4152 break;
4153 case MTOFFL:
4154 printk(OSST_DEB_MSG "%s:D: Ejecting tape.\n", name);
4155 break;
4156 }
4157 }
4158#endif
4159 fileno = blkno = at_sm = frame_seq_numbr = logical_blk_num = 0 ;
4160 break;
4161 case MTNOP:
4162#if DEBUG
4163 if (debugging)
4164 printk(OSST_DEB_MSG "%s:D: No-op on tape.\n", name);
4165#endif
4166 return 0; /* Should do something ? */
4167 break;
4168 case MTEOM:
4169#if DEBUG
4170 if (debugging)
4171 printk(OSST_DEB_MSG "%s:D: Spacing to end of recorded medium.\n", name);
4172#endif
4173 if ((osst_position_tape_and_confirm(STp, &SRpnt, STp->eod_frame_ppos) < 0) ||
4174 (osst_get_logical_frame(STp, &SRpnt, -1, 0) < 0)) {
4175 ioctl_result = -EIO;
4176 goto os_bypass;
4177 }
4178 if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_EOD) {
4179#if DEBUG
4180 printk(OSST_DEB_MSG "%s:D: No EOD frame found where expected.\n", name);
4181#endif
4182 ioctl_result = -EIO;
4183 goto os_bypass;
4184 }
4185 ioctl_result = osst_set_frame_position(STp, &SRpnt, STp->eod_frame_ppos, 0);
4186 fileno = STp->filemark_cnt;
4187 blkno = at_sm = 0;
4188 goto os_bypass;
4189
4190 case MTERASE:
4191 if (STp->write_prot)
4192 return (-EACCES);
4193 ioctl_result = osst_reset_header(STp, &SRpnt);
4194 i = osst_write_eod(STp, &SRpnt);
4195 if (i < ioctl_result) ioctl_result = i;
4196 i = osst_position_tape_and_confirm(STp, &SRpnt, STp->eod_frame_ppos);
4197 if (i < ioctl_result) ioctl_result = i;
4198 fileno = blkno = at_sm = 0 ;
4199 goto os_bypass;
4200
4201 case MTREW:
4202 cmd[0] = REZERO_UNIT; /* rewind */
4203 cmd[1] = 1;
4204#if DEBUG
4205 if (debugging)
4206 printk(OSST_DEB_MSG "%s:D: Rewinding tape, Immed=%d.\n", name, cmd[1]);
4207#endif
4208 fileno = blkno = at_sm = frame_seq_numbr = logical_blk_num = 0 ;
4209 break;
4210
4211 case MTSETBLK: /* Set block length */
4212 if ((STps->drv_block == 0 ) &&
4213 !STp->dirty &&
4214 ((STp->buffer)->buffer_bytes == 0) &&
4215 ((arg & MT_ST_BLKSIZE_MASK) >= 512 ) &&
4216 ((arg & MT_ST_BLKSIZE_MASK) <= OS_DATA_SIZE) &&
4217 !(OS_DATA_SIZE % (arg & MT_ST_BLKSIZE_MASK)) ) {
4218 /*
4219 * Only allowed to change the block size if you opened the
4220 * device at the beginning of a file before writing anything.
4221 * Note, that when reading, changing block_size is futile,
4222 * as the size used when writing overrides it.
4223 */
4224 STp->block_size = (arg & MT_ST_BLKSIZE_MASK);
4225 printk(KERN_INFO "%s:I: Block size set to %d bytes.\n",
4226 name, STp->block_size);
4227 return 0;
4228 }
4229 case MTSETDENSITY: /* Set tape density */
4230 case MTSETDRVBUFFER: /* Set drive buffering */
4231 case SET_DENS_AND_BLK: /* Set density and block size */
4232 chg_eof = 0;
4233 if (STp->dirty || (STp->buffer)->buffer_bytes != 0)
4234 return (-EIO); /* Not allowed if data in buffer */
4235 if ((cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) &&
4236 (arg & MT_ST_BLKSIZE_MASK) != 0 &&
4237 (arg & MT_ST_BLKSIZE_MASK) != STp->block_size ) {
4238 printk(KERN_WARNING "%s:W: Illegal to set block size to %d%s.\n",
4239 name, (int)(arg & MT_ST_BLKSIZE_MASK),
4240 (OS_DATA_SIZE % (arg & MT_ST_BLKSIZE_MASK))?"":" now");
4241 return (-EINVAL);
4242 }
4243 return 0; /* FIXME silently ignore if block size didn't change */
4244
4245 default:
4246 return (-ENOSYS);
4247 }
4248
4249 SRpnt = osst_do_scsi(SRpnt, STp, cmd, datalen, direction, timeout, MAX_RETRIES, 1);
4250
4251 ioctl_result = (STp->buffer)->syscall_result;
4252
4253 if (!SRpnt) {
4254#if DEBUG
4255 printk(OSST_DEB_MSG "%s:D: Couldn't exec scsi cmd for IOCTL\n", name);
4256#endif
4257 return ioctl_result;
4258 }
4259
4260 if (!ioctl_result) { /* SCSI command successful */
4261 STp->frame_seq_number = frame_seq_numbr;
4262 STp->logical_blk_num = logical_blk_num;
4263 }
4264
4265os_bypass:
4266#if DEBUG
4267 if (debugging)
4268 printk(OSST_DEB_MSG "%s:D: IOCTL (%d) Result=%d\n", name, cmd_in, ioctl_result);
4269#endif
4270
4271 if (!ioctl_result) { /* success */
4272
4273 if (cmd_in == MTFSFM) {
4274 fileno--;
4275 blkno--;
4276 }
4277 if (cmd_in == MTBSFM) {
4278 fileno++;
4279 blkno++;
4280 }
4281 STps->drv_block = blkno;
4282 STps->drv_file = fileno;
4283 STps->at_sm = at_sm;
4284
4285 if (cmd_in == MTEOM)
4286 STps->eof = ST_EOD;
4287 else if ((cmd_in == MTFSFM || cmd_in == MTBSF) && STps->eof == ST_FM_HIT) {
4288 ioctl_result = osst_seek_logical_blk(STp, &SRpnt, STp->logical_blk_num-1);
4289 STps->drv_block++;
4290 STp->logical_blk_num++;
4291 STp->frame_seq_number++;
4292 STp->frame_in_buffer = 0;
4293 STp->buffer->read_pointer = 0;
4294 }
4295 else if (cmd_in == MTFSF)
4296 STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD:ST_FM;
4297 else if (chg_eof)
4298 STps->eof = ST_NOEOF;
4299
4300 if (cmd_in == MTOFFL || cmd_in == MTUNLOAD)
4301 STp->rew_at_close = 0;
4302 else if (cmd_in == MTLOAD) {
4303 for (i=0; i < ST_NBR_PARTITIONS; i++) {
4304 STp->ps[i].rw = ST_IDLE;
4305 STp->ps[i].last_block_valid = 0;/* FIXME - where else is this field maintained? */
4306 }
4307 STp->partition = 0;
4308 }
4309
4310 if (cmd_in == MTREW) {
4311 ioctl_result = osst_position_tape_and_confirm(STp, &SRpnt, STp->first_data_ppos);
4312 if (ioctl_result > 0)
4313 ioctl_result = 0;
4314 }
4315
4316 } else if (cmd_in == MTBSF || cmd_in == MTBSFM ) {
4317 if (osst_position_tape_and_confirm(STp, &SRpnt, STp->first_data_ppos) < 0)
4318 STps->drv_file = STps->drv_block = -1;
4319 else
4320 STps->drv_file = STps->drv_block = 0;
4321 STps->eof = ST_NOEOF;
4322 } else if (cmd_in == MTFSF || cmd_in == MTFSFM) {
4323 if (osst_position_tape_and_confirm(STp, &SRpnt, STp->eod_frame_ppos) < 0)
4324 STps->drv_file = STps->drv_block = -1;
4325 else {
4326 STps->drv_file = STp->filemark_cnt;
4327 STps->drv_block = 0;
4328 }
4329 STps->eof = ST_EOD;
4330 } else if (cmd_in == MTBSR || cmd_in == MTFSR || cmd_in == MTWEOF || cmd_in == MTEOM) {
4331 STps->drv_file = STps->drv_block = (-1);
4332 STps->eof = ST_NOEOF;
4333 STp->header_ok = 0;
4334 } else if (cmd_in == MTERASE) {
4335 STp->header_ok = 0;
4336 } else if (SRpnt) { /* SCSI command was not completely successful. */
Willem Riede5e6575c2006-02-11 14:46:56 -05004337 if (SRpnt->sense[2] & 0x40) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004338 STps->eof = ST_EOM_OK;
4339 STps->drv_block = 0;
4340 }
4341 if (chg_eof)
4342 STps->eof = ST_NOEOF;
4343
Willem Riede5e6575c2006-02-11 14:46:56 -05004344 if ((SRpnt->sense[2] & 0x0f) == BLANK_CHECK)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004345 STps->eof = ST_EOD;
4346
4347 if (cmd_in == MTLOAD && osst_wait_for_medium(STp, &SRpnt, 60))
4348 ioctl_result = osst_wait_ready(STp, &SRpnt, 5 * 60, OSST_WAIT_POSITION_COMPLETE);
4349 }
4350 *aSRpnt = SRpnt;
4351
4352 return ioctl_result;
4353}
4354
4355
4356/* Open the device */
4357static int os_scsi_tape_open(struct inode * inode, struct file * filp)
4358{
4359 unsigned short flags;
4360 int i, b_size, new_session = 0, retval = 0;
4361 unsigned char cmd[MAX_COMMAND_SIZE];
Willem Riede5e6575c2006-02-11 14:46:56 -05004362 struct osst_request * SRpnt = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004363 struct osst_tape * STp;
4364 struct st_modedef * STm;
4365 struct st_partstat * STps;
4366 char * name;
4367 int dev = TAPE_NR(inode);
4368 int mode = TAPE_MODE(inode);
4369
4370 /*
4371 * We really want to do nonseekable_open(inode, filp); here, but some
4372 * versions of tar incorrectly call lseek on tapes and bail out if that
4373 * fails. So we disallow pread() and pwrite(), but permit lseeks.
4374 */
4375 filp->f_mode &= ~(FMODE_PREAD | FMODE_PWRITE);
4376
4377 write_lock(&os_scsi_tapes_lock);
4378 if (dev >= osst_max_dev || os_scsi_tapes == NULL ||
4379 (STp = os_scsi_tapes[dev]) == NULL || !STp->device) {
4380 write_unlock(&os_scsi_tapes_lock);
4381 return (-ENXIO);
4382 }
4383
4384 name = tape_name(STp);
4385
4386 if (STp->in_use) {
4387 write_unlock(&os_scsi_tapes_lock);
4388#if DEBUG
4389 printk(OSST_DEB_MSG "%s:D: Device already in use.\n", name);
4390#endif
4391 return (-EBUSY);
4392 }
4393 if (scsi_device_get(STp->device)) {
4394 write_unlock(&os_scsi_tapes_lock);
4395#if DEBUG
4396 printk(OSST_DEB_MSG "%s:D: Failed scsi_device_get.\n", name);
4397#endif
4398 return (-ENXIO);
4399 }
4400 filp->private_data = STp;
4401 STp->in_use = 1;
4402 write_unlock(&os_scsi_tapes_lock);
4403 STp->rew_at_close = TAPE_REWIND(inode);
4404
4405 if( !scsi_block_when_processing_errors(STp->device) ) {
4406 return -ENXIO;
4407 }
4408
4409 if (mode != STp->current_mode) {
4410#if DEBUG
4411 if (debugging)
4412 printk(OSST_DEB_MSG "%s:D: Mode change from %d to %d.\n",
4413 name, STp->current_mode, mode);
4414#endif
4415 new_session = 1;
4416 STp->current_mode = mode;
4417 }
4418 STm = &(STp->modes[STp->current_mode]);
4419
4420 flags = filp->f_flags;
4421 STp->write_prot = ((flags & O_ACCMODE) == O_RDONLY);
4422
4423 STp->raw = TAPE_IS_RAW(inode);
4424 if (STp->raw)
4425 STp->header_ok = 0;
4426
4427 /* Allocate data segments for this device's tape buffer */
4428 if (!enlarge_buffer(STp->buffer, STp->restr_dma)) {
4429 printk(KERN_ERR "%s:E: Unable to allocate memory segments for tape buffer.\n", name);
4430 retval = (-EOVERFLOW);
4431 goto err_out;
4432 }
4433 if (STp->buffer->buffer_size >= OS_FRAME_SIZE) {
4434 for (i = 0, b_size = 0;
4435 (i < STp->buffer->sg_segs) && ((b_size + STp->buffer->sg[i].length) <= OS_DATA_SIZE);
4436 b_size += STp->buffer->sg[i++].length);
4437 STp->buffer->aux = (os_aux_t *) (page_address(STp->buffer->sg[i].page) + OS_DATA_SIZE - b_size);
4438#if DEBUG
4439 printk(OSST_DEB_MSG "%s:D: b_data points to %p in segment 0 at %p\n", name,
4440 STp->buffer->b_data, page_address(STp->buffer->sg[0].page));
4441 printk(OSST_DEB_MSG "%s:D: AUX points to %p in segment %d at %p\n", name,
4442 STp->buffer->aux, i, page_address(STp->buffer->sg[i].page));
4443#endif
4444 } else {
4445 STp->buffer->aux = NULL; /* this had better never happen! */
4446 printk(KERN_NOTICE "%s:A: Framesize %d too large for buffer.\n", name, OS_FRAME_SIZE);
4447 retval = (-EIO);
4448 goto err_out;
4449 }
4450 STp->buffer->writing = 0;
4451 STp->buffer->syscall_result = 0;
4452 STp->dirty = 0;
4453 for (i=0; i < ST_NBR_PARTITIONS; i++) {
4454 STps = &(STp->ps[i]);
4455 STps->rw = ST_IDLE;
4456 }
4457 STp->ready = ST_READY;
4458#if DEBUG
4459 STp->nbr_waits = STp->nbr_finished = 0;
4460#endif
4461
4462 memset (cmd, 0, MAX_COMMAND_SIZE);
4463 cmd[0] = TEST_UNIT_READY;
4464
4465 SRpnt = osst_do_scsi(NULL, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1);
4466 if (!SRpnt) {
4467 retval = (STp->buffer)->syscall_result; /* FIXME - valid? */
4468 goto err_out;
4469 }
Willem Riede5e6575c2006-02-11 14:46:56 -05004470 if ((SRpnt->sense[0] & 0x70) == 0x70 &&
4471 (SRpnt->sense[2] & 0x0f) == NOT_READY &&
4472 SRpnt->sense[12] == 4 ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004473#if DEBUG
Willem Riede5e6575c2006-02-11 14:46:56 -05004474 printk(OSST_DEB_MSG "%s:D: Unit not ready, cause %x\n", name, SRpnt->sense[13]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004475#endif
4476 if (filp->f_flags & O_NONBLOCK) {
4477 retval = -EAGAIN;
4478 goto err_out;
4479 }
Willem Riede5e6575c2006-02-11 14:46:56 -05004480 if (SRpnt->sense[13] == 2) { /* initialize command required (LOAD) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004481 memset (cmd, 0, MAX_COMMAND_SIZE);
4482 cmd[0] = START_STOP;
4483 cmd[1] = 1;
4484 cmd[4] = 1;
4485 SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE,
4486 STp->timeout, MAX_RETRIES, 1);
4487 }
Willem Riede5e6575c2006-02-11 14:46:56 -05004488 osst_wait_ready(STp, &SRpnt, (SRpnt->sense[13]==1?15:3) * 60, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004489 }
Willem Riede5e6575c2006-02-11 14:46:56 -05004490 if ((SRpnt->sense[0] & 0x70) == 0x70 &&
4491 (SRpnt->sense[2] & 0x0f) == UNIT_ATTENTION) { /* New media? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004492#if DEBUG
4493 printk(OSST_DEB_MSG "%s:D: Unit wants attention\n", name);
4494#endif
4495 STp->header_ok = 0;
4496
4497 for (i=0; i < 10; i++) {
4498
4499 memset (cmd, 0, MAX_COMMAND_SIZE);
4500 cmd[0] = TEST_UNIT_READY;
4501
4502 SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE,
4503 STp->timeout, MAX_RETRIES, 1);
Willem Riede5e6575c2006-02-11 14:46:56 -05004504 if ((SRpnt->sense[0] & 0x70) != 0x70 ||
4505 (SRpnt->sense[2] & 0x0f) != UNIT_ATTENTION)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004506 break;
4507 }
4508
4509 STp->pos_unknown = 0;
4510 STp->partition = STp->new_partition = 0;
4511 if (STp->can_partitions)
4512 STp->nbr_partitions = 1; /* This guess will be updated later if necessary */
4513 for (i=0; i < ST_NBR_PARTITIONS; i++) {
4514 STps = &(STp->ps[i]);
4515 STps->rw = ST_IDLE; /* FIXME - seems to be redundant... */
4516 STps->eof = ST_NOEOF;
4517 STps->at_sm = 0;
4518 STps->last_block_valid = 0;
4519 STps->drv_block = 0;
4520 STps->drv_file = 0 ;
4521 }
4522 new_session = 1;
4523 STp->recover_count = 0;
4524 STp->abort_count = 0;
4525 }
4526 /*
4527 * if we have valid headers from before, and the drive/tape seem untouched,
4528 * open without reconfiguring and re-reading the headers
4529 */
4530 if (!STp->buffer->syscall_result && STp->header_ok &&
Willem Riede5e6575c2006-02-11 14:46:56 -05004531 !SRpnt->result && SRpnt->sense[0] == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004532
4533 memset(cmd, 0, MAX_COMMAND_SIZE);
4534 cmd[0] = MODE_SENSE;
4535 cmd[1] = 8;
4536 cmd[2] = VENDOR_IDENT_PAGE;
4537 cmd[4] = VENDOR_IDENT_PAGE_LENGTH + MODE_HEADER_LENGTH;
4538
4539 SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_FROM_DEVICE, STp->timeout, 0, 1);
4540
4541 if (STp->buffer->syscall_result ||
4542 STp->buffer->b_data[MODE_HEADER_LENGTH + 2] != 'L' ||
4543 STp->buffer->b_data[MODE_HEADER_LENGTH + 3] != 'I' ||
4544 STp->buffer->b_data[MODE_HEADER_LENGTH + 4] != 'N' ||
4545 STp->buffer->b_data[MODE_HEADER_LENGTH + 5] != '4' ) {
4546#if DEBUG
4547 printk(OSST_DEB_MSG "%s:D: Signature was changed to %c%c%c%c\n", name,
4548 STp->buffer->b_data[MODE_HEADER_LENGTH + 2],
4549 STp->buffer->b_data[MODE_HEADER_LENGTH + 3],
4550 STp->buffer->b_data[MODE_HEADER_LENGTH + 4],
4551 STp->buffer->b_data[MODE_HEADER_LENGTH + 5]);
4552#endif
4553 STp->header_ok = 0;
4554 }
4555 i = STp->first_frame_position;
4556 if (STp->header_ok && i == osst_get_frame_position(STp, &SRpnt)) {
4557 if (STp->door_locked == ST_UNLOCKED) {
4558 if (do_door_lock(STp, 1))
4559 printk(KERN_INFO "%s:I: Can't lock drive door\n", name);
4560 else
4561 STp->door_locked = ST_LOCKED_AUTO;
4562 }
4563 if (!STp->frame_in_buffer) {
4564 STp->block_size = (STm->default_blksize > 0) ?
4565 STm->default_blksize : OS_DATA_SIZE;
4566 STp->buffer->buffer_bytes = STp->buffer->read_pointer = 0;
4567 }
4568 STp->buffer->buffer_blocks = OS_DATA_SIZE / STp->block_size;
4569 STp->fast_open = 1;
Willem Riede5e6575c2006-02-11 14:46:56 -05004570 osst_release_request(SRpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004571 return 0;
4572 }
4573#if DEBUG
4574 if (i != STp->first_frame_position)
4575 printk(OSST_DEB_MSG "%s:D: Tape position changed from %d to %d\n",
4576 name, i, STp->first_frame_position);
4577#endif
4578 STp->header_ok = 0;
4579 }
4580 STp->fast_open = 0;
4581
4582 if ((STp->buffer)->syscall_result != 0 && /* in all error conditions except no medium */
Willem Riede5e6575c2006-02-11 14:46:56 -05004583 (SRpnt->sense[2] != 2 || SRpnt->sense[12] != 0x3A) ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004584
4585 memset(cmd, 0, MAX_COMMAND_SIZE);
4586 cmd[0] = MODE_SELECT;
4587 cmd[1] = 0x10;
4588 cmd[4] = 4 + MODE_HEADER_LENGTH;
4589
4590 (STp->buffer)->b_data[0] = cmd[4] - 1;
4591 (STp->buffer)->b_data[1] = 0; /* Medium Type - ignoring */
4592 (STp->buffer)->b_data[2] = 0; /* Reserved */
4593 (STp->buffer)->b_data[3] = 0; /* Block Descriptor Length */
4594 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 0] = 0x3f;
4595 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 1] = 1;
4596 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] = 2;
4597 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] = 3;
4598
4599#if DEBUG
4600 printk(OSST_DEB_MSG "%s:D: Applying soft reset\n", name);
4601#endif
4602 SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_TO_DEVICE, STp->timeout, 0, 1);
4603
4604 STp->header_ok = 0;
4605
4606 for (i=0; i < 10; i++) {
4607
4608 memset (cmd, 0, MAX_COMMAND_SIZE);
4609 cmd[0] = TEST_UNIT_READY;
4610
4611 SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE,
4612 STp->timeout, MAX_RETRIES, 1);
Willem Riede5e6575c2006-02-11 14:46:56 -05004613 if ((SRpnt->sense[0] & 0x70) != 0x70 ||
4614 (SRpnt->sense[2] & 0x0f) == NOT_READY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004615 break;
4616
Willem Riede5e6575c2006-02-11 14:46:56 -05004617 if ((SRpnt->sense[2] & 0x0f) == UNIT_ATTENTION) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004618 STp->pos_unknown = 0;
4619 STp->partition = STp->new_partition = 0;
4620 if (STp->can_partitions)
4621 STp->nbr_partitions = 1; /* This guess will be updated later if necessary */
4622 for (i=0; i < ST_NBR_PARTITIONS; i++) {
4623 STps = &(STp->ps[i]);
4624 STps->rw = ST_IDLE;
4625 STps->eof = ST_NOEOF;
4626 STps->at_sm = 0;
4627 STps->last_block_valid = 0;
4628 STps->drv_block = 0;
4629 STps->drv_file = 0 ;
4630 }
4631 new_session = 1;
4632 }
4633 }
4634 }
4635
4636 if (osst_wait_ready(STp, &SRpnt, 15 * 60, 0)) /* FIXME - not allowed with NOBLOCK */
4637 printk(KERN_INFO "%s:I: Device did not become Ready in open\n", name);
4638
4639 if ((STp->buffer)->syscall_result != 0) {
4640 if ((STp->device)->scsi_level >= SCSI_2 &&
Willem Riede5e6575c2006-02-11 14:46:56 -05004641 (SRpnt->sense[0] & 0x70) == 0x70 &&
4642 (SRpnt->sense[2] & 0x0f) == NOT_READY &&
4643 SRpnt->sense[12] == 0x3a) { /* Check ASC */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004644 STp->ready = ST_NO_TAPE;
4645 } else
4646 STp->ready = ST_NOT_READY;
Willem Riede5e6575c2006-02-11 14:46:56 -05004647 osst_release_request(SRpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004648 SRpnt = NULL;
4649 STp->density = 0; /* Clear the erroneous "residue" */
4650 STp->write_prot = 0;
4651 STp->block_size = 0;
4652 STp->ps[0].drv_file = STp->ps[0].drv_block = (-1);
4653 STp->partition = STp->new_partition = 0;
4654 STp->door_locked = ST_UNLOCKED;
4655 return 0;
4656 }
4657
4658 osst_configure_onstream(STp, &SRpnt);
4659
4660 STp->block_size = STp->raw ? OS_FRAME_SIZE : (
4661 (STm->default_blksize > 0) ? STm->default_blksize : OS_DATA_SIZE);
4662 STp->buffer->buffer_blocks = STp->raw ? 1 : OS_DATA_SIZE / STp->block_size;
4663 STp->buffer->buffer_bytes =
4664 STp->buffer->read_pointer =
4665 STp->frame_in_buffer = 0;
4666
4667#if DEBUG
4668 if (debugging)
4669 printk(OSST_DEB_MSG "%s:D: Block size: %d, frame size: %d, buffer size: %d (%d blocks).\n",
4670 name, STp->block_size, OS_FRAME_SIZE, (STp->buffer)->buffer_size,
4671 (STp->buffer)->buffer_blocks);
4672#endif
4673
4674 if (STp->drv_write_prot) {
4675 STp->write_prot = 1;
4676#if DEBUG
4677 if (debugging)
4678 printk(OSST_DEB_MSG "%s:D: Write protected\n", name);
4679#endif
4680 if ((flags & O_ACCMODE) == O_WRONLY || (flags & O_ACCMODE) == O_RDWR) {
4681 retval = (-EROFS);
4682 goto err_out;
4683 }
4684 }
4685
4686 if (new_session) { /* Change the drive parameters for the new mode */
4687#if DEBUG
4688 if (debugging)
4689 printk(OSST_DEB_MSG "%s:D: New Session\n", name);
4690#endif
4691 STp->density_changed = STp->blksize_changed = 0;
4692 STp->compression_changed = 0;
4693 }
4694
4695 /*
4696 * properly position the tape and check the ADR headers
4697 */
4698 if (STp->door_locked == ST_UNLOCKED) {
4699 if (do_door_lock(STp, 1))
4700 printk(KERN_INFO "%s:I: Can't lock drive door\n", name);
4701 else
4702 STp->door_locked = ST_LOCKED_AUTO;
4703 }
4704
4705 osst_analyze_headers(STp, &SRpnt);
4706
Willem Riede5e6575c2006-02-11 14:46:56 -05004707 osst_release_request(SRpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004708 SRpnt = NULL;
4709
4710 return 0;
4711
4712err_out:
4713 if (SRpnt != NULL)
Willem Riede5e6575c2006-02-11 14:46:56 -05004714 osst_release_request(SRpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004715 normalize_buffer(STp->buffer);
4716 STp->header_ok = 0;
4717 STp->in_use = 0;
4718 scsi_device_put(STp->device);
4719
4720 return retval;
4721}
4722
4723
4724/* Flush the tape buffer before close */
4725static int os_scsi_tape_flush(struct file * filp)
4726{
4727 int result = 0, result2;
4728 struct osst_tape * STp = filp->private_data;
4729 struct st_modedef * STm = &(STp->modes[STp->current_mode]);
4730 struct st_partstat * STps = &(STp->ps[STp->partition]);
Willem Riede5e6575c2006-02-11 14:46:56 -05004731 struct osst_request * SRpnt = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004732 char * name = tape_name(STp);
4733
4734 if (file_count(filp) > 1)
4735 return 0;
4736
4737 if ((STps->rw == ST_WRITING || STp->dirty) && !STp->pos_unknown) {
4738 STp->write_type = OS_WRITE_DATA;
4739 result = osst_flush_write_buffer(STp, &SRpnt);
4740 if (result != 0 && result != (-ENOSPC))
4741 goto out;
4742 }
4743 if ( STps->rw >= ST_WRITING && !STp->pos_unknown) {
4744
4745#if DEBUG
4746 if (debugging) {
4747 printk(OSST_DEB_MSG "%s:D: File length %ld bytes.\n",
4748 name, (long)(filp->f_pos));
4749 printk(OSST_DEB_MSG "%s:D: Async write waits %d, finished %d.\n",
4750 name, STp->nbr_waits, STp->nbr_finished);
4751 }
4752#endif
4753 result = osst_write_trailer(STp, &SRpnt, !(STp->rew_at_close));
4754#if DEBUG
4755 if (debugging)
4756 printk(OSST_DEB_MSG "%s:D: Buffer flushed, %d EOF(s) written\n",
4757 name, 1+STp->two_fm);
4758#endif
4759 }
4760 else if (!STp->rew_at_close) {
4761 STps = &(STp->ps[STp->partition]);
4762 if (!STm->sysv || STps->rw != ST_READING) {
4763 if (STp->can_bsr)
4764 result = osst_flush_buffer(STp, &SRpnt, 0); /* this is the default path */
4765 else if (STps->eof == ST_FM_HIT) {
4766 result = cross_eof(STp, &SRpnt, 0);
4767 if (result) {
4768 if (STps->drv_file >= 0)
4769 STps->drv_file++;
4770 STps->drv_block = 0;
4771 STps->eof = ST_FM;
4772 }
4773 else
4774 STps->eof = ST_NOEOF;
4775 }
4776 }
4777 else if ((STps->eof == ST_NOEOF &&
4778 !(result = cross_eof(STp, &SRpnt, 1))) ||
4779 STps->eof == ST_FM_HIT) {
4780 if (STps->drv_file >= 0)
4781 STps->drv_file++;
4782 STps->drv_block = 0;
4783 STps->eof = ST_FM;
4784 }
4785 }
4786
4787out:
4788 if (STp->rew_at_close) {
4789 result2 = osst_position_tape_and_confirm(STp, &SRpnt, STp->first_data_ppos);
4790 STps->drv_file = STps->drv_block = STp->frame_seq_number = STp->logical_blk_num = 0;
4791 if (result == 0 && result2 < 0)
4792 result = result2;
4793 }
Willem Riede5e6575c2006-02-11 14:46:56 -05004794 if (SRpnt) osst_release_request(SRpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004795
4796 if (STp->abort_count || STp->recover_count) {
4797 printk(KERN_INFO "%s:I:", name);
4798 if (STp->abort_count)
4799 printk(" %d unrecovered errors", STp->abort_count);
4800 if (STp->recover_count)
4801 printk(" %d recovered errors", STp->recover_count);
4802 if (STp->write_count)
4803 printk(" in %d frames written", STp->write_count);
4804 if (STp->read_count)
4805 printk(" in %d frames read", STp->read_count);
4806 printk("\n");
4807 STp->recover_count = 0;
4808 STp->abort_count = 0;
4809 }
4810 STp->write_count = 0;
4811 STp->read_count = 0;
4812
4813 return result;
4814}
4815
4816
4817/* Close the device and release it */
4818static int os_scsi_tape_close(struct inode * inode, struct file * filp)
4819{
4820 int result = 0;
4821 struct osst_tape * STp = filp->private_data;
4822
4823 if (STp->door_locked == ST_LOCKED_AUTO)
4824 do_door_lock(STp, 0);
4825
4826 if (STp->raw)
4827 STp->header_ok = 0;
4828
4829 normalize_buffer(STp->buffer);
4830 write_lock(&os_scsi_tapes_lock);
4831 STp->in_use = 0;
4832 write_unlock(&os_scsi_tapes_lock);
4833
4834 scsi_device_put(STp->device);
4835
4836 return result;
4837}
4838
4839
4840/* The ioctl command */
4841static int osst_ioctl(struct inode * inode,struct file * file,
4842 unsigned int cmd_in, unsigned long arg)
4843{
4844 int i, cmd_nr, cmd_type, retval = 0;
4845 unsigned int blk;
4846 struct st_modedef * STm;
4847 struct st_partstat * STps;
Willem Riede5e6575c2006-02-11 14:46:56 -05004848 struct osst_request * SRpnt = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004849 struct osst_tape * STp = file->private_data;
4850 char * name = tape_name(STp);
4851 void __user * p = (void __user *)arg;
4852
4853 if (down_interruptible(&STp->lock))
4854 return -ERESTARTSYS;
4855
4856#if DEBUG
4857 if (debugging && !STp->in_use) {
4858 printk(OSST_DEB_MSG "%s:D: Incorrect device.\n", name);
4859 retval = (-EIO);
4860 goto out;
4861 }
4862#endif
4863 STm = &(STp->modes[STp->current_mode]);
4864 STps = &(STp->ps[STp->partition]);
4865
4866 /*
4867 * If we are in the middle of error recovery, don't let anyone
4868 * else try and use this device. Also, if error recovery fails, it
4869 * may try and take the device offline, in which case all further
4870 * access to the device is prohibited.
4871 */
4872 if( !scsi_block_when_processing_errors(STp->device) ) {
4873 retval = (-ENXIO);
4874 goto out;
4875 }
4876
4877 cmd_type = _IOC_TYPE(cmd_in);
4878 cmd_nr = _IOC_NR(cmd_in);
4879#if DEBUG
4880 printk(OSST_DEB_MSG "%s:D: Ioctl %d,%d in %s mode\n", name,
4881 cmd_type, cmd_nr, STp->raw?"raw":"normal");
4882#endif
4883 if (cmd_type == _IOC_TYPE(MTIOCTOP) && cmd_nr == _IOC_NR(MTIOCTOP)) {
4884 struct mtop mtc;
4885 int auto_weof = 0;
4886
4887 if (_IOC_SIZE(cmd_in) != sizeof(mtc)) {
4888 retval = (-EINVAL);
4889 goto out;
4890 }
4891
4892 i = copy_from_user((char *) &mtc, p, sizeof(struct mtop));
4893 if (i) {
4894 retval = (-EFAULT);
4895 goto out;
4896 }
4897
4898 if (mtc.mt_op == MTSETDRVBUFFER && !capable(CAP_SYS_ADMIN)) {
4899 printk(KERN_WARNING "%s:W: MTSETDRVBUFFER only allowed for root.\n", name);
4900 retval = (-EPERM);
4901 goto out;
4902 }
4903
4904 if (!STm->defined && (mtc.mt_op != MTSETDRVBUFFER && (mtc.mt_count & MT_ST_OPTIONS) == 0)) {
4905 retval = (-ENXIO);
4906 goto out;
4907 }
4908
4909 if (!STp->pos_unknown) {
4910
4911 if (STps->eof == ST_FM_HIT) {
4912 if (mtc.mt_op == MTFSF || mtc.mt_op == MTFSFM|| mtc.mt_op == MTEOM) {
4913 mtc.mt_count -= 1;
4914 if (STps->drv_file >= 0)
4915 STps->drv_file += 1;
4916 }
4917 else if (mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM) {
4918 mtc.mt_count += 1;
4919 if (STps->drv_file >= 0)
4920 STps->drv_file += 1;
4921 }
4922 }
4923
4924 if (mtc.mt_op == MTSEEK) {
4925 /* Old position must be restored if partition will be changed */
4926 i = !STp->can_partitions || (STp->new_partition != STp->partition);
4927 }
4928 else {
4929 i = mtc.mt_op == MTREW || mtc.mt_op == MTOFFL ||
4930 mtc.mt_op == MTRETEN || mtc.mt_op == MTEOM ||
4931 mtc.mt_op == MTLOCK || mtc.mt_op == MTLOAD ||
4932 mtc.mt_op == MTFSF || mtc.mt_op == MTFSFM ||
4933 mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM ||
4934 mtc.mt_op == MTCOMPRESSION;
4935 }
4936 i = osst_flush_buffer(STp, &SRpnt, i);
4937 if (i < 0) {
4938 retval = i;
4939 goto out;
4940 }
4941 }
4942 else {
4943 /*
4944 * If there was a bus reset, block further access
4945 * to this device. If the user wants to rewind the tape,
4946 * then reset the flag and allow access again.
4947 */
4948 if(mtc.mt_op != MTREW &&
4949 mtc.mt_op != MTOFFL &&
4950 mtc.mt_op != MTRETEN &&
4951 mtc.mt_op != MTERASE &&
4952 mtc.mt_op != MTSEEK &&
4953 mtc.mt_op != MTEOM) {
4954 retval = (-EIO);
4955 goto out;
4956 }
4957 reset_state(STp);
4958 /* remove this when the midlevel properly clears was_reset */
4959 STp->device->was_reset = 0;
4960 }
4961
4962 if (mtc.mt_op != MTCOMPRESSION && mtc.mt_op != MTLOCK &&
4963 mtc.mt_op != MTNOP && mtc.mt_op != MTSETBLK &&
4964 mtc.mt_op != MTSETDENSITY && mtc.mt_op != MTSETDRVBUFFER &&
4965 mtc.mt_op != MTMKPART && mtc.mt_op != MTSETPART &&
4966 mtc.mt_op != MTWEOF && mtc.mt_op != MTWSM ) {
4967
4968 /*
4969 * The user tells us to move to another position on the tape.
4970 * If we were appending to the tape content, that would leave
4971 * the tape without proper end, in that case write EOD and
4972 * update the header to reflect its position.
4973 */
4974#if DEBUG
4975 printk(KERN_WARNING "%s:D: auto_weod %s at ffp=%d,efp=%d,fsn=%d,lbn=%d,fn=%d,bn=%d\n", name,
4976 STps->rw >= ST_WRITING ? "write" : STps->rw == ST_READING ? "read" : "idle",
4977 STp->first_frame_position, STp->eod_frame_ppos, STp->frame_seq_number,
4978 STp->logical_blk_num, STps->drv_file, STps->drv_block );
4979#endif
4980 if (STps->rw >= ST_WRITING && STp->first_frame_position >= STp->eod_frame_ppos) {
4981 auto_weof = ((STp->write_type != OS_WRITE_NEW_MARK) &&
4982 !(mtc.mt_op == MTREW || mtc.mt_op == MTOFFL));
4983 i = osst_write_trailer(STp, &SRpnt,
4984 !(mtc.mt_op == MTREW || mtc.mt_op == MTOFFL));
4985#if DEBUG
4986 printk(KERN_WARNING "%s:D: post trailer xeof=%d,ffp=%d,efp=%d,fsn=%d,lbn=%d,fn=%d,bn=%d\n",
4987 name, auto_weof, STp->first_frame_position, STp->eod_frame_ppos,
4988 STp->frame_seq_number, STp->logical_blk_num, STps->drv_file, STps->drv_block );
4989#endif
4990 if (i < 0) {
4991 retval = i;
4992 goto out;
4993 }
4994 }
4995 STps->rw = ST_IDLE;
4996 }
4997
4998 if (mtc.mt_op == MTOFFL && STp->door_locked != ST_UNLOCKED)
4999 do_door_lock(STp, 0); /* Ignore result! */
5000
5001 if (mtc.mt_op == MTSETDRVBUFFER &&
5002 (mtc.mt_count & MT_ST_OPTIONS) != 0) {
5003 retval = osst_set_options(STp, mtc.mt_count);
5004 goto out;
5005 }
5006
5007 if (mtc.mt_op == MTSETPART) {
5008 if (mtc.mt_count >= STp->nbr_partitions)
5009 retval = -EINVAL;
5010 else {
5011 STp->new_partition = mtc.mt_count;
5012 retval = 0;
5013 }
5014 goto out;
5015 }
5016
5017 if (mtc.mt_op == MTMKPART) {
5018 if (!STp->can_partitions) {
5019 retval = (-EINVAL);
5020 goto out;
5021 }
5022 if ((i = osst_int_ioctl(STp, &SRpnt, MTREW, 0)) < 0 /*||
5023 (i = partition_tape(inode, mtc.mt_count)) < 0*/) {
5024 retval = i;
5025 goto out;
5026 }
5027 for (i=0; i < ST_NBR_PARTITIONS; i++) {
5028 STp->ps[i].rw = ST_IDLE;
5029 STp->ps[i].at_sm = 0;
5030 STp->ps[i].last_block_valid = 0;
5031 }
5032 STp->partition = STp->new_partition = 0;
5033 STp->nbr_partitions = 1; /* Bad guess ?-) */
5034 STps->drv_block = STps->drv_file = 0;
5035 retval = 0;
5036 goto out;
5037 }
5038
5039 if (mtc.mt_op == MTSEEK) {
5040 if (STp->raw)
5041 i = osst_set_frame_position(STp, &SRpnt, mtc.mt_count, 0);
5042 else
5043 i = osst_seek_sector(STp, &SRpnt, mtc.mt_count);
5044 if (!STp->can_partitions)
5045 STp->ps[0].rw = ST_IDLE;
5046 retval = i;
5047 goto out;
5048 }
5049
5050 if (mtc.mt_op == MTLOCK || mtc.mt_op == MTUNLOCK) {
5051 retval = do_door_lock(STp, (mtc.mt_op == MTLOCK));
5052 goto out;
5053 }
5054
5055 if (auto_weof)
5056 cross_eof(STp, &SRpnt, 0);
5057
5058 if (mtc.mt_op == MTCOMPRESSION)
5059 retval = -EINVAL; /* OnStream drives don't have compression hardware */
5060 else
5061 /* MTBSF MTBSFM MTBSR MTBSS MTEOM MTERASE MTFSF MTFSFB MTFSR MTFSS
5062 * MTLOAD MTOFFL MTRESET MTRETEN MTREW MTUNLOAD MTWEOF MTWSM */
5063 retval = osst_int_ioctl(STp, &SRpnt, mtc.mt_op, mtc.mt_count);
5064 goto out;
5065 }
5066
5067 if (!STm->defined) {
5068 retval = (-ENXIO);
5069 goto out;
5070 }
5071
5072 if ((i = osst_flush_buffer(STp, &SRpnt, 0)) < 0) {
5073 retval = i;
5074 goto out;
5075 }
5076
5077 if (cmd_type == _IOC_TYPE(MTIOCGET) && cmd_nr == _IOC_NR(MTIOCGET)) {
5078 struct mtget mt_status;
5079
5080 if (_IOC_SIZE(cmd_in) != sizeof(struct mtget)) {
5081 retval = (-EINVAL);
5082 goto out;
5083 }
5084
5085 mt_status.mt_type = MT_ISONSTREAM_SC;
5086 mt_status.mt_erreg = STp->recover_erreg << MT_ST_SOFTERR_SHIFT;
5087 mt_status.mt_dsreg =
5088 ((STp->block_size << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK) |
5089 ((STp->density << MT_ST_DENSITY_SHIFT) & MT_ST_DENSITY_MASK);
5090 mt_status.mt_blkno = STps->drv_block;
5091 mt_status.mt_fileno = STps->drv_file;
5092 if (STp->block_size != 0) {
5093 if (STps->rw == ST_WRITING)
5094 mt_status.mt_blkno += (STp->buffer)->buffer_bytes / STp->block_size;
5095 else if (STps->rw == ST_READING)
5096 mt_status.mt_blkno -= ((STp->buffer)->buffer_bytes +
5097 STp->block_size - 1) / STp->block_size;
5098 }
5099
5100 mt_status.mt_gstat = 0;
5101 if (STp->drv_write_prot)
5102 mt_status.mt_gstat |= GMT_WR_PROT(0xffffffff);
5103 if (mt_status.mt_blkno == 0) {
5104 if (mt_status.mt_fileno == 0)
5105 mt_status.mt_gstat |= GMT_BOT(0xffffffff);
5106 else
5107 mt_status.mt_gstat |= GMT_EOF(0xffffffff);
5108 }
5109 mt_status.mt_resid = STp->partition;
5110 if (STps->eof == ST_EOM_OK || STps->eof == ST_EOM_ERROR)
5111 mt_status.mt_gstat |= GMT_EOT(0xffffffff);
5112 else if (STps->eof >= ST_EOM_OK)
5113 mt_status.mt_gstat |= GMT_EOD(0xffffffff);
5114 if (STp->density == 1)
5115 mt_status.mt_gstat |= GMT_D_800(0xffffffff);
5116 else if (STp->density == 2)
5117 mt_status.mt_gstat |= GMT_D_1600(0xffffffff);
5118 else if (STp->density == 3)
5119 mt_status.mt_gstat |= GMT_D_6250(0xffffffff);
5120 if (STp->ready == ST_READY)
5121 mt_status.mt_gstat |= GMT_ONLINE(0xffffffff);
5122 if (STp->ready == ST_NO_TAPE)
5123 mt_status.mt_gstat |= GMT_DR_OPEN(0xffffffff);
5124 if (STps->at_sm)
5125 mt_status.mt_gstat |= GMT_SM(0xffffffff);
5126 if (STm->do_async_writes || (STm->do_buffer_writes && STp->block_size != 0) ||
5127 STp->drv_buffer != 0)
5128 mt_status.mt_gstat |= GMT_IM_REP_EN(0xffffffff);
5129
5130 i = copy_to_user(p, &mt_status, sizeof(struct mtget));
5131 if (i) {
5132 retval = (-EFAULT);
5133 goto out;
5134 }
5135
5136 STp->recover_erreg = 0; /* Clear after read */
5137 retval = 0;
5138 goto out;
5139 } /* End of MTIOCGET */
5140
5141 if (cmd_type == _IOC_TYPE(MTIOCPOS) && cmd_nr == _IOC_NR(MTIOCPOS)) {
5142 struct mtpos mt_pos;
5143
5144 if (_IOC_SIZE(cmd_in) != sizeof(struct mtpos)) {
5145 retval = (-EINVAL);
5146 goto out;
5147 }
5148 if (STp->raw)
5149 blk = osst_get_frame_position(STp, &SRpnt);
5150 else
5151 blk = osst_get_sector(STp, &SRpnt);
5152 if (blk < 0) {
5153 retval = blk;
5154 goto out;
5155 }
5156 mt_pos.mt_blkno = blk;
5157 i = copy_to_user(p, &mt_pos, sizeof(struct mtpos));
5158 if (i)
5159 retval = -EFAULT;
5160 goto out;
5161 }
Willem Riede5e6575c2006-02-11 14:46:56 -05005162 if (SRpnt) osst_release_request(SRpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005163
5164 up(&STp->lock);
5165
5166 return scsi_ioctl(STp->device, cmd_in, p);
5167
5168out:
Willem Riede5e6575c2006-02-11 14:46:56 -05005169 if (SRpnt) osst_release_request(SRpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005170
5171 up(&STp->lock);
5172
5173 return retval;
5174}
5175
5176#ifdef CONFIG_COMPAT
5177static long osst_compat_ioctl(struct file * file, unsigned int cmd_in, unsigned long arg)
5178{
5179 struct osst_tape *STp = file->private_data;
5180 struct scsi_device *sdev = STp->device;
5181 int ret = -ENOIOCTLCMD;
5182 if (sdev->host->hostt->compat_ioctl) {
5183
5184 ret = sdev->host->hostt->compat_ioctl(sdev, cmd_in, (void __user *)arg);
5185
5186 }
5187 return ret;
5188}
5189#endif
5190
5191
5192
5193/* Memory handling routines */
5194
5195/* Try to allocate a new tape buffer skeleton. Caller must not hold os_scsi_tapes_lock */
5196static struct osst_buffer * new_tape_buffer( int from_initialization, int need_dma, int max_sg )
5197{
Al Viroc53033f2005-10-21 03:22:08 -04005198 int i;
5199 gfp_t priority;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005200 struct osst_buffer *tb;
5201
5202 if (from_initialization)
5203 priority = GFP_ATOMIC;
5204 else
5205 priority = GFP_KERNEL;
5206
5207 i = sizeof(struct osst_buffer) + (osst_max_sg_segs - 1) * sizeof(struct scatterlist);
5208 tb = (struct osst_buffer *)kmalloc(i, priority);
5209 if (!tb) {
5210 printk(KERN_NOTICE "osst :I: Can't allocate new tape buffer.\n");
5211 return NULL;
5212 }
5213 memset(tb, 0, i);
5214 tb->sg_segs = tb->orig_sg_segs = 0;
5215 tb->use_sg = max_sg;
5216 tb->in_use = 1;
5217 tb->dma = need_dma;
5218 tb->buffer_size = 0;
5219#if DEBUG
5220 if (debugging)
5221 printk(OSST_DEB_MSG
5222 "osst :D: Allocated tape buffer skeleton (%d bytes, %d segments, dma: %d).\n",
5223 i, max_sg, need_dma);
5224#endif
5225 return tb;
5226}
5227
5228/* Try to allocate a temporary (while a user has the device open) enlarged tape buffer */
5229static int enlarge_buffer(struct osst_buffer *STbuffer, int need_dma)
5230{
Al Viroc53033f2005-10-21 03:22:08 -04005231 int segs, nbr, max_segs, b_size, order, got;
5232 gfp_t priority;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005233
5234 if (STbuffer->buffer_size >= OS_FRAME_SIZE)
5235 return 1;
5236
5237 if (STbuffer->sg_segs) {
5238 printk(KERN_WARNING "osst :A: Buffer not previously normalized.\n");
5239 normalize_buffer(STbuffer);
5240 }
5241 /* See how many segments we can use -- need at least two */
5242 nbr = max_segs = STbuffer->use_sg;
5243 if (nbr <= 2)
5244 return 0;
5245
5246 priority = GFP_KERNEL /* | __GFP_NOWARN */;
5247 if (need_dma)
5248 priority |= GFP_DMA;
5249
5250 /* Try to allocate the first segment up to OS_DATA_SIZE and the others
5251 big enough to reach the goal (code assumes no segments in place) */
5252 for (b_size = OS_DATA_SIZE, order = OSST_FIRST_ORDER; b_size >= PAGE_SIZE; order--, b_size /= 2) {
5253 STbuffer->sg[0].page = alloc_pages(priority, order);
5254 STbuffer->sg[0].offset = 0;
5255 if (STbuffer->sg[0].page != NULL) {
5256 STbuffer->sg[0].length = b_size;
5257 STbuffer->b_data = page_address(STbuffer->sg[0].page);
5258 break;
5259 }
5260 }
5261 if (STbuffer->sg[0].page == NULL) {
5262 printk(KERN_NOTICE "osst :I: Can't allocate tape buffer main segment.\n");
5263 return 0;
5264 }
5265 /* Got initial segment of 'bsize,order', continue with same size if possible, except for AUX */
5266 for (segs=STbuffer->sg_segs=1, got=b_size;
5267 segs < max_segs && got < OS_FRAME_SIZE; ) {
5268 STbuffer->sg[segs].page =
5269 alloc_pages(priority, (OS_FRAME_SIZE - got <= PAGE_SIZE) ? 0 : order);
5270 STbuffer->sg[segs].offset = 0;
5271 if (STbuffer->sg[segs].page == NULL) {
5272 if (OS_FRAME_SIZE - got <= (max_segs - segs) * b_size / 2 && order) {
5273 b_size /= 2; /* Large enough for the rest of the buffers */
5274 order--;
5275 continue;
5276 }
5277 printk(KERN_WARNING "osst :W: Failed to enlarge buffer to %d bytes.\n",
5278 OS_FRAME_SIZE);
5279#if DEBUG
5280 STbuffer->buffer_size = got;
5281#endif
5282 normalize_buffer(STbuffer);
5283 return 0;
5284 }
5285 STbuffer->sg[segs].length = (OS_FRAME_SIZE - got <= PAGE_SIZE / 2) ? (OS_FRAME_SIZE - got) : b_size;
5286 got += STbuffer->sg[segs].length;
5287 STbuffer->buffer_size = got;
5288 STbuffer->sg_segs = ++segs;
5289 }
5290#if DEBUG
5291 if (debugging) {
5292 printk(OSST_DEB_MSG
5293 "osst :D: Expanded tape buffer (%d bytes, %d->%d segments, dma: %d, at: %p).\n",
5294 got, STbuffer->orig_sg_segs, STbuffer->sg_segs, need_dma, STbuffer->b_data);
5295 printk(OSST_DEB_MSG
5296 "osst :D: segment sizes: first %d at %p, last %d bytes at %p.\n",
5297 STbuffer->sg[0].length, page_address(STbuffer->sg[0].page),
5298 STbuffer->sg[segs-1].length, page_address(STbuffer->sg[segs-1].page));
5299 }
5300#endif
5301
5302 return 1;
5303}
5304
5305
5306/* Release the segments */
5307static void normalize_buffer(struct osst_buffer *STbuffer)
5308{
5309 int i, order, b_size;
5310
5311 for (i=0; i < STbuffer->sg_segs; i++) {
5312
5313 for (b_size = PAGE_SIZE, order = 0;
5314 b_size < STbuffer->sg[i].length;
5315 b_size *= 2, order++);
5316
5317 __free_pages(STbuffer->sg[i].page, order);
5318 STbuffer->buffer_size -= STbuffer->sg[i].length;
5319 }
5320#if DEBUG
5321 if (debugging && STbuffer->orig_sg_segs < STbuffer->sg_segs)
5322 printk(OSST_DEB_MSG "osst :D: Buffer at %p normalized to %d bytes (segs %d).\n",
5323 STbuffer->b_data, STbuffer->buffer_size, STbuffer->sg_segs);
5324#endif
5325 STbuffer->sg_segs = STbuffer->orig_sg_segs = 0;
5326}
5327
5328
5329/* Move data from the user buffer to the tape buffer. Returns zero (success) or
5330 negative error code. */
5331static int append_to_buffer(const char __user *ubp, struct osst_buffer *st_bp, int do_count)
5332{
5333 int i, cnt, res, offset;
5334
5335 for (i=0, offset=st_bp->buffer_bytes;
5336 i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++)
5337 offset -= st_bp->sg[i].length;
5338 if (i == st_bp->sg_segs) { /* Should never happen */
5339 printk(KERN_WARNING "osst :A: Append_to_buffer offset overflow.\n");
5340 return (-EIO);
5341 }
5342 for ( ; i < st_bp->sg_segs && do_count > 0; i++) {
5343 cnt = st_bp->sg[i].length - offset < do_count ?
5344 st_bp->sg[i].length - offset : do_count;
5345 res = copy_from_user(page_address(st_bp->sg[i].page) + offset, ubp, cnt);
5346 if (res)
5347 return (-EFAULT);
5348 do_count -= cnt;
5349 st_bp->buffer_bytes += cnt;
5350 ubp += cnt;
5351 offset = 0;
5352 }
5353 if (do_count) { /* Should never happen */
5354 printk(KERN_WARNING "osst :A: Append_to_buffer overflow (left %d).\n",
5355 do_count);
5356 return (-EIO);
5357 }
5358 return 0;
5359}
5360
5361
5362/* Move data from the tape buffer to the user buffer. Returns zero (success) or
5363 negative error code. */
5364static int from_buffer(struct osst_buffer *st_bp, char __user *ubp, int do_count)
5365{
5366 int i, cnt, res, offset;
5367
5368 for (i=0, offset=st_bp->read_pointer;
5369 i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++)
5370 offset -= st_bp->sg[i].length;
5371 if (i == st_bp->sg_segs) { /* Should never happen */
5372 printk(KERN_WARNING "osst :A: From_buffer offset overflow.\n");
5373 return (-EIO);
5374 }
5375 for ( ; i < st_bp->sg_segs && do_count > 0; i++) {
5376 cnt = st_bp->sg[i].length - offset < do_count ?
5377 st_bp->sg[i].length - offset : do_count;
5378 res = copy_to_user(ubp, page_address(st_bp->sg[i].page) + offset, cnt);
5379 if (res)
5380 return (-EFAULT);
5381 do_count -= cnt;
5382 st_bp->buffer_bytes -= cnt;
5383 st_bp->read_pointer += cnt;
5384 ubp += cnt;
5385 offset = 0;
5386 }
5387 if (do_count) { /* Should never happen */
5388 printk(KERN_WARNING "osst :A: From_buffer overflow (left %d).\n", do_count);
5389 return (-EIO);
5390 }
5391 return 0;
5392}
5393
5394/* Sets the tail of the buffer after fill point to zero.
5395 Returns zero (success) or negative error code. */
5396static int osst_zero_buffer_tail(struct osst_buffer *st_bp)
5397{
5398 int i, offset, do_count, cnt;
5399
5400 for (i = 0, offset = st_bp->buffer_bytes;
5401 i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++)
5402 offset -= st_bp->sg[i].length;
5403 if (i == st_bp->sg_segs) { /* Should never happen */
5404 printk(KERN_WARNING "osst :A: Zero_buffer offset overflow.\n");
5405 return (-EIO);
5406 }
5407 for (do_count = OS_DATA_SIZE - st_bp->buffer_bytes;
5408 i < st_bp->sg_segs && do_count > 0; i++) {
5409 cnt = st_bp->sg[i].length - offset < do_count ?
5410 st_bp->sg[i].length - offset : do_count ;
5411 memset(page_address(st_bp->sg[i].page) + offset, 0, cnt);
5412 do_count -= cnt;
5413 offset = 0;
5414 }
5415 if (do_count) { /* Should never happen */
5416 printk(KERN_WARNING "osst :A: Zero_buffer overflow (left %d).\n", do_count);
5417 return (-EIO);
5418 }
5419 return 0;
5420}
5421
5422/* Copy a osst 32K chunk of memory into the buffer.
5423 Returns zero (success) or negative error code. */
5424static int osst_copy_to_buffer(struct osst_buffer *st_bp, unsigned char *ptr)
5425{
5426 int i, cnt, do_count = OS_DATA_SIZE;
5427
5428 for (i = 0; i < st_bp->sg_segs && do_count > 0; i++) {
5429 cnt = st_bp->sg[i].length < do_count ?
5430 st_bp->sg[i].length : do_count ;
5431 memcpy(page_address(st_bp->sg[i].page), ptr, cnt);
5432 do_count -= cnt;
5433 ptr += cnt;
5434 }
5435 if (do_count || i != st_bp->sg_segs-1) { /* Should never happen */
5436 printk(KERN_WARNING "osst :A: Copy_to_buffer overflow (left %d at sg %d).\n",
5437 do_count, i);
5438 return (-EIO);
5439 }
5440 return 0;
5441}
5442
5443/* Copy a osst 32K chunk of memory from the buffer.
5444 Returns zero (success) or negative error code. */
5445static int osst_copy_from_buffer(struct osst_buffer *st_bp, unsigned char *ptr)
5446{
5447 int i, cnt, do_count = OS_DATA_SIZE;
5448
5449 for (i = 0; i < st_bp->sg_segs && do_count > 0; i++) {
5450 cnt = st_bp->sg[i].length < do_count ?
5451 st_bp->sg[i].length : do_count ;
5452 memcpy(ptr, page_address(st_bp->sg[i].page), cnt);
5453 do_count -= cnt;
5454 ptr += cnt;
5455 }
5456 if (do_count || i != st_bp->sg_segs-1) { /* Should never happen */
5457 printk(KERN_WARNING "osst :A: Copy_from_buffer overflow (left %d at sg %d).\n",
5458 do_count, i);
5459 return (-EIO);
5460 }
5461 return 0;
5462}
5463
5464
5465/* Module housekeeping */
5466
5467static void validate_options (void)
5468{
5469 if (max_dev > 0)
5470 osst_max_dev = max_dev;
5471 if (write_threshold_kbs > 0)
5472 osst_write_threshold = write_threshold_kbs * ST_KILOBYTE;
5473 if (osst_write_threshold > osst_buffer_size)
5474 osst_write_threshold = osst_buffer_size;
5475 if (max_sg_segs >= OSST_FIRST_SG)
5476 osst_max_sg_segs = max_sg_segs;
5477#if DEBUG
5478 printk(OSST_DEB_MSG "osst :D: max tapes %d, write threshold %d, max s/g segs %d.\n",
5479 osst_max_dev, osst_write_threshold, osst_max_sg_segs);
5480#endif
5481}
5482
5483#ifndef MODULE
5484/* Set the boot options. Syntax: osst=xxx,yyy,...
5485 where xxx is write threshold in 1024 byte blocks,
5486 and yyy is number of s/g segments to use. */
5487static int __init osst_setup (char *str)
5488{
5489 int i, ints[5];
5490 char *stp;
5491
5492 stp = get_options(str, ARRAY_SIZE(ints), ints);
5493
5494 if (ints[0] > 0) {
5495 for (i = 0; i < ints[0] && i < ARRAY_SIZE(parms); i++)
5496 *parms[i].val = ints[i + 1];
5497 } else {
5498 while (stp != NULL) {
5499 for (i = 0; i < ARRAY_SIZE(parms); i++) {
5500 int len = strlen(parms[i].name);
5501 if (!strncmp(stp, parms[i].name, len) &&
5502 (*(stp + len) == ':' || *(stp + len) == '=')) {
5503 *parms[i].val =
5504 simple_strtoul(stp + len + 1, NULL, 0);
5505 break;
5506 }
5507 }
5508 if (i >= sizeof(parms) / sizeof(struct osst_dev_parm))
5509 printk(KERN_INFO "osst :I: Illegal parameter in '%s'\n",
5510 stp);
5511 stp = strchr(stp, ',');
5512 if (stp)
5513 stp++;
5514 }
5515 }
5516
5517 return 1;
5518}
5519
5520__setup("osst=", osst_setup);
5521
5522#endif
5523
5524static struct file_operations osst_fops = {
5525 .owner = THIS_MODULE,
5526 .read = osst_read,
5527 .write = osst_write,
5528 .ioctl = osst_ioctl,
5529#ifdef CONFIG_COMPAT
5530 .compat_ioctl = osst_compat_ioctl,
5531#endif
5532 .open = os_scsi_tape_open,
5533 .flush = os_scsi_tape_flush,
5534 .release = os_scsi_tape_close,
5535};
5536
5537static int osst_supports(struct scsi_device * SDp)
5538{
5539 struct osst_support_data {
5540 char *vendor;
5541 char *model;
5542 char *rev;
5543 char *driver_hint; /* Name of the correct driver, NULL if unknown */
5544 };
5545
5546static struct osst_support_data support_list[] = {
5547 /* {"XXX", "Yy-", "", NULL}, example */
5548 SIGS_FROM_OSST,
5549 {NULL, }};
5550
5551 struct osst_support_data *rp;
5552
5553 /* We are willing to drive OnStream SC-x0 as well as the
5554 * * IDE, ParPort, FireWire, USB variants, if accessible by
5555 * * emulation layer (ide-scsi, usb-storage, ...) */
5556
5557 for (rp=&(support_list[0]); rp->vendor != NULL; rp++)
5558 if (!strncmp(rp->vendor, SDp->vendor, strlen(rp->vendor)) &&
5559 !strncmp(rp->model, SDp->model, strlen(rp->model)) &&
5560 !strncmp(rp->rev, SDp->rev, strlen(rp->rev)))
5561 return 1;
5562 return 0;
5563}
5564
5565/*
5566 * sysfs support for osst driver parameter information
5567 */
5568
5569static ssize_t osst_version_show(struct device_driver *ddd, char *buf)
5570{
5571 return snprintf(buf, PAGE_SIZE, "%s\n", osst_version);
5572}
5573
5574static DRIVER_ATTR(version, S_IRUGO, osst_version_show, NULL);
5575
5576static void osst_create_driverfs_files(struct device_driver *driverfs)
5577{
5578 driver_create_file(driverfs, &driver_attr_version);
5579}
5580
5581static void osst_remove_driverfs_files(struct device_driver *driverfs)
5582{
5583 driver_remove_file(driverfs, &driver_attr_version);
5584}
5585
5586/*
5587 * sysfs support for accessing ADR header information
5588 */
5589
5590static ssize_t osst_adr_rev_show(struct class_device *class_dev, char *buf)
5591{
5592 struct osst_tape * STp = (struct osst_tape *) class_get_devdata (class_dev);
5593 ssize_t l = 0;
5594
5595 if (STp && STp->header_ok && STp->linux_media)
5596 l = snprintf(buf, PAGE_SIZE, "%d.%d\n", STp->header_cache->major_rev, STp->header_cache->minor_rev);
5597 return l;
5598}
5599
5600CLASS_DEVICE_ATTR(ADR_rev, S_IRUGO, osst_adr_rev_show, NULL);
5601
5602static ssize_t osst_linux_media_version_show(struct class_device *class_dev, char *buf)
5603{
5604 struct osst_tape * STp = (struct osst_tape *) class_get_devdata (class_dev);
5605 ssize_t l = 0;
5606
5607 if (STp && STp->header_ok && STp->linux_media)
5608 l = snprintf(buf, PAGE_SIZE, "LIN%d\n", STp->linux_media_version);
5609 return l;
5610}
5611
5612CLASS_DEVICE_ATTR(media_version, S_IRUGO, osst_linux_media_version_show, NULL);
5613
5614static ssize_t osst_capacity_show(struct class_device *class_dev, char *buf)
5615{
5616 struct osst_tape * STp = (struct osst_tape *) class_get_devdata (class_dev);
5617 ssize_t l = 0;
5618
5619 if (STp && STp->header_ok && STp->linux_media)
5620 l = snprintf(buf, PAGE_SIZE, "%d\n", STp->capacity);
5621 return l;
5622}
5623
5624CLASS_DEVICE_ATTR(capacity, S_IRUGO, osst_capacity_show, NULL);
5625
5626static ssize_t osst_first_data_ppos_show(struct class_device *class_dev, char *buf)
5627{
5628 struct osst_tape * STp = (struct osst_tape *) class_get_devdata (class_dev);
5629 ssize_t l = 0;
5630
5631 if (STp && STp->header_ok && STp->linux_media)
5632 l = snprintf(buf, PAGE_SIZE, "%d\n", STp->first_data_ppos);
5633 return l;
5634}
5635
5636CLASS_DEVICE_ATTR(BOT_frame, S_IRUGO, osst_first_data_ppos_show, NULL);
5637
5638static ssize_t osst_eod_frame_ppos_show(struct class_device *class_dev, char *buf)
5639{
5640 struct osst_tape * STp = (struct osst_tape *) class_get_devdata (class_dev);
5641 ssize_t l = 0;
5642
5643 if (STp && STp->header_ok && STp->linux_media)
5644 l = snprintf(buf, PAGE_SIZE, "%d\n", STp->eod_frame_ppos);
5645 return l;
5646}
5647
5648CLASS_DEVICE_ATTR(EOD_frame, S_IRUGO, osst_eod_frame_ppos_show, NULL);
5649
5650static ssize_t osst_filemark_cnt_show(struct class_device *class_dev, char *buf)
5651{
5652 struct osst_tape * STp = (struct osst_tape *) class_get_devdata (class_dev);
5653 ssize_t l = 0;
5654
5655 if (STp && STp->header_ok && STp->linux_media)
5656 l = snprintf(buf, PAGE_SIZE, "%d\n", STp->filemark_cnt);
5657 return l;
5658}
5659
5660CLASS_DEVICE_ATTR(file_count, S_IRUGO, osst_filemark_cnt_show, NULL);
5661
gregkh@suse.ded2538782005-03-23 09:55:22 -08005662static struct class *osst_sysfs_class;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005663
5664static int osst_sysfs_valid = 0;
5665
5666static void osst_sysfs_init(void)
5667{
gregkh@suse.ded2538782005-03-23 09:55:22 -08005668 osst_sysfs_class = class_create(THIS_MODULE, "onstream_tape");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005669 if ( IS_ERR(osst_sysfs_class) )
5670 printk(KERN_WARNING "osst :W: Unable to register sysfs class\n");
5671 else
5672 osst_sysfs_valid = 1;
5673}
5674
5675static void osst_sysfs_add(dev_t dev, struct device *device, struct osst_tape * STp, char * name)
5676{
5677 struct class_device *osst_class_member;
5678
5679 if (!osst_sysfs_valid) return;
5680
Greg Kroah-Hartman53f46542005-10-27 22:25:43 -07005681 osst_class_member = class_device_create(osst_sysfs_class, NULL, dev, device, "%s", name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005682 if (IS_ERR(osst_class_member)) {
5683 printk(KERN_WARNING "osst :W: Unable to add sysfs class member %s\n", name);
5684 return;
5685 }
5686 class_set_devdata(osst_class_member, STp);
5687 class_device_create_file(osst_class_member, &class_device_attr_ADR_rev);
5688 class_device_create_file(osst_class_member, &class_device_attr_media_version);
5689 class_device_create_file(osst_class_member, &class_device_attr_capacity);
5690 class_device_create_file(osst_class_member, &class_device_attr_BOT_frame);
5691 class_device_create_file(osst_class_member, &class_device_attr_EOD_frame);
5692 class_device_create_file(osst_class_member, &class_device_attr_file_count);
5693}
5694
5695static void osst_sysfs_destroy(dev_t dev)
5696{
5697 if (!osst_sysfs_valid) return;
5698
gregkh@suse.ded2538782005-03-23 09:55:22 -08005699 class_device_destroy(osst_sysfs_class, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005700}
5701
5702static void osst_sysfs_cleanup(void)
5703{
5704 if (osst_sysfs_valid) {
gregkh@suse.ded2538782005-03-23 09:55:22 -08005705 class_destroy(osst_sysfs_class);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005706 osst_sysfs_valid = 0;
5707 }
5708}
5709
5710/*
5711 * osst startup / cleanup code
5712 */
5713
5714static int osst_probe(struct device *dev)
5715{
5716 struct scsi_device * SDp = to_scsi_device(dev);
5717 struct osst_tape * tpnt;
5718 struct st_modedef * STm;
5719 struct st_partstat * STps;
5720 struct osst_buffer * buffer;
5721 struct gendisk * drive;
Greg KH5e3c34c2006-01-18 16:17:46 -08005722 int i, dev_num;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005723
5724 if (SDp->type != TYPE_TAPE || !osst_supports(SDp))
5725 return -ENODEV;
5726
5727 drive = alloc_disk(1);
5728 if (!drive) {
5729 printk(KERN_ERR "osst :E: Out of memory. Device not attached.\n");
5730 return -ENODEV;
5731 }
5732
5733 /* if this is the first attach, build the infrastructure */
5734 write_lock(&os_scsi_tapes_lock);
5735 if (os_scsi_tapes == NULL) {
5736 os_scsi_tapes =
5737 (struct osst_tape **)kmalloc(osst_max_dev * sizeof(struct osst_tape *),
5738 GFP_ATOMIC);
5739 if (os_scsi_tapes == NULL) {
5740 write_unlock(&os_scsi_tapes_lock);
5741 printk(KERN_ERR "osst :E: Unable to allocate array for OnStream SCSI tapes.\n");
5742 goto out_put_disk;
5743 }
5744 for (i=0; i < osst_max_dev; ++i) os_scsi_tapes[i] = NULL;
5745 }
5746
5747 if (osst_nr_dev >= osst_max_dev) {
5748 write_unlock(&os_scsi_tapes_lock);
5749 printk(KERN_ERR "osst :E: Too many tape devices (max. %d).\n", osst_max_dev);
5750 goto out_put_disk;
5751 }
5752
5753 /* find a free minor number */
5754 for (i=0; os_scsi_tapes[i] && i<osst_max_dev; i++);
5755 if(i >= osst_max_dev) panic ("Scsi_devices corrupt (osst)");
5756 dev_num = i;
5757
5758 /* allocate a struct osst_tape for this device */
5759 tpnt = (struct osst_tape *)kmalloc(sizeof(struct osst_tape), GFP_ATOMIC);
5760 if (tpnt == NULL) {
5761 write_unlock(&os_scsi_tapes_lock);
5762 printk(KERN_ERR "osst :E: Can't allocate device descriptor, device not attached.\n");
5763 goto out_put_disk;
5764 }
5765 memset(tpnt, 0, sizeof(struct osst_tape));
5766
5767 /* allocate a buffer for this device */
5768 i = SDp->host->sg_tablesize;
5769 if (osst_max_sg_segs < i)
5770 i = osst_max_sg_segs;
5771 buffer = new_tape_buffer(1, SDp->host->unchecked_isa_dma, i);
5772 if (buffer == NULL) {
5773 write_unlock(&os_scsi_tapes_lock);
5774 printk(KERN_ERR "osst :E: Unable to allocate a tape buffer, device not attached.\n");
5775 kfree(tpnt);
5776 goto out_put_disk;
5777 }
5778 os_scsi_tapes[dev_num] = tpnt;
5779 tpnt->buffer = buffer;
5780 tpnt->device = SDp;
5781 drive->private_data = &tpnt->driver;
5782 sprintf(drive->disk_name, "osst%d", dev_num);
5783 tpnt->driver = &osst_template;
5784 tpnt->drive = drive;
5785 tpnt->in_use = 0;
5786 tpnt->capacity = 0xfffff;
5787 tpnt->dirty = 0;
5788 tpnt->drv_buffer = 1; /* Try buffering if no mode sense */
5789 tpnt->restr_dma = (SDp->host)->unchecked_isa_dma;
5790 tpnt->density = 0;
5791 tpnt->do_auto_lock = OSST_AUTO_LOCK;
5792 tpnt->can_bsr = OSST_IN_FILE_POS;
5793 tpnt->can_partitions = 0;
5794 tpnt->two_fm = OSST_TWO_FM;
5795 tpnt->fast_mteom = OSST_FAST_MTEOM;
5796 tpnt->scsi2_logical = OSST_SCSI2LOGICAL; /* FIXME */
5797 tpnt->write_threshold = osst_write_threshold;
5798 tpnt->default_drvbuffer = 0xff; /* No forced buffering */
5799 tpnt->partition = 0;
5800 tpnt->new_partition = 0;
5801 tpnt->nbr_partitions = 0;
5802 tpnt->min_block = 512;
5803 tpnt->max_block = OS_DATA_SIZE;
5804 tpnt->timeout = OSST_TIMEOUT;
5805 tpnt->long_timeout = OSST_LONG_TIMEOUT;
5806
5807 /* Recognize OnStream tapes */
5808 /* We don't need to test for OnStream, as this has been done in detect () */
5809 tpnt->os_fw_rev = osst_parse_firmware_rev (SDp->rev);
5810 tpnt->omit_blklims = 1;
5811
5812 tpnt->poll = (strncmp(SDp->model, "DI-", 3) == 0) ||
5813 (strncmp(SDp->model, "FW-", 3) == 0) || OSST_FW_NEED_POLL(tpnt->os_fw_rev,SDp);
5814 tpnt->frame_in_buffer = 0;
5815 tpnt->header_ok = 0;
5816 tpnt->linux_media = 0;
5817 tpnt->header_cache = NULL;
5818
5819 for (i=0; i < ST_NBR_MODES; i++) {
5820 STm = &(tpnt->modes[i]);
5821 STm->defined = 0;
5822 STm->sysv = OSST_SYSV;
5823 STm->defaults_for_writes = 0;
5824 STm->do_async_writes = OSST_ASYNC_WRITES;
5825 STm->do_buffer_writes = OSST_BUFFER_WRITES;
5826 STm->do_read_ahead = OSST_READ_AHEAD;
5827 STm->default_compression = ST_DONT_TOUCH;
5828 STm->default_blksize = 512;
5829 STm->default_density = (-1); /* No forced density */
5830 }
5831
5832 for (i=0; i < ST_NBR_PARTITIONS; i++) {
5833 STps = &(tpnt->ps[i]);
5834 STps->rw = ST_IDLE;
5835 STps->eof = ST_NOEOF;
5836 STps->at_sm = 0;
5837 STps->last_block_valid = 0;
5838 STps->drv_block = (-1);
5839 STps->drv_file = (-1);
5840 }
5841
5842 tpnt->current_mode = 0;
5843 tpnt->modes[0].defined = 1;
5844 tpnt->modes[2].defined = 1;
5845 tpnt->density_changed = tpnt->compression_changed = tpnt->blksize_changed = 0;
5846
5847 init_MUTEX(&tpnt->lock);
5848 osst_nr_dev++;
5849 write_unlock(&os_scsi_tapes_lock);
5850 {
5851 char name[8];
5852 /* Rewind entry */
5853 osst_sysfs_add(MKDEV(OSST_MAJOR, dev_num), dev, tpnt, tape_name(tpnt));
5854 /* No-rewind entry */
5855 snprintf(name, 8, "%s%s", "n", tape_name(tpnt));
5856 osst_sysfs_add(MKDEV(OSST_MAJOR, dev_num + 128), dev, tpnt, name);
5857 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005858
James Bottomley80e23ba2005-10-29 09:42:17 -05005859 sdev_printk(KERN_INFO, SDp,
James Bottomley9ccfc752005-10-02 11:45:08 -05005860 "osst :I: Attached OnStream %.5s tape as %s\n",
5861 SDp->model, tape_name(tpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005862
5863 return 0;
5864
5865out_put_disk:
5866 put_disk(drive);
5867 return -ENODEV;
5868};
5869
5870static int osst_remove(struct device *dev)
5871{
5872 struct scsi_device * SDp = to_scsi_device(dev);
5873 struct osst_tape * tpnt;
Greg KH5e3c34c2006-01-18 16:17:46 -08005874 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005875
5876 if ((SDp->type != TYPE_TAPE) || (osst_nr_dev <= 0))
5877 return 0;
5878
5879 write_lock(&os_scsi_tapes_lock);
5880 for(i=0; i < osst_max_dev; i++) {
5881 if((tpnt = os_scsi_tapes[i]) && (tpnt->device == SDp)) {
5882 osst_sysfs_destroy(MKDEV(OSST_MAJOR, i));
5883 osst_sysfs_destroy(MKDEV(OSST_MAJOR, i+128));
5884 tpnt->device = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005885 put_disk(tpnt->drive);
5886 os_scsi_tapes[i] = NULL;
5887 osst_nr_dev--;
5888 write_unlock(&os_scsi_tapes_lock);
Jesper Juhlf91012102005-09-10 00:26:54 -07005889 vfree(tpnt->header_cache);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005890 if (tpnt->buffer) {
5891 normalize_buffer(tpnt->buffer);
5892 kfree(tpnt->buffer);
5893 }
5894 kfree(tpnt);
5895 return 0;
5896 }
5897 }
5898 write_unlock(&os_scsi_tapes_lock);
5899 return 0;
5900}
5901
5902static int __init init_osst(void)
5903{
5904 printk(KERN_INFO "osst :I: Tape driver with OnStream support version %s\nosst :I: %s\n", osst_version, cvsid);
5905
5906 validate_options();
5907 osst_sysfs_init();
5908
5909 if ((register_chrdev(OSST_MAJOR,"osst", &osst_fops) < 0) || scsi_register_driver(&osst_template.gendrv)) {
5910 printk(KERN_ERR "osst :E: Unable to register major %d for OnStream tapes\n", OSST_MAJOR);
5911 osst_sysfs_cleanup();
5912 return 1;
5913 }
5914 osst_create_driverfs_files(&osst_template.gendrv);
5915
5916 return 0;
5917}
5918
5919static void __exit exit_osst (void)
5920{
5921 int i;
5922 struct osst_tape * STp;
5923
5924 osst_remove_driverfs_files(&osst_template.gendrv);
5925 scsi_unregister_driver(&osst_template.gendrv);
5926 unregister_chrdev(OSST_MAJOR, "osst");
5927 osst_sysfs_cleanup();
5928
5929 if (os_scsi_tapes) {
5930 for (i=0; i < osst_max_dev; ++i) {
5931 if (!(STp = os_scsi_tapes[i])) continue;
5932 /* This is defensive, supposed to happen during detach */
Jesper Juhlf91012102005-09-10 00:26:54 -07005933 vfree(STp->header_cache);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005934 if (STp->buffer) {
5935 normalize_buffer(STp->buffer);
5936 kfree(STp->buffer);
5937 }
5938 put_disk(STp->drive);
5939 kfree(STp);
5940 }
5941 kfree(os_scsi_tapes);
5942 }
5943 printk(KERN_INFO "osst :I: Unloaded.\n");
5944}
5945
5946module_init(init_osst);
5947module_exit(exit_osst);