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