blob: 243d8becd30fbb9047b49b29a89a2bcb5167c1e1 [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++)
Jens Axboe45711f12007-10-22 21:19:53 +0200545 memset(page_address(sg_page(&STp->buffer->sg[i])),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 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) {
Ilpo Järvinenccd14432007-10-23 13:42:04 -0700596 if (!quiet) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597#if DEBUG
598 printk(OSST_DEB_MSG "%s:D: Skipping frame, frame type %x\n", name, aux->frame_type);
599#endif
Ilpo Järvinenccd14432007-10-23 13:42:04 -0700600 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 goto err_out;
602 }
603 if (aux->frame_type == OS_FRAME_TYPE_EOD &&
604 STp->first_frame_position < STp->eod_frame_ppos) {
605 printk(KERN_INFO "%s:I: Skipping premature EOD frame %d\n", name,
606 STp->first_frame_position);
607 goto err_out;
608 }
609 if (frame_seq_number != -1 && ntohl(aux->frame_seq_num) != frame_seq_number) {
Ilpo Järvinenccd14432007-10-23 13:42:04 -0700610 if (!quiet) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611#if DEBUG
612 printk(OSST_DEB_MSG "%s:D: Skipping frame, sequence number %u (expected %d)\n",
613 name, ntohl(aux->frame_seq_num), frame_seq_number);
614#endif
Ilpo Järvinenccd14432007-10-23 13:42:04 -0700615 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 goto err_out;
617 }
618 if (aux->frame_type == OS_FRAME_TYPE_MARKER) {
619 STps->eof = ST_FM_HIT;
620
621 i = ntohl(aux->filemark_cnt);
622 if (STp->header_cache != NULL && i < OS_FM_TAB_MAX && (i > STp->filemark_cnt ||
623 STp->first_frame_position - 1 != ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[i]))) {
624#if DEBUG
625 printk(OSST_DEB_MSG "%s:D: %s filemark %d at frame pos %d\n", name,
626 STp->header_cache->dat_fm_tab.fm_tab_ent[i] == 0?"Learned":"Corrected",
627 i, STp->first_frame_position - 1);
628#endif
629 STp->header_cache->dat_fm_tab.fm_tab_ent[i] = htonl(STp->first_frame_position - 1);
630 if (i >= STp->filemark_cnt)
631 STp->filemark_cnt = i+1;
632 }
633 }
634 if (aux->frame_type == OS_FRAME_TYPE_EOD) {
635 STps->eof = ST_EOD_1;
636 STp->frame_in_buffer = 1;
637 }
638 if (aux->frame_type == OS_FRAME_TYPE_DATA) {
639 blk_cnt = ntohs(aux->dat.dat_list[0].blk_cnt);
640 blk_sz = ntohl(aux->dat.dat_list[0].blk_sz);
641 STp->buffer->buffer_bytes = blk_cnt * blk_sz;
642 STp->buffer->read_pointer = 0;
643 STp->frame_in_buffer = 1;
644
645 /* See what block size was used to write file */
646 if (STp->block_size != blk_sz && blk_sz > 0) {
647 printk(KERN_INFO
648 "%s:I: File was written with block size %d%c, currently %d%c, adjusted to match.\n",
649 name, blk_sz<1024?blk_sz:blk_sz/1024,blk_sz<1024?'b':'k',
650 STp->block_size<1024?STp->block_size:STp->block_size/1024,
651 STp->block_size<1024?'b':'k');
652 STp->block_size = blk_sz;
653 STp->buffer->buffer_blocks = OS_DATA_SIZE / blk_sz;
654 }
655 STps->eof = ST_NOEOF;
656 }
657 STp->frame_seq_number = ntohl(aux->frame_seq_num);
658 STp->logical_blk_num = ntohl(aux->logical_blk_num);
659 return 1;
660
661err_out:
662 if (STp->read_error_frame == 0)
663 STp->read_error_frame = STp->first_frame_position - 1;
664 return 0;
665}
666
667/*
668 * Wait for the unit to become Ready
669 */
Willem Riede5e6575c2006-02-11 14:46:56 -0500670static int osst_wait_ready(struct osst_tape * STp, struct osst_request ** aSRpnt,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 unsigned timeout, int initial_delay)
672{
673 unsigned char cmd[MAX_COMMAND_SIZE];
Willem Riede5e6575c2006-02-11 14:46:56 -0500674 struct osst_request * SRpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 unsigned long startwait = jiffies;
676#if DEBUG
677 int dbg = debugging;
678 char * name = tape_name(STp);
679
680 printk(OSST_DEB_MSG "%s:D: Reached onstream wait ready\n", name);
681#endif
682
683 if (initial_delay > 0)
684 msleep(jiffies_to_msecs(initial_delay));
685
686 memset(cmd, 0, MAX_COMMAND_SIZE);
687 cmd[0] = TEST_UNIT_READY;
688
689 SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1);
690 *aSRpnt = SRpnt;
691 if (!SRpnt) return (-EBUSY);
692
693 while ( STp->buffer->syscall_result && time_before(jiffies, startwait + timeout*HZ) &&
Willem Riede5e6575c2006-02-11 14:46:56 -0500694 (( SRpnt->sense[2] == 2 && SRpnt->sense[12] == 4 &&
695 (SRpnt->sense[13] == 1 || SRpnt->sense[13] == 8) ) ||
696 ( SRpnt->sense[2] == 6 && SRpnt->sense[12] == 0x28 &&
697 SRpnt->sense[13] == 0 ) )) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698#if DEBUG
699 if (debugging) {
700 printk(OSST_DEB_MSG "%s:D: Sleeping in onstream wait ready\n", name);
701 printk(OSST_DEB_MSG "%s:D: Turning off debugging for a while\n", name);
702 debugging = 0;
703 }
704#endif
705 msleep(100);
706
707 memset(cmd, 0, MAX_COMMAND_SIZE);
708 cmd[0] = TEST_UNIT_READY;
709
710 SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1);
711 }
712 *aSRpnt = SRpnt;
713#if DEBUG
714 debugging = dbg;
715#endif
716 if ( STp->buffer->syscall_result &&
717 osst_write_error_recovery(STp, aSRpnt, 0) ) {
718#if DEBUG
719 printk(OSST_DEB_MSG "%s:D: Abnormal exit from onstream wait ready\n", name);
720 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 -0500721 STp->buffer->syscall_result, SRpnt->sense[0], SRpnt->sense[2],
722 SRpnt->sense[12], SRpnt->sense[13]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723#endif
724 return (-EIO);
725 }
726#if DEBUG
727 printk(OSST_DEB_MSG "%s:D: Normal exit from onstream wait ready\n", name);
728#endif
729 return 0;
730}
731
732/*
733 * Wait for a tape to be inserted in the unit
734 */
Willem Riede5e6575c2006-02-11 14:46:56 -0500735static int osst_wait_for_medium(struct osst_tape * STp, struct osst_request ** aSRpnt, unsigned timeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736{
737 unsigned char cmd[MAX_COMMAND_SIZE];
Willem Riede5e6575c2006-02-11 14:46:56 -0500738 struct osst_request * SRpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 unsigned long startwait = jiffies;
740#if DEBUG
741 int dbg = debugging;
742 char * name = tape_name(STp);
743
744 printk(OSST_DEB_MSG "%s:D: Reached onstream wait for medium\n", name);
745#endif
746
747 memset(cmd, 0, MAX_COMMAND_SIZE);
748 cmd[0] = TEST_UNIT_READY;
749
750 SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1);
751 *aSRpnt = SRpnt;
752 if (!SRpnt) return (-EBUSY);
753
754 while ( STp->buffer->syscall_result && time_before(jiffies, startwait + timeout*HZ) &&
Willem Riede5e6575c2006-02-11 14:46:56 -0500755 SRpnt->sense[2] == 2 && SRpnt->sense[12] == 0x3a && SRpnt->sense[13] == 0 ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756#if DEBUG
757 if (debugging) {
758 printk(OSST_DEB_MSG "%s:D: Sleeping in onstream wait medium\n", name);
759 printk(OSST_DEB_MSG "%s:D: Turning off debugging for a while\n", name);
760 debugging = 0;
761 }
762#endif
763 msleep(100);
764
765 memset(cmd, 0, MAX_COMMAND_SIZE);
766 cmd[0] = TEST_UNIT_READY;
767
768 SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1);
769 }
770 *aSRpnt = SRpnt;
771#if DEBUG
772 debugging = dbg;
773#endif
Willem Riede5e6575c2006-02-11 14:46:56 -0500774 if ( STp->buffer->syscall_result && SRpnt->sense[2] != 2 &&
775 SRpnt->sense[12] != 4 && SRpnt->sense[13] == 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776#if DEBUG
777 printk(OSST_DEB_MSG "%s:D: Abnormal exit from onstream wait medium\n", name);
778 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 -0500779 STp->buffer->syscall_result, SRpnt->sense[0], SRpnt->sense[2],
780 SRpnt->sense[12], SRpnt->sense[13]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781#endif
782 return 0;
783 }
784#if DEBUG
785 printk(OSST_DEB_MSG "%s:D: Normal exit from onstream wait medium\n", name);
786#endif
787 return 1;
788}
789
Willem Riede5e6575c2006-02-11 14:46:56 -0500790static int osst_position_tape_and_confirm(struct osst_tape * STp, struct osst_request ** aSRpnt, int frame)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791{
792 int retval;
793
794 osst_wait_ready(STp, aSRpnt, 15 * 60, 0); /* TODO - can this catch a write error? */
795 retval = osst_set_frame_position(STp, aSRpnt, frame, 0);
796 if (retval) return (retval);
797 osst_wait_ready(STp, aSRpnt, 15 * 60, OSST_WAIT_POSITION_COMPLETE);
798 return (osst_get_frame_position(STp, aSRpnt));
799}
800
801/*
802 * Wait for write(s) to complete
803 */
Willem Riede5e6575c2006-02-11 14:46:56 -0500804static int osst_flush_drive_buffer(struct osst_tape * STp, struct osst_request ** aSRpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805{
806 unsigned char cmd[MAX_COMMAND_SIZE];
Willem Riede5e6575c2006-02-11 14:46:56 -0500807 struct osst_request * SRpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 int result = 0;
809 int delay = OSST_WAIT_WRITE_COMPLETE;
810#if DEBUG
811 char * name = tape_name(STp);
812
813 printk(OSST_DEB_MSG "%s:D: Reached onstream flush drive buffer (write filemark)\n", name);
814#endif
815
816 memset(cmd, 0, MAX_COMMAND_SIZE);
817 cmd[0] = WRITE_FILEMARKS;
818 cmd[1] = 1;
819
820 SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1);
821 *aSRpnt = SRpnt;
822 if (!SRpnt) return (-EBUSY);
823 if (STp->buffer->syscall_result) {
Willem Riede5e6575c2006-02-11 14:46:56 -0500824 if ((SRpnt->sense[2] & 0x0f) == 2 && SRpnt->sense[12] == 4) {
825 if (SRpnt->sense[13] == 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 delay = OSST_WAIT_LONG_WRITE_COMPLETE;
827 }
828 } else
829 result = osst_write_error_recovery(STp, aSRpnt, 0);
830 }
831 result |= osst_wait_ready(STp, aSRpnt, 5 * 60, delay);
832 STp->ps[STp->partition].rw = OS_WRITING_COMPLETE;
833
834 return (result);
835}
836
837#define OSST_POLL_PER_SEC 10
Willem Riede5e6575c2006-02-11 14:46:56 -0500838static 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 -0700839{
840 unsigned long startwait = jiffies;
841 char * name = tape_name(STp);
842#if DEBUG
843 char notyetprinted = 1;
844#endif
845 if (minlast >= 0 && STp->ps[STp->partition].rw != ST_READING)
846 printk(KERN_ERR "%s:A: Waiting for frame without having initialized read!\n", name);
847
848 while (time_before (jiffies, startwait + to*HZ))
849 {
850 int result;
851 result = osst_get_frame_position(STp, aSRpnt);
852 if (result == -EIO)
853 if ((result = osst_write_error_recovery(STp, aSRpnt, 0)) == 0)
854 return 0; /* successful recovery leaves drive ready for frame */
855 if (result < 0) break;
856 if (STp->first_frame_position == curr &&
857 ((minlast < 0 &&
858 (signed)STp->last_frame_position > (signed)curr + minlast) ||
859 (minlast >= 0 && STp->cur_frames > minlast)
860 ) && result >= 0)
861 {
862#if DEBUG
Marcelo Feitoza Parisi60c904a2006-03-28 01:56:47 -0800863 if (debugging || time_after_eq(jiffies, startwait + 2*HZ/OSST_POLL_PER_SEC))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 printk (OSST_DEB_MSG
865 "%s:D: Succ wait f fr %i (>%i): %i-%i %i (%i): %3li.%li s\n",
866 name, curr, curr+minlast, STp->first_frame_position,
867 STp->last_frame_position, STp->cur_frames,
868 result, (jiffies-startwait)/HZ,
869 (((jiffies-startwait)%HZ)*10)/HZ);
870#endif
871 return 0;
872 }
873#if DEBUG
Marcelo Feitoza Parisi60c904a2006-03-28 01:56:47 -0800874 if (time_after_eq(jiffies, startwait + 2*HZ/OSST_POLL_PER_SEC) && notyetprinted)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 {
876 printk (OSST_DEB_MSG "%s:D: Wait for frame %i (>%i): %i-%i %i (%i)\n",
877 name, curr, curr+minlast, STp->first_frame_position,
878 STp->last_frame_position, STp->cur_frames, result);
879 notyetprinted--;
880 }
881#endif
882 msleep(1000 / OSST_POLL_PER_SEC);
883 }
884#if DEBUG
885 printk (OSST_DEB_MSG "%s:D: Fail wait f fr %i (>%i): %i-%i %i: %3li.%li s\n",
886 name, curr, curr+minlast, STp->first_frame_position,
887 STp->last_frame_position, STp->cur_frames,
888 (jiffies-startwait)/HZ, (((jiffies-startwait)%HZ)*10)/HZ);
889#endif
890 return -EBUSY;
891}
892
Willem Riede5e6575c2006-02-11 14:46:56 -0500893static int osst_recover_wait_frame(struct osst_tape * STp, struct osst_request ** aSRpnt, int writing)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894{
Willem Riede5e6575c2006-02-11 14:46:56 -0500895 struct osst_request * SRpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 unsigned char cmd[MAX_COMMAND_SIZE];
897 unsigned long startwait = jiffies;
898 int retval = 1;
899 char * name = tape_name(STp);
900
901 if (writing) {
902 char mybuf[24];
903 char * olddata = STp->buffer->b_data;
904 int oldsize = STp->buffer->buffer_size;
905
906 /* write zero fm then read pos - if shows write error, try to recover - if no progress, wait */
907
908 memset(cmd, 0, MAX_COMMAND_SIZE);
909 cmd[0] = WRITE_FILEMARKS;
910 cmd[1] = 1;
911 SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, DMA_NONE, STp->timeout,
912 MAX_RETRIES, 1);
913
914 while (retval && time_before (jiffies, startwait + 5*60*HZ)) {
915
Willem Riede5e6575c2006-02-11 14:46:56 -0500916 if (STp->buffer->syscall_result && (SRpnt->sense[2] & 0x0f) != 2) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917
918 /* some failure - not just not-ready */
919 retval = osst_write_error_recovery(STp, aSRpnt, 0);
920 break;
921 }
Nishanth Aravamudana9a30472005-11-07 01:01:20 -0800922 schedule_timeout_interruptible(HZ / OSST_POLL_PER_SEC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923
924 STp->buffer->b_data = mybuf; STp->buffer->buffer_size = 24;
925 memset(cmd, 0, MAX_COMMAND_SIZE);
926 cmd[0] = READ_POSITION;
927
928 SRpnt = osst_do_scsi(SRpnt, STp, cmd, 20, DMA_FROM_DEVICE, STp->timeout,
929 MAX_RETRIES, 1);
930
931 retval = ( STp->buffer->syscall_result || (STp->buffer)->b_data[15] > 25 );
932 STp->buffer->b_data = olddata; STp->buffer->buffer_size = oldsize;
933 }
934 if (retval)
935 printk(KERN_ERR "%s:E: Device did not succeed to write buffered data\n", name);
936 } else
937 /* TODO - figure out which error conditions can be handled */
938 if (STp->buffer->syscall_result)
939 printk(KERN_WARNING
940 "%s:W: Recover_wait_frame(read) cannot handle %02x:%02x:%02x\n", name,
Willem Riede5e6575c2006-02-11 14:46:56 -0500941 (*aSRpnt)->sense[ 2] & 0x0f,
942 (*aSRpnt)->sense[12],
943 (*aSRpnt)->sense[13]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944
945 return retval;
946}
947
948/*
949 * Read the next OnStream tape frame at the current location
950 */
Willem Riede5e6575c2006-02-11 14:46:56 -0500951static int osst_read_frame(struct osst_tape * STp, struct osst_request ** aSRpnt, int timeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952{
953 unsigned char cmd[MAX_COMMAND_SIZE];
Willem Riede5e6575c2006-02-11 14:46:56 -0500954 struct osst_request * SRpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955 int retval = 0;
956#if DEBUG
957 os_aux_t * aux = STp->buffer->aux;
958 char * name = tape_name(STp);
959#endif
960
961 if (STp->poll)
962 if (osst_wait_frame (STp, aSRpnt, STp->first_frame_position, 0, timeout))
963 retval = osst_recover_wait_frame(STp, aSRpnt, 0);
964
965 memset(cmd, 0, MAX_COMMAND_SIZE);
966 cmd[0] = READ_6;
967 cmd[1] = 1;
968 cmd[4] = 1;
969
970#if DEBUG
971 if (debugging)
972 printk(OSST_DEB_MSG "%s:D: Reading frame from OnStream tape\n", name);
973#endif
974 SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, OS_FRAME_SIZE, DMA_FROM_DEVICE,
975 STp->timeout, MAX_RETRIES, 1);
976 *aSRpnt = SRpnt;
977 if (!SRpnt)
978 return (-EBUSY);
979
980 if ((STp->buffer)->syscall_result) {
981 retval = 1;
982 if (STp->read_error_frame == 0) {
983 STp->read_error_frame = STp->first_frame_position;
984#if DEBUG
985 printk(OSST_DEB_MSG "%s:D: Recording read error at %d\n", name, STp->read_error_frame);
986#endif
987 }
988#if DEBUG
989 if (debugging)
990 printk(OSST_DEB_MSG "%s:D: Sense: %2x %2x %2x %2x %2x %2x %2x %2x\n",
991 name,
Willem Riede5e6575c2006-02-11 14:46:56 -0500992 SRpnt->sense[0], SRpnt->sense[1],
993 SRpnt->sense[2], SRpnt->sense[3],
994 SRpnt->sense[4], SRpnt->sense[5],
995 SRpnt->sense[6], SRpnt->sense[7]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996#endif
997 }
998 else
999 STp->first_frame_position++;
1000#if DEBUG
1001 if (debugging) {
1002 char sig[8]; int i;
1003 for (i=0;i<4;i++)
1004 sig[i] = aux->application_sig[i]<32?'^':aux->application_sig[i];
1005 sig[4] = '\0';
1006 printk(OSST_DEB_MSG
1007 "%s:D: AUX: %s UpdFrCt#%d Wpass#%d %s FrSeq#%d LogBlk#%d Qty=%d Sz=%d\n", name, sig,
1008 ntohl(aux->update_frame_cntr), ntohs(aux->partition.wrt_pass_cntr),
1009 aux->frame_type==1?"EOD":aux->frame_type==2?"MARK":
1010 aux->frame_type==8?"HEADR":aux->frame_type==0x80?"DATA":"FILL",
1011 ntohl(aux->frame_seq_num), ntohl(aux->logical_blk_num),
1012 ntohs(aux->dat.dat_list[0].blk_cnt), ntohl(aux->dat.dat_list[0].blk_sz) );
1013 if (aux->frame_type==2)
1014 printk(OSST_DEB_MSG "%s:D: mark_cnt=%d, last_mark_ppos=%d, last_mark_lbn=%d\n", name,
1015 ntohl(aux->filemark_cnt), ntohl(aux->last_mark_ppos), ntohl(aux->last_mark_lbn));
1016 printk(OSST_DEB_MSG "%s:D: Exit read frame from OnStream tape with code %d\n", name, retval);
1017 }
1018#endif
1019 return (retval);
1020}
1021
Willem Riede5e6575c2006-02-11 14:46:56 -05001022static int osst_initiate_read(struct osst_tape * STp, struct osst_request ** aSRpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023{
1024 struct st_partstat * STps = &(STp->ps[STp->partition]);
Willem Riede5e6575c2006-02-11 14:46:56 -05001025 struct osst_request * SRpnt ;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026 unsigned char cmd[MAX_COMMAND_SIZE];
1027 int retval = 0;
1028 char * name = tape_name(STp);
1029
1030 if (STps->rw != ST_READING) { /* Initialize read operation */
1031 if (STps->rw == ST_WRITING || STp->dirty) {
1032 STp->write_type = OS_WRITE_DATA;
1033 osst_flush_write_buffer(STp, aSRpnt);
1034 osst_flush_drive_buffer(STp, aSRpnt);
1035 }
1036 STps->rw = ST_READING;
1037 STp->frame_in_buffer = 0;
1038
1039 /*
1040 * Issue a read 0 command to get the OnStream drive
1041 * read frames into its buffer.
1042 */
1043 memset(cmd, 0, MAX_COMMAND_SIZE);
1044 cmd[0] = READ_6;
1045 cmd[1] = 1;
1046
1047#if DEBUG
1048 printk(OSST_DEB_MSG "%s:D: Start Read Ahead on OnStream tape\n", name);
1049#endif
1050 SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1);
1051 *aSRpnt = SRpnt;
1052 if ((retval = STp->buffer->syscall_result))
1053 printk(KERN_WARNING "%s:W: Error starting read ahead\n", name);
1054 }
1055
1056 return retval;
1057}
1058
Willem Riede5e6575c2006-02-11 14:46:56 -05001059static int osst_get_logical_frame(struct osst_tape * STp, struct osst_request ** aSRpnt,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060 int frame_seq_number, int quiet)
1061{
1062 struct st_partstat * STps = &(STp->ps[STp->partition]);
1063 char * name = tape_name(STp);
1064 int cnt = 0,
1065 bad = 0,
1066 past = 0,
1067 x,
1068 position;
1069
1070 /*
1071 * If we want just any frame (-1) and there is a frame in the buffer, return it
1072 */
1073 if (frame_seq_number == -1 && STp->frame_in_buffer) {
1074#if DEBUG
1075 printk(OSST_DEB_MSG "%s:D: Frame %d still in buffer\n", name, STp->frame_seq_number);
1076#endif
1077 return (STps->eof);
1078 }
1079 /*
1080 * Search and wait for the next logical tape frame
1081 */
1082 while (1) {
1083 if (cnt++ > 400) {
1084 printk(KERN_ERR "%s:E: Couldn't find logical frame %d, aborting\n",
1085 name, frame_seq_number);
1086 if (STp->read_error_frame) {
1087 osst_set_frame_position(STp, aSRpnt, STp->read_error_frame, 0);
1088#if DEBUG
1089 printk(OSST_DEB_MSG "%s:D: Repositioning tape to bad frame %d\n",
1090 name, STp->read_error_frame);
1091#endif
1092 STp->read_error_frame = 0;
1093 STp->abort_count++;
1094 }
1095 return (-EIO);
1096 }
1097#if DEBUG
1098 if (debugging)
1099 printk(OSST_DEB_MSG "%s:D: Looking for frame %d, attempt %d\n",
1100 name, frame_seq_number, cnt);
1101#endif
1102 if ( osst_initiate_read(STp, aSRpnt)
1103 || ( (!STp->frame_in_buffer) && osst_read_frame(STp, aSRpnt, 30) ) ) {
1104 if (STp->raw)
1105 return (-EIO);
1106 position = osst_get_frame_position(STp, aSRpnt);
1107 if (position >= 0xbae && position < 0xbb8)
1108 position = 0xbb8;
1109 else if (position > STp->eod_frame_ppos || ++bad == 10) {
1110 position = STp->read_error_frame - 1;
1111 bad = 0;
1112 }
1113 else {
1114 position += 29;
1115 cnt += 19;
1116 }
1117#if DEBUG
1118 printk(OSST_DEB_MSG "%s:D: Bad frame detected, positioning tape to block %d\n",
1119 name, position);
1120#endif
1121 osst_set_frame_position(STp, aSRpnt, position, 0);
1122 continue;
1123 }
1124 if (osst_verify_frame(STp, frame_seq_number, quiet))
1125 break;
1126 if (osst_verify_frame(STp, -1, quiet)) {
1127 x = ntohl(STp->buffer->aux->frame_seq_num);
1128 if (STp->fast_open) {
1129 printk(KERN_WARNING
1130 "%s:W: Found logical frame %d instead of %d after fast open\n",
1131 name, x, frame_seq_number);
1132 STp->header_ok = 0;
1133 STp->read_error_frame = 0;
1134 return (-EIO);
1135 }
1136 if (x > frame_seq_number) {
1137 if (++past > 3) {
1138 /* positioning backwards did not bring us to the desired frame */
1139 position = STp->read_error_frame - 1;
1140 }
1141 else {
1142 position = osst_get_frame_position(STp, aSRpnt)
1143 + frame_seq_number - x - 1;
1144
1145 if (STp->first_frame_position >= 3000 && position < 3000)
1146 position -= 10;
1147 }
1148#if DEBUG
1149 printk(OSST_DEB_MSG
1150 "%s:D: Found logical frame %d while looking for %d: back up %d\n",
1151 name, x, frame_seq_number,
1152 STp->first_frame_position - position);
1153#endif
1154 osst_set_frame_position(STp, aSRpnt, position, 0);
1155 cnt += 10;
1156 }
1157 else
1158 past = 0;
1159 }
1160 if (osst_get_frame_position(STp, aSRpnt) == 0xbaf) {
1161#if DEBUG
1162 printk(OSST_DEB_MSG "%s:D: Skipping config partition\n", name);
1163#endif
1164 osst_set_frame_position(STp, aSRpnt, 0xbb8, 0);
1165 cnt--;
1166 }
1167 STp->frame_in_buffer = 0;
1168 }
1169 if (cnt > 1) {
1170 STp->recover_count++;
1171 STp->recover_erreg++;
1172 printk(KERN_WARNING "%s:I: Don't worry, Read error at position %d recovered\n",
1173 name, STp->read_error_frame);
1174 }
1175 STp->read_count++;
1176
1177#if DEBUG
1178 if (debugging || STps->eof)
1179 printk(OSST_DEB_MSG
1180 "%s:D: Exit get logical frame (%d=>%d) from OnStream tape with code %d\n",
1181 name, frame_seq_number, STp->frame_seq_number, STps->eof);
1182#endif
1183 STp->fast_open = 0;
1184 STp->read_error_frame = 0;
1185 return (STps->eof);
1186}
1187
Willem Riede5e6575c2006-02-11 14:46:56 -05001188static int osst_seek_logical_blk(struct osst_tape * STp, struct osst_request ** aSRpnt, int logical_blk_num)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189{
1190 struct st_partstat * STps = &(STp->ps[STp->partition]);
1191 char * name = tape_name(STp);
1192 int retries = 0;
1193 int frame_seq_estimate, ppos_estimate, move;
1194
1195 if (logical_blk_num < 0) logical_blk_num = 0;
1196#if DEBUG
1197 printk(OSST_DEB_MSG "%s:D: Seeking logical block %d (now at %d, size %d%c)\n",
1198 name, logical_blk_num, STp->logical_blk_num,
1199 STp->block_size<1024?STp->block_size:STp->block_size/1024,
1200 STp->block_size<1024?'b':'k');
1201#endif
1202 /* Do we know where we are? */
1203 if (STps->drv_block >= 0) {
1204 move = logical_blk_num - STp->logical_blk_num;
1205 if (move < 0) move -= (OS_DATA_SIZE / STp->block_size) - 1;
1206 move /= (OS_DATA_SIZE / STp->block_size);
1207 frame_seq_estimate = STp->frame_seq_number + move;
1208 } else
1209 frame_seq_estimate = logical_blk_num * STp->block_size / OS_DATA_SIZE;
1210
1211 if (frame_seq_estimate < 2980) ppos_estimate = frame_seq_estimate + 10;
1212 else ppos_estimate = frame_seq_estimate + 20;
1213 while (++retries < 10) {
1214 if (ppos_estimate > STp->eod_frame_ppos-2) {
1215 frame_seq_estimate += STp->eod_frame_ppos - 2 - ppos_estimate;
1216 ppos_estimate = STp->eod_frame_ppos - 2;
1217 }
1218 if (frame_seq_estimate < 0) {
1219 frame_seq_estimate = 0;
1220 ppos_estimate = 10;
1221 }
1222 osst_set_frame_position(STp, aSRpnt, ppos_estimate, 0);
1223 if (osst_get_logical_frame(STp, aSRpnt, frame_seq_estimate, 1) >= 0) {
1224 /* we've located the estimated frame, now does it have our block? */
1225 if (logical_blk_num < STp->logical_blk_num ||
1226 logical_blk_num >= STp->logical_blk_num + ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt)) {
1227 if (STps->eof == ST_FM_HIT)
1228 move = logical_blk_num < STp->logical_blk_num? -2 : 1;
1229 else {
1230 move = logical_blk_num - STp->logical_blk_num;
1231 if (move < 0) move -= (OS_DATA_SIZE / STp->block_size) - 1;
1232 move /= (OS_DATA_SIZE / STp->block_size);
1233 }
1234 if (!move) move = logical_blk_num > STp->logical_blk_num ? 1 : -1;
1235#if DEBUG
1236 printk(OSST_DEB_MSG
1237 "%s:D: Seek retry %d at ppos %d fsq %d (est %d) lbn %d (need %d) move %d\n",
1238 name, retries, ppos_estimate, STp->frame_seq_number, frame_seq_estimate,
1239 STp->logical_blk_num, logical_blk_num, move);
1240#endif
1241 frame_seq_estimate += move;
1242 ppos_estimate += move;
1243 continue;
1244 } else {
1245 STp->buffer->read_pointer = (logical_blk_num - STp->logical_blk_num) * STp->block_size;
1246 STp->buffer->buffer_bytes -= STp->buffer->read_pointer;
1247 STp->logical_blk_num = logical_blk_num;
1248#if DEBUG
1249 printk(OSST_DEB_MSG
1250 "%s:D: Seek success at ppos %d fsq %d in_buf %d, bytes %d, ptr %d*%d\n",
1251 name, ppos_estimate, STp->frame_seq_number, STp->frame_in_buffer,
1252 STp->buffer->buffer_bytes, STp->buffer->read_pointer / STp->block_size,
1253 STp->block_size);
1254#endif
1255 STps->drv_file = ntohl(STp->buffer->aux->filemark_cnt);
1256 if (STps->eof == ST_FM_HIT) {
1257 STps->drv_file++;
1258 STps->drv_block = 0;
1259 } else {
1260 STps->drv_block = ntohl(STp->buffer->aux->last_mark_lbn)?
1261 STp->logical_blk_num -
1262 (STps->drv_file ? ntohl(STp->buffer->aux->last_mark_lbn) + 1 : 0):
1263 -1;
1264 }
1265 STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD:ST_NOEOF;
1266 return 0;
1267 }
1268 }
1269 if (osst_get_logical_frame(STp, aSRpnt, -1, 1) < 0)
1270 goto error;
1271 /* we are not yet at the estimated frame, adjust our estimate of its physical position */
1272#if DEBUG
1273 printk(OSST_DEB_MSG "%s:D: Seek retry %d at ppos %d fsq %d (est %d) lbn %d (need %d)\n",
1274 name, retries, ppos_estimate, STp->frame_seq_number, frame_seq_estimate,
1275 STp->logical_blk_num, logical_blk_num);
1276#endif
1277 if (frame_seq_estimate != STp->frame_seq_number)
1278 ppos_estimate += frame_seq_estimate - STp->frame_seq_number;
1279 else
1280 break;
1281 }
1282error:
1283 printk(KERN_ERR "%s:E: Couldn't seek to logical block %d (at %d), %d retries\n",
1284 name, logical_blk_num, STp->logical_blk_num, retries);
1285 return (-EIO);
1286}
1287
1288/* The values below are based on the OnStream frame payload size of 32K == 2**15,
1289 * that is, OSST_FRAME_SHIFT + OSST_SECTOR_SHIFT must be 15. With a minimum block
1290 * size of 512 bytes, we need to be able to resolve 32K/512 == 64 == 2**6 positions
1291 * inside each frame. Finaly, OSST_SECTOR_MASK == 2**OSST_FRAME_SHIFT - 1.
1292 */
1293#define OSST_FRAME_SHIFT 6
1294#define OSST_SECTOR_SHIFT 9
1295#define OSST_SECTOR_MASK 0x03F
1296
Willem Riede5e6575c2006-02-11 14:46:56 -05001297static int osst_get_sector(struct osst_tape * STp, struct osst_request ** aSRpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298{
1299 int sector;
1300#if DEBUG
1301 char * name = tape_name(STp);
1302
1303 printk(OSST_DEB_MSG
1304 "%s:D: Positioned at ppos %d, frame %d, lbn %d, file %d, blk %d, %cptr %d, eof %d\n",
1305 name, STp->first_frame_position, STp->frame_seq_number, STp->logical_blk_num,
1306 STp->ps[STp->partition].drv_file, STp->ps[STp->partition].drv_block,
1307 STp->ps[STp->partition].rw == ST_WRITING?'w':'r',
1308 STp->ps[STp->partition].rw == ST_WRITING?STp->buffer->buffer_bytes:
1309 STp->buffer->read_pointer, STp->ps[STp->partition].eof);
1310#endif
1311 /* do we know where we are inside a file? */
1312 if (STp->ps[STp->partition].drv_block >= 0) {
1313 sector = (STp->frame_in_buffer ? STp->first_frame_position-1 :
1314 STp->first_frame_position) << OSST_FRAME_SHIFT;
1315 if (STp->ps[STp->partition].rw == ST_WRITING)
1316 sector |= (STp->buffer->buffer_bytes >> OSST_SECTOR_SHIFT) & OSST_SECTOR_MASK;
1317 else
1318 sector |= (STp->buffer->read_pointer >> OSST_SECTOR_SHIFT) & OSST_SECTOR_MASK;
1319 } else {
1320 sector = osst_get_frame_position(STp, aSRpnt);
1321 if (sector > 0)
1322 sector <<= OSST_FRAME_SHIFT;
1323 }
1324 return sector;
1325}
1326
Willem Riede5e6575c2006-02-11 14:46:56 -05001327static int osst_seek_sector(struct osst_tape * STp, struct osst_request ** aSRpnt, int sector)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328{
1329 struct st_partstat * STps = &(STp->ps[STp->partition]);
1330 int frame = sector >> OSST_FRAME_SHIFT,
1331 offset = (sector & OSST_SECTOR_MASK) << OSST_SECTOR_SHIFT,
1332 r;
1333#if DEBUG
1334 char * name = tape_name(STp);
1335
1336 printk(OSST_DEB_MSG "%s:D: Seeking sector %d in frame %d at offset %d\n",
1337 name, sector, frame, offset);
1338#endif
1339 if (frame < 0 || frame >= STp->capacity) return (-ENXIO);
1340
1341 if (frame <= STp->first_data_ppos) {
1342 STp->frame_seq_number = STp->logical_blk_num = STps->drv_file = STps->drv_block = 0;
1343 return (osst_set_frame_position(STp, aSRpnt, frame, 0));
1344 }
1345 r = osst_set_frame_position(STp, aSRpnt, offset?frame:frame-1, 0);
1346 if (r < 0) return r;
1347
1348 r = osst_get_logical_frame(STp, aSRpnt, -1, 1);
1349 if (r < 0) return r;
1350
1351 if (osst_get_frame_position(STp, aSRpnt) != (offset?frame+1:frame)) return (-EIO);
1352
1353 if (offset) {
1354 STp->logical_blk_num += offset / STp->block_size;
1355 STp->buffer->read_pointer = offset;
1356 STp->buffer->buffer_bytes -= offset;
1357 } else {
1358 STp->frame_seq_number++;
1359 STp->frame_in_buffer = 0;
1360 STp->logical_blk_num += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
1361 STp->buffer->buffer_bytes = STp->buffer->read_pointer = 0;
1362 }
1363 STps->drv_file = ntohl(STp->buffer->aux->filemark_cnt);
1364 if (STps->eof == ST_FM_HIT) {
1365 STps->drv_file++;
1366 STps->drv_block = 0;
1367 } else {
1368 STps->drv_block = ntohl(STp->buffer->aux->last_mark_lbn)?
1369 STp->logical_blk_num -
1370 (STps->drv_file ? ntohl(STp->buffer->aux->last_mark_lbn) + 1 : 0):
1371 -1;
1372 }
1373 STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD:ST_NOEOF;
1374#if DEBUG
1375 printk(OSST_DEB_MSG
1376 "%s:D: Now positioned at ppos %d, frame %d, lbn %d, file %d, blk %d, rptr %d, eof %d\n",
1377 name, STp->first_frame_position, STp->frame_seq_number, STp->logical_blk_num,
1378 STps->drv_file, STps->drv_block, STp->buffer->read_pointer, STps->eof);
1379#endif
1380 return 0;
1381}
1382
1383/*
1384 * Read back the drive's internal buffer contents, as a part
1385 * of the write error recovery mechanism for old OnStream
1386 * firmware revisions.
1387 * Precondition for this function to work: all frames in the
1388 * drive's buffer must be of one type (DATA, MARK or EOD)!
1389 */
Willem Riede5e6575c2006-02-11 14:46:56 -05001390static int osst_read_back_buffer_and_rewrite(struct osst_tape * STp, struct osst_request ** aSRpnt,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391 unsigned int frame, unsigned int skip, int pending)
1392{
Willem Riede5e6575c2006-02-11 14:46:56 -05001393 struct osst_request * SRpnt = * aSRpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394 unsigned char * buffer, * p;
1395 unsigned char cmd[MAX_COMMAND_SIZE];
1396 int flag, new_frame, i;
1397 int nframes = STp->cur_frames;
1398 int blks_per_frame = ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
1399 int frame_seq_number = ntohl(STp->buffer->aux->frame_seq_num)
1400 - (nframes + pending - 1);
1401 int logical_blk_num = ntohl(STp->buffer->aux->logical_blk_num)
1402 - (nframes + pending - 1) * blks_per_frame;
1403 char * name = tape_name(STp);
1404 unsigned long startwait = jiffies;
1405#if DEBUG
1406 int dbg = debugging;
1407#endif
1408
1409 if ((buffer = (unsigned char *)vmalloc((nframes + 1) * OS_DATA_SIZE)) == NULL)
1410 return (-EIO);
1411
1412 printk(KERN_INFO "%s:I: Reading back %d frames from drive buffer%s\n",
1413 name, nframes, pending?" and one that was pending":"");
1414
1415 osst_copy_from_buffer(STp->buffer, (p = &buffer[nframes * OS_DATA_SIZE]));
1416#if DEBUG
1417 if (pending && debugging)
1418 printk(OSST_DEB_MSG "%s:D: Pending frame %d (lblk %d), data %02x %02x %02x %02x\n",
1419 name, frame_seq_number + nframes,
1420 logical_blk_num + nframes * blks_per_frame,
1421 p[0], p[1], p[2], p[3]);
1422#endif
1423 for (i = 0, p = buffer; i < nframes; i++, p += OS_DATA_SIZE) {
1424
1425 memset(cmd, 0, MAX_COMMAND_SIZE);
1426 cmd[0] = 0x3C; /* Buffer Read */
1427 cmd[1] = 6; /* Retrieve Faulty Block */
1428 cmd[7] = 32768 >> 8;
1429 cmd[8] = 32768 & 0xff;
1430
1431 SRpnt = osst_do_scsi(SRpnt, STp, cmd, OS_FRAME_SIZE, DMA_FROM_DEVICE,
1432 STp->timeout, MAX_RETRIES, 1);
1433
1434 if ((STp->buffer)->syscall_result || !SRpnt) {
1435 printk(KERN_ERR "%s:E: Failed to read frame back from OnStream buffer\n", name);
Jesper Juhlf91012102005-09-10 00:26:54 -07001436 vfree(buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437 *aSRpnt = SRpnt;
1438 return (-EIO);
1439 }
1440 osst_copy_from_buffer(STp->buffer, p);
1441#if DEBUG
1442 if (debugging)
1443 printk(OSST_DEB_MSG "%s:D: Read back logical frame %d, data %02x %02x %02x %02x\n",
1444 name, frame_seq_number + i, p[0], p[1], p[2], p[3]);
1445#endif
1446 }
1447 *aSRpnt = SRpnt;
1448 osst_get_frame_position(STp, aSRpnt);
1449
1450#if DEBUG
1451 printk(OSST_DEB_MSG "%s:D: Frames left in buffer: %d\n", name, STp->cur_frames);
1452#endif
1453 /* Write synchronously so we can be sure we're OK again and don't have to recover recursively */
1454 /* In the header we don't actually re-write the frames that fail, just the ones after them */
1455
1456 for (flag=1, new_frame=frame, p=buffer, i=0; i < nframes + pending; ) {
1457
1458 if (flag) {
1459 if (STp->write_type == OS_WRITE_HEADER) {
1460 i += skip;
1461 p += skip * OS_DATA_SIZE;
1462 }
1463 else if (new_frame < 2990 && new_frame+skip+nframes+pending >= 2990)
1464 new_frame = 3000-i;
1465 else
1466 new_frame += skip;
1467#if DEBUG
1468 printk(OSST_DEB_MSG "%s:D: Position to frame %d, write fseq %d\n",
1469 name, new_frame+i, frame_seq_number+i);
1470#endif
1471 osst_set_frame_position(STp, aSRpnt, new_frame + i, 0);
1472 osst_wait_ready(STp, aSRpnt, 60, OSST_WAIT_POSITION_COMPLETE);
1473 osst_get_frame_position(STp, aSRpnt);
1474 SRpnt = * aSRpnt;
1475
1476 if (new_frame > frame + 1000) {
1477 printk(KERN_ERR "%s:E: Failed to find writable tape media\n", name);
Jesper Juhlf91012102005-09-10 00:26:54 -07001478 vfree(buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479 return (-EIO);
1480 }
1481 if ( i >= nframes + pending ) break;
1482 flag = 0;
1483 }
1484 osst_copy_to_buffer(STp->buffer, p);
1485 /*
1486 * IMPORTANT: for error recovery to work, _never_ queue frames with mixed frame type!
1487 */
1488 osst_init_aux(STp, STp->buffer->aux->frame_type, frame_seq_number+i,
1489 logical_blk_num + i*blks_per_frame,
1490 ntohl(STp->buffer->aux->dat.dat_list[0].blk_sz), blks_per_frame);
1491 memset(cmd, 0, MAX_COMMAND_SIZE);
1492 cmd[0] = WRITE_6;
1493 cmd[1] = 1;
1494 cmd[4] = 1;
1495
1496#if DEBUG
1497 if (debugging)
1498 printk(OSST_DEB_MSG
1499 "%s:D: About to write frame %d, seq %d, lbn %d, data %02x %02x %02x %02x\n",
1500 name, new_frame+i, frame_seq_number+i, logical_blk_num + i*blks_per_frame,
1501 p[0], p[1], p[2], p[3]);
1502#endif
1503 SRpnt = osst_do_scsi(SRpnt, STp, cmd, OS_FRAME_SIZE, DMA_TO_DEVICE,
1504 STp->timeout, MAX_RETRIES, 1);
1505
1506 if (STp->buffer->syscall_result)
1507 flag = 1;
1508 else {
1509 p += OS_DATA_SIZE; i++;
1510
1511 /* if we just sent the last frame, wait till all successfully written */
1512 if ( i == nframes + pending ) {
1513#if DEBUG
1514 printk(OSST_DEB_MSG "%s:D: Check re-write successful\n", name);
1515#endif
1516 memset(cmd, 0, MAX_COMMAND_SIZE);
1517 cmd[0] = WRITE_FILEMARKS;
1518 cmd[1] = 1;
1519 SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE,
1520 STp->timeout, MAX_RETRIES, 1);
1521#if DEBUG
1522 if (debugging) {
1523 printk(OSST_DEB_MSG "%s:D: Sleeping in re-write wait ready\n", name);
1524 printk(OSST_DEB_MSG "%s:D: Turning off debugging for a while\n", name);
1525 debugging = 0;
1526 }
1527#endif
1528 flag = STp->buffer->syscall_result;
1529 while ( !flag && time_before(jiffies, startwait + 60*HZ) ) {
1530
1531 memset(cmd, 0, MAX_COMMAND_SIZE);
1532 cmd[0] = TEST_UNIT_READY;
1533
1534 SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE, STp->timeout,
1535 MAX_RETRIES, 1);
1536
Willem Riede5e6575c2006-02-11 14:46:56 -05001537 if (SRpnt->sense[2] == 2 && SRpnt->sense[12] == 4 &&
1538 (SRpnt->sense[13] == 1 || SRpnt->sense[13] == 8)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539 /* in the process of becoming ready */
1540 msleep(100);
1541 continue;
1542 }
1543 if (STp->buffer->syscall_result)
1544 flag = 1;
1545 break;
1546 }
1547#if DEBUG
1548 debugging = dbg;
1549 printk(OSST_DEB_MSG "%s:D: Wait re-write finished\n", name);
1550#endif
1551 }
1552 }
1553 *aSRpnt = SRpnt;
1554 if (flag) {
Willem Riede5e6575c2006-02-11 14:46:56 -05001555 if ((SRpnt->sense[ 2] & 0x0f) == 13 &&
1556 SRpnt->sense[12] == 0 &&
1557 SRpnt->sense[13] == 2) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558 printk(KERN_ERR "%s:E: Volume overflow in write error recovery\n", name);
Jesper Juhlf91012102005-09-10 00:26:54 -07001559 vfree(buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001560 return (-EIO); /* hit end of tape = fail */
1561 }
Willem Riede5e6575c2006-02-11 14:46:56 -05001562 i = ((SRpnt->sense[3] << 24) |
1563 (SRpnt->sense[4] << 16) |
1564 (SRpnt->sense[5] << 8) |
1565 SRpnt->sense[6] ) - new_frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566 p = &buffer[i * OS_DATA_SIZE];
1567#if DEBUG
1568 printk(OSST_DEB_MSG "%s:D: Additional write error at %d\n", name, new_frame+i);
1569#endif
1570 osst_get_frame_position(STp, aSRpnt);
1571#if DEBUG
1572 printk(OSST_DEB_MSG "%s:D: reported frame positions: host = %d, tape = %d, buffer = %d\n",
1573 name, STp->first_frame_position, STp->last_frame_position, STp->cur_frames);
1574#endif
1575 }
1576 }
1577 if (flag) {
1578 /* error recovery did not successfully complete */
1579 printk(KERN_ERR "%s:D: Write error recovery failed in %s\n", name,
1580 STp->write_type == OS_WRITE_HEADER?"header":"body");
1581 }
1582 if (!pending)
1583 osst_copy_to_buffer(STp->buffer, p); /* so buffer content == at entry in all cases */
Jesper Juhlf91012102005-09-10 00:26:54 -07001584 vfree(buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001585 return 0;
1586}
1587
Willem Riede5e6575c2006-02-11 14:46:56 -05001588static int osst_reposition_and_retry(struct osst_tape * STp, struct osst_request ** aSRpnt,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589 unsigned int frame, unsigned int skip, int pending)
1590{
1591 unsigned char cmd[MAX_COMMAND_SIZE];
Willem Riede5e6575c2006-02-11 14:46:56 -05001592 struct osst_request * SRpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001593 char * name = tape_name(STp);
1594 int expected = 0;
1595 int attempts = 1000 / skip;
1596 int flag = 1;
1597 unsigned long startwait = jiffies;
1598#if DEBUG
1599 int dbg = debugging;
1600#endif
1601
1602 while (attempts && time_before(jiffies, startwait + 60*HZ)) {
1603 if (flag) {
1604#if DEBUG
1605 debugging = dbg;
1606#endif
1607 if (frame < 2990 && frame+skip+STp->cur_frames+pending >= 2990)
1608 frame = 3000-skip;
1609 expected = frame+skip+STp->cur_frames+pending;
1610#if DEBUG
1611 printk(OSST_DEB_MSG "%s:D: Position to fppos %d, re-write from fseq %d\n",
1612 name, frame+skip, STp->frame_seq_number-STp->cur_frames-pending);
1613#endif
1614 osst_set_frame_position(STp, aSRpnt, frame + skip, 1);
1615 flag = 0;
1616 attempts--;
Nishanth Aravamudana9a30472005-11-07 01:01:20 -08001617 schedule_timeout_interruptible(msecs_to_jiffies(100));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618 }
1619 if (osst_get_frame_position(STp, aSRpnt) < 0) { /* additional write error */
1620#if DEBUG
1621 printk(OSST_DEB_MSG "%s:D: Addl error, host %d, tape %d, buffer %d\n",
1622 name, STp->first_frame_position,
1623 STp->last_frame_position, STp->cur_frames);
1624#endif
1625 frame = STp->last_frame_position;
1626 flag = 1;
1627 continue;
1628 }
1629 if (pending && STp->cur_frames < 50) {
1630
1631 memset(cmd, 0, MAX_COMMAND_SIZE);
1632 cmd[0] = WRITE_6;
1633 cmd[1] = 1;
1634 cmd[4] = 1;
1635#if DEBUG
1636 printk(OSST_DEB_MSG "%s:D: About to write pending fseq %d at fppos %d\n",
1637 name, STp->frame_seq_number-1, STp->first_frame_position);
1638#endif
1639 SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, OS_FRAME_SIZE, DMA_TO_DEVICE,
1640 STp->timeout, MAX_RETRIES, 1);
1641 *aSRpnt = SRpnt;
1642
1643 if (STp->buffer->syscall_result) { /* additional write error */
Willem Riede5e6575c2006-02-11 14:46:56 -05001644 if ((SRpnt->sense[ 2] & 0x0f) == 13 &&
1645 SRpnt->sense[12] == 0 &&
1646 SRpnt->sense[13] == 2) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647 printk(KERN_ERR
1648 "%s:E: Volume overflow in write error recovery\n",
1649 name);
1650 break; /* hit end of tape = fail */
1651 }
1652 flag = 1;
1653 }
1654 else
1655 pending = 0;
1656
1657 continue;
1658 }
1659 if (STp->cur_frames == 0) {
1660#if DEBUG
1661 debugging = dbg;
1662 printk(OSST_DEB_MSG "%s:D: Wait re-write finished\n", name);
1663#endif
1664 if (STp->first_frame_position != expected) {
1665 printk(KERN_ERR "%s:A: Actual position %d - expected %d\n",
1666 name, STp->first_frame_position, expected);
1667 return (-EIO);
1668 }
1669 return 0;
1670 }
1671#if DEBUG
1672 if (debugging) {
1673 printk(OSST_DEB_MSG "%s:D: Sleeping in re-write wait ready\n", name);
1674 printk(OSST_DEB_MSG "%s:D: Turning off debugging for a while\n", name);
1675 debugging = 0;
1676 }
1677#endif
Nishanth Aravamudana9a30472005-11-07 01:01:20 -08001678 schedule_timeout_interruptible(msecs_to_jiffies(100));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679 }
1680 printk(KERN_ERR "%s:E: Failed to find valid tape media\n", name);
1681#if DEBUG
1682 debugging = dbg;
1683#endif
1684 return (-EIO);
1685}
1686
1687/*
1688 * Error recovery algorithm for the OnStream tape.
1689 */
1690
Willem Riede5e6575c2006-02-11 14:46:56 -05001691static int osst_write_error_recovery(struct osst_tape * STp, struct osst_request ** aSRpnt, int pending)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692{
Willem Riede5e6575c2006-02-11 14:46:56 -05001693 struct osst_request * SRpnt = * aSRpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694 struct st_partstat * STps = & STp->ps[STp->partition];
1695 char * name = tape_name(STp);
1696 int retval = 0;
1697 int rw_state;
1698 unsigned int frame, skip;
1699
1700 rw_state = STps->rw;
1701
Willem Riede5e6575c2006-02-11 14:46:56 -05001702 if ((SRpnt->sense[ 2] & 0x0f) != 3
1703 || SRpnt->sense[12] != 12
1704 || SRpnt->sense[13] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705#if DEBUG
1706 printk(OSST_DEB_MSG "%s:D: Write error recovery cannot handle %02x:%02x:%02x\n", name,
Willem Riede5e6575c2006-02-11 14:46:56 -05001707 SRpnt->sense[2], SRpnt->sense[12], SRpnt->sense[13]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708#endif
1709 return (-EIO);
1710 }
Willem Riede5e6575c2006-02-11 14:46:56 -05001711 frame = (SRpnt->sense[3] << 24) |
1712 (SRpnt->sense[4] << 16) |
1713 (SRpnt->sense[5] << 8) |
1714 SRpnt->sense[6];
1715 skip = SRpnt->sense[9];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716
1717#if DEBUG
1718 printk(OSST_DEB_MSG "%s:D: Detected physical bad frame at %u, advised to skip %d\n", name, frame, skip);
1719#endif
1720 osst_get_frame_position(STp, aSRpnt);
1721#if DEBUG
1722 printk(OSST_DEB_MSG "%s:D: reported frame positions: host = %d, tape = %d\n",
1723 name, STp->first_frame_position, STp->last_frame_position);
1724#endif
1725 switch (STp->write_type) {
1726 case OS_WRITE_DATA:
1727 case OS_WRITE_EOD:
1728 case OS_WRITE_NEW_MARK:
1729 printk(KERN_WARNING
1730 "%s:I: Relocating %d buffered logical frames from position %u to %u\n",
1731 name, STp->cur_frames, frame, (frame + skip > 3000 && frame < 3000)?3000:frame + skip);
1732 if (STp->os_fw_rev >= 10600)
1733 retval = osst_reposition_and_retry(STp, aSRpnt, frame, skip, pending);
1734 else
1735 retval = osst_read_back_buffer_and_rewrite(STp, aSRpnt, frame, skip, pending);
1736 printk(KERN_WARNING "%s:%s: %sWrite error%srecovered\n", name,
1737 retval?"E" :"I",
1738 retval?"" :"Don't worry, ",
1739 retval?" not ":" ");
1740 break;
1741 case OS_WRITE_LAST_MARK:
1742 printk(KERN_ERR "%s:E: Bad frame in update last marker, fatal\n", name);
1743 osst_set_frame_position(STp, aSRpnt, frame + STp->cur_frames + pending, 0);
1744 retval = -EIO;
1745 break;
1746 case OS_WRITE_HEADER:
1747 printk(KERN_WARNING "%s:I: Bad frame in header partition, skipped\n", name);
1748 retval = osst_read_back_buffer_and_rewrite(STp, aSRpnt, frame, 1, pending);
1749 break;
1750 default:
1751 printk(KERN_INFO "%s:I: Bad frame in filler, ignored\n", name);
1752 osst_set_frame_position(STp, aSRpnt, frame + STp->cur_frames + pending, 0);
1753 }
1754 osst_get_frame_position(STp, aSRpnt);
1755#if DEBUG
1756 printk(OSST_DEB_MSG "%s:D: Positioning complete, cur_frames %d, pos %d, tape pos %d\n",
1757 name, STp->cur_frames, STp->first_frame_position, STp->last_frame_position);
1758 printk(OSST_DEB_MSG "%s:D: next logical frame to write: %d\n", name, STp->logical_blk_num);
1759#endif
1760 if (retval == 0) {
1761 STp->recover_count++;
1762 STp->recover_erreg++;
1763 } else
1764 STp->abort_count++;
1765
1766 STps->rw = rw_state;
1767 return retval;
1768}
1769
Willem Riede5e6575c2006-02-11 14:46:56 -05001770static int osst_space_over_filemarks_backward(struct osst_tape * STp, struct osst_request ** aSRpnt,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771 int mt_op, int mt_count)
1772{
1773 char * name = tape_name(STp);
1774 int cnt;
1775 int last_mark_ppos = -1;
1776
1777#if DEBUG
1778 printk(OSST_DEB_MSG "%s:D: Reached space_over_filemarks_backwards %d %d\n", name, mt_op, mt_count);
1779#endif
1780 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
1781#if DEBUG
1782 printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks_bwd\n", name);
1783#endif
1784 return -EIO;
1785 }
1786 if (STp->linux_media_version >= 4) {
1787 /*
1788 * direct lookup in header filemark list
1789 */
1790 cnt = ntohl(STp->buffer->aux->filemark_cnt);
1791 if (STp->header_ok &&
1792 STp->header_cache != NULL &&
1793 (cnt - mt_count) >= 0 &&
1794 (cnt - mt_count) < OS_FM_TAB_MAX &&
1795 (cnt - mt_count) < STp->filemark_cnt &&
1796 STp->header_cache->dat_fm_tab.fm_tab_ent[cnt-1] == STp->buffer->aux->last_mark_ppos)
1797
1798 last_mark_ppos = ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[cnt - mt_count]);
1799#if DEBUG
1800 if (STp->header_cache == NULL || (cnt - mt_count) < 0 || (cnt - mt_count) >= OS_FM_TAB_MAX)
1801 printk(OSST_DEB_MSG "%s:D: Filemark lookup fail due to %s\n", name,
1802 STp->header_cache == NULL?"lack of header cache":"count out of range");
1803 else
1804 printk(OSST_DEB_MSG "%s:D: Filemark lookup: prev mark %d (%s), skip %d to %d\n",
1805 name, cnt,
1806 ((cnt == -1 && ntohl(STp->buffer->aux->last_mark_ppos) == -1) ||
1807 (STp->header_cache->dat_fm_tab.fm_tab_ent[cnt-1] ==
1808 STp->buffer->aux->last_mark_ppos))?"match":"error",
1809 mt_count, last_mark_ppos);
1810#endif
1811 if (last_mark_ppos > 10 && last_mark_ppos < STp->eod_frame_ppos) {
1812 osst_position_tape_and_confirm(STp, aSRpnt, last_mark_ppos);
1813 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
1814#if DEBUG
1815 printk(OSST_DEB_MSG
1816 "%s:D: Couldn't get logical blk num in space_filemarks\n", name);
1817#endif
1818 return (-EIO);
1819 }
1820 if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
1821 printk(KERN_WARNING "%s:W: Expected to find marker at ppos %d, not found\n",
1822 name, last_mark_ppos);
1823 return (-EIO);
1824 }
1825 goto found;
1826 }
1827#if DEBUG
1828 printk(OSST_DEB_MSG "%s:D: Reverting to scan filemark backwards\n", name);
1829#endif
1830 }
1831 cnt = 0;
1832 while (cnt != mt_count) {
1833 last_mark_ppos = ntohl(STp->buffer->aux->last_mark_ppos);
1834 if (last_mark_ppos == -1)
1835 return (-EIO);
1836#if DEBUG
1837 printk(OSST_DEB_MSG "%s:D: Positioning to last mark at %d\n", name, last_mark_ppos);
1838#endif
1839 osst_position_tape_and_confirm(STp, aSRpnt, last_mark_ppos);
1840 cnt++;
1841 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
1842#if DEBUG
1843 printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks\n", name);
1844#endif
1845 return (-EIO);
1846 }
1847 if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
1848 printk(KERN_WARNING "%s:W: Expected to find marker at ppos %d, not found\n",
1849 name, last_mark_ppos);
1850 return (-EIO);
1851 }
1852 }
1853found:
1854 if (mt_op == MTBSFM) {
1855 STp->frame_seq_number++;
1856 STp->frame_in_buffer = 0;
1857 STp->buffer->buffer_bytes = 0;
1858 STp->buffer->read_pointer = 0;
1859 STp->logical_blk_num += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
1860 }
1861 return 0;
1862}
1863
1864/*
1865 * ADRL 1.1 compatible "slow" space filemarks fwd version
1866 *
1867 * Just scans for the filemark sequentially.
1868 */
Willem Riede5e6575c2006-02-11 14:46:56 -05001869static int osst_space_over_filemarks_forward_slow(struct osst_tape * STp, struct osst_request ** aSRpnt,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870 int mt_op, int mt_count)
1871{
1872 int cnt = 0;
1873#if DEBUG
1874 char * name = tape_name(STp);
1875
1876 printk(OSST_DEB_MSG "%s:D: Reached space_over_filemarks_forward_slow %d %d\n", name, mt_op, mt_count);
1877#endif
1878 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
1879#if DEBUG
1880 printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks_fwd\n", name);
1881#endif
1882 return (-EIO);
1883 }
1884 while (1) {
1885 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
1886#if DEBUG
1887 printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks\n", name);
1888#endif
1889 return (-EIO);
1890 }
1891 if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_MARKER)
1892 cnt++;
1893 if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_EOD) {
1894#if DEBUG
1895 printk(OSST_DEB_MSG "%s:D: space_fwd: EOD reached\n", name);
1896#endif
1897 if (STp->first_frame_position > STp->eod_frame_ppos+1) {
1898#if DEBUG
1899 printk(OSST_DEB_MSG "%s:D: EOD position corrected (%d=>%d)\n",
1900 name, STp->eod_frame_ppos, STp->first_frame_position-1);
1901#endif
1902 STp->eod_frame_ppos = STp->first_frame_position-1;
1903 }
1904 return (-EIO);
1905 }
1906 if (cnt == mt_count)
1907 break;
1908 STp->frame_in_buffer = 0;
1909 }
1910 if (mt_op == MTFSF) {
1911 STp->frame_seq_number++;
1912 STp->frame_in_buffer = 0;
1913 STp->buffer->buffer_bytes = 0;
1914 STp->buffer->read_pointer = 0;
1915 STp->logical_blk_num += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
1916 }
1917 return 0;
1918}
1919
1920/*
1921 * Fast linux specific version of OnStream FSF
1922 */
Willem Riede5e6575c2006-02-11 14:46:56 -05001923static int osst_space_over_filemarks_forward_fast(struct osst_tape * STp, struct osst_request ** aSRpnt,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924 int mt_op, int mt_count)
1925{
1926 char * name = tape_name(STp);
1927 int cnt = 0,
1928 next_mark_ppos = -1;
1929
1930#if DEBUG
1931 printk(OSST_DEB_MSG "%s:D: Reached space_over_filemarks_forward_fast %d %d\n", name, mt_op, mt_count);
1932#endif
1933 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
1934#if DEBUG
1935 printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks_fwd\n", name);
1936#endif
1937 return (-EIO);
1938 }
1939
1940 if (STp->linux_media_version >= 4) {
1941 /*
1942 * direct lookup in header filemark list
1943 */
1944 cnt = ntohl(STp->buffer->aux->filemark_cnt) - 1;
1945 if (STp->header_ok &&
1946 STp->header_cache != NULL &&
1947 (cnt + mt_count) < OS_FM_TAB_MAX &&
1948 (cnt + mt_count) < STp->filemark_cnt &&
1949 ((cnt == -1 && ntohl(STp->buffer->aux->last_mark_ppos) == -1) ||
1950 (STp->header_cache->dat_fm_tab.fm_tab_ent[cnt] == STp->buffer->aux->last_mark_ppos)))
1951
1952 next_mark_ppos = ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[cnt + mt_count]);
1953#if DEBUG
1954 if (STp->header_cache == NULL || (cnt + mt_count) >= OS_FM_TAB_MAX)
1955 printk(OSST_DEB_MSG "%s:D: Filemark lookup fail due to %s\n", name,
1956 STp->header_cache == NULL?"lack of header cache":"count out of range");
1957 else
1958 printk(OSST_DEB_MSG "%s:D: Filemark lookup: prev mark %d (%s), skip %d to %d\n",
1959 name, cnt,
1960 ((cnt == -1 && ntohl(STp->buffer->aux->last_mark_ppos) == -1) ||
1961 (STp->header_cache->dat_fm_tab.fm_tab_ent[cnt] ==
1962 STp->buffer->aux->last_mark_ppos))?"match":"error",
1963 mt_count, next_mark_ppos);
1964#endif
1965 if (next_mark_ppos <= 10 || next_mark_ppos > STp->eod_frame_ppos) {
1966#if DEBUG
1967 printk(OSST_DEB_MSG "%s:D: Reverting to slow filemark space\n", name);
1968#endif
1969 return osst_space_over_filemarks_forward_slow(STp, aSRpnt, mt_op, mt_count);
1970 } else {
1971 osst_position_tape_and_confirm(STp, aSRpnt, next_mark_ppos);
1972 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
1973#if DEBUG
1974 printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks\n",
1975 name);
1976#endif
1977 return (-EIO);
1978 }
1979 if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
1980 printk(KERN_WARNING "%s:W: Expected to find marker at ppos %d, not found\n",
1981 name, next_mark_ppos);
1982 return (-EIO);
1983 }
1984 if (ntohl(STp->buffer->aux->filemark_cnt) != cnt + mt_count) {
1985 printk(KERN_WARNING "%s:W: Expected to find marker %d at ppos %d, not %d\n",
1986 name, cnt+mt_count, next_mark_ppos,
1987 ntohl(STp->buffer->aux->filemark_cnt));
1988 return (-EIO);
1989 }
1990 }
1991 } else {
1992 /*
1993 * Find nearest (usually previous) marker, then jump from marker to marker
1994 */
1995 while (1) {
1996 if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_MARKER)
1997 break;
1998 if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_EOD) {
1999#if DEBUG
2000 printk(OSST_DEB_MSG "%s:D: space_fwd: EOD reached\n", name);
2001#endif
2002 return (-EIO);
2003 }
2004 if (ntohl(STp->buffer->aux->filemark_cnt) == 0) {
2005 if (STp->first_mark_ppos == -1) {
2006#if DEBUG
2007 printk(OSST_DEB_MSG "%s:D: Reverting to slow filemark space\n", name);
2008#endif
2009 return osst_space_over_filemarks_forward_slow(STp, aSRpnt, mt_op, mt_count);
2010 }
2011 osst_position_tape_and_confirm(STp, aSRpnt, STp->first_mark_ppos);
2012 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
2013#if DEBUG
2014 printk(OSST_DEB_MSG
2015 "%s:D: Couldn't get logical blk num in space_filemarks_fwd_fast\n",
2016 name);
2017#endif
2018 return (-EIO);
2019 }
2020 if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
2021 printk(KERN_WARNING "%s:W: Expected to find filemark at %d\n",
2022 name, STp->first_mark_ppos);
2023 return (-EIO);
2024 }
2025 } else {
2026 if (osst_space_over_filemarks_backward(STp, aSRpnt, MTBSF, 1) < 0)
2027 return (-EIO);
2028 mt_count++;
2029 }
2030 }
2031 cnt++;
2032 while (cnt != mt_count) {
2033 next_mark_ppos = ntohl(STp->buffer->aux->next_mark_ppos);
2034 if (!next_mark_ppos || next_mark_ppos > STp->eod_frame_ppos) {
2035#if DEBUG
2036 printk(OSST_DEB_MSG "%s:D: Reverting to slow filemark space\n", name);
2037#endif
2038 return osst_space_over_filemarks_forward_slow(STp, aSRpnt, mt_op, mt_count - cnt);
2039 }
2040#if DEBUG
2041 else printk(OSST_DEB_MSG "%s:D: Positioning to next mark at %d\n", name, next_mark_ppos);
2042#endif
2043 osst_position_tape_and_confirm(STp, aSRpnt, next_mark_ppos);
2044 cnt++;
2045 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
2046#if DEBUG
2047 printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks\n",
2048 name);
2049#endif
2050 return (-EIO);
2051 }
2052 if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
2053 printk(KERN_WARNING "%s:W: Expected to find marker at ppos %d, not found\n",
2054 name, next_mark_ppos);
2055 return (-EIO);
2056 }
2057 }
2058 }
2059 if (mt_op == MTFSF) {
2060 STp->frame_seq_number++;
2061 STp->frame_in_buffer = 0;
2062 STp->buffer->buffer_bytes = 0;
2063 STp->buffer->read_pointer = 0;
2064 STp->logical_blk_num += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
2065 }
2066 return 0;
2067}
2068
2069/*
2070 * In debug mode, we want to see as many errors as possible
2071 * to test the error recovery mechanism.
2072 */
2073#if DEBUG
Willem Riede5e6575c2006-02-11 14:46:56 -05002074static void osst_set_retries(struct osst_tape * STp, struct osst_request ** aSRpnt, int retries)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002075{
2076 unsigned char cmd[MAX_COMMAND_SIZE];
Willem Riede5e6575c2006-02-11 14:46:56 -05002077 struct osst_request * SRpnt = * aSRpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002078 char * name = tape_name(STp);
2079
2080 memset(cmd, 0, MAX_COMMAND_SIZE);
2081 cmd[0] = MODE_SELECT;
2082 cmd[1] = 0x10;
2083 cmd[4] = NUMBER_RETRIES_PAGE_LENGTH + MODE_HEADER_LENGTH;
2084
2085 (STp->buffer)->b_data[0] = cmd[4] - 1;
2086 (STp->buffer)->b_data[1] = 0; /* Medium Type - ignoring */
2087 (STp->buffer)->b_data[2] = 0; /* Reserved */
2088 (STp->buffer)->b_data[3] = 0; /* Block Descriptor Length */
2089 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 0] = NUMBER_RETRIES_PAGE | (1 << 7);
2090 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 1] = 2;
2091 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] = 4;
2092 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] = retries;
2093
2094 if (debugging)
2095 printk(OSST_DEB_MSG "%s:D: Setting number of retries on OnStream tape to %d\n", name, retries);
2096
2097 SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_TO_DEVICE, STp->timeout, 0, 1);
2098 *aSRpnt = SRpnt;
2099
2100 if ((STp->buffer)->syscall_result)
2101 printk (KERN_ERR "%s:D: Couldn't set retries to %d\n", name, retries);
2102}
2103#endif
2104
2105
Willem Riede5e6575c2006-02-11 14:46:56 -05002106static int osst_write_filemark(struct osst_tape * STp, struct osst_request ** aSRpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002107{
2108 int result;
2109 int this_mark_ppos = STp->first_frame_position;
2110 int this_mark_lbn = STp->logical_blk_num;
2111#if DEBUG
2112 char * name = tape_name(STp);
2113#endif
2114
2115 if (STp->raw) return 0;
2116
2117 STp->write_type = OS_WRITE_NEW_MARK;
2118#if DEBUG
2119 printk(OSST_DEB_MSG "%s:D: Writing Filemark %i at fppos %d (fseq %d, lblk %d)\n",
2120 name, STp->filemark_cnt, this_mark_ppos, STp->frame_seq_number, this_mark_lbn);
2121#endif
2122 STp->dirty = 1;
2123 result = osst_flush_write_buffer(STp, aSRpnt);
2124 result |= osst_flush_drive_buffer(STp, aSRpnt);
2125 STp->last_mark_ppos = this_mark_ppos;
2126 STp->last_mark_lbn = this_mark_lbn;
2127 if (STp->header_cache != NULL && STp->filemark_cnt < OS_FM_TAB_MAX)
2128 STp->header_cache->dat_fm_tab.fm_tab_ent[STp->filemark_cnt] = htonl(this_mark_ppos);
2129 if (STp->filemark_cnt++ == 0)
2130 STp->first_mark_ppos = this_mark_ppos;
2131 return result;
2132}
2133
Willem Riede5e6575c2006-02-11 14:46:56 -05002134static int osst_write_eod(struct osst_tape * STp, struct osst_request ** aSRpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002135{
2136 int result;
2137#if DEBUG
2138 char * name = tape_name(STp);
2139#endif
2140
2141 if (STp->raw) return 0;
2142
2143 STp->write_type = OS_WRITE_EOD;
2144 STp->eod_frame_ppos = STp->first_frame_position;
2145#if DEBUG
2146 printk(OSST_DEB_MSG "%s:D: Writing EOD at fppos %d (fseq %d, lblk %d)\n", name,
2147 STp->eod_frame_ppos, STp->frame_seq_number, STp->logical_blk_num);
2148#endif
2149 STp->dirty = 1;
2150
2151 result = osst_flush_write_buffer(STp, aSRpnt);
2152 result |= osst_flush_drive_buffer(STp, aSRpnt);
2153 STp->eod_frame_lfa = --(STp->frame_seq_number);
2154 return result;
2155}
2156
Willem Riede5e6575c2006-02-11 14:46:56 -05002157static int osst_write_filler(struct osst_tape * STp, struct osst_request ** aSRpnt, int where, int count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002158{
2159 char * name = tape_name(STp);
2160
2161#if DEBUG
2162 printk(OSST_DEB_MSG "%s:D: Reached onstream write filler group %d\n", name, where);
2163#endif
2164 osst_wait_ready(STp, aSRpnt, 60 * 5, 0);
2165 osst_set_frame_position(STp, aSRpnt, where, 0);
2166 STp->write_type = OS_WRITE_FILLER;
2167 while (count--) {
2168 memcpy(STp->buffer->b_data, "Filler", 6);
2169 STp->buffer->buffer_bytes = 6;
2170 STp->dirty = 1;
2171 if (osst_flush_write_buffer(STp, aSRpnt)) {
2172 printk(KERN_INFO "%s:I: Couldn't write filler frame\n", name);
2173 return (-EIO);
2174 }
2175 }
2176#if DEBUG
2177 printk(OSST_DEB_MSG "%s:D: Exiting onstream write filler group\n", name);
2178#endif
2179 return osst_flush_drive_buffer(STp, aSRpnt);
2180}
2181
Willem Riede5e6575c2006-02-11 14:46:56 -05002182static int __osst_write_header(struct osst_tape * STp, struct osst_request ** aSRpnt, int where, int count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002183{
2184 char * name = tape_name(STp);
2185 int result;
2186
2187#if DEBUG
2188 printk(OSST_DEB_MSG "%s:D: Reached onstream write header group %d\n", name, where);
2189#endif
2190 osst_wait_ready(STp, aSRpnt, 60 * 5, 0);
2191 osst_set_frame_position(STp, aSRpnt, where, 0);
2192 STp->write_type = OS_WRITE_HEADER;
2193 while (count--) {
2194 osst_copy_to_buffer(STp->buffer, (unsigned char *)STp->header_cache);
2195 STp->buffer->buffer_bytes = sizeof(os_header_t);
2196 STp->dirty = 1;
2197 if (osst_flush_write_buffer(STp, aSRpnt)) {
2198 printk(KERN_INFO "%s:I: Couldn't write header frame\n", name);
2199 return (-EIO);
2200 }
2201 }
2202 result = osst_flush_drive_buffer(STp, aSRpnt);
2203#if DEBUG
2204 printk(OSST_DEB_MSG "%s:D: Write onstream header group %s\n", name, result?"failed":"done");
2205#endif
2206 return result;
2207}
2208
Willem Riede5e6575c2006-02-11 14:46:56 -05002209static int osst_write_header(struct osst_tape * STp, struct osst_request ** aSRpnt, int locate_eod)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002210{
2211 os_header_t * header;
2212 int result;
2213 char * name = tape_name(STp);
2214
2215#if DEBUG
2216 printk(OSST_DEB_MSG "%s:D: Writing tape header\n", name);
2217#endif
2218 if (STp->raw) return 0;
2219
2220 if (STp->header_cache == NULL) {
2221 if ((STp->header_cache = (os_header_t *)vmalloc(sizeof(os_header_t))) == NULL) {
2222 printk(KERN_ERR "%s:E: Failed to allocate header cache\n", name);
2223 return (-ENOMEM);
2224 }
2225 memset(STp->header_cache, 0, sizeof(os_header_t));
2226#if DEBUG
2227 printk(OSST_DEB_MSG "%s:D: Allocated and cleared memory for header cache\n", name);
2228#endif
2229 }
2230 if (STp->header_ok) STp->update_frame_cntr++;
2231 else STp->update_frame_cntr = 0;
2232
2233 header = STp->header_cache;
2234 strcpy(header->ident_str, "ADR_SEQ");
2235 header->major_rev = 1;
2236 header->minor_rev = 4;
2237 header->ext_trk_tb_off = htons(17192);
2238 header->pt_par_num = 1;
2239 header->partition[0].partition_num = OS_DATA_PARTITION;
2240 header->partition[0].par_desc_ver = OS_PARTITION_VERSION;
2241 header->partition[0].wrt_pass_cntr = htons(STp->wrt_pass_cntr);
2242 header->partition[0].first_frame_ppos = htonl(STp->first_data_ppos);
2243 header->partition[0].last_frame_ppos = htonl(STp->capacity);
2244 header->partition[0].eod_frame_ppos = htonl(STp->eod_frame_ppos);
2245 header->cfg_col_width = htonl(20);
2246 header->dat_col_width = htonl(1500);
2247 header->qfa_col_width = htonl(0);
2248 header->ext_track_tb.nr_stream_part = 1;
2249 header->ext_track_tb.et_ent_sz = 32;
2250 header->ext_track_tb.dat_ext_trk_ey.et_part_num = 0;
2251 header->ext_track_tb.dat_ext_trk_ey.fmt = 1;
2252 header->ext_track_tb.dat_ext_trk_ey.fm_tab_off = htons(17736);
2253 header->ext_track_tb.dat_ext_trk_ey.last_hlb_hi = 0;
2254 header->ext_track_tb.dat_ext_trk_ey.last_hlb = htonl(STp->eod_frame_lfa);
2255 header->ext_track_tb.dat_ext_trk_ey.last_pp = htonl(STp->eod_frame_ppos);
2256 header->dat_fm_tab.fm_part_num = 0;
2257 header->dat_fm_tab.fm_tab_ent_sz = 4;
2258 header->dat_fm_tab.fm_tab_ent_cnt = htons(STp->filemark_cnt<OS_FM_TAB_MAX?
2259 STp->filemark_cnt:OS_FM_TAB_MAX);
2260
2261 result = __osst_write_header(STp, aSRpnt, 0xbae, 5);
2262 if (STp->update_frame_cntr == 0)
2263 osst_write_filler(STp, aSRpnt, 0xbb3, 5);
2264 result &= __osst_write_header(STp, aSRpnt, 5, 5);
2265
2266 if (locate_eod) {
2267#if DEBUG
2268 printk(OSST_DEB_MSG "%s:D: Locating back to eod frame addr %d\n", name, STp->eod_frame_ppos);
2269#endif
2270 osst_set_frame_position(STp, aSRpnt, STp->eod_frame_ppos, 0);
2271 }
2272 if (result)
2273 printk(KERN_ERR "%s:E: Write header failed\n", name);
2274 else {
2275 memcpy(STp->application_sig, "LIN4", 4);
2276 STp->linux_media = 1;
2277 STp->linux_media_version = 4;
2278 STp->header_ok = 1;
2279 }
2280 return result;
2281}
2282
Willem Riede5e6575c2006-02-11 14:46:56 -05002283static int osst_reset_header(struct osst_tape * STp, struct osst_request ** aSRpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002284{
2285 if (STp->header_cache != NULL)
2286 memset(STp->header_cache, 0, sizeof(os_header_t));
2287
2288 STp->logical_blk_num = STp->frame_seq_number = 0;
2289 STp->frame_in_buffer = 0;
2290 STp->eod_frame_ppos = STp->first_data_ppos = 0x0000000A;
2291 STp->filemark_cnt = 0;
2292 STp->first_mark_ppos = STp->last_mark_ppos = STp->last_mark_lbn = -1;
2293 return osst_write_header(STp, aSRpnt, 1);
2294}
2295
Willem Riede5e6575c2006-02-11 14:46:56 -05002296static int __osst_analyze_headers(struct osst_tape * STp, struct osst_request ** aSRpnt, int ppos)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002297{
2298 char * name = tape_name(STp);
2299 os_header_t * header;
2300 os_aux_t * aux;
2301 char id_string[8];
2302 int linux_media_version,
2303 update_frame_cntr;
2304
2305 if (STp->raw)
2306 return 1;
2307
2308 if (ppos == 5 || ppos == 0xbae || STp->buffer->syscall_result) {
2309 if (osst_set_frame_position(STp, aSRpnt, ppos, 0))
2310 printk(KERN_WARNING "%s:W: Couldn't position tape\n", name);
2311 osst_wait_ready(STp, aSRpnt, 60 * 15, 0);
2312 if (osst_initiate_read (STp, aSRpnt)) {
2313 printk(KERN_WARNING "%s:W: Couldn't initiate read\n", name);
2314 return 0;
2315 }
2316 }
2317 if (osst_read_frame(STp, aSRpnt, 180)) {
2318#if DEBUG
2319 printk(OSST_DEB_MSG "%s:D: Couldn't read header frame\n", name);
2320#endif
2321 return 0;
2322 }
2323 header = (os_header_t *) STp->buffer->b_data; /* warning: only first segment addressable */
2324 aux = STp->buffer->aux;
2325 if (aux->frame_type != OS_FRAME_TYPE_HEADER) {
2326#if DEBUG
2327 printk(OSST_DEB_MSG "%s:D: Skipping non-header frame (%d)\n", name, ppos);
2328#endif
2329 return 0;
2330 }
2331 if (ntohl(aux->frame_seq_num) != 0 ||
2332 ntohl(aux->logical_blk_num) != 0 ||
2333 aux->partition.partition_num != OS_CONFIG_PARTITION ||
2334 ntohl(aux->partition.first_frame_ppos) != 0 ||
2335 ntohl(aux->partition.last_frame_ppos) != 0xbb7 ) {
2336#if DEBUG
2337 printk(OSST_DEB_MSG "%s:D: Invalid header frame (%d,%d,%d,%d,%d)\n", name,
2338 ntohl(aux->frame_seq_num), ntohl(aux->logical_blk_num),
2339 aux->partition.partition_num, ntohl(aux->partition.first_frame_ppos),
2340 ntohl(aux->partition.last_frame_ppos));
2341#endif
2342 return 0;
2343 }
2344 if (strncmp(header->ident_str, "ADR_SEQ", 7) != 0 &&
2345 strncmp(header->ident_str, "ADR-SEQ", 7) != 0) {
2346 strlcpy(id_string, header->ident_str, 8);
2347#if DEBUG
2348 printk(OSST_DEB_MSG "%s:D: Invalid header identification string %s\n", name, id_string);
2349#endif
2350 return 0;
2351 }
2352 update_frame_cntr = ntohl(aux->update_frame_cntr);
2353 if (update_frame_cntr < STp->update_frame_cntr) {
2354#if DEBUG
2355 printk(OSST_DEB_MSG "%s:D: Skipping frame %d with update_frame_counter %d<%d\n",
2356 name, ppos, update_frame_cntr, STp->update_frame_cntr);
2357#endif
2358 return 0;
2359 }
2360 if (header->major_rev != 1 || header->minor_rev != 4 ) {
2361#if DEBUG
2362 printk(OSST_DEB_MSG "%s:D: %s revision %d.%d detected (1.4 supported)\n",
2363 name, (header->major_rev != 1 || header->minor_rev < 2 ||
2364 header->minor_rev > 4 )? "Invalid" : "Warning:",
2365 header->major_rev, header->minor_rev);
2366#endif
2367 if (header->major_rev != 1 || header->minor_rev < 2 || header->minor_rev > 4)
2368 return 0;
2369 }
2370#if DEBUG
2371 if (header->pt_par_num != 1)
2372 printk(KERN_INFO "%s:W: %d partitions defined, only one supported\n",
2373 name, header->pt_par_num);
2374#endif
2375 memcpy(id_string, aux->application_sig, 4);
2376 id_string[4] = 0;
2377 if (memcmp(id_string, "LIN", 3) == 0) {
2378 STp->linux_media = 1;
2379 linux_media_version = id_string[3] - '0';
2380 if (linux_media_version != 4)
2381 printk(KERN_INFO "%s:I: Linux media version %d detected (current 4)\n",
2382 name, linux_media_version);
2383 } else {
2384 printk(KERN_WARNING "%s:W: Non Linux media detected (%s)\n", name, id_string);
2385 return 0;
2386 }
2387 if (linux_media_version < STp->linux_media_version) {
2388#if DEBUG
2389 printk(OSST_DEB_MSG "%s:D: Skipping frame %d with linux_media_version %d\n",
2390 name, ppos, linux_media_version);
2391#endif
2392 return 0;
2393 }
2394 if (linux_media_version > STp->linux_media_version) {
2395#if DEBUG
2396 printk(OSST_DEB_MSG "%s:D: Frame %d sets linux_media_version to %d\n",
2397 name, ppos, linux_media_version);
2398#endif
2399 memcpy(STp->application_sig, id_string, 5);
2400 STp->linux_media_version = linux_media_version;
2401 STp->update_frame_cntr = -1;
2402 }
2403 if (update_frame_cntr > STp->update_frame_cntr) {
2404#if DEBUG
2405 printk(OSST_DEB_MSG "%s:D: Frame %d sets update_frame_counter to %d\n",
2406 name, ppos, update_frame_cntr);
2407#endif
2408 if (STp->header_cache == NULL) {
2409 if ((STp->header_cache = (os_header_t *)vmalloc(sizeof(os_header_t))) == NULL) {
2410 printk(KERN_ERR "%s:E: Failed to allocate header cache\n", name);
2411 return 0;
2412 }
2413#if DEBUG
2414 printk(OSST_DEB_MSG "%s:D: Allocated memory for header cache\n", name);
2415#endif
2416 }
2417 osst_copy_from_buffer(STp->buffer, (unsigned char *)STp->header_cache);
2418 header = STp->header_cache; /* further accesses from cached (full) copy */
2419
2420 STp->wrt_pass_cntr = ntohs(header->partition[0].wrt_pass_cntr);
2421 STp->first_data_ppos = ntohl(header->partition[0].first_frame_ppos);
2422 STp->eod_frame_ppos = ntohl(header->partition[0].eod_frame_ppos);
2423 STp->eod_frame_lfa = ntohl(header->ext_track_tb.dat_ext_trk_ey.last_hlb);
2424 STp->filemark_cnt = ntohl(aux->filemark_cnt);
2425 STp->first_mark_ppos = ntohl(aux->next_mark_ppos);
2426 STp->last_mark_ppos = ntohl(aux->last_mark_ppos);
2427 STp->last_mark_lbn = ntohl(aux->last_mark_lbn);
2428 STp->update_frame_cntr = update_frame_cntr;
2429#if DEBUG
2430 printk(OSST_DEB_MSG "%s:D: Detected write pass %d, update frame counter %d, filemark counter %d\n",
2431 name, STp->wrt_pass_cntr, STp->update_frame_cntr, STp->filemark_cnt);
2432 printk(OSST_DEB_MSG "%s:D: first data frame on tape = %d, last = %d, eod frame = %d\n", name,
2433 STp->first_data_ppos,
2434 ntohl(header->partition[0].last_frame_ppos),
2435 ntohl(header->partition[0].eod_frame_ppos));
2436 printk(OSST_DEB_MSG "%s:D: first mark on tape = %d, last = %d, eod frame = %d\n",
2437 name, STp->first_mark_ppos, STp->last_mark_ppos, STp->eod_frame_ppos);
2438#endif
2439 if (header->minor_rev < 4 && STp->linux_media_version == 4) {
2440#if DEBUG
2441 printk(OSST_DEB_MSG "%s:D: Moving filemark list to ADR 1.4 location\n", name);
2442#endif
2443 memcpy((void *)header->dat_fm_tab.fm_tab_ent,
2444 (void *)header->old_filemark_list, sizeof(header->dat_fm_tab.fm_tab_ent));
2445 memset((void *)header->old_filemark_list, 0, sizeof(header->old_filemark_list));
2446 }
2447 if (header->minor_rev == 4 &&
2448 (header->ext_trk_tb_off != htons(17192) ||
2449 header->partition[0].partition_num != OS_DATA_PARTITION ||
2450 header->partition[0].par_desc_ver != OS_PARTITION_VERSION ||
2451 header->partition[0].last_frame_ppos != htonl(STp->capacity) ||
2452 header->cfg_col_width != htonl(20) ||
2453 header->dat_col_width != htonl(1500) ||
2454 header->qfa_col_width != htonl(0) ||
2455 header->ext_track_tb.nr_stream_part != 1 ||
2456 header->ext_track_tb.et_ent_sz != 32 ||
2457 header->ext_track_tb.dat_ext_trk_ey.et_part_num != OS_DATA_PARTITION ||
2458 header->ext_track_tb.dat_ext_trk_ey.fmt != 1 ||
2459 header->ext_track_tb.dat_ext_trk_ey.fm_tab_off != htons(17736) ||
2460 header->ext_track_tb.dat_ext_trk_ey.last_hlb_hi != 0 ||
2461 header->ext_track_tb.dat_ext_trk_ey.last_pp != htonl(STp->eod_frame_ppos) ||
2462 header->dat_fm_tab.fm_part_num != OS_DATA_PARTITION ||
2463 header->dat_fm_tab.fm_tab_ent_sz != 4 ||
2464 header->dat_fm_tab.fm_tab_ent_cnt !=
2465 htons(STp->filemark_cnt<OS_FM_TAB_MAX?STp->filemark_cnt:OS_FM_TAB_MAX)))
2466 printk(KERN_WARNING "%s:W: Failed consistency check ADR 1.4 format\n", name);
2467
2468 }
2469
2470 return 1;
2471}
2472
Willem Riede5e6575c2006-02-11 14:46:56 -05002473static int osst_analyze_headers(struct osst_tape * STp, struct osst_request ** aSRpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002474{
2475 int position, ppos;
2476 int first, last;
2477 int valid = 0;
2478 char * name = tape_name(STp);
2479
2480 position = osst_get_frame_position(STp, aSRpnt);
2481
2482 if (STp->raw) {
2483 STp->header_ok = STp->linux_media = 1;
2484 STp->linux_media_version = 0;
2485 return 1;
2486 }
2487 STp->header_ok = STp->linux_media = STp->linux_media_version = 0;
2488 STp->wrt_pass_cntr = STp->update_frame_cntr = -1;
2489 STp->eod_frame_ppos = STp->first_data_ppos = -1;
2490 STp->first_mark_ppos = STp->last_mark_ppos = STp->last_mark_lbn = -1;
2491#if DEBUG
2492 printk(OSST_DEB_MSG "%s:D: Reading header\n", name);
2493#endif
2494
2495 /* optimization for speed - if we are positioned at ppos 10, read second group first */
2496 /* TODO try the ADR 1.1 locations for the second group if we have no valid one yet... */
2497
2498 first = position==10?0xbae: 5;
2499 last = position==10?0xbb3:10;
2500
2501 for (ppos = first; ppos < last; ppos++)
2502 if (__osst_analyze_headers(STp, aSRpnt, ppos))
2503 valid = 1;
2504
2505 first = position==10? 5:0xbae;
2506 last = position==10?10:0xbb3;
2507
2508 for (ppos = first; ppos < last; ppos++)
2509 if (__osst_analyze_headers(STp, aSRpnt, ppos))
2510 valid = 1;
2511
2512 if (!valid) {
2513 printk(KERN_ERR "%s:E: Failed to find valid ADRL header, new media?\n", name);
2514 STp->eod_frame_ppos = STp->first_data_ppos = 0;
2515 osst_set_frame_position(STp, aSRpnt, 10, 0);
2516 return 0;
2517 }
2518 if (position <= STp->first_data_ppos) {
2519 position = STp->first_data_ppos;
2520 STp->ps[0].drv_file = STp->ps[0].drv_block = STp->frame_seq_number = STp->logical_blk_num = 0;
2521 }
2522 osst_set_frame_position(STp, aSRpnt, position, 0);
2523 STp->header_ok = 1;
2524
2525 return 1;
2526}
2527
Willem Riede5e6575c2006-02-11 14:46:56 -05002528static int osst_verify_position(struct osst_tape * STp, struct osst_request ** aSRpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529{
2530 int frame_position = STp->first_frame_position;
2531 int frame_seq_numbr = STp->frame_seq_number;
2532 int logical_blk_num = STp->logical_blk_num;
2533 int halfway_frame = STp->frame_in_buffer;
2534 int read_pointer = STp->buffer->read_pointer;
2535 int prev_mark_ppos = -1;
2536 int actual_mark_ppos, i, n;
2537#if DEBUG
2538 char * name = tape_name(STp);
2539
2540 printk(OSST_DEB_MSG "%s:D: Verify that the tape is really the one we think before writing\n", name);
2541#endif
2542 osst_set_frame_position(STp, aSRpnt, frame_position - 1, 0);
2543 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
2544#if DEBUG
2545 printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in verify_position\n", name);
2546#endif
2547 return (-EIO);
2548 }
2549 if (STp->linux_media_version >= 4) {
2550 for (i=0; i<STp->filemark_cnt; i++)
2551 if ((n=ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[i])) < frame_position)
2552 prev_mark_ppos = n;
2553 } else
2554 prev_mark_ppos = frame_position - 1; /* usually - we don't really know */
2555 actual_mark_ppos = STp->buffer->aux->frame_type == OS_FRAME_TYPE_MARKER ?
2556 frame_position - 1 : ntohl(STp->buffer->aux->last_mark_ppos);
2557 if (frame_position != STp->first_frame_position ||
2558 frame_seq_numbr != STp->frame_seq_number + (halfway_frame?0:1) ||
2559 prev_mark_ppos != actual_mark_ppos ) {
2560#if DEBUG
2561 printk(OSST_DEB_MSG "%s:D: Block mismatch: fppos %d-%d, fseq %d-%d, mark %d-%d\n", name,
2562 STp->first_frame_position, frame_position,
2563 STp->frame_seq_number + (halfway_frame?0:1),
2564 frame_seq_numbr, actual_mark_ppos, prev_mark_ppos);
2565#endif
2566 return (-EIO);
2567 }
2568 if (halfway_frame) {
2569 /* prepare buffer for append and rewrite on top of original */
2570 osst_set_frame_position(STp, aSRpnt, frame_position - 1, 0);
2571 STp->buffer->buffer_bytes = read_pointer;
2572 STp->ps[STp->partition].rw = ST_WRITING;
2573 STp->dirty = 1;
2574 }
2575 STp->frame_in_buffer = halfway_frame;
2576 STp->frame_seq_number = frame_seq_numbr;
2577 STp->logical_blk_num = logical_blk_num;
2578 return 0;
2579}
2580
2581/* Acc. to OnStream, the vers. numbering is the following:
2582 * X.XX for released versions (X=digit),
2583 * XXXY for unreleased versions (Y=letter)
2584 * Ordering 1.05 < 106A < 106B < ... < 106a < ... < 1.06
2585 * This fn makes monoton numbers out of this scheme ...
2586 */
2587static unsigned int osst_parse_firmware_rev (const char * str)
2588{
2589 if (str[1] == '.') {
2590 return (str[0]-'0')*10000
2591 +(str[2]-'0')*1000
2592 +(str[3]-'0')*100;
2593 } else {
2594 return (str[0]-'0')*10000
2595 +(str[1]-'0')*1000
2596 +(str[2]-'0')*100 - 100
2597 +(str[3]-'@');
2598 }
2599}
2600
2601/*
2602 * Configure the OnStream SCII tape drive for default operation
2603 */
Willem Riede5e6575c2006-02-11 14:46:56 -05002604static int osst_configure_onstream(struct osst_tape *STp, struct osst_request ** aSRpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002605{
2606 unsigned char cmd[MAX_COMMAND_SIZE];
2607 char * name = tape_name(STp);
Willem Riede5e6575c2006-02-11 14:46:56 -05002608 struct osst_request * SRpnt = * aSRpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002609 osst_mode_parameter_header_t * header;
2610 osst_block_size_page_t * bs;
2611 osst_capabilities_page_t * cp;
2612 osst_tape_paramtr_page_t * prm;
2613 int drive_buffer_size;
2614
2615 if (STp->ready != ST_READY) {
2616#if DEBUG
2617 printk(OSST_DEB_MSG "%s:D: Not Ready\n", name);
2618#endif
2619 return (-EIO);
2620 }
2621
2622 if (STp->os_fw_rev < 10600) {
2623 printk(KERN_INFO "%s:I: Old OnStream firmware revision detected (%s),\n", name, STp->device->rev);
2624 printk(KERN_INFO "%s:I: an upgrade to version 1.06 or above is recommended\n", name);
2625 }
2626
2627 /*
2628 * Configure 32.5KB (data+aux) frame size.
2629 * Get the current frame size from the block size mode page
2630 */
2631 memset(cmd, 0, MAX_COMMAND_SIZE);
2632 cmd[0] = MODE_SENSE;
2633 cmd[1] = 8;
2634 cmd[2] = BLOCK_SIZE_PAGE;
2635 cmd[4] = BLOCK_SIZE_PAGE_LENGTH + MODE_HEADER_LENGTH;
2636
2637 SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_FROM_DEVICE, STp->timeout, 0, 1);
2638 if (SRpnt == NULL) {
2639#if DEBUG
2640 printk(OSST_DEB_MSG "osst :D: Busy\n");
2641#endif
2642 return (-EBUSY);
2643 }
2644 *aSRpnt = SRpnt;
2645 if ((STp->buffer)->syscall_result != 0) {
2646 printk (KERN_ERR "%s:E: Can't get tape block size mode page\n", name);
2647 return (-EIO);
2648 }
2649
2650 header = (osst_mode_parameter_header_t *) (STp->buffer)->b_data;
2651 bs = (osst_block_size_page_t *) ((STp->buffer)->b_data + sizeof(osst_mode_parameter_header_t) + header->bdl);
2652
2653#if DEBUG
2654 printk(OSST_DEB_MSG "%s:D: 32KB play back: %s\n", name, bs->play32 ? "Yes" : "No");
2655 printk(OSST_DEB_MSG "%s:D: 32.5KB play back: %s\n", name, bs->play32_5 ? "Yes" : "No");
2656 printk(OSST_DEB_MSG "%s:D: 32KB record: %s\n", name, bs->record32 ? "Yes" : "No");
2657 printk(OSST_DEB_MSG "%s:D: 32.5KB record: %s\n", name, bs->record32_5 ? "Yes" : "No");
2658#endif
2659
2660 /*
2661 * Configure default auto columns mode, 32.5KB transfer mode
2662 */
2663 bs->one = 1;
2664 bs->play32 = 0;
2665 bs->play32_5 = 1;
2666 bs->record32 = 0;
2667 bs->record32_5 = 1;
2668
2669 memset(cmd, 0, MAX_COMMAND_SIZE);
2670 cmd[0] = MODE_SELECT;
2671 cmd[1] = 0x10;
2672 cmd[4] = BLOCK_SIZE_PAGE_LENGTH + MODE_HEADER_LENGTH;
2673
2674 SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_TO_DEVICE, STp->timeout, 0, 1);
2675 *aSRpnt = SRpnt;
2676 if ((STp->buffer)->syscall_result != 0) {
2677 printk (KERN_ERR "%s:E: Couldn't set tape block size mode page\n", name);
2678 return (-EIO);
2679 }
2680
2681#if DEBUG
2682 printk(KERN_INFO "%s:D: Drive Block Size changed to 32.5K\n", name);
2683 /*
2684 * In debug mode, we want to see as many errors as possible
2685 * to test the error recovery mechanism.
2686 */
2687 osst_set_retries(STp, aSRpnt, 0);
2688 SRpnt = * aSRpnt;
2689#endif
2690
2691 /*
2692 * Set vendor name to 'LIN4' for "Linux support version 4".
2693 */
2694
2695 memset(cmd, 0, MAX_COMMAND_SIZE);
2696 cmd[0] = MODE_SELECT;
2697 cmd[1] = 0x10;
2698 cmd[4] = VENDOR_IDENT_PAGE_LENGTH + MODE_HEADER_LENGTH;
2699
2700 header->mode_data_length = VENDOR_IDENT_PAGE_LENGTH + MODE_HEADER_LENGTH - 1;
2701 header->medium_type = 0; /* Medium Type - ignoring */
2702 header->dsp = 0; /* Reserved */
2703 header->bdl = 0; /* Block Descriptor Length */
2704
2705 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 0] = VENDOR_IDENT_PAGE | (1 << 7);
2706 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 1] = 6;
2707 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] = 'L';
2708 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] = 'I';
2709 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 4] = 'N';
2710 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 5] = '4';
2711 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 6] = 0;
2712 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 7] = 0;
2713
2714 SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_TO_DEVICE, STp->timeout, 0, 1);
2715 *aSRpnt = SRpnt;
2716
2717 if ((STp->buffer)->syscall_result != 0) {
2718 printk (KERN_ERR "%s:E: Couldn't set vendor name to %s\n", name,
2719 (char *) ((STp->buffer)->b_data + MODE_HEADER_LENGTH + 2));
2720 return (-EIO);
2721 }
2722
2723 memset(cmd, 0, MAX_COMMAND_SIZE);
2724 cmd[0] = MODE_SENSE;
2725 cmd[1] = 8;
2726 cmd[2] = CAPABILITIES_PAGE;
2727 cmd[4] = CAPABILITIES_PAGE_LENGTH + MODE_HEADER_LENGTH;
2728
2729 SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_FROM_DEVICE, STp->timeout, 0, 1);
2730 *aSRpnt = SRpnt;
2731
2732 if ((STp->buffer)->syscall_result != 0) {
2733 printk (KERN_ERR "%s:E: Can't get capabilities page\n", name);
2734 return (-EIO);
2735 }
2736
2737 header = (osst_mode_parameter_header_t *) (STp->buffer)->b_data;
2738 cp = (osst_capabilities_page_t *) ((STp->buffer)->b_data +
2739 sizeof(osst_mode_parameter_header_t) + header->bdl);
2740
2741 drive_buffer_size = ntohs(cp->buffer_size) / 2;
2742
2743 memset(cmd, 0, MAX_COMMAND_SIZE);
2744 cmd[0] = MODE_SENSE;
2745 cmd[1] = 8;
2746 cmd[2] = TAPE_PARAMTR_PAGE;
2747 cmd[4] = TAPE_PARAMTR_PAGE_LENGTH + MODE_HEADER_LENGTH;
2748
2749 SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_FROM_DEVICE, STp->timeout, 0, 1);
2750 *aSRpnt = SRpnt;
2751
2752 if ((STp->buffer)->syscall_result != 0) {
2753 printk (KERN_ERR "%s:E: Can't get tape parameter page\n", name);
2754 return (-EIO);
2755 }
2756
2757 header = (osst_mode_parameter_header_t *) (STp->buffer)->b_data;
2758 prm = (osst_tape_paramtr_page_t *) ((STp->buffer)->b_data +
2759 sizeof(osst_mode_parameter_header_t) + header->bdl);
2760
2761 STp->density = prm->density;
2762 STp->capacity = ntohs(prm->segtrk) * ntohs(prm->trks);
2763#if DEBUG
2764 printk(OSST_DEB_MSG "%s:D: Density %d, tape length: %dMB, drive buffer size: %dKB\n",
2765 name, STp->density, STp->capacity / 32, drive_buffer_size);
2766#endif
2767
2768 return 0;
2769
2770}
2771
2772
2773/* Step over EOF if it has been inadvertently crossed (ioctl not used because
2774 it messes up the block number). */
Willem Riede5e6575c2006-02-11 14:46:56 -05002775static int cross_eof(struct osst_tape *STp, struct osst_request ** aSRpnt, int forward)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002776{
2777 int result;
2778 char * name = tape_name(STp);
2779
2780#if DEBUG
2781 if (debugging)
2782 printk(OSST_DEB_MSG "%s:D: Stepping over filemark %s.\n",
2783 name, forward ? "forward" : "backward");
2784#endif
2785
2786 if (forward) {
2787 /* assumes that the filemark is already read by the drive, so this is low cost */
2788 result = osst_space_over_filemarks_forward_slow(STp, aSRpnt, MTFSF, 1);
2789 }
2790 else
2791 /* assumes this is only called if we just read the filemark! */
2792 result = osst_seek_logical_blk(STp, aSRpnt, STp->logical_blk_num - 1);
2793
2794 if (result < 0)
2795 printk(KERN_WARNING "%s:W: Stepping over filemark %s failed.\n",
2796 name, forward ? "forward" : "backward");
2797
2798 return result;
2799}
2800
2801
2802/* Get the tape position. */
2803
Willem Riede5e6575c2006-02-11 14:46:56 -05002804static int osst_get_frame_position(struct osst_tape *STp, struct osst_request ** aSRpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002805{
2806 unsigned char scmd[MAX_COMMAND_SIZE];
Willem Riede5e6575c2006-02-11 14:46:56 -05002807 struct osst_request * SRpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002808 int result = 0;
2809 char * name = tape_name(STp);
2810
2811 /* KG: We want to be able to use it for checking Write Buffer availability
2812 * and thus don't want to risk to overwrite anything. Exchange buffers ... */
2813 char mybuf[24];
2814 char * olddata = STp->buffer->b_data;
2815 int oldsize = STp->buffer->buffer_size;
2816
2817 if (STp->ready != ST_READY) return (-EIO);
2818
2819 memset (scmd, 0, MAX_COMMAND_SIZE);
2820 scmd[0] = READ_POSITION;
2821
2822 STp->buffer->b_data = mybuf; STp->buffer->buffer_size = 24;
2823 SRpnt = osst_do_scsi(*aSRpnt, STp, scmd, 20, DMA_FROM_DEVICE,
2824 STp->timeout, MAX_RETRIES, 1);
2825 if (!SRpnt) {
2826 STp->buffer->b_data = olddata; STp->buffer->buffer_size = oldsize;
2827 return (-EBUSY);
2828 }
2829 *aSRpnt = SRpnt;
2830
2831 if (STp->buffer->syscall_result)
Willem Riede5e6575c2006-02-11 14:46:56 -05002832 result = ((SRpnt->sense[2] & 0x0f) == 3) ? -EIO : -EINVAL; /* 3: Write Error */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002833
2834 if (result == -EINVAL)
2835 printk(KERN_ERR "%s:E: Can't read tape position.\n", name);
2836 else {
2837 if (result == -EIO) { /* re-read position - this needs to preserve media errors */
2838 unsigned char mysense[16];
Willem Riede5e6575c2006-02-11 14:46:56 -05002839 memcpy (mysense, SRpnt->sense, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002840 memset (scmd, 0, MAX_COMMAND_SIZE);
2841 scmd[0] = READ_POSITION;
2842 STp->buffer->b_data = mybuf; STp->buffer->buffer_size = 24;
2843 SRpnt = osst_do_scsi(SRpnt, STp, scmd, 20, DMA_FROM_DEVICE,
2844 STp->timeout, MAX_RETRIES, 1);
2845#if DEBUG
2846 printk(OSST_DEB_MSG "%s:D: Reread position, reason=[%02x:%02x:%02x], result=[%s%02x:%02x:%02x]\n",
2847 name, mysense[2], mysense[12], mysense[13], STp->buffer->syscall_result?"":"ok:",
Willem Riede5e6575c2006-02-11 14:46:56 -05002848 SRpnt->sense[2],SRpnt->sense[12],SRpnt->sense[13]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002849#endif
2850 if (!STp->buffer->syscall_result)
Willem Riede5e6575c2006-02-11 14:46:56 -05002851 memcpy (SRpnt->sense, mysense, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002852 else
2853 printk(KERN_WARNING "%s:W: Double error in get position\n", name);
2854 }
2855 STp->first_frame_position = ((STp->buffer)->b_data[4] << 24)
2856 + ((STp->buffer)->b_data[5] << 16)
2857 + ((STp->buffer)->b_data[6] << 8)
2858 + (STp->buffer)->b_data[7];
2859 STp->last_frame_position = ((STp->buffer)->b_data[ 8] << 24)
2860 + ((STp->buffer)->b_data[ 9] << 16)
2861 + ((STp->buffer)->b_data[10] << 8)
2862 + (STp->buffer)->b_data[11];
2863 STp->cur_frames = (STp->buffer)->b_data[15];
2864#if DEBUG
2865 if (debugging) {
2866 printk(OSST_DEB_MSG "%s:D: Drive Positions: host %d, tape %d%s, buffer %d\n", name,
2867 STp->first_frame_position, STp->last_frame_position,
2868 ((STp->buffer)->b_data[0]&0x80)?" (BOP)":
2869 ((STp->buffer)->b_data[0]&0x40)?" (EOP)":"",
2870 STp->cur_frames);
2871 }
2872#endif
2873 if (STp->cur_frames == 0 && STp->first_frame_position != STp->last_frame_position) {
2874#if DEBUG
2875 printk(OSST_DEB_MSG "%s:D: Correcting read position %d, %d, %d\n", name,
2876 STp->first_frame_position, STp->last_frame_position, STp->cur_frames);
2877#endif
2878 STp->first_frame_position = STp->last_frame_position;
2879 }
2880 }
2881 STp->buffer->b_data = olddata; STp->buffer->buffer_size = oldsize;
2882
2883 return (result == 0 ? STp->first_frame_position : result);
2884}
2885
2886
2887/* Set the tape block */
Willem Riede5e6575c2006-02-11 14:46:56 -05002888static int osst_set_frame_position(struct osst_tape *STp, struct osst_request ** aSRpnt, int ppos, int skip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002889{
2890 unsigned char scmd[MAX_COMMAND_SIZE];
Willem Riede5e6575c2006-02-11 14:46:56 -05002891 struct osst_request * SRpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002892 struct st_partstat * STps;
2893 int result = 0;
2894 int pp = (ppos == 3000 && !skip)? 0 : ppos;
2895 char * name = tape_name(STp);
2896
2897 if (STp->ready != ST_READY) return (-EIO);
2898
2899 STps = &(STp->ps[STp->partition]);
2900
2901 if (ppos < 0 || ppos > STp->capacity) {
2902 printk(KERN_WARNING "%s:W: Reposition request %d out of range\n", name, ppos);
2903 pp = ppos = ppos < 0 ? 0 : (STp->capacity - 1);
2904 result = (-EINVAL);
2905 }
2906
2907 do {
2908#if DEBUG
2909 if (debugging)
2910 printk(OSST_DEB_MSG "%s:D: Setting ppos to %d.\n", name, pp);
2911#endif
2912 memset (scmd, 0, MAX_COMMAND_SIZE);
2913 scmd[0] = SEEK_10;
2914 scmd[1] = 1;
2915 scmd[3] = (pp >> 24);
2916 scmd[4] = (pp >> 16);
2917 scmd[5] = (pp >> 8);
2918 scmd[6] = pp;
2919 if (skip)
2920 scmd[9] = 0x80;
2921
2922 SRpnt = osst_do_scsi(*aSRpnt, STp, scmd, 0, DMA_NONE, STp->long_timeout,
2923 MAX_RETRIES, 1);
2924 if (!SRpnt)
2925 return (-EBUSY);
2926 *aSRpnt = SRpnt;
2927
2928 if ((STp->buffer)->syscall_result != 0) {
2929#if DEBUG
2930 printk(OSST_DEB_MSG "%s:D: SEEK command from %d to %d failed.\n",
2931 name, STp->first_frame_position, pp);
2932#endif
2933 result = (-EIO);
2934 }
2935 if (pp != ppos)
2936 osst_wait_ready(STp, aSRpnt, 5 * 60, OSST_WAIT_POSITION_COMPLETE);
2937 } while ((pp != ppos) && (pp = ppos));
2938 STp->first_frame_position = STp->last_frame_position = ppos;
2939 STps->eof = ST_NOEOF;
2940 STps->at_sm = 0;
2941 STps->rw = ST_IDLE;
2942 STp->frame_in_buffer = 0;
2943 return result;
2944}
2945
Willem Riede5e6575c2006-02-11 14:46:56 -05002946static int osst_write_trailer(struct osst_tape *STp, struct osst_request ** aSRpnt, int leave_at_EOT)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002947{
2948 struct st_partstat * STps = &(STp->ps[STp->partition]);
2949 int result = 0;
2950
2951 if (STp->write_type != OS_WRITE_NEW_MARK) {
2952 /* true unless the user wrote the filemark for us */
2953 result = osst_flush_drive_buffer(STp, aSRpnt);
2954 if (result < 0) goto out;
2955 result = osst_write_filemark(STp, aSRpnt);
2956 if (result < 0) goto out;
2957
2958 if (STps->drv_file >= 0)
2959 STps->drv_file++ ;
2960 STps->drv_block = 0;
2961 }
2962 result = osst_write_eod(STp, aSRpnt);
2963 osst_write_header(STp, aSRpnt, leave_at_EOT);
2964
2965 STps->eof = ST_FM;
2966out:
2967 return result;
2968}
2969
2970/* osst versions of st functions - augmented and stripped to suit OnStream only */
2971
2972/* Flush the write buffer (never need to write if variable blocksize). */
Willem Riede5e6575c2006-02-11 14:46:56 -05002973static int osst_flush_write_buffer(struct osst_tape *STp, struct osst_request ** aSRpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002974{
2975 int offset, transfer, blks = 0;
2976 int result = 0;
2977 unsigned char cmd[MAX_COMMAND_SIZE];
Willem Riede5e6575c2006-02-11 14:46:56 -05002978 struct osst_request * SRpnt = *aSRpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002979 struct st_partstat * STps;
2980 char * name = tape_name(STp);
2981
2982 if ((STp->buffer)->writing) {
2983 if (SRpnt == (STp->buffer)->last_SRpnt)
2984#if DEBUG
2985 { printk(OSST_DEB_MSG
Willem Riede5e6575c2006-02-11 14:46:56 -05002986 "%s:D: aSRpnt points to osst_request that write_behind_check will release -- cleared\n", name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002987#endif
2988 *aSRpnt = SRpnt = NULL;
2989#if DEBUG
2990 } else if (SRpnt)
2991 printk(OSST_DEB_MSG
Willem Riede5e6575c2006-02-11 14:46:56 -05002992 "%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 -07002993#endif
2994 osst_write_behind_check(STp);
2995 if ((STp->buffer)->syscall_result) {
2996#if DEBUG
2997 if (debugging)
2998 printk(OSST_DEB_MSG "%s:D: Async write error (flush) %x.\n",
2999 name, (STp->buffer)->midlevel_result);
3000#endif
3001 if ((STp->buffer)->midlevel_result == INT_MAX)
3002 return (-ENOSPC);
3003 return (-EIO);
3004 }
3005 }
3006
3007 result = 0;
3008 if (STp->dirty == 1) {
3009
3010 STp->write_count++;
3011 STps = &(STp->ps[STp->partition]);
3012 STps->rw = ST_WRITING;
3013 offset = STp->buffer->buffer_bytes;
3014 blks = (offset + STp->block_size - 1) / STp->block_size;
3015 transfer = OS_FRAME_SIZE;
3016
3017 if (offset < OS_DATA_SIZE)
3018 osst_zero_buffer_tail(STp->buffer);
3019
3020 if (STp->poll)
3021 if (osst_wait_frame (STp, aSRpnt, STp->first_frame_position, -50, 120))
3022 result = osst_recover_wait_frame(STp, aSRpnt, 1);
3023
3024 memset(cmd, 0, MAX_COMMAND_SIZE);
3025 cmd[0] = WRITE_6;
3026 cmd[1] = 1;
3027 cmd[4] = 1;
3028
3029 switch (STp->write_type) {
3030 case OS_WRITE_DATA:
3031#if DEBUG
3032 if (debugging)
3033 printk(OSST_DEB_MSG "%s:D: Writing %d blocks to frame %d, lblks %d-%d\n",
3034 name, blks, STp->frame_seq_number,
3035 STp->logical_blk_num - blks, STp->logical_blk_num - 1);
3036#endif
3037 osst_init_aux(STp, OS_FRAME_TYPE_DATA, STp->frame_seq_number++,
3038 STp->logical_blk_num - blks, STp->block_size, blks);
3039 break;
3040 case OS_WRITE_EOD:
3041 osst_init_aux(STp, OS_FRAME_TYPE_EOD, STp->frame_seq_number++,
3042 STp->logical_blk_num, 0, 0);
3043 break;
3044 case OS_WRITE_NEW_MARK:
3045 osst_init_aux(STp, OS_FRAME_TYPE_MARKER, STp->frame_seq_number++,
3046 STp->logical_blk_num++, 0, blks=1);
3047 break;
3048 case OS_WRITE_HEADER:
3049 osst_init_aux(STp, OS_FRAME_TYPE_HEADER, 0, 0, 0, blks=0);
3050 break;
3051 default: /* probably FILLER */
3052 osst_init_aux(STp, OS_FRAME_TYPE_FILL, 0, 0, 0, 0);
3053 }
3054#if DEBUG
3055 if (debugging)
3056 printk(OSST_DEB_MSG "%s:D: Flushing %d bytes, Transfering %d bytes in %d lblocks.\n",
3057 name, offset, transfer, blks);
3058#endif
3059
3060 SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, transfer, DMA_TO_DEVICE,
3061 STp->timeout, MAX_RETRIES, 1);
3062 *aSRpnt = SRpnt;
3063 if (!SRpnt)
3064 return (-EBUSY);
3065
3066 if ((STp->buffer)->syscall_result != 0) {
3067#if DEBUG
3068 printk(OSST_DEB_MSG
3069 "%s:D: write sense [0]=0x%02x [2]=%02x [12]=%02x [13]=%02x\n",
Willem Riede5e6575c2006-02-11 14:46:56 -05003070 name, SRpnt->sense[0], SRpnt->sense[2],
3071 SRpnt->sense[12], SRpnt->sense[13]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003072#endif
Willem Riede5e6575c2006-02-11 14:46:56 -05003073 if ((SRpnt->sense[0] & 0x70) == 0x70 &&
3074 (SRpnt->sense[2] & 0x40) && /* FIXME - SC-30 drive doesn't assert EOM bit */
3075 (SRpnt->sense[2] & 0x0f) == NO_SENSE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003076 STp->dirty = 0;
3077 (STp->buffer)->buffer_bytes = 0;
3078 result = (-ENOSPC);
3079 }
3080 else {
3081 if (osst_write_error_recovery(STp, aSRpnt, 1)) {
3082 printk(KERN_ERR "%s:E: Error on flush write.\n", name);
3083 result = (-EIO);
3084 }
3085 }
3086 STps->drv_block = (-1); /* FIXME - even if write recovery succeeds? */
3087 }
3088 else {
3089 STp->first_frame_position++;
3090 STp->dirty = 0;
3091 (STp->buffer)->buffer_bytes = 0;
3092 }
3093 }
3094#if DEBUG
3095 printk(OSST_DEB_MSG "%s:D: Exit flush write buffer with code %d\n", name, result);
3096#endif
3097 return result;
3098}
3099
3100
3101/* Flush the tape buffer. The tape will be positioned correctly unless
3102 seek_next is true. */
Willem Riede5e6575c2006-02-11 14:46:56 -05003103static int osst_flush_buffer(struct osst_tape * STp, struct osst_request ** aSRpnt, int seek_next)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003104{
3105 struct st_partstat * STps;
3106 int backspace = 0, result = 0;
3107#if DEBUG
3108 char * name = tape_name(STp);
3109#endif
3110
3111 /*
3112 * If there was a bus reset, block further access
3113 * to this device.
3114 */
3115 if( STp->pos_unknown)
3116 return (-EIO);
3117
3118 if (STp->ready != ST_READY)
3119 return 0;
3120
3121 STps = &(STp->ps[STp->partition]);
3122 if (STps->rw == ST_WRITING || STp->dirty) { /* Writing */
3123 STp->write_type = OS_WRITE_DATA;
3124 return osst_flush_write_buffer(STp, aSRpnt);
3125 }
3126 if (STp->block_size == 0)
3127 return 0;
3128
3129#if DEBUG
3130 printk(OSST_DEB_MSG "%s:D: Reached flush (read) buffer\n", name);
3131#endif
3132
3133 if (!STp->can_bsr) {
3134 backspace = ((STp->buffer)->buffer_bytes + (STp->buffer)->read_pointer) / STp->block_size -
3135 ((STp->buffer)->read_pointer + STp->block_size - 1 ) / STp->block_size ;
3136 (STp->buffer)->buffer_bytes = 0;
3137 (STp->buffer)->read_pointer = 0;
3138 STp->frame_in_buffer = 0; /* FIXME is this relevant w. OSST? */
3139 }
3140
3141 if (!seek_next) {
3142 if (STps->eof == ST_FM_HIT) {
3143 result = cross_eof(STp, aSRpnt, 0); /* Back over the EOF hit */
3144 if (!result)
3145 STps->eof = ST_NOEOF;
3146 else {
3147 if (STps->drv_file >= 0)
3148 STps->drv_file++;
3149 STps->drv_block = 0;
3150 }
3151 }
3152 if (!result && backspace > 0) /* TODO -- design and run a test case for this */
3153 result = osst_seek_logical_blk(STp, aSRpnt, STp->logical_blk_num - backspace);
3154 }
3155 else if (STps->eof == ST_FM_HIT) {
3156 if (STps->drv_file >= 0)
3157 STps->drv_file++;
3158 STps->drv_block = 0;
3159 STps->eof = ST_NOEOF;
3160 }
3161
3162 return result;
3163}
3164
Willem Riede5e6575c2006-02-11 14:46:56 -05003165static int osst_write_frame(struct osst_tape * STp, struct osst_request ** aSRpnt, int synchronous)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003166{
3167 unsigned char cmd[MAX_COMMAND_SIZE];
Willem Riede5e6575c2006-02-11 14:46:56 -05003168 struct osst_request * SRpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003169 int blks;
3170#if DEBUG
3171 char * name = tape_name(STp);
3172#endif
3173
3174 if ((!STp-> raw) && (STp->first_frame_position == 0xbae)) { /* _must_ preserve buffer! */
3175#if DEBUG
3176 printk(OSST_DEB_MSG "%s:D: Reaching config partition.\n", name);
3177#endif
3178 if (osst_flush_drive_buffer(STp, aSRpnt) < 0) {
3179 return (-EIO);
3180 }
3181 /* error recovery may have bumped us past the header partition */
3182 if (osst_get_frame_position(STp, aSRpnt) < 0xbb8) {
3183#if DEBUG
3184 printk(OSST_DEB_MSG "%s:D: Skipping over config partition.\n", name);
3185#endif
3186 osst_position_tape_and_confirm(STp, aSRpnt, 0xbb8);
3187 }
3188 }
3189
3190 if (STp->poll)
3191 if (osst_wait_frame (STp, aSRpnt, STp->first_frame_position, -48, 120))
3192 if (osst_recover_wait_frame(STp, aSRpnt, 1))
3193 return (-EIO);
3194
3195// osst_build_stats(STp, &SRpnt);
3196
3197 STp->ps[STp->partition].rw = ST_WRITING;
3198 STp->write_type = OS_WRITE_DATA;
3199
3200 memset(cmd, 0, MAX_COMMAND_SIZE);
3201 cmd[0] = WRITE_6;
3202 cmd[1] = 1;
3203 cmd[4] = 1; /* one frame at a time... */
3204 blks = STp->buffer->buffer_bytes / STp->block_size;
3205#if DEBUG
3206 if (debugging)
3207 printk(OSST_DEB_MSG "%s:D: Writing %d blocks to frame %d, lblks %d-%d\n", name, blks,
3208 STp->frame_seq_number, STp->logical_blk_num - blks, STp->logical_blk_num - 1);
3209#endif
3210 osst_init_aux(STp, OS_FRAME_TYPE_DATA, STp->frame_seq_number++,
3211 STp->logical_blk_num - blks, STp->block_size, blks);
3212
3213#if DEBUG
3214 if (!synchronous)
3215 STp->write_pending = 1;
3216#endif
3217 SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, OS_FRAME_SIZE, DMA_TO_DEVICE, STp->timeout,
3218 MAX_RETRIES, synchronous);
3219 if (!SRpnt)
3220 return (-EBUSY);
3221 *aSRpnt = SRpnt;
3222
3223 if (synchronous) {
3224 if (STp->buffer->syscall_result != 0) {
3225#if DEBUG
3226 if (debugging)
3227 printk(OSST_DEB_MSG "%s:D: Error on write:\n", name);
3228#endif
Willem Riede5e6575c2006-02-11 14:46:56 -05003229 if ((SRpnt->sense[0] & 0x70) == 0x70 &&
3230 (SRpnt->sense[2] & 0x40)) {
3231 if ((SRpnt->sense[2] & 0x0f) == VOLUME_OVERFLOW)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003232 return (-ENOSPC);
3233 }
3234 else {
3235 if (osst_write_error_recovery(STp, aSRpnt, 1))
3236 return (-EIO);
3237 }
3238 }
3239 else
3240 STp->first_frame_position++;
3241 }
3242
3243 STp->write_count++;
3244
3245 return 0;
3246}
3247
Willem Riede5e6575c2006-02-11 14:46:56 -05003248/* Lock or unlock the drive door. Don't use when struct osst_request allocated. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003249static int do_door_lock(struct osst_tape * STp, int do_lock)
3250{
3251 int retval, cmd;
3252
3253 cmd = do_lock ? SCSI_IOCTL_DOORLOCK : SCSI_IOCTL_DOORUNLOCK;
3254#if DEBUG
3255 printk(OSST_DEB_MSG "%s:D: %socking drive door.\n", tape_name(STp), do_lock ? "L" : "Unl");
3256#endif
3257 retval = scsi_ioctl(STp->device, cmd, NULL);
3258 if (!retval) {
3259 STp->door_locked = do_lock ? ST_LOCKED_EXPLICIT : ST_UNLOCKED;
3260 }
3261 else {
3262 STp->door_locked = ST_LOCK_FAILS;
3263 }
3264 return retval;
3265}
3266
3267/* Set the internal state after reset */
3268static void reset_state(struct osst_tape *STp)
3269{
3270 int i;
3271 struct st_partstat *STps;
3272
3273 STp->pos_unknown = 0;
3274 for (i = 0; i < ST_NBR_PARTITIONS; i++) {
3275 STps = &(STp->ps[i]);
3276 STps->rw = ST_IDLE;
3277 STps->eof = ST_NOEOF;
3278 STps->at_sm = 0;
3279 STps->last_block_valid = 0;
3280 STps->drv_block = -1;
3281 STps->drv_file = -1;
3282 }
3283}
3284
3285
3286/* Entry points to osst */
3287
3288/* Write command */
3289static ssize_t osst_write(struct file * filp, const char __user * buf, size_t count, loff_t *ppos)
3290{
3291 ssize_t total, retval = 0;
3292 ssize_t i, do_count, blks, transfer;
3293 int write_threshold;
3294 int doing_write = 0;
3295 const char __user * b_point;
Willem Riede5e6575c2006-02-11 14:46:56 -05003296 struct osst_request * SRpnt = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003297 struct st_modedef * STm;
3298 struct st_partstat * STps;
3299 struct osst_tape * STp = filp->private_data;
3300 char * name = tape_name(STp);
3301
3302
Matthias Kaehlcke4390e602007-08-10 14:50:44 -07003303 if (mutex_lock_interruptible(&STp->lock))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003304 return (-ERESTARTSYS);
3305
3306 /*
3307 * If we are in the middle of error recovery, don't let anyone
3308 * else try and use this device. Also, if error recovery fails, it
3309 * may try and take the device offline, in which case all further
3310 * access to the device is prohibited.
3311 */
3312 if( !scsi_block_when_processing_errors(STp->device) ) {
3313 retval = (-ENXIO);
3314 goto out;
3315 }
3316
3317 if (STp->ready != ST_READY) {
3318 if (STp->ready == ST_NO_TAPE)
3319 retval = (-ENOMEDIUM);
3320 else
3321 retval = (-EIO);
3322 goto out;
3323 }
3324 STm = &(STp->modes[STp->current_mode]);
3325 if (!STm->defined) {
3326 retval = (-ENXIO);
3327 goto out;
3328 }
3329 if (count == 0)
3330 goto out;
3331
3332 /*
3333 * If there was a bus reset, block further access
3334 * to this device.
3335 */
3336 if (STp->pos_unknown) {
3337 retval = (-EIO);
3338 goto out;
3339 }
3340
3341#if DEBUG
3342 if (!STp->in_use) {
3343 printk(OSST_DEB_MSG "%s:D: Incorrect device.\n", name);
3344 retval = (-EIO);
3345 goto out;
3346 }
3347#endif
3348
3349 if (STp->write_prot) {
3350 retval = (-EACCES);
3351 goto out;
3352 }
3353
3354 /* Write must be integral number of blocks */
3355 if (STp->block_size != 0 && (count % STp->block_size) != 0) {
3356 printk(KERN_ERR "%s:E: Write (%Zd bytes) not multiple of tape block size (%d%c).\n",
3357 name, count, STp->block_size<1024?
3358 STp->block_size:STp->block_size/1024, STp->block_size<1024?'b':'k');
3359 retval = (-EINVAL);
3360 goto out;
3361 }
3362
3363 if (STp->first_frame_position >= STp->capacity - OSST_EOM_RESERVE) {
3364 printk(KERN_ERR "%s:E: Write truncated at EOM early warning (frame %d).\n",
3365 name, STp->first_frame_position);
3366 retval = (-ENOSPC);
3367 goto out;
3368 }
3369
3370 if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED && !do_door_lock(STp, 1))
3371 STp->door_locked = ST_LOCKED_AUTO;
3372
3373 STps = &(STp->ps[STp->partition]);
3374
3375 if (STps->rw == ST_READING) {
3376#if DEBUG
3377 printk(OSST_DEB_MSG "%s:D: Switching from read to write at file %d, block %d\n", name,
3378 STps->drv_file, STps->drv_block);
3379#endif
3380 retval = osst_flush_buffer(STp, &SRpnt, 0);
3381 if (retval)
3382 goto out;
3383 STps->rw = ST_IDLE;
3384 }
3385 if (STps->rw != ST_WRITING) {
3386 /* Are we totally rewriting this tape? */
3387 if (!STp->header_ok ||
3388 (STp->first_frame_position == STp->first_data_ppos && STps->drv_block < 0) ||
3389 (STps->drv_file == 0 && STps->drv_block == 0)) {
3390 STp->wrt_pass_cntr++;
3391#if DEBUG
3392 printk(OSST_DEB_MSG "%s:D: Allocating next write pass counter: %d\n",
3393 name, STp->wrt_pass_cntr);
3394#endif
3395 osst_reset_header(STp, &SRpnt);
3396 STps->drv_file = STps->drv_block = 0;
3397 }
3398 /* Do we know where we'll be writing on the tape? */
3399 else {
3400 if ((STp->fast_open && osst_verify_position(STp, &SRpnt)) ||
3401 STps->drv_file < 0 || STps->drv_block < 0) {
3402 if (STp->first_frame_position == STp->eod_frame_ppos) { /* at EOD */
3403 STps->drv_file = STp->filemark_cnt;
3404 STps->drv_block = 0;
3405 }
3406 else {
3407 /* We have no idea where the tape is positioned - give up */
3408#if DEBUG
3409 printk(OSST_DEB_MSG
3410 "%s:D: Cannot write at indeterminate position.\n", name);
3411#endif
3412 retval = (-EIO);
3413 goto out;
3414 }
3415 }
3416 if ((STps->drv_file + STps->drv_block) > 0 && STps->drv_file < STp->filemark_cnt) {
3417 STp->filemark_cnt = STps->drv_file;
3418 STp->last_mark_ppos =
3419 ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[STp->filemark_cnt-1]);
3420 printk(KERN_WARNING
3421 "%s:W: Overwriting file %d with old write pass counter %d\n",
3422 name, STps->drv_file, STp->wrt_pass_cntr);
3423 printk(KERN_WARNING
3424 "%s:W: may lead to stale data being accepted on reading back!\n",
3425 name);
3426#if DEBUG
3427 printk(OSST_DEB_MSG
3428 "%s:D: resetting filemark count to %d and last mark ppos,lbn to %d,%d\n",
3429 name, STp->filemark_cnt, STp->last_mark_ppos, STp->last_mark_lbn);
3430#endif
3431 }
3432 }
3433 STp->fast_open = 0;
3434 }
3435 if (!STp->header_ok) {
3436#if DEBUG
3437 printk(OSST_DEB_MSG "%s:D: Write cannot proceed without valid headers\n", name);
3438#endif
3439 retval = (-EIO);
3440 goto out;
3441 }
3442
3443 if ((STp->buffer)->writing) {
3444if (SRpnt) printk(KERN_ERR "%s:A: Not supposed to have SRpnt at line %d\n", name, __LINE__);
3445 osst_write_behind_check(STp);
3446 if ((STp->buffer)->syscall_result) {
3447#if DEBUG
3448 if (debugging)
3449 printk(OSST_DEB_MSG "%s:D: Async write error (write) %x.\n", name,
3450 (STp->buffer)->midlevel_result);
3451#endif
3452 if ((STp->buffer)->midlevel_result == INT_MAX)
3453 STps->eof = ST_EOM_OK;
3454 else
3455 STps->eof = ST_EOM_ERROR;
3456 }
3457 }
3458 if (STps->eof == ST_EOM_OK) {
3459 retval = (-ENOSPC);
3460 goto out;
3461 }
3462 else if (STps->eof == ST_EOM_ERROR) {
3463 retval = (-EIO);
3464 goto out;
3465 }
3466
3467 /* Check the buffer readability in cases where copy_user might catch
3468 the problems after some tape movement. */
3469 if ((copy_from_user(&i, buf, 1) != 0 ||
3470 copy_from_user(&i, buf + count - 1, 1) != 0)) {
3471 retval = (-EFAULT);
3472 goto out;
3473 }
3474
3475 if (!STm->do_buffer_writes) {
3476 write_threshold = 1;
3477 }
3478 else
3479 write_threshold = (STp->buffer)->buffer_blocks * STp->block_size;
3480 if (!STm->do_async_writes)
3481 write_threshold--;
3482
3483 total = count;
3484#if DEBUG
3485 if (debugging)
3486 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 -05003487 name, (int) count, STps->drv_file, STps->drv_block,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003488 STp->logical_blk_num, STp->frame_seq_number, STp->first_frame_position);
3489#endif
3490 b_point = buf;
3491 while ((STp->buffer)->buffer_bytes + count > write_threshold)
3492 {
3493 doing_write = 1;
3494 do_count = (STp->buffer)->buffer_blocks * STp->block_size -
3495 (STp->buffer)->buffer_bytes;
3496 if (do_count > count)
3497 do_count = count;
3498
3499 i = append_to_buffer(b_point, STp->buffer, do_count);
3500 if (i) {
3501 retval = i;
3502 goto out;
3503 }
3504
3505 blks = do_count / STp->block_size;
3506 STp->logical_blk_num += blks; /* logical_blk_num is incremented as data is moved from user */
3507
3508 i = osst_write_frame(STp, &SRpnt, 1);
3509
3510 if (i == (-ENOSPC)) {
3511 transfer = STp->buffer->writing; /* FIXME -- check this logic */
3512 if (transfer <= do_count) {
3513 filp->f_pos += do_count - transfer;
3514 count -= do_count - transfer;
3515 if (STps->drv_block >= 0) {
3516 STps->drv_block += (do_count - transfer) / STp->block_size;
3517 }
3518 STps->eof = ST_EOM_OK;
3519 retval = (-ENOSPC); /* EOM within current request */
3520#if DEBUG
3521 if (debugging)
3522 printk(OSST_DEB_MSG "%s:D: EOM with %d bytes unwritten.\n",
Willem Riede5e6575c2006-02-11 14:46:56 -05003523 name, (int) transfer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003524#endif
3525 }
3526 else {
3527 STps->eof = ST_EOM_ERROR;
3528 STps->drv_block = (-1); /* Too cautious? */
3529 retval = (-EIO); /* EOM for old data */
3530#if DEBUG
3531 if (debugging)
3532 printk(OSST_DEB_MSG "%s:D: EOM with lost data.\n", name);
3533#endif
3534 }
3535 }
3536 else
3537 retval = i;
3538
3539 if (retval < 0) {
3540 if (SRpnt != NULL) {
Willem Riede5e6575c2006-02-11 14:46:56 -05003541 osst_release_request(SRpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003542 SRpnt = NULL;
3543 }
3544 STp->buffer->buffer_bytes = 0;
3545 STp->dirty = 0;
3546 if (count < total)
3547 retval = total - count;
3548 goto out;
3549 }
3550
3551 filp->f_pos += do_count;
3552 b_point += do_count;
3553 count -= do_count;
3554 if (STps->drv_block >= 0) {
3555 STps->drv_block += blks;
3556 }
3557 STp->buffer->buffer_bytes = 0;
3558 STp->dirty = 0;
3559 } /* end while write threshold exceeded */
3560
3561 if (count != 0) {
3562 STp->dirty = 1;
3563 i = append_to_buffer(b_point, STp->buffer, count);
3564 if (i) {
3565 retval = i;
3566 goto out;
3567 }
3568 blks = count / STp->block_size;
3569 STp->logical_blk_num += blks;
3570 if (STps->drv_block >= 0) {
3571 STps->drv_block += blks;
3572 }
3573 filp->f_pos += count;
3574 count = 0;
3575 }
3576
3577 if (doing_write && (STp->buffer)->syscall_result != 0) {
3578 retval = (STp->buffer)->syscall_result;
3579 goto out;
3580 }
3581
3582 if (STm->do_async_writes && ((STp->buffer)->buffer_bytes >= STp->write_threshold)) {
3583 /* Schedule an asynchronous write */
3584 (STp->buffer)->writing = ((STp->buffer)->buffer_bytes /
3585 STp->block_size) * STp->block_size;
3586 STp->dirty = !((STp->buffer)->writing ==
3587 (STp->buffer)->buffer_bytes);
3588
3589 i = osst_write_frame(STp, &SRpnt, 0);
3590 if (i < 0) {
3591 retval = (-EIO);
3592 goto out;
3593 }
3594 SRpnt = NULL; /* Prevent releasing this request! */
3595 }
3596 STps->at_sm &= (total == 0);
3597 if (total > 0)
3598 STps->eof = ST_NOEOF;
3599
3600 retval = total;
3601
3602out:
Willem Riede5e6575c2006-02-11 14:46:56 -05003603 if (SRpnt != NULL) osst_release_request(SRpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003604
Matthias Kaehlcke4390e602007-08-10 14:50:44 -07003605 mutex_unlock(&STp->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003606
3607 return retval;
3608}
3609
3610
3611/* Read command */
3612static ssize_t osst_read(struct file * filp, char __user * buf, size_t count, loff_t *ppos)
3613{
3614 ssize_t total, retval = 0;
3615 ssize_t i, transfer;
3616 int special;
3617 struct st_modedef * STm;
3618 struct st_partstat * STps;
Willem Riede5e6575c2006-02-11 14:46:56 -05003619 struct osst_request * SRpnt = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003620 struct osst_tape * STp = filp->private_data;
3621 char * name = tape_name(STp);
3622
3623
Matthias Kaehlcke4390e602007-08-10 14:50:44 -07003624 if (mutex_lock_interruptible(&STp->lock))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003625 return (-ERESTARTSYS);
3626
3627 /*
3628 * If we are in the middle of error recovery, don't let anyone
3629 * else try and use this device. Also, if error recovery fails, it
3630 * may try and take the device offline, in which case all further
3631 * access to the device is prohibited.
3632 */
3633 if( !scsi_block_when_processing_errors(STp->device) ) {
3634 retval = (-ENXIO);
3635 goto out;
3636 }
3637
3638 if (STp->ready != ST_READY) {
3639 if (STp->ready == ST_NO_TAPE)
3640 retval = (-ENOMEDIUM);
3641 else
3642 retval = (-EIO);
3643 goto out;
3644 }
3645 STm = &(STp->modes[STp->current_mode]);
3646 if (!STm->defined) {
3647 retval = (-ENXIO);
3648 goto out;
3649 }
3650#if DEBUG
3651 if (!STp->in_use) {
3652 printk(OSST_DEB_MSG "%s:D: Incorrect device.\n", name);
3653 retval = (-EIO);
3654 goto out;
3655 }
3656#endif
3657 /* Must have initialized medium */
3658 if (!STp->header_ok) {
3659 retval = (-EIO);
3660 goto out;
3661 }
3662
3663 if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED && !do_door_lock(STp, 1))
3664 STp->door_locked = ST_LOCKED_AUTO;
3665
3666 STps = &(STp->ps[STp->partition]);
3667 if (STps->rw == ST_WRITING) {
3668 retval = osst_flush_buffer(STp, &SRpnt, 0);
3669 if (retval)
3670 goto out;
3671 STps->rw = ST_IDLE;
3672 /* FIXME -- this may leave the tape without EOD and up2date headers */
3673 }
3674
3675 if ((count % STp->block_size) != 0) {
3676 printk(KERN_WARNING
3677 "%s:W: Read (%Zd bytes) not multiple of tape block size (%d%c).\n", name, count,
3678 STp->block_size<1024?STp->block_size:STp->block_size/1024, STp->block_size<1024?'b':'k');
3679 }
3680
3681#if DEBUG
3682 if (debugging && STps->eof != ST_NOEOF)
3683 printk(OSST_DEB_MSG "%s:D: EOF/EOM flag up (%d). Bytes %d\n", name,
3684 STps->eof, (STp->buffer)->buffer_bytes);
3685#endif
3686 if ((STp->buffer)->buffer_bytes == 0 &&
3687 STps->eof >= ST_EOD_1) {
3688 if (STps->eof < ST_EOD) {
3689 STps->eof += 1;
3690 retval = 0;
3691 goto out;
3692 }
3693 retval = (-EIO); /* EOM or Blank Check */
3694 goto out;
3695 }
3696
3697 /* Check the buffer writability before any tape movement. Don't alter
3698 buffer data. */
3699 if (copy_from_user(&i, buf, 1) != 0 ||
3700 copy_to_user (buf, &i, 1) != 0 ||
3701 copy_from_user(&i, buf + count - 1, 1) != 0 ||
3702 copy_to_user (buf + count - 1, &i, 1) != 0) {
3703 retval = (-EFAULT);
3704 goto out;
3705 }
3706
3707 /* Loop until enough data in buffer or a special condition found */
3708 for (total = 0, special = 0; total < count - STp->block_size + 1 && !special; ) {
3709
3710 /* Get new data if the buffer is empty */
3711 if ((STp->buffer)->buffer_bytes == 0) {
3712 if (STps->eof == ST_FM_HIT)
3713 break;
3714 special = osst_get_logical_frame(STp, &SRpnt, STp->frame_seq_number, 0);
3715 if (special < 0) { /* No need to continue read */
3716 STp->frame_in_buffer = 0;
3717 retval = special;
3718 goto out;
3719 }
3720 }
3721
3722 /* Move the data from driver buffer to user buffer */
3723 if ((STp->buffer)->buffer_bytes > 0) {
3724#if DEBUG
3725 if (debugging && STps->eof != ST_NOEOF)
3726 printk(OSST_DEB_MSG "%s:D: EOF up (%d). Left %d, needed %d.\n", name,
Willem Riede5e6575c2006-02-11 14:46:56 -05003727 STps->eof, (STp->buffer)->buffer_bytes, (int) (count - total));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003728#endif
3729 /* force multiple of block size, note block_size may have been adjusted */
3730 transfer = (((STp->buffer)->buffer_bytes < count - total ?
3731 (STp->buffer)->buffer_bytes : count - total)/
3732 STp->block_size) * STp->block_size;
3733
3734 if (transfer == 0) {
3735 printk(KERN_WARNING
3736 "%s:W: Nothing can be transfered, requested %Zd, tape block size (%d%c).\n",
3737 name, count, STp->block_size < 1024?
3738 STp->block_size:STp->block_size/1024,
3739 STp->block_size<1024?'b':'k');
3740 break;
3741 }
3742 i = from_buffer(STp->buffer, buf, transfer);
3743 if (i) {
3744 retval = i;
3745 goto out;
3746 }
3747 STp->logical_blk_num += transfer / STp->block_size;
3748 STps->drv_block += transfer / STp->block_size;
3749 filp->f_pos += transfer;
3750 buf += transfer;
3751 total += transfer;
3752 }
3753
3754 if ((STp->buffer)->buffer_bytes == 0) {
3755#if DEBUG
3756 if (debugging)
3757 printk(OSST_DEB_MSG "%s:D: Finished with frame %d\n",
3758 name, STp->frame_seq_number);
3759#endif
3760 STp->frame_in_buffer = 0;
3761 STp->frame_seq_number++; /* frame to look for next time */
3762 }
3763 } /* for (total = 0, special = 0; total < count && !special; ) */
3764
3765 /* Change the eof state if no data from tape or buffer */
3766 if (total == 0) {
3767 if (STps->eof == ST_FM_HIT) {
3768 STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD_2:ST_FM;
3769 STps->drv_block = 0;
3770 if (STps->drv_file >= 0)
3771 STps->drv_file++;
3772 }
3773 else if (STps->eof == ST_EOD_1) {
3774 STps->eof = ST_EOD_2;
3775 if (STps->drv_block > 0 && STps->drv_file >= 0)
3776 STps->drv_file++;
3777 STps->drv_block = 0;
3778 }
3779 else if (STps->eof == ST_EOD_2)
3780 STps->eof = ST_EOD;
3781 }
3782 else if (STps->eof == ST_FM)
3783 STps->eof = ST_NOEOF;
3784
3785 retval = total;
3786
3787out:
Willem Riede5e6575c2006-02-11 14:46:56 -05003788 if (SRpnt != NULL) osst_release_request(SRpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003789
Matthias Kaehlcke4390e602007-08-10 14:50:44 -07003790 mutex_unlock(&STp->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003791
3792 return retval;
3793}
3794
3795
3796/* Set the driver options */
3797static void osst_log_options(struct osst_tape *STp, struct st_modedef *STm, char *name)
3798{
3799 printk(KERN_INFO
3800"%s:I: Mode %d options: buffer writes: %d, async writes: %d, read ahead: %d\n",
3801 name, STp->current_mode, STm->do_buffer_writes, STm->do_async_writes,
3802 STm->do_read_ahead);
3803 printk(KERN_INFO
3804"%s:I: can bsr: %d, two FMs: %d, fast mteom: %d, auto lock: %d,\n",
3805 name, STp->can_bsr, STp->two_fm, STp->fast_mteom, STp->do_auto_lock);
3806 printk(KERN_INFO
3807"%s:I: defs for wr: %d, no block limits: %d, partitions: %d, s2 log: %d\n",
3808 name, STm->defaults_for_writes, STp->omit_blklims, STp->can_partitions,
3809 STp->scsi2_logical);
3810 printk(KERN_INFO
3811"%s:I: sysv: %d\n", name, STm->sysv);
3812#if DEBUG
3813 printk(KERN_INFO
3814 "%s:D: debugging: %d\n",
3815 name, debugging);
3816#endif
3817}
3818
3819
3820static int osst_set_options(struct osst_tape *STp, long options)
3821{
3822 int value;
3823 long code;
3824 struct st_modedef * STm;
3825 char * name = tape_name(STp);
3826
3827 STm = &(STp->modes[STp->current_mode]);
3828 if (!STm->defined) {
3829 memcpy(STm, &(STp->modes[0]), sizeof(*STm));
3830 modes_defined = 1;
3831#if DEBUG
3832 if (debugging)
3833 printk(OSST_DEB_MSG "%s:D: Initialized mode %d definition from mode 0\n",
3834 name, STp->current_mode);
3835#endif
3836 }
3837
3838 code = options & MT_ST_OPTIONS;
3839 if (code == MT_ST_BOOLEANS) {
3840 STm->do_buffer_writes = (options & MT_ST_BUFFER_WRITES) != 0;
3841 STm->do_async_writes = (options & MT_ST_ASYNC_WRITES) != 0;
3842 STm->defaults_for_writes = (options & MT_ST_DEF_WRITES) != 0;
3843 STm->do_read_ahead = (options & MT_ST_READ_AHEAD) != 0;
3844 STp->two_fm = (options & MT_ST_TWO_FM) != 0;
3845 STp->fast_mteom = (options & MT_ST_FAST_MTEOM) != 0;
3846 STp->do_auto_lock = (options & MT_ST_AUTO_LOCK) != 0;
3847 STp->can_bsr = (options & MT_ST_CAN_BSR) != 0;
3848 STp->omit_blklims = (options & MT_ST_NO_BLKLIMS) != 0;
3849 if ((STp->device)->scsi_level >= SCSI_2)
3850 STp->can_partitions = (options & MT_ST_CAN_PARTITIONS) != 0;
3851 STp->scsi2_logical = (options & MT_ST_SCSI2LOGICAL) != 0;
3852 STm->sysv = (options & MT_ST_SYSV) != 0;
3853#if DEBUG
3854 debugging = (options & MT_ST_DEBUGGING) != 0;
3855#endif
3856 osst_log_options(STp, STm, name);
3857 }
3858 else if (code == MT_ST_SETBOOLEANS || code == MT_ST_CLEARBOOLEANS) {
3859 value = (code == MT_ST_SETBOOLEANS);
3860 if ((options & MT_ST_BUFFER_WRITES) != 0)
3861 STm->do_buffer_writes = value;
3862 if ((options & MT_ST_ASYNC_WRITES) != 0)
3863 STm->do_async_writes = value;
3864 if ((options & MT_ST_DEF_WRITES) != 0)
3865 STm->defaults_for_writes = value;
3866 if ((options & MT_ST_READ_AHEAD) != 0)
3867 STm->do_read_ahead = value;
3868 if ((options & MT_ST_TWO_FM) != 0)
3869 STp->two_fm = value;
3870 if ((options & MT_ST_FAST_MTEOM) != 0)
3871 STp->fast_mteom = value;
3872 if ((options & MT_ST_AUTO_LOCK) != 0)
3873 STp->do_auto_lock = value;
3874 if ((options & MT_ST_CAN_BSR) != 0)
3875 STp->can_bsr = value;
3876 if ((options & MT_ST_NO_BLKLIMS) != 0)
3877 STp->omit_blklims = value;
3878 if ((STp->device)->scsi_level >= SCSI_2 &&
3879 (options & MT_ST_CAN_PARTITIONS) != 0)
3880 STp->can_partitions = value;
3881 if ((options & MT_ST_SCSI2LOGICAL) != 0)
3882 STp->scsi2_logical = value;
3883 if ((options & MT_ST_SYSV) != 0)
3884 STm->sysv = value;
3885#if DEBUG
3886 if ((options & MT_ST_DEBUGGING) != 0)
3887 debugging = value;
3888#endif
3889 osst_log_options(STp, STm, name);
3890 }
3891 else if (code == MT_ST_WRITE_THRESHOLD) {
3892 value = (options & ~MT_ST_OPTIONS) * ST_KILOBYTE;
3893 if (value < 1 || value > osst_buffer_size) {
3894 printk(KERN_WARNING "%s:W: Write threshold %d too small or too large.\n",
3895 name, value);
3896 return (-EIO);
3897 }
3898 STp->write_threshold = value;
3899 printk(KERN_INFO "%s:I: Write threshold set to %d bytes.\n",
3900 name, value);
3901 }
3902 else if (code == MT_ST_DEF_BLKSIZE) {
3903 value = (options & ~MT_ST_OPTIONS);
3904 if (value == ~MT_ST_OPTIONS) {
3905 STm->default_blksize = (-1);
3906 printk(KERN_INFO "%s:I: Default block size disabled.\n", name);
3907 }
3908 else {
3909 if (value < 512 || value > OS_DATA_SIZE || OS_DATA_SIZE % value) {
3910 printk(KERN_WARNING "%s:W: Default block size cannot be set to %d.\n",
3911 name, value);
3912 return (-EINVAL);
3913 }
3914 STm->default_blksize = value;
3915 printk(KERN_INFO "%s:I: Default block size set to %d bytes.\n",
3916 name, STm->default_blksize);
3917 }
3918 }
3919 else if (code == MT_ST_TIMEOUTS) {
3920 value = (options & ~MT_ST_OPTIONS);
3921 if ((value & MT_ST_SET_LONG_TIMEOUT) != 0) {
3922 STp->long_timeout = (value & ~MT_ST_SET_LONG_TIMEOUT) * HZ;
3923 printk(KERN_INFO "%s:I: Long timeout set to %d seconds.\n", name,
3924 (value & ~MT_ST_SET_LONG_TIMEOUT));
3925 }
3926 else {
3927 STp->timeout = value * HZ;
3928 printk(KERN_INFO "%s:I: Normal timeout set to %d seconds.\n", name, value);
3929 }
3930 }
3931 else if (code == MT_ST_DEF_OPTIONS) {
3932 code = (options & ~MT_ST_CLEAR_DEFAULT);
3933 value = (options & MT_ST_CLEAR_DEFAULT);
3934 if (code == MT_ST_DEF_DENSITY) {
3935 if (value == MT_ST_CLEAR_DEFAULT) {
3936 STm->default_density = (-1);
3937 printk(KERN_INFO "%s:I: Density default disabled.\n", name);
3938 }
3939 else {
3940 STm->default_density = value & 0xff;
3941 printk(KERN_INFO "%s:I: Density default set to %x\n",
3942 name, STm->default_density);
3943 }
3944 }
3945 else if (code == MT_ST_DEF_DRVBUFFER) {
3946 if (value == MT_ST_CLEAR_DEFAULT) {
3947 STp->default_drvbuffer = 0xff;
3948 printk(KERN_INFO "%s:I: Drive buffer default disabled.\n", name);
3949 }
3950 else {
3951 STp->default_drvbuffer = value & 7;
3952 printk(KERN_INFO "%s:I: Drive buffer default set to %x\n",
3953 name, STp->default_drvbuffer);
3954 }
3955 }
3956 else if (code == MT_ST_DEF_COMPRESSION) {
3957 if (value == MT_ST_CLEAR_DEFAULT) {
3958 STm->default_compression = ST_DONT_TOUCH;
3959 printk(KERN_INFO "%s:I: Compression default disabled.\n", name);
3960 }
3961 else {
3962 STm->default_compression = (value & 1 ? ST_YES : ST_NO);
3963 printk(KERN_INFO "%s:I: Compression default set to %x\n",
3964 name, (value & 1));
3965 }
3966 }
3967 }
3968 else
3969 return (-EIO);
3970
3971 return 0;
3972}
3973
3974
3975/* Internal ioctl function */
Willem Riede5e6575c2006-02-11 14:46:56 -05003976static int osst_int_ioctl(struct osst_tape * STp, struct osst_request ** aSRpnt,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003977 unsigned int cmd_in, unsigned long arg)
3978{
3979 int timeout;
3980 long ltmp;
3981 int i, ioctl_result;
3982 int chg_eof = 1;
3983 unsigned char cmd[MAX_COMMAND_SIZE];
Willem Riede5e6575c2006-02-11 14:46:56 -05003984 struct osst_request * SRpnt = * aSRpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003985 struct st_partstat * STps;
3986 int fileno, blkno, at_sm, frame_seq_numbr, logical_blk_num;
3987 int datalen = 0, direction = DMA_NONE;
3988 char * name = tape_name(STp);
3989
3990 if (STp->ready != ST_READY && cmd_in != MTLOAD) {
3991 if (STp->ready == ST_NO_TAPE)
3992 return (-ENOMEDIUM);
3993 else
3994 return (-EIO);
3995 }
3996 timeout = STp->long_timeout;
3997 STps = &(STp->ps[STp->partition]);
3998 fileno = STps->drv_file;
3999 blkno = STps->drv_block;
4000 at_sm = STps->at_sm;
4001 frame_seq_numbr = STp->frame_seq_number;
4002 logical_blk_num = STp->logical_blk_num;
4003
4004 memset(cmd, 0, MAX_COMMAND_SIZE);
4005 switch (cmd_in) {
4006 case MTFSFM:
4007 chg_eof = 0; /* Changed from the FSF after this */
4008 case MTFSF:
4009 if (STp->raw)
4010 return (-EIO);
4011 if (STp->linux_media)
4012 ioctl_result = osst_space_over_filemarks_forward_fast(STp, &SRpnt, cmd_in, arg);
4013 else
4014 ioctl_result = osst_space_over_filemarks_forward_slow(STp, &SRpnt, cmd_in, arg);
4015 if (fileno >= 0)
4016 fileno += arg;
4017 blkno = 0;
4018 at_sm &= (arg == 0);
4019 goto os_bypass;
4020
4021 case MTBSF:
4022 chg_eof = 0; /* Changed from the FSF after this */
4023 case MTBSFM:
4024 if (STp->raw)
4025 return (-EIO);
4026 ioctl_result = osst_space_over_filemarks_backward(STp, &SRpnt, cmd_in, arg);
4027 if (fileno >= 0)
4028 fileno -= arg;
4029 blkno = (-1); /* We can't know the block number */
4030 at_sm &= (arg == 0);
4031 goto os_bypass;
4032
4033 case MTFSR:
4034 case MTBSR:
4035#if DEBUG
4036 if (debugging)
4037 printk(OSST_DEB_MSG "%s:D: Skipping %lu blocks %s from logical block %d\n",
4038 name, arg, cmd_in==MTFSR?"forward":"backward", logical_blk_num);
4039#endif
4040 if (cmd_in == MTFSR) {
4041 logical_blk_num += arg;
4042 if (blkno >= 0) blkno += arg;
4043 }
4044 else {
4045 logical_blk_num -= arg;
4046 if (blkno >= 0) blkno -= arg;
4047 }
4048 ioctl_result = osst_seek_logical_blk(STp, &SRpnt, logical_blk_num);
4049 fileno = STps->drv_file;
4050 blkno = STps->drv_block;
4051 at_sm &= (arg == 0);
4052 goto os_bypass;
4053
4054 case MTFSS:
4055 cmd[0] = SPACE;
4056 cmd[1] = 0x04; /* Space Setmarks */ /* FIXME -- OS can't do this? */
4057 cmd[2] = (arg >> 16);
4058 cmd[3] = (arg >> 8);
4059 cmd[4] = arg;
4060#if DEBUG
4061 if (debugging)
4062 printk(OSST_DEB_MSG "%s:D: Spacing tape forward %d setmarks.\n", name,
4063 cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
4064#endif
4065 if (arg != 0) {
4066 blkno = fileno = (-1);
4067 at_sm = 1;
4068 }
4069 break;
4070 case MTBSS:
4071 cmd[0] = SPACE;
4072 cmd[1] = 0x04; /* Space Setmarks */ /* FIXME -- OS can't do this? */
4073 ltmp = (-arg);
4074 cmd[2] = (ltmp >> 16);
4075 cmd[3] = (ltmp >> 8);
4076 cmd[4] = ltmp;
4077#if DEBUG
4078 if (debugging) {
4079 if (cmd[2] & 0x80)
4080 ltmp = 0xff000000;
4081 ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4];
4082 printk(OSST_DEB_MSG "%s:D: Spacing tape backward %ld setmarks.\n",
4083 name, (-ltmp));
4084 }
4085#endif
4086 if (arg != 0) {
4087 blkno = fileno = (-1);
4088 at_sm = 1;
4089 }
4090 break;
4091 case MTWEOF:
4092 if ((STps->rw == ST_WRITING || STp->dirty) && !STp->pos_unknown) {
4093 STp->write_type = OS_WRITE_DATA;
4094 ioctl_result = osst_flush_write_buffer(STp, &SRpnt);
4095 } else
4096 ioctl_result = 0;
4097#if DEBUG
4098 if (debugging)
4099 printk(OSST_DEB_MSG "%s:D: Writing %ld filemark(s).\n", name, arg);
4100#endif
4101 for (i=0; i<arg; i++)
4102 ioctl_result |= osst_write_filemark(STp, &SRpnt);
4103 if (fileno >= 0) fileno += arg;
4104 if (blkno >= 0) blkno = 0;
4105 goto os_bypass;
4106
4107 case MTWSM:
4108 if (STp->write_prot)
4109 return (-EACCES);
4110 if (!STp->raw)
4111 return 0;
4112 cmd[0] = WRITE_FILEMARKS; /* FIXME -- need OS version */
4113 if (cmd_in == MTWSM)
4114 cmd[1] = 2;
4115 cmd[2] = (arg >> 16);
4116 cmd[3] = (arg >> 8);
4117 cmd[4] = arg;
4118 timeout = STp->timeout;
4119#if DEBUG
4120 if (debugging)
4121 printk(OSST_DEB_MSG "%s:D: Writing %d setmark(s).\n", name,
4122 cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
4123#endif
4124 if (fileno >= 0)
4125 fileno += arg;
4126 blkno = 0;
4127 at_sm = (cmd_in == MTWSM);
4128 break;
4129 case MTOFFL:
4130 case MTLOAD:
4131 case MTUNLOAD:
4132 case MTRETEN:
4133 cmd[0] = START_STOP;
4134 cmd[1] = 1; /* Don't wait for completion */
4135 if (cmd_in == MTLOAD) {
4136 if (STp->ready == ST_NO_TAPE)
4137 cmd[4] = 4; /* open tray */
4138 else
4139 cmd[4] = 1; /* load */
4140 }
4141 if (cmd_in == MTRETEN)
4142 cmd[4] = 3; /* retension then mount */
4143 if (cmd_in == MTOFFL)
4144 cmd[4] = 4; /* rewind then eject */
4145 timeout = STp->timeout;
4146#if DEBUG
4147 if (debugging) {
4148 switch (cmd_in) {
4149 case MTUNLOAD:
4150 printk(OSST_DEB_MSG "%s:D: Unloading tape.\n", name);
4151 break;
4152 case MTLOAD:
4153 printk(OSST_DEB_MSG "%s:D: Loading tape.\n", name);
4154 break;
4155 case MTRETEN:
4156 printk(OSST_DEB_MSG "%s:D: Retensioning tape.\n", name);
4157 break;
4158 case MTOFFL:
4159 printk(OSST_DEB_MSG "%s:D: Ejecting tape.\n", name);
4160 break;
4161 }
4162 }
4163#endif
4164 fileno = blkno = at_sm = frame_seq_numbr = logical_blk_num = 0 ;
4165 break;
4166 case MTNOP:
4167#if DEBUG
4168 if (debugging)
4169 printk(OSST_DEB_MSG "%s:D: No-op on tape.\n", name);
4170#endif
4171 return 0; /* Should do something ? */
4172 break;
4173 case MTEOM:
4174#if DEBUG
4175 if (debugging)
4176 printk(OSST_DEB_MSG "%s:D: Spacing to end of recorded medium.\n", name);
4177#endif
4178 if ((osst_position_tape_and_confirm(STp, &SRpnt, STp->eod_frame_ppos) < 0) ||
4179 (osst_get_logical_frame(STp, &SRpnt, -1, 0) < 0)) {
4180 ioctl_result = -EIO;
4181 goto os_bypass;
4182 }
4183 if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_EOD) {
4184#if DEBUG
4185 printk(OSST_DEB_MSG "%s:D: No EOD frame found where expected.\n", name);
4186#endif
4187 ioctl_result = -EIO;
4188 goto os_bypass;
4189 }
4190 ioctl_result = osst_set_frame_position(STp, &SRpnt, STp->eod_frame_ppos, 0);
4191 fileno = STp->filemark_cnt;
4192 blkno = at_sm = 0;
4193 goto os_bypass;
4194
4195 case MTERASE:
4196 if (STp->write_prot)
4197 return (-EACCES);
4198 ioctl_result = osst_reset_header(STp, &SRpnt);
4199 i = osst_write_eod(STp, &SRpnt);
4200 if (i < ioctl_result) ioctl_result = i;
4201 i = osst_position_tape_and_confirm(STp, &SRpnt, STp->eod_frame_ppos);
4202 if (i < ioctl_result) ioctl_result = i;
4203 fileno = blkno = at_sm = 0 ;
4204 goto os_bypass;
4205
4206 case MTREW:
4207 cmd[0] = REZERO_UNIT; /* rewind */
4208 cmd[1] = 1;
4209#if DEBUG
4210 if (debugging)
4211 printk(OSST_DEB_MSG "%s:D: Rewinding tape, Immed=%d.\n", name, cmd[1]);
4212#endif
4213 fileno = blkno = at_sm = frame_seq_numbr = logical_blk_num = 0 ;
4214 break;
4215
4216 case MTSETBLK: /* Set block length */
4217 if ((STps->drv_block == 0 ) &&
4218 !STp->dirty &&
4219 ((STp->buffer)->buffer_bytes == 0) &&
4220 ((arg & MT_ST_BLKSIZE_MASK) >= 512 ) &&
4221 ((arg & MT_ST_BLKSIZE_MASK) <= OS_DATA_SIZE) &&
4222 !(OS_DATA_SIZE % (arg & MT_ST_BLKSIZE_MASK)) ) {
4223 /*
4224 * Only allowed to change the block size if you opened the
4225 * device at the beginning of a file before writing anything.
4226 * Note, that when reading, changing block_size is futile,
4227 * as the size used when writing overrides it.
4228 */
4229 STp->block_size = (arg & MT_ST_BLKSIZE_MASK);
4230 printk(KERN_INFO "%s:I: Block size set to %d bytes.\n",
4231 name, STp->block_size);
4232 return 0;
4233 }
4234 case MTSETDENSITY: /* Set tape density */
4235 case MTSETDRVBUFFER: /* Set drive buffering */
4236 case SET_DENS_AND_BLK: /* Set density and block size */
4237 chg_eof = 0;
4238 if (STp->dirty || (STp->buffer)->buffer_bytes != 0)
4239 return (-EIO); /* Not allowed if data in buffer */
4240 if ((cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) &&
4241 (arg & MT_ST_BLKSIZE_MASK) != 0 &&
4242 (arg & MT_ST_BLKSIZE_MASK) != STp->block_size ) {
4243 printk(KERN_WARNING "%s:W: Illegal to set block size to %d%s.\n",
4244 name, (int)(arg & MT_ST_BLKSIZE_MASK),
4245 (OS_DATA_SIZE % (arg & MT_ST_BLKSIZE_MASK))?"":" now");
4246 return (-EINVAL);
4247 }
4248 return 0; /* FIXME silently ignore if block size didn't change */
4249
4250 default:
4251 return (-ENOSYS);
4252 }
4253
4254 SRpnt = osst_do_scsi(SRpnt, STp, cmd, datalen, direction, timeout, MAX_RETRIES, 1);
4255
4256 ioctl_result = (STp->buffer)->syscall_result;
4257
4258 if (!SRpnt) {
4259#if DEBUG
4260 printk(OSST_DEB_MSG "%s:D: Couldn't exec scsi cmd for IOCTL\n", name);
4261#endif
4262 return ioctl_result;
4263 }
4264
4265 if (!ioctl_result) { /* SCSI command successful */
4266 STp->frame_seq_number = frame_seq_numbr;
4267 STp->logical_blk_num = logical_blk_num;
4268 }
4269
4270os_bypass:
4271#if DEBUG
4272 if (debugging)
4273 printk(OSST_DEB_MSG "%s:D: IOCTL (%d) Result=%d\n", name, cmd_in, ioctl_result);
4274#endif
4275
4276 if (!ioctl_result) { /* success */
4277
4278 if (cmd_in == MTFSFM) {
4279 fileno--;
4280 blkno--;
4281 }
4282 if (cmd_in == MTBSFM) {
4283 fileno++;
4284 blkno++;
4285 }
4286 STps->drv_block = blkno;
4287 STps->drv_file = fileno;
4288 STps->at_sm = at_sm;
4289
4290 if (cmd_in == MTEOM)
4291 STps->eof = ST_EOD;
4292 else if ((cmd_in == MTFSFM || cmd_in == MTBSF) && STps->eof == ST_FM_HIT) {
4293 ioctl_result = osst_seek_logical_blk(STp, &SRpnt, STp->logical_blk_num-1);
4294 STps->drv_block++;
4295 STp->logical_blk_num++;
4296 STp->frame_seq_number++;
4297 STp->frame_in_buffer = 0;
4298 STp->buffer->read_pointer = 0;
4299 }
4300 else if (cmd_in == MTFSF)
4301 STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD:ST_FM;
4302 else if (chg_eof)
4303 STps->eof = ST_NOEOF;
4304
4305 if (cmd_in == MTOFFL || cmd_in == MTUNLOAD)
4306 STp->rew_at_close = 0;
4307 else if (cmd_in == MTLOAD) {
4308 for (i=0; i < ST_NBR_PARTITIONS; i++) {
4309 STp->ps[i].rw = ST_IDLE;
4310 STp->ps[i].last_block_valid = 0;/* FIXME - where else is this field maintained? */
4311 }
4312 STp->partition = 0;
4313 }
4314
4315 if (cmd_in == MTREW) {
4316 ioctl_result = osst_position_tape_and_confirm(STp, &SRpnt, STp->first_data_ppos);
4317 if (ioctl_result > 0)
4318 ioctl_result = 0;
4319 }
4320
4321 } else if (cmd_in == MTBSF || cmd_in == MTBSFM ) {
4322 if (osst_position_tape_and_confirm(STp, &SRpnt, STp->first_data_ppos) < 0)
4323 STps->drv_file = STps->drv_block = -1;
4324 else
4325 STps->drv_file = STps->drv_block = 0;
4326 STps->eof = ST_NOEOF;
4327 } else if (cmd_in == MTFSF || cmd_in == MTFSFM) {
4328 if (osst_position_tape_and_confirm(STp, &SRpnt, STp->eod_frame_ppos) < 0)
4329 STps->drv_file = STps->drv_block = -1;
4330 else {
4331 STps->drv_file = STp->filemark_cnt;
4332 STps->drv_block = 0;
4333 }
4334 STps->eof = ST_EOD;
4335 } else if (cmd_in == MTBSR || cmd_in == MTFSR || cmd_in == MTWEOF || cmd_in == MTEOM) {
4336 STps->drv_file = STps->drv_block = (-1);
4337 STps->eof = ST_NOEOF;
4338 STp->header_ok = 0;
4339 } else if (cmd_in == MTERASE) {
4340 STp->header_ok = 0;
4341 } else if (SRpnt) { /* SCSI command was not completely successful. */
Willem Riede5e6575c2006-02-11 14:46:56 -05004342 if (SRpnt->sense[2] & 0x40) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004343 STps->eof = ST_EOM_OK;
4344 STps->drv_block = 0;
4345 }
4346 if (chg_eof)
4347 STps->eof = ST_NOEOF;
4348
Willem Riede5e6575c2006-02-11 14:46:56 -05004349 if ((SRpnt->sense[2] & 0x0f) == BLANK_CHECK)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004350 STps->eof = ST_EOD;
4351
4352 if (cmd_in == MTLOAD && osst_wait_for_medium(STp, &SRpnt, 60))
4353 ioctl_result = osst_wait_ready(STp, &SRpnt, 5 * 60, OSST_WAIT_POSITION_COMPLETE);
4354 }
4355 *aSRpnt = SRpnt;
4356
4357 return ioctl_result;
4358}
4359
4360
4361/* Open the device */
4362static int os_scsi_tape_open(struct inode * inode, struct file * filp)
4363{
4364 unsigned short flags;
4365 int i, b_size, new_session = 0, retval = 0;
4366 unsigned char cmd[MAX_COMMAND_SIZE];
Willem Riede5e6575c2006-02-11 14:46:56 -05004367 struct osst_request * SRpnt = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004368 struct osst_tape * STp;
4369 struct st_modedef * STm;
4370 struct st_partstat * STps;
4371 char * name;
4372 int dev = TAPE_NR(inode);
4373 int mode = TAPE_MODE(inode);
4374
4375 /*
4376 * We really want to do nonseekable_open(inode, filp); here, but some
4377 * versions of tar incorrectly call lseek on tapes and bail out if that
4378 * fails. So we disallow pread() and pwrite(), but permit lseeks.
4379 */
4380 filp->f_mode &= ~(FMODE_PREAD | FMODE_PWRITE);
4381
4382 write_lock(&os_scsi_tapes_lock);
4383 if (dev >= osst_max_dev || os_scsi_tapes == NULL ||
4384 (STp = os_scsi_tapes[dev]) == NULL || !STp->device) {
4385 write_unlock(&os_scsi_tapes_lock);
4386 return (-ENXIO);
4387 }
4388
4389 name = tape_name(STp);
4390
4391 if (STp->in_use) {
4392 write_unlock(&os_scsi_tapes_lock);
4393#if DEBUG
4394 printk(OSST_DEB_MSG "%s:D: Device already in use.\n", name);
4395#endif
4396 return (-EBUSY);
4397 }
4398 if (scsi_device_get(STp->device)) {
4399 write_unlock(&os_scsi_tapes_lock);
4400#if DEBUG
4401 printk(OSST_DEB_MSG "%s:D: Failed scsi_device_get.\n", name);
4402#endif
4403 return (-ENXIO);
4404 }
4405 filp->private_data = STp;
4406 STp->in_use = 1;
4407 write_unlock(&os_scsi_tapes_lock);
4408 STp->rew_at_close = TAPE_REWIND(inode);
4409
4410 if( !scsi_block_when_processing_errors(STp->device) ) {
4411 return -ENXIO;
4412 }
4413
4414 if (mode != STp->current_mode) {
4415#if DEBUG
4416 if (debugging)
4417 printk(OSST_DEB_MSG "%s:D: Mode change from %d to %d.\n",
4418 name, STp->current_mode, mode);
4419#endif
4420 new_session = 1;
4421 STp->current_mode = mode;
4422 }
4423 STm = &(STp->modes[STp->current_mode]);
4424
4425 flags = filp->f_flags;
4426 STp->write_prot = ((flags & O_ACCMODE) == O_RDONLY);
4427
4428 STp->raw = TAPE_IS_RAW(inode);
4429 if (STp->raw)
4430 STp->header_ok = 0;
4431
4432 /* Allocate data segments for this device's tape buffer */
4433 if (!enlarge_buffer(STp->buffer, STp->restr_dma)) {
4434 printk(KERN_ERR "%s:E: Unable to allocate memory segments for tape buffer.\n", name);
4435 retval = (-EOVERFLOW);
4436 goto err_out;
4437 }
4438 if (STp->buffer->buffer_size >= OS_FRAME_SIZE) {
4439 for (i = 0, b_size = 0;
4440 (i < STp->buffer->sg_segs) && ((b_size + STp->buffer->sg[i].length) <= OS_DATA_SIZE);
4441 b_size += STp->buffer->sg[i++].length);
Jens Axboe45711f12007-10-22 21:19:53 +02004442 STp->buffer->aux = (os_aux_t *) (page_address(sg_page(&STp->buffer->sg[i])) + OS_DATA_SIZE - b_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004443#if DEBUG
4444 printk(OSST_DEB_MSG "%s:D: b_data points to %p in segment 0 at %p\n", name,
4445 STp->buffer->b_data, page_address(STp->buffer->sg[0].page));
4446 printk(OSST_DEB_MSG "%s:D: AUX points to %p in segment %d at %p\n", name,
4447 STp->buffer->aux, i, page_address(STp->buffer->sg[i].page));
4448#endif
4449 } else {
4450 STp->buffer->aux = NULL; /* this had better never happen! */
4451 printk(KERN_NOTICE "%s:A: Framesize %d too large for buffer.\n", name, OS_FRAME_SIZE);
4452 retval = (-EIO);
4453 goto err_out;
4454 }
4455 STp->buffer->writing = 0;
4456 STp->buffer->syscall_result = 0;
4457 STp->dirty = 0;
4458 for (i=0; i < ST_NBR_PARTITIONS; i++) {
4459 STps = &(STp->ps[i]);
4460 STps->rw = ST_IDLE;
4461 }
4462 STp->ready = ST_READY;
4463#if DEBUG
4464 STp->nbr_waits = STp->nbr_finished = 0;
4465#endif
4466
4467 memset (cmd, 0, MAX_COMMAND_SIZE);
4468 cmd[0] = TEST_UNIT_READY;
4469
4470 SRpnt = osst_do_scsi(NULL, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1);
4471 if (!SRpnt) {
4472 retval = (STp->buffer)->syscall_result; /* FIXME - valid? */
4473 goto err_out;
4474 }
Willem Riede5e6575c2006-02-11 14:46:56 -05004475 if ((SRpnt->sense[0] & 0x70) == 0x70 &&
4476 (SRpnt->sense[2] & 0x0f) == NOT_READY &&
4477 SRpnt->sense[12] == 4 ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004478#if DEBUG
Willem Riede5e6575c2006-02-11 14:46:56 -05004479 printk(OSST_DEB_MSG "%s:D: Unit not ready, cause %x\n", name, SRpnt->sense[13]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004480#endif
4481 if (filp->f_flags & O_NONBLOCK) {
4482 retval = -EAGAIN;
4483 goto err_out;
4484 }
Willem Riede5e6575c2006-02-11 14:46:56 -05004485 if (SRpnt->sense[13] == 2) { /* initialize command required (LOAD) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004486 memset (cmd, 0, MAX_COMMAND_SIZE);
4487 cmd[0] = START_STOP;
4488 cmd[1] = 1;
4489 cmd[4] = 1;
4490 SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE,
4491 STp->timeout, MAX_RETRIES, 1);
4492 }
Willem Riede5e6575c2006-02-11 14:46:56 -05004493 osst_wait_ready(STp, &SRpnt, (SRpnt->sense[13]==1?15:3) * 60, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004494 }
Willem Riede5e6575c2006-02-11 14:46:56 -05004495 if ((SRpnt->sense[0] & 0x70) == 0x70 &&
4496 (SRpnt->sense[2] & 0x0f) == UNIT_ATTENTION) { /* New media? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004497#if DEBUG
4498 printk(OSST_DEB_MSG "%s:D: Unit wants attention\n", name);
4499#endif
4500 STp->header_ok = 0;
4501
4502 for (i=0; i < 10; i++) {
4503
4504 memset (cmd, 0, MAX_COMMAND_SIZE);
4505 cmd[0] = TEST_UNIT_READY;
4506
4507 SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE,
4508 STp->timeout, MAX_RETRIES, 1);
Willem Riede5e6575c2006-02-11 14:46:56 -05004509 if ((SRpnt->sense[0] & 0x70) != 0x70 ||
4510 (SRpnt->sense[2] & 0x0f) != UNIT_ATTENTION)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004511 break;
4512 }
4513
4514 STp->pos_unknown = 0;
4515 STp->partition = STp->new_partition = 0;
4516 if (STp->can_partitions)
4517 STp->nbr_partitions = 1; /* This guess will be updated later if necessary */
4518 for (i=0; i < ST_NBR_PARTITIONS; i++) {
4519 STps = &(STp->ps[i]);
4520 STps->rw = ST_IDLE; /* FIXME - seems to be redundant... */
4521 STps->eof = ST_NOEOF;
4522 STps->at_sm = 0;
4523 STps->last_block_valid = 0;
4524 STps->drv_block = 0;
4525 STps->drv_file = 0 ;
4526 }
4527 new_session = 1;
4528 STp->recover_count = 0;
4529 STp->abort_count = 0;
4530 }
4531 /*
4532 * if we have valid headers from before, and the drive/tape seem untouched,
4533 * open without reconfiguring and re-reading the headers
4534 */
4535 if (!STp->buffer->syscall_result && STp->header_ok &&
Willem Riede5e6575c2006-02-11 14:46:56 -05004536 !SRpnt->result && SRpnt->sense[0] == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004537
4538 memset(cmd, 0, MAX_COMMAND_SIZE);
4539 cmd[0] = MODE_SENSE;
4540 cmd[1] = 8;
4541 cmd[2] = VENDOR_IDENT_PAGE;
4542 cmd[4] = VENDOR_IDENT_PAGE_LENGTH + MODE_HEADER_LENGTH;
4543
4544 SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_FROM_DEVICE, STp->timeout, 0, 1);
4545
4546 if (STp->buffer->syscall_result ||
4547 STp->buffer->b_data[MODE_HEADER_LENGTH + 2] != 'L' ||
4548 STp->buffer->b_data[MODE_HEADER_LENGTH + 3] != 'I' ||
4549 STp->buffer->b_data[MODE_HEADER_LENGTH + 4] != 'N' ||
4550 STp->buffer->b_data[MODE_HEADER_LENGTH + 5] != '4' ) {
4551#if DEBUG
4552 printk(OSST_DEB_MSG "%s:D: Signature was changed to %c%c%c%c\n", name,
4553 STp->buffer->b_data[MODE_HEADER_LENGTH + 2],
4554 STp->buffer->b_data[MODE_HEADER_LENGTH + 3],
4555 STp->buffer->b_data[MODE_HEADER_LENGTH + 4],
4556 STp->buffer->b_data[MODE_HEADER_LENGTH + 5]);
4557#endif
4558 STp->header_ok = 0;
4559 }
4560 i = STp->first_frame_position;
4561 if (STp->header_ok && i == osst_get_frame_position(STp, &SRpnt)) {
4562 if (STp->door_locked == ST_UNLOCKED) {
4563 if (do_door_lock(STp, 1))
4564 printk(KERN_INFO "%s:I: Can't lock drive door\n", name);
4565 else
4566 STp->door_locked = ST_LOCKED_AUTO;
4567 }
4568 if (!STp->frame_in_buffer) {
4569 STp->block_size = (STm->default_blksize > 0) ?
4570 STm->default_blksize : OS_DATA_SIZE;
4571 STp->buffer->buffer_bytes = STp->buffer->read_pointer = 0;
4572 }
4573 STp->buffer->buffer_blocks = OS_DATA_SIZE / STp->block_size;
4574 STp->fast_open = 1;
Willem Riede5e6575c2006-02-11 14:46:56 -05004575 osst_release_request(SRpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004576 return 0;
4577 }
4578#if DEBUG
4579 if (i != STp->first_frame_position)
4580 printk(OSST_DEB_MSG "%s:D: Tape position changed from %d to %d\n",
4581 name, i, STp->first_frame_position);
4582#endif
4583 STp->header_ok = 0;
4584 }
4585 STp->fast_open = 0;
4586
4587 if ((STp->buffer)->syscall_result != 0 && /* in all error conditions except no medium */
Willem Riede5e6575c2006-02-11 14:46:56 -05004588 (SRpnt->sense[2] != 2 || SRpnt->sense[12] != 0x3A) ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004589
4590 memset(cmd, 0, MAX_COMMAND_SIZE);
4591 cmd[0] = MODE_SELECT;
4592 cmd[1] = 0x10;
4593 cmd[4] = 4 + MODE_HEADER_LENGTH;
4594
4595 (STp->buffer)->b_data[0] = cmd[4] - 1;
4596 (STp->buffer)->b_data[1] = 0; /* Medium Type - ignoring */
4597 (STp->buffer)->b_data[2] = 0; /* Reserved */
4598 (STp->buffer)->b_data[3] = 0; /* Block Descriptor Length */
4599 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 0] = 0x3f;
4600 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 1] = 1;
4601 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] = 2;
4602 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] = 3;
4603
4604#if DEBUG
4605 printk(OSST_DEB_MSG "%s:D: Applying soft reset\n", name);
4606#endif
4607 SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_TO_DEVICE, STp->timeout, 0, 1);
4608
4609 STp->header_ok = 0;
4610
4611 for (i=0; i < 10; i++) {
4612
4613 memset (cmd, 0, MAX_COMMAND_SIZE);
4614 cmd[0] = TEST_UNIT_READY;
4615
4616 SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE,
4617 STp->timeout, MAX_RETRIES, 1);
Willem Riede5e6575c2006-02-11 14:46:56 -05004618 if ((SRpnt->sense[0] & 0x70) != 0x70 ||
4619 (SRpnt->sense[2] & 0x0f) == NOT_READY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004620 break;
4621
Willem Riede5e6575c2006-02-11 14:46:56 -05004622 if ((SRpnt->sense[2] & 0x0f) == UNIT_ATTENTION) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004623 STp->pos_unknown = 0;
4624 STp->partition = STp->new_partition = 0;
4625 if (STp->can_partitions)
4626 STp->nbr_partitions = 1; /* This guess will be updated later if necessary */
4627 for (i=0; i < ST_NBR_PARTITIONS; i++) {
4628 STps = &(STp->ps[i]);
4629 STps->rw = ST_IDLE;
4630 STps->eof = ST_NOEOF;
4631 STps->at_sm = 0;
4632 STps->last_block_valid = 0;
4633 STps->drv_block = 0;
4634 STps->drv_file = 0 ;
4635 }
4636 new_session = 1;
4637 }
4638 }
4639 }
4640
4641 if (osst_wait_ready(STp, &SRpnt, 15 * 60, 0)) /* FIXME - not allowed with NOBLOCK */
4642 printk(KERN_INFO "%s:I: Device did not become Ready in open\n", name);
4643
4644 if ((STp->buffer)->syscall_result != 0) {
4645 if ((STp->device)->scsi_level >= SCSI_2 &&
Willem Riede5e6575c2006-02-11 14:46:56 -05004646 (SRpnt->sense[0] & 0x70) == 0x70 &&
4647 (SRpnt->sense[2] & 0x0f) == NOT_READY &&
4648 SRpnt->sense[12] == 0x3a) { /* Check ASC */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004649 STp->ready = ST_NO_TAPE;
4650 } else
4651 STp->ready = ST_NOT_READY;
Willem Riede5e6575c2006-02-11 14:46:56 -05004652 osst_release_request(SRpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004653 SRpnt = NULL;
4654 STp->density = 0; /* Clear the erroneous "residue" */
4655 STp->write_prot = 0;
4656 STp->block_size = 0;
4657 STp->ps[0].drv_file = STp->ps[0].drv_block = (-1);
4658 STp->partition = STp->new_partition = 0;
4659 STp->door_locked = ST_UNLOCKED;
4660 return 0;
4661 }
4662
4663 osst_configure_onstream(STp, &SRpnt);
4664
4665 STp->block_size = STp->raw ? OS_FRAME_SIZE : (
4666 (STm->default_blksize > 0) ? STm->default_blksize : OS_DATA_SIZE);
4667 STp->buffer->buffer_blocks = STp->raw ? 1 : OS_DATA_SIZE / STp->block_size;
4668 STp->buffer->buffer_bytes =
4669 STp->buffer->read_pointer =
4670 STp->frame_in_buffer = 0;
4671
4672#if DEBUG
4673 if (debugging)
4674 printk(OSST_DEB_MSG "%s:D: Block size: %d, frame size: %d, buffer size: %d (%d blocks).\n",
4675 name, STp->block_size, OS_FRAME_SIZE, (STp->buffer)->buffer_size,
4676 (STp->buffer)->buffer_blocks);
4677#endif
4678
4679 if (STp->drv_write_prot) {
4680 STp->write_prot = 1;
4681#if DEBUG
4682 if (debugging)
4683 printk(OSST_DEB_MSG "%s:D: Write protected\n", name);
4684#endif
4685 if ((flags & O_ACCMODE) == O_WRONLY || (flags & O_ACCMODE) == O_RDWR) {
4686 retval = (-EROFS);
4687 goto err_out;
4688 }
4689 }
4690
4691 if (new_session) { /* Change the drive parameters for the new mode */
4692#if DEBUG
4693 if (debugging)
4694 printk(OSST_DEB_MSG "%s:D: New Session\n", name);
4695#endif
4696 STp->density_changed = STp->blksize_changed = 0;
4697 STp->compression_changed = 0;
4698 }
4699
4700 /*
4701 * properly position the tape and check the ADR headers
4702 */
4703 if (STp->door_locked == ST_UNLOCKED) {
4704 if (do_door_lock(STp, 1))
4705 printk(KERN_INFO "%s:I: Can't lock drive door\n", name);
4706 else
4707 STp->door_locked = ST_LOCKED_AUTO;
4708 }
4709
4710 osst_analyze_headers(STp, &SRpnt);
4711
Willem Riede5e6575c2006-02-11 14:46:56 -05004712 osst_release_request(SRpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004713 SRpnt = NULL;
4714
4715 return 0;
4716
4717err_out:
4718 if (SRpnt != NULL)
Willem Riede5e6575c2006-02-11 14:46:56 -05004719 osst_release_request(SRpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004720 normalize_buffer(STp->buffer);
4721 STp->header_ok = 0;
4722 STp->in_use = 0;
4723 scsi_device_put(STp->device);
4724
4725 return retval;
4726}
4727
4728
4729/* Flush the tape buffer before close */
Miklos Szeredi75e1fcc2006-06-23 02:05:12 -07004730static int os_scsi_tape_flush(struct file * filp, fl_owner_t id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004731{
4732 int result = 0, result2;
4733 struct osst_tape * STp = filp->private_data;
4734 struct st_modedef * STm = &(STp->modes[STp->current_mode]);
4735 struct st_partstat * STps = &(STp->ps[STp->partition]);
Willem Riede5e6575c2006-02-11 14:46:56 -05004736 struct osst_request * SRpnt = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004737 char * name = tape_name(STp);
4738
4739 if (file_count(filp) > 1)
4740 return 0;
4741
4742 if ((STps->rw == ST_WRITING || STp->dirty) && !STp->pos_unknown) {
4743 STp->write_type = OS_WRITE_DATA;
4744 result = osst_flush_write_buffer(STp, &SRpnt);
4745 if (result != 0 && result != (-ENOSPC))
4746 goto out;
4747 }
4748 if ( STps->rw >= ST_WRITING && !STp->pos_unknown) {
4749
4750#if DEBUG
4751 if (debugging) {
4752 printk(OSST_DEB_MSG "%s:D: File length %ld bytes.\n",
4753 name, (long)(filp->f_pos));
4754 printk(OSST_DEB_MSG "%s:D: Async write waits %d, finished %d.\n",
4755 name, STp->nbr_waits, STp->nbr_finished);
4756 }
4757#endif
4758 result = osst_write_trailer(STp, &SRpnt, !(STp->rew_at_close));
4759#if DEBUG
4760 if (debugging)
4761 printk(OSST_DEB_MSG "%s:D: Buffer flushed, %d EOF(s) written\n",
4762 name, 1+STp->two_fm);
4763#endif
4764 }
4765 else if (!STp->rew_at_close) {
4766 STps = &(STp->ps[STp->partition]);
4767 if (!STm->sysv || STps->rw != ST_READING) {
4768 if (STp->can_bsr)
4769 result = osst_flush_buffer(STp, &SRpnt, 0); /* this is the default path */
4770 else if (STps->eof == ST_FM_HIT) {
4771 result = cross_eof(STp, &SRpnt, 0);
4772 if (result) {
4773 if (STps->drv_file >= 0)
4774 STps->drv_file++;
4775 STps->drv_block = 0;
4776 STps->eof = ST_FM;
4777 }
4778 else
4779 STps->eof = ST_NOEOF;
4780 }
4781 }
4782 else if ((STps->eof == ST_NOEOF &&
4783 !(result = cross_eof(STp, &SRpnt, 1))) ||
4784 STps->eof == ST_FM_HIT) {
4785 if (STps->drv_file >= 0)
4786 STps->drv_file++;
4787 STps->drv_block = 0;
4788 STps->eof = ST_FM;
4789 }
4790 }
4791
4792out:
4793 if (STp->rew_at_close) {
4794 result2 = osst_position_tape_and_confirm(STp, &SRpnt, STp->first_data_ppos);
4795 STps->drv_file = STps->drv_block = STp->frame_seq_number = STp->logical_blk_num = 0;
4796 if (result == 0 && result2 < 0)
4797 result = result2;
4798 }
Willem Riede5e6575c2006-02-11 14:46:56 -05004799 if (SRpnt) osst_release_request(SRpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004800
4801 if (STp->abort_count || STp->recover_count) {
4802 printk(KERN_INFO "%s:I:", name);
4803 if (STp->abort_count)
4804 printk(" %d unrecovered errors", STp->abort_count);
4805 if (STp->recover_count)
4806 printk(" %d recovered errors", STp->recover_count);
4807 if (STp->write_count)
4808 printk(" in %d frames written", STp->write_count);
4809 if (STp->read_count)
4810 printk(" in %d frames read", STp->read_count);
4811 printk("\n");
4812 STp->recover_count = 0;
4813 STp->abort_count = 0;
4814 }
4815 STp->write_count = 0;
4816 STp->read_count = 0;
4817
4818 return result;
4819}
4820
4821
4822/* Close the device and release it */
4823static int os_scsi_tape_close(struct inode * inode, struct file * filp)
4824{
4825 int result = 0;
4826 struct osst_tape * STp = filp->private_data;
4827
4828 if (STp->door_locked == ST_LOCKED_AUTO)
4829 do_door_lock(STp, 0);
4830
4831 if (STp->raw)
4832 STp->header_ok = 0;
4833
4834 normalize_buffer(STp->buffer);
4835 write_lock(&os_scsi_tapes_lock);
4836 STp->in_use = 0;
4837 write_unlock(&os_scsi_tapes_lock);
4838
4839 scsi_device_put(STp->device);
4840
4841 return result;
4842}
4843
4844
4845/* The ioctl command */
4846static int osst_ioctl(struct inode * inode,struct file * file,
4847 unsigned int cmd_in, unsigned long arg)
4848{
Eric Sesterhenn45223fd2006-09-25 16:59:08 -07004849 int i, cmd_nr, cmd_type, blk, retval = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004850 struct st_modedef * STm;
4851 struct st_partstat * STps;
Willem Riede5e6575c2006-02-11 14:46:56 -05004852 struct osst_request * SRpnt = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004853 struct osst_tape * STp = file->private_data;
4854 char * name = tape_name(STp);
4855 void __user * p = (void __user *)arg;
4856
Matthias Kaehlcke4390e602007-08-10 14:50:44 -07004857 if (mutex_lock_interruptible(&STp->lock))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004858 return -ERESTARTSYS;
4859
4860#if DEBUG
4861 if (debugging && !STp->in_use) {
4862 printk(OSST_DEB_MSG "%s:D: Incorrect device.\n", name);
4863 retval = (-EIO);
4864 goto out;
4865 }
4866#endif
4867 STm = &(STp->modes[STp->current_mode]);
4868 STps = &(STp->ps[STp->partition]);
4869
4870 /*
4871 * If we are in the middle of error recovery, don't let anyone
4872 * else try and use this device. Also, if error recovery fails, it
4873 * may try and take the device offline, in which case all further
4874 * access to the device is prohibited.
4875 */
4876 if( !scsi_block_when_processing_errors(STp->device) ) {
4877 retval = (-ENXIO);
4878 goto out;
4879 }
4880
4881 cmd_type = _IOC_TYPE(cmd_in);
4882 cmd_nr = _IOC_NR(cmd_in);
4883#if DEBUG
4884 printk(OSST_DEB_MSG "%s:D: Ioctl %d,%d in %s mode\n", name,
4885 cmd_type, cmd_nr, STp->raw?"raw":"normal");
4886#endif
4887 if (cmd_type == _IOC_TYPE(MTIOCTOP) && cmd_nr == _IOC_NR(MTIOCTOP)) {
4888 struct mtop mtc;
4889 int auto_weof = 0;
4890
4891 if (_IOC_SIZE(cmd_in) != sizeof(mtc)) {
4892 retval = (-EINVAL);
4893 goto out;
4894 }
4895
4896 i = copy_from_user((char *) &mtc, p, sizeof(struct mtop));
4897 if (i) {
4898 retval = (-EFAULT);
4899 goto out;
4900 }
4901
4902 if (mtc.mt_op == MTSETDRVBUFFER && !capable(CAP_SYS_ADMIN)) {
4903 printk(KERN_WARNING "%s:W: MTSETDRVBUFFER only allowed for root.\n", name);
4904 retval = (-EPERM);
4905 goto out;
4906 }
4907
4908 if (!STm->defined && (mtc.mt_op != MTSETDRVBUFFER && (mtc.mt_count & MT_ST_OPTIONS) == 0)) {
4909 retval = (-ENXIO);
4910 goto out;
4911 }
4912
4913 if (!STp->pos_unknown) {
4914
4915 if (STps->eof == ST_FM_HIT) {
4916 if (mtc.mt_op == MTFSF || mtc.mt_op == MTFSFM|| mtc.mt_op == MTEOM) {
4917 mtc.mt_count -= 1;
4918 if (STps->drv_file >= 0)
4919 STps->drv_file += 1;
4920 }
4921 else if (mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM) {
4922 mtc.mt_count += 1;
4923 if (STps->drv_file >= 0)
4924 STps->drv_file += 1;
4925 }
4926 }
4927
4928 if (mtc.mt_op == MTSEEK) {
4929 /* Old position must be restored if partition will be changed */
4930 i = !STp->can_partitions || (STp->new_partition != STp->partition);
4931 }
4932 else {
4933 i = mtc.mt_op == MTREW || mtc.mt_op == MTOFFL ||
4934 mtc.mt_op == MTRETEN || mtc.mt_op == MTEOM ||
4935 mtc.mt_op == MTLOCK || mtc.mt_op == MTLOAD ||
4936 mtc.mt_op == MTFSF || mtc.mt_op == MTFSFM ||
4937 mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM ||
4938 mtc.mt_op == MTCOMPRESSION;
4939 }
4940 i = osst_flush_buffer(STp, &SRpnt, i);
4941 if (i < 0) {
4942 retval = i;
4943 goto out;
4944 }
4945 }
4946 else {
4947 /*
4948 * If there was a bus reset, block further access
4949 * to this device. If the user wants to rewind the tape,
4950 * then reset the flag and allow access again.
4951 */
4952 if(mtc.mt_op != MTREW &&
4953 mtc.mt_op != MTOFFL &&
4954 mtc.mt_op != MTRETEN &&
4955 mtc.mt_op != MTERASE &&
4956 mtc.mt_op != MTSEEK &&
4957 mtc.mt_op != MTEOM) {
4958 retval = (-EIO);
4959 goto out;
4960 }
4961 reset_state(STp);
4962 /* remove this when the midlevel properly clears was_reset */
4963 STp->device->was_reset = 0;
4964 }
4965
4966 if (mtc.mt_op != MTCOMPRESSION && mtc.mt_op != MTLOCK &&
4967 mtc.mt_op != MTNOP && mtc.mt_op != MTSETBLK &&
4968 mtc.mt_op != MTSETDENSITY && mtc.mt_op != MTSETDRVBUFFER &&
4969 mtc.mt_op != MTMKPART && mtc.mt_op != MTSETPART &&
4970 mtc.mt_op != MTWEOF && mtc.mt_op != MTWSM ) {
4971
4972 /*
4973 * The user tells us to move to another position on the tape.
4974 * If we were appending to the tape content, that would leave
4975 * the tape without proper end, in that case write EOD and
4976 * update the header to reflect its position.
4977 */
4978#if DEBUG
4979 printk(KERN_WARNING "%s:D: auto_weod %s at ffp=%d,efp=%d,fsn=%d,lbn=%d,fn=%d,bn=%d\n", name,
4980 STps->rw >= ST_WRITING ? "write" : STps->rw == ST_READING ? "read" : "idle",
4981 STp->first_frame_position, STp->eod_frame_ppos, STp->frame_seq_number,
4982 STp->logical_blk_num, STps->drv_file, STps->drv_block );
4983#endif
4984 if (STps->rw >= ST_WRITING && STp->first_frame_position >= STp->eod_frame_ppos) {
4985 auto_weof = ((STp->write_type != OS_WRITE_NEW_MARK) &&
4986 !(mtc.mt_op == MTREW || mtc.mt_op == MTOFFL));
4987 i = osst_write_trailer(STp, &SRpnt,
4988 !(mtc.mt_op == MTREW || mtc.mt_op == MTOFFL));
4989#if DEBUG
4990 printk(KERN_WARNING "%s:D: post trailer xeof=%d,ffp=%d,efp=%d,fsn=%d,lbn=%d,fn=%d,bn=%d\n",
4991 name, auto_weof, STp->first_frame_position, STp->eod_frame_ppos,
4992 STp->frame_seq_number, STp->logical_blk_num, STps->drv_file, STps->drv_block );
4993#endif
4994 if (i < 0) {
4995 retval = i;
4996 goto out;
4997 }
4998 }
4999 STps->rw = ST_IDLE;
5000 }
5001
5002 if (mtc.mt_op == MTOFFL && STp->door_locked != ST_UNLOCKED)
5003 do_door_lock(STp, 0); /* Ignore result! */
5004
5005 if (mtc.mt_op == MTSETDRVBUFFER &&
5006 (mtc.mt_count & MT_ST_OPTIONS) != 0) {
5007 retval = osst_set_options(STp, mtc.mt_count);
5008 goto out;
5009 }
5010
5011 if (mtc.mt_op == MTSETPART) {
5012 if (mtc.mt_count >= STp->nbr_partitions)
5013 retval = -EINVAL;
5014 else {
5015 STp->new_partition = mtc.mt_count;
5016 retval = 0;
5017 }
5018 goto out;
5019 }
5020
5021 if (mtc.mt_op == MTMKPART) {
5022 if (!STp->can_partitions) {
5023 retval = (-EINVAL);
5024 goto out;
5025 }
5026 if ((i = osst_int_ioctl(STp, &SRpnt, MTREW, 0)) < 0 /*||
5027 (i = partition_tape(inode, mtc.mt_count)) < 0*/) {
5028 retval = i;
5029 goto out;
5030 }
5031 for (i=0; i < ST_NBR_PARTITIONS; i++) {
5032 STp->ps[i].rw = ST_IDLE;
5033 STp->ps[i].at_sm = 0;
5034 STp->ps[i].last_block_valid = 0;
5035 }
5036 STp->partition = STp->new_partition = 0;
5037 STp->nbr_partitions = 1; /* Bad guess ?-) */
5038 STps->drv_block = STps->drv_file = 0;
5039 retval = 0;
5040 goto out;
5041 }
5042
5043 if (mtc.mt_op == MTSEEK) {
5044 if (STp->raw)
5045 i = osst_set_frame_position(STp, &SRpnt, mtc.mt_count, 0);
5046 else
5047 i = osst_seek_sector(STp, &SRpnt, mtc.mt_count);
5048 if (!STp->can_partitions)
5049 STp->ps[0].rw = ST_IDLE;
5050 retval = i;
5051 goto out;
5052 }
5053
5054 if (mtc.mt_op == MTLOCK || mtc.mt_op == MTUNLOCK) {
5055 retval = do_door_lock(STp, (mtc.mt_op == MTLOCK));
5056 goto out;
5057 }
5058
5059 if (auto_weof)
5060 cross_eof(STp, &SRpnt, 0);
5061
5062 if (mtc.mt_op == MTCOMPRESSION)
5063 retval = -EINVAL; /* OnStream drives don't have compression hardware */
5064 else
5065 /* MTBSF MTBSFM MTBSR MTBSS MTEOM MTERASE MTFSF MTFSFB MTFSR MTFSS
5066 * MTLOAD MTOFFL MTRESET MTRETEN MTREW MTUNLOAD MTWEOF MTWSM */
5067 retval = osst_int_ioctl(STp, &SRpnt, mtc.mt_op, mtc.mt_count);
5068 goto out;
5069 }
5070
5071 if (!STm->defined) {
5072 retval = (-ENXIO);
5073 goto out;
5074 }
5075
5076 if ((i = osst_flush_buffer(STp, &SRpnt, 0)) < 0) {
5077 retval = i;
5078 goto out;
5079 }
5080
5081 if (cmd_type == _IOC_TYPE(MTIOCGET) && cmd_nr == _IOC_NR(MTIOCGET)) {
5082 struct mtget mt_status;
5083
5084 if (_IOC_SIZE(cmd_in) != sizeof(struct mtget)) {
5085 retval = (-EINVAL);
5086 goto out;
5087 }
5088
5089 mt_status.mt_type = MT_ISONSTREAM_SC;
5090 mt_status.mt_erreg = STp->recover_erreg << MT_ST_SOFTERR_SHIFT;
5091 mt_status.mt_dsreg =
5092 ((STp->block_size << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK) |
5093 ((STp->density << MT_ST_DENSITY_SHIFT) & MT_ST_DENSITY_MASK);
5094 mt_status.mt_blkno = STps->drv_block;
5095 mt_status.mt_fileno = STps->drv_file;
5096 if (STp->block_size != 0) {
5097 if (STps->rw == ST_WRITING)
5098 mt_status.mt_blkno += (STp->buffer)->buffer_bytes / STp->block_size;
5099 else if (STps->rw == ST_READING)
5100 mt_status.mt_blkno -= ((STp->buffer)->buffer_bytes +
5101 STp->block_size - 1) / STp->block_size;
5102 }
5103
5104 mt_status.mt_gstat = 0;
5105 if (STp->drv_write_prot)
5106 mt_status.mt_gstat |= GMT_WR_PROT(0xffffffff);
5107 if (mt_status.mt_blkno == 0) {
5108 if (mt_status.mt_fileno == 0)
5109 mt_status.mt_gstat |= GMT_BOT(0xffffffff);
5110 else
5111 mt_status.mt_gstat |= GMT_EOF(0xffffffff);
5112 }
5113 mt_status.mt_resid = STp->partition;
5114 if (STps->eof == ST_EOM_OK || STps->eof == ST_EOM_ERROR)
5115 mt_status.mt_gstat |= GMT_EOT(0xffffffff);
5116 else if (STps->eof >= ST_EOM_OK)
5117 mt_status.mt_gstat |= GMT_EOD(0xffffffff);
5118 if (STp->density == 1)
5119 mt_status.mt_gstat |= GMT_D_800(0xffffffff);
5120 else if (STp->density == 2)
5121 mt_status.mt_gstat |= GMT_D_1600(0xffffffff);
5122 else if (STp->density == 3)
5123 mt_status.mt_gstat |= GMT_D_6250(0xffffffff);
5124 if (STp->ready == ST_READY)
5125 mt_status.mt_gstat |= GMT_ONLINE(0xffffffff);
5126 if (STp->ready == ST_NO_TAPE)
5127 mt_status.mt_gstat |= GMT_DR_OPEN(0xffffffff);
5128 if (STps->at_sm)
5129 mt_status.mt_gstat |= GMT_SM(0xffffffff);
5130 if (STm->do_async_writes || (STm->do_buffer_writes && STp->block_size != 0) ||
5131 STp->drv_buffer != 0)
5132 mt_status.mt_gstat |= GMT_IM_REP_EN(0xffffffff);
5133
5134 i = copy_to_user(p, &mt_status, sizeof(struct mtget));
5135 if (i) {
5136 retval = (-EFAULT);
5137 goto out;
5138 }
5139
5140 STp->recover_erreg = 0; /* Clear after read */
5141 retval = 0;
5142 goto out;
5143 } /* End of MTIOCGET */
5144
5145 if (cmd_type == _IOC_TYPE(MTIOCPOS) && cmd_nr == _IOC_NR(MTIOCPOS)) {
5146 struct mtpos mt_pos;
5147
5148 if (_IOC_SIZE(cmd_in) != sizeof(struct mtpos)) {
5149 retval = (-EINVAL);
5150 goto out;
5151 }
5152 if (STp->raw)
5153 blk = osst_get_frame_position(STp, &SRpnt);
5154 else
5155 blk = osst_get_sector(STp, &SRpnt);
5156 if (blk < 0) {
5157 retval = blk;
5158 goto out;
5159 }
5160 mt_pos.mt_blkno = blk;
5161 i = copy_to_user(p, &mt_pos, sizeof(struct mtpos));
5162 if (i)
5163 retval = -EFAULT;
5164 goto out;
5165 }
Willem Riede5e6575c2006-02-11 14:46:56 -05005166 if (SRpnt) osst_release_request(SRpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005167
Matthias Kaehlcke4390e602007-08-10 14:50:44 -07005168 mutex_unlock(&STp->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005169
5170 return scsi_ioctl(STp->device, cmd_in, p);
5171
5172out:
Willem Riede5e6575c2006-02-11 14:46:56 -05005173 if (SRpnt) osst_release_request(SRpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005174
Matthias Kaehlcke4390e602007-08-10 14:50:44 -07005175 mutex_unlock(&STp->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005176
5177 return retval;
5178}
5179
5180#ifdef CONFIG_COMPAT
5181static long osst_compat_ioctl(struct file * file, unsigned int cmd_in, unsigned long arg)
5182{
5183 struct osst_tape *STp = file->private_data;
5184 struct scsi_device *sdev = STp->device;
5185 int ret = -ENOIOCTLCMD;
5186 if (sdev->host->hostt->compat_ioctl) {
5187
5188 ret = sdev->host->hostt->compat_ioctl(sdev, cmd_in, (void __user *)arg);
5189
5190 }
5191 return ret;
5192}
5193#endif
5194
5195
5196
5197/* Memory handling routines */
5198
5199/* Try to allocate a new tape buffer skeleton. Caller must not hold os_scsi_tapes_lock */
5200static struct osst_buffer * new_tape_buffer( int from_initialization, int need_dma, int max_sg )
5201{
Al Viroc53033f2005-10-21 03:22:08 -04005202 int i;
5203 gfp_t priority;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005204 struct osst_buffer *tb;
5205
5206 if (from_initialization)
5207 priority = GFP_ATOMIC;
5208 else
5209 priority = GFP_KERNEL;
5210
5211 i = sizeof(struct osst_buffer) + (osst_max_sg_segs - 1) * sizeof(struct scatterlist);
Jeff Garzik37e03332006-10-04 05:23:04 -04005212 tb = kzalloc(i, priority);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005213 if (!tb) {
5214 printk(KERN_NOTICE "osst :I: Can't allocate new tape buffer.\n");
5215 return NULL;
5216 }
Jeff Garzik37e03332006-10-04 05:23:04 -04005217
Linus Torvalds1da177e2005-04-16 15:20:36 -07005218 tb->sg_segs = tb->orig_sg_segs = 0;
5219 tb->use_sg = max_sg;
5220 tb->in_use = 1;
5221 tb->dma = need_dma;
5222 tb->buffer_size = 0;
5223#if DEBUG
5224 if (debugging)
5225 printk(OSST_DEB_MSG
5226 "osst :D: Allocated tape buffer skeleton (%d bytes, %d segments, dma: %d).\n",
5227 i, max_sg, need_dma);
5228#endif
5229 return tb;
5230}
5231
5232/* Try to allocate a temporary (while a user has the device open) enlarged tape buffer */
5233static int enlarge_buffer(struct osst_buffer *STbuffer, int need_dma)
5234{
Al Viroc53033f2005-10-21 03:22:08 -04005235 int segs, nbr, max_segs, b_size, order, got;
5236 gfp_t priority;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005237
5238 if (STbuffer->buffer_size >= OS_FRAME_SIZE)
5239 return 1;
5240
5241 if (STbuffer->sg_segs) {
5242 printk(KERN_WARNING "osst :A: Buffer not previously normalized.\n");
5243 normalize_buffer(STbuffer);
5244 }
5245 /* See how many segments we can use -- need at least two */
5246 nbr = max_segs = STbuffer->use_sg;
5247 if (nbr <= 2)
5248 return 0;
5249
5250 priority = GFP_KERNEL /* | __GFP_NOWARN */;
5251 if (need_dma)
5252 priority |= GFP_DMA;
5253
5254 /* Try to allocate the first segment up to OS_DATA_SIZE and the others
5255 big enough to reach the goal (code assumes no segments in place) */
5256 for (b_size = OS_DATA_SIZE, order = OSST_FIRST_ORDER; b_size >= PAGE_SIZE; order--, b_size /= 2) {
Jens Axboe45711f12007-10-22 21:19:53 +02005257 struct page *page = alloc_pages(priority, order);
5258
Linus Torvalds1da177e2005-04-16 15:20:36 -07005259 STbuffer->sg[0].offset = 0;
Jens Axboe45711f12007-10-22 21:19:53 +02005260 if (page != NULL) {
Jens Axboe642f1492007-10-24 11:20:47 +02005261 sg_set_page(&STbuffer->sg[0], page, b_size, 0);
Jens Axboe45711f12007-10-22 21:19:53 +02005262 STbuffer->b_data = page_address(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005263 break;
5264 }
5265 }
Jens Axboe45711f12007-10-22 21:19:53 +02005266 if (sg_page(&STbuffer->sg[0]) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005267 printk(KERN_NOTICE "osst :I: Can't allocate tape buffer main segment.\n");
5268 return 0;
5269 }
5270 /* Got initial segment of 'bsize,order', continue with same size if possible, except for AUX */
5271 for (segs=STbuffer->sg_segs=1, got=b_size;
5272 segs < max_segs && got < OS_FRAME_SIZE; ) {
Jens Axboe45711f12007-10-22 21:19:53 +02005273 struct page *page = alloc_pages(priority, (OS_FRAME_SIZE - got <= PAGE_SIZE) ? 0 : order);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005274 STbuffer->sg[segs].offset = 0;
Jens Axboe45711f12007-10-22 21:19:53 +02005275 if (page == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005276 if (OS_FRAME_SIZE - got <= (max_segs - segs) * b_size / 2 && order) {
5277 b_size /= 2; /* Large enough for the rest of the buffers */
5278 order--;
5279 continue;
5280 }
5281 printk(KERN_WARNING "osst :W: Failed to enlarge buffer to %d bytes.\n",
5282 OS_FRAME_SIZE);
5283#if DEBUG
5284 STbuffer->buffer_size = got;
5285#endif
5286 normalize_buffer(STbuffer);
5287 return 0;
5288 }
Jens Axboe642f1492007-10-24 11:20:47 +02005289 sg_set_page(&STbuffer->sg[segs], page, (OS_FRAME_SIZE - got <= PAGE_SIZE / 2) ? (OS_FRAME_SIZE - got) : b_size, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005290 got += STbuffer->sg[segs].length;
5291 STbuffer->buffer_size = got;
5292 STbuffer->sg_segs = ++segs;
5293 }
5294#if DEBUG
5295 if (debugging) {
5296 printk(OSST_DEB_MSG
5297 "osst :D: Expanded tape buffer (%d bytes, %d->%d segments, dma: %d, at: %p).\n",
5298 got, STbuffer->orig_sg_segs, STbuffer->sg_segs, need_dma, STbuffer->b_data);
5299 printk(OSST_DEB_MSG
5300 "osst :D: segment sizes: first %d at %p, last %d bytes at %p.\n",
5301 STbuffer->sg[0].length, page_address(STbuffer->sg[0].page),
5302 STbuffer->sg[segs-1].length, page_address(STbuffer->sg[segs-1].page));
5303 }
5304#endif
5305
5306 return 1;
5307}
5308
5309
5310/* Release the segments */
5311static void normalize_buffer(struct osst_buffer *STbuffer)
5312{
5313 int i, order, b_size;
5314
5315 for (i=0; i < STbuffer->sg_segs; i++) {
5316
5317 for (b_size = PAGE_SIZE, order = 0;
5318 b_size < STbuffer->sg[i].length;
5319 b_size *= 2, order++);
5320
Jens Axboe45711f12007-10-22 21:19:53 +02005321 __free_pages(sg_page(&STbuffer->sg[i]), order);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005322 STbuffer->buffer_size -= STbuffer->sg[i].length;
5323 }
5324#if DEBUG
5325 if (debugging && STbuffer->orig_sg_segs < STbuffer->sg_segs)
5326 printk(OSST_DEB_MSG "osst :D: Buffer at %p normalized to %d bytes (segs %d).\n",
5327 STbuffer->b_data, STbuffer->buffer_size, STbuffer->sg_segs);
5328#endif
5329 STbuffer->sg_segs = STbuffer->orig_sg_segs = 0;
5330}
5331
5332
5333/* Move data from the user buffer to the tape buffer. Returns zero (success) or
5334 negative error code. */
5335static int append_to_buffer(const char __user *ubp, struct osst_buffer *st_bp, int do_count)
5336{
5337 int i, cnt, res, offset;
5338
5339 for (i=0, offset=st_bp->buffer_bytes;
5340 i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++)
5341 offset -= st_bp->sg[i].length;
5342 if (i == st_bp->sg_segs) { /* Should never happen */
5343 printk(KERN_WARNING "osst :A: Append_to_buffer offset overflow.\n");
5344 return (-EIO);
5345 }
5346 for ( ; i < st_bp->sg_segs && do_count > 0; i++) {
5347 cnt = st_bp->sg[i].length - offset < do_count ?
5348 st_bp->sg[i].length - offset : do_count;
Jens Axboe45711f12007-10-22 21:19:53 +02005349 res = copy_from_user(page_address(sg_page(&st_bp->sg[i])) + offset, ubp, cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005350 if (res)
5351 return (-EFAULT);
5352 do_count -= cnt;
5353 st_bp->buffer_bytes += cnt;
5354 ubp += cnt;
5355 offset = 0;
5356 }
5357 if (do_count) { /* Should never happen */
5358 printk(KERN_WARNING "osst :A: Append_to_buffer overflow (left %d).\n",
5359 do_count);
5360 return (-EIO);
5361 }
5362 return 0;
5363}
5364
5365
5366/* Move data from the tape buffer to the user buffer. Returns zero (success) or
5367 negative error code. */
5368static int from_buffer(struct osst_buffer *st_bp, char __user *ubp, int do_count)
5369{
5370 int i, cnt, res, offset;
5371
5372 for (i=0, offset=st_bp->read_pointer;
5373 i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++)
5374 offset -= st_bp->sg[i].length;
5375 if (i == st_bp->sg_segs) { /* Should never happen */
5376 printk(KERN_WARNING "osst :A: From_buffer offset overflow.\n");
5377 return (-EIO);
5378 }
5379 for ( ; i < st_bp->sg_segs && do_count > 0; i++) {
5380 cnt = st_bp->sg[i].length - offset < do_count ?
5381 st_bp->sg[i].length - offset : do_count;
Jens Axboe45711f12007-10-22 21:19:53 +02005382 res = copy_to_user(ubp, page_address(sg_page(&st_bp->sg[i])) + offset, cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005383 if (res)
5384 return (-EFAULT);
5385 do_count -= cnt;
5386 st_bp->buffer_bytes -= cnt;
5387 st_bp->read_pointer += cnt;
5388 ubp += cnt;
5389 offset = 0;
5390 }
5391 if (do_count) { /* Should never happen */
5392 printk(KERN_WARNING "osst :A: From_buffer overflow (left %d).\n", do_count);
5393 return (-EIO);
5394 }
5395 return 0;
5396}
5397
5398/* Sets the tail of the buffer after fill point to zero.
5399 Returns zero (success) or negative error code. */
5400static int osst_zero_buffer_tail(struct osst_buffer *st_bp)
5401{
5402 int i, offset, do_count, cnt;
5403
5404 for (i = 0, offset = st_bp->buffer_bytes;
5405 i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++)
5406 offset -= st_bp->sg[i].length;
5407 if (i == st_bp->sg_segs) { /* Should never happen */
5408 printk(KERN_WARNING "osst :A: Zero_buffer offset overflow.\n");
5409 return (-EIO);
5410 }
5411 for (do_count = OS_DATA_SIZE - st_bp->buffer_bytes;
5412 i < st_bp->sg_segs && do_count > 0; i++) {
5413 cnt = st_bp->sg[i].length - offset < do_count ?
5414 st_bp->sg[i].length - offset : do_count ;
Jens Axboe45711f12007-10-22 21:19:53 +02005415 memset(page_address(sg_page(&st_bp->sg[i])) + offset, 0, cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005416 do_count -= cnt;
5417 offset = 0;
5418 }
5419 if (do_count) { /* Should never happen */
5420 printk(KERN_WARNING "osst :A: Zero_buffer overflow (left %d).\n", do_count);
5421 return (-EIO);
5422 }
5423 return 0;
5424}
5425
5426/* Copy a osst 32K chunk of memory into the buffer.
5427 Returns zero (success) or negative error code. */
5428static int osst_copy_to_buffer(struct osst_buffer *st_bp, unsigned char *ptr)
5429{
5430 int i, cnt, do_count = OS_DATA_SIZE;
5431
5432 for (i = 0; i < st_bp->sg_segs && do_count > 0; i++) {
5433 cnt = st_bp->sg[i].length < do_count ?
5434 st_bp->sg[i].length : do_count ;
Jens Axboe45711f12007-10-22 21:19:53 +02005435 memcpy(page_address(sg_page(&st_bp->sg[i])), ptr, cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005436 do_count -= cnt;
5437 ptr += cnt;
5438 }
5439 if (do_count || i != st_bp->sg_segs-1) { /* Should never happen */
5440 printk(KERN_WARNING "osst :A: Copy_to_buffer overflow (left %d at sg %d).\n",
5441 do_count, i);
5442 return (-EIO);
5443 }
5444 return 0;
5445}
5446
5447/* Copy a osst 32K chunk of memory from the buffer.
5448 Returns zero (success) or negative error code. */
5449static int osst_copy_from_buffer(struct osst_buffer *st_bp, unsigned char *ptr)
5450{
5451 int i, cnt, do_count = OS_DATA_SIZE;
5452
5453 for (i = 0; i < st_bp->sg_segs && do_count > 0; i++) {
5454 cnt = st_bp->sg[i].length < do_count ?
5455 st_bp->sg[i].length : do_count ;
Jens Axboe45711f12007-10-22 21:19:53 +02005456 memcpy(ptr, page_address(sg_page(&st_bp->sg[i])), cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005457 do_count -= cnt;
5458 ptr += cnt;
5459 }
5460 if (do_count || i != st_bp->sg_segs-1) { /* Should never happen */
5461 printk(KERN_WARNING "osst :A: Copy_from_buffer overflow (left %d at sg %d).\n",
5462 do_count, i);
5463 return (-EIO);
5464 }
5465 return 0;
5466}
5467
5468
5469/* Module housekeeping */
5470
5471static void validate_options (void)
5472{
5473 if (max_dev > 0)
5474 osst_max_dev = max_dev;
5475 if (write_threshold_kbs > 0)
5476 osst_write_threshold = write_threshold_kbs * ST_KILOBYTE;
5477 if (osst_write_threshold > osst_buffer_size)
5478 osst_write_threshold = osst_buffer_size;
5479 if (max_sg_segs >= OSST_FIRST_SG)
5480 osst_max_sg_segs = max_sg_segs;
5481#if DEBUG
5482 printk(OSST_DEB_MSG "osst :D: max tapes %d, write threshold %d, max s/g segs %d.\n",
5483 osst_max_dev, osst_write_threshold, osst_max_sg_segs);
5484#endif
5485}
5486
5487#ifndef MODULE
5488/* Set the boot options. Syntax: osst=xxx,yyy,...
5489 where xxx is write threshold in 1024 byte blocks,
5490 and yyy is number of s/g segments to use. */
5491static int __init osst_setup (char *str)
5492{
5493 int i, ints[5];
5494 char *stp;
5495
5496 stp = get_options(str, ARRAY_SIZE(ints), ints);
Tobias Klauser6391a112006-06-08 22:23:48 -07005497
Linus Torvalds1da177e2005-04-16 15:20:36 -07005498 if (ints[0] > 0) {
5499 for (i = 0; i < ints[0] && i < ARRAY_SIZE(parms); i++)
5500 *parms[i].val = ints[i + 1];
5501 } else {
5502 while (stp != NULL) {
5503 for (i = 0; i < ARRAY_SIZE(parms); i++) {
5504 int len = strlen(parms[i].name);
5505 if (!strncmp(stp, parms[i].name, len) &&
5506 (*(stp + len) == ':' || *(stp + len) == '=')) {
5507 *parms[i].val =
5508 simple_strtoul(stp + len + 1, NULL, 0);
5509 break;
5510 }
5511 }
Tobias Klauser6391a112006-06-08 22:23:48 -07005512 if (i >= ARRAY_SIZE(parms))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005513 printk(KERN_INFO "osst :I: Illegal parameter in '%s'\n",
5514 stp);
5515 stp = strchr(stp, ',');
5516 if (stp)
5517 stp++;
5518 }
5519 }
5520
5521 return 1;
5522}
5523
5524__setup("osst=", osst_setup);
5525
5526#endif
5527
Arjan van de Ven00977a52007-02-12 00:55:34 -08005528static const struct file_operations osst_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005529 .owner = THIS_MODULE,
5530 .read = osst_read,
5531 .write = osst_write,
5532 .ioctl = osst_ioctl,
5533#ifdef CONFIG_COMPAT
5534 .compat_ioctl = osst_compat_ioctl,
5535#endif
5536 .open = os_scsi_tape_open,
5537 .flush = os_scsi_tape_flush,
5538 .release = os_scsi_tape_close,
5539};
5540
5541static int osst_supports(struct scsi_device * SDp)
5542{
5543 struct osst_support_data {
5544 char *vendor;
5545 char *model;
5546 char *rev;
5547 char *driver_hint; /* Name of the correct driver, NULL if unknown */
5548 };
5549
5550static struct osst_support_data support_list[] = {
5551 /* {"XXX", "Yy-", "", NULL}, example */
5552 SIGS_FROM_OSST,
5553 {NULL, }};
5554
5555 struct osst_support_data *rp;
5556
5557 /* We are willing to drive OnStream SC-x0 as well as the
5558 * * IDE, ParPort, FireWire, USB variants, if accessible by
5559 * * emulation layer (ide-scsi, usb-storage, ...) */
5560
5561 for (rp=&(support_list[0]); rp->vendor != NULL; rp++)
5562 if (!strncmp(rp->vendor, SDp->vendor, strlen(rp->vendor)) &&
5563 !strncmp(rp->model, SDp->model, strlen(rp->model)) &&
5564 !strncmp(rp->rev, SDp->rev, strlen(rp->rev)))
5565 return 1;
5566 return 0;
5567}
5568
5569/*
5570 * sysfs support for osst driver parameter information
5571 */
5572
5573static ssize_t osst_version_show(struct device_driver *ddd, char *buf)
5574{
5575 return snprintf(buf, PAGE_SIZE, "%s\n", osst_version);
5576}
5577
5578static DRIVER_ATTR(version, S_IRUGO, osst_version_show, NULL);
5579
Robert P. J. Day405ae7d2007-02-17 19:13:42 +01005580static int osst_create_sysfs_files(struct device_driver *sysfs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005581{
Robert P. J. Day405ae7d2007-02-17 19:13:42 +01005582 return driver_create_file(sysfs, &driver_attr_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005583}
5584
Robert P. J. Day405ae7d2007-02-17 19:13:42 +01005585static void osst_remove_sysfs_files(struct device_driver *sysfs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005586{
Robert P. J. Day405ae7d2007-02-17 19:13:42 +01005587 driver_remove_file(sysfs, &driver_attr_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005588}
5589
5590/*
5591 * sysfs support for accessing ADR header information
5592 */
5593
Tony Jonesee959b02008-02-22 00:13:36 +01005594static ssize_t osst_adr_rev_show(struct device *dev,
5595 struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005596{
Tony Jonesee959b02008-02-22 00:13:36 +01005597 struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005598 ssize_t l = 0;
5599
5600 if (STp && STp->header_ok && STp->linux_media)
5601 l = snprintf(buf, PAGE_SIZE, "%d.%d\n", STp->header_cache->major_rev, STp->header_cache->minor_rev);
5602 return l;
5603}
5604
Tony Jonesee959b02008-02-22 00:13:36 +01005605DEVICE_ATTR(ADR_rev, S_IRUGO, osst_adr_rev_show, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005606
Tony Jonesee959b02008-02-22 00:13:36 +01005607static ssize_t osst_linux_media_version_show(struct device *dev,
5608 struct device_attribute *attr,
5609 char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005610{
Tony Jonesee959b02008-02-22 00:13:36 +01005611 struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005612 ssize_t l = 0;
5613
5614 if (STp && STp->header_ok && STp->linux_media)
5615 l = snprintf(buf, PAGE_SIZE, "LIN%d\n", STp->linux_media_version);
5616 return l;
5617}
5618
Tony Jonesee959b02008-02-22 00:13:36 +01005619DEVICE_ATTR(media_version, S_IRUGO, osst_linux_media_version_show, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005620
Tony Jonesee959b02008-02-22 00:13:36 +01005621static ssize_t osst_capacity_show(struct device *dev,
5622 struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005623{
Tony Jonesee959b02008-02-22 00:13:36 +01005624 struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005625 ssize_t l = 0;
5626
5627 if (STp && STp->header_ok && STp->linux_media)
5628 l = snprintf(buf, PAGE_SIZE, "%d\n", STp->capacity);
5629 return l;
5630}
5631
Tony Jonesee959b02008-02-22 00:13:36 +01005632DEVICE_ATTR(capacity, S_IRUGO, osst_capacity_show, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005633
Tony Jonesee959b02008-02-22 00:13:36 +01005634static ssize_t osst_first_data_ppos_show(struct device *dev,
5635 struct device_attribute *attr,
5636 char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005637{
Tony Jonesee959b02008-02-22 00:13:36 +01005638 struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005639 ssize_t l = 0;
5640
5641 if (STp && STp->header_ok && STp->linux_media)
5642 l = snprintf(buf, PAGE_SIZE, "%d\n", STp->first_data_ppos);
5643 return l;
5644}
5645
Tony Jonesee959b02008-02-22 00:13:36 +01005646DEVICE_ATTR(BOT_frame, S_IRUGO, osst_first_data_ppos_show, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005647
Tony Jonesee959b02008-02-22 00:13:36 +01005648static ssize_t osst_eod_frame_ppos_show(struct device *dev,
5649 struct device_attribute *attr,
5650 char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005651{
Tony Jonesee959b02008-02-22 00:13:36 +01005652 struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005653 ssize_t l = 0;
5654
5655 if (STp && STp->header_ok && STp->linux_media)
5656 l = snprintf(buf, PAGE_SIZE, "%d\n", STp->eod_frame_ppos);
5657 return l;
5658}
5659
Tony Jonesee959b02008-02-22 00:13:36 +01005660DEVICE_ATTR(EOD_frame, S_IRUGO, osst_eod_frame_ppos_show, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005661
Tony Jonesee959b02008-02-22 00:13:36 +01005662static ssize_t osst_filemark_cnt_show(struct device *dev,
5663 struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005664{
Tony Jonesee959b02008-02-22 00:13:36 +01005665 struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005666 ssize_t l = 0;
5667
5668 if (STp && STp->header_ok && STp->linux_media)
5669 l = snprintf(buf, PAGE_SIZE, "%d\n", STp->filemark_cnt);
5670 return l;
5671}
5672
Tony Jonesee959b02008-02-22 00:13:36 +01005673DEVICE_ATTR(file_count, S_IRUGO, osst_filemark_cnt_show, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005674
gregkh@suse.ded2538782005-03-23 09:55:22 -08005675static struct class *osst_sysfs_class;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005676
Jeff Garzik37e03332006-10-04 05:23:04 -04005677static int osst_sysfs_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005678{
gregkh@suse.ded2538782005-03-23 09:55:22 -08005679 osst_sysfs_class = class_create(THIS_MODULE, "onstream_tape");
Jeff Garzik37e03332006-10-04 05:23:04 -04005680 if (IS_ERR(osst_sysfs_class)) {
5681 printk(KERN_ERR "osst :W: Unable to register sysfs class\n");
5682 return PTR_ERR(osst_sysfs_class);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005683 }
Jeff Garzik37e03332006-10-04 05:23:04 -04005684
5685 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005686}
5687
5688static void osst_sysfs_destroy(dev_t dev)
5689{
Tony Jonesee959b02008-02-22 00:13:36 +01005690 device_destroy(osst_sysfs_class, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005691}
5692
Jeff Garzik37e03332006-10-04 05:23:04 -04005693static int osst_sysfs_add(dev_t dev, struct device *device, struct osst_tape * STp, char * name)
5694{
Tony Jonesee959b02008-02-22 00:13:36 +01005695 struct device *osst_member;
Jeff Garzik37e03332006-10-04 05:23:04 -04005696 int err;
5697
Greg Kroah-Hartman24b42562008-05-16 17:55:12 -07005698 osst_member = device_create_drvdata(osst_sysfs_class, device, dev, STp, "%s", name);
Tony Jonesee959b02008-02-22 00:13:36 +01005699 if (IS_ERR(osst_member)) {
Jeff Garzik37e03332006-10-04 05:23:04 -04005700 printk(KERN_WARNING "osst :W: Unable to add sysfs class member %s\n", name);
Tony Jonesee959b02008-02-22 00:13:36 +01005701 return PTR_ERR(osst_member);
Jeff Garzik37e03332006-10-04 05:23:04 -04005702 }
5703
Tony Jonesee959b02008-02-22 00:13:36 +01005704 err = device_create_file(osst_member, &dev_attr_ADR_rev);
Jeff Garzik37e03332006-10-04 05:23:04 -04005705 if (err)
5706 goto err_out;
Tony Jonesee959b02008-02-22 00:13:36 +01005707 err = device_create_file(osst_member, &dev_attr_media_version);
Jeff Garzik37e03332006-10-04 05:23:04 -04005708 if (err)
5709 goto err_out;
Tony Jonesee959b02008-02-22 00:13:36 +01005710 err = device_create_file(osst_member, &dev_attr_capacity);
Jeff Garzik37e03332006-10-04 05:23:04 -04005711 if (err)
5712 goto err_out;
Tony Jonesee959b02008-02-22 00:13:36 +01005713 err = device_create_file(osst_member, &dev_attr_BOT_frame);
Jeff Garzik37e03332006-10-04 05:23:04 -04005714 if (err)
5715 goto err_out;
Tony Jonesee959b02008-02-22 00:13:36 +01005716 err = device_create_file(osst_member, &dev_attr_EOD_frame);
Jeff Garzik37e03332006-10-04 05:23:04 -04005717 if (err)
5718 goto err_out;
Tony Jonesee959b02008-02-22 00:13:36 +01005719 err = device_create_file(osst_member, &dev_attr_file_count);
Jeff Garzik37e03332006-10-04 05:23:04 -04005720 if (err)
5721 goto err_out;
5722
5723 return 0;
5724
5725err_out:
5726 osst_sysfs_destroy(dev);
5727 return err;
5728}
5729
Linus Torvalds1da177e2005-04-16 15:20:36 -07005730static void osst_sysfs_cleanup(void)
5731{
Jeff Garzik37e03332006-10-04 05:23:04 -04005732 class_destroy(osst_sysfs_class);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005733}
5734
5735/*
5736 * osst startup / cleanup code
5737 */
5738
5739static int osst_probe(struct device *dev)
5740{
5741 struct scsi_device * SDp = to_scsi_device(dev);
5742 struct osst_tape * tpnt;
5743 struct st_modedef * STm;
5744 struct st_partstat * STps;
5745 struct osst_buffer * buffer;
5746 struct gendisk * drive;
Jeff Garzik37e03332006-10-04 05:23:04 -04005747 int i, dev_num, err = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005748
5749 if (SDp->type != TYPE_TAPE || !osst_supports(SDp))
5750 return -ENODEV;
5751
5752 drive = alloc_disk(1);
5753 if (!drive) {
5754 printk(KERN_ERR "osst :E: Out of memory. Device not attached.\n");
5755 return -ENODEV;
5756 }
5757
5758 /* if this is the first attach, build the infrastructure */
5759 write_lock(&os_scsi_tapes_lock);
5760 if (os_scsi_tapes == NULL) {
5761 os_scsi_tapes =
5762 (struct osst_tape **)kmalloc(osst_max_dev * sizeof(struct osst_tape *),
5763 GFP_ATOMIC);
5764 if (os_scsi_tapes == NULL) {
5765 write_unlock(&os_scsi_tapes_lock);
5766 printk(KERN_ERR "osst :E: Unable to allocate array for OnStream SCSI tapes.\n");
5767 goto out_put_disk;
5768 }
5769 for (i=0; i < osst_max_dev; ++i) os_scsi_tapes[i] = NULL;
5770 }
5771
5772 if (osst_nr_dev >= osst_max_dev) {
5773 write_unlock(&os_scsi_tapes_lock);
5774 printk(KERN_ERR "osst :E: Too many tape devices (max. %d).\n", osst_max_dev);
5775 goto out_put_disk;
5776 }
5777
5778 /* find a free minor number */
5779 for (i=0; os_scsi_tapes[i] && i<osst_max_dev; i++);
5780 if(i >= osst_max_dev) panic ("Scsi_devices corrupt (osst)");
5781 dev_num = i;
5782
5783 /* allocate a struct osst_tape for this device */
Mariusz Kozlowskibbfbbbc2007-08-11 10:13:24 +02005784 tpnt = kzalloc(sizeof(struct osst_tape), GFP_ATOMIC);
5785 if (!tpnt) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005786 write_unlock(&os_scsi_tapes_lock);
5787 printk(KERN_ERR "osst :E: Can't allocate device descriptor, device not attached.\n");
5788 goto out_put_disk;
5789 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005790
5791 /* allocate a buffer for this device */
5792 i = SDp->host->sg_tablesize;
5793 if (osst_max_sg_segs < i)
5794 i = osst_max_sg_segs;
5795 buffer = new_tape_buffer(1, SDp->host->unchecked_isa_dma, i);
5796 if (buffer == NULL) {
5797 write_unlock(&os_scsi_tapes_lock);
5798 printk(KERN_ERR "osst :E: Unable to allocate a tape buffer, device not attached.\n");
5799 kfree(tpnt);
5800 goto out_put_disk;
5801 }
5802 os_scsi_tapes[dev_num] = tpnt;
5803 tpnt->buffer = buffer;
5804 tpnt->device = SDp;
5805 drive->private_data = &tpnt->driver;
5806 sprintf(drive->disk_name, "osst%d", dev_num);
5807 tpnt->driver = &osst_template;
5808 tpnt->drive = drive;
5809 tpnt->in_use = 0;
5810 tpnt->capacity = 0xfffff;
5811 tpnt->dirty = 0;
5812 tpnt->drv_buffer = 1; /* Try buffering if no mode sense */
5813 tpnt->restr_dma = (SDp->host)->unchecked_isa_dma;
5814 tpnt->density = 0;
5815 tpnt->do_auto_lock = OSST_AUTO_LOCK;
5816 tpnt->can_bsr = OSST_IN_FILE_POS;
5817 tpnt->can_partitions = 0;
5818 tpnt->two_fm = OSST_TWO_FM;
5819 tpnt->fast_mteom = OSST_FAST_MTEOM;
5820 tpnt->scsi2_logical = OSST_SCSI2LOGICAL; /* FIXME */
5821 tpnt->write_threshold = osst_write_threshold;
5822 tpnt->default_drvbuffer = 0xff; /* No forced buffering */
5823 tpnt->partition = 0;
5824 tpnt->new_partition = 0;
5825 tpnt->nbr_partitions = 0;
5826 tpnt->min_block = 512;
5827 tpnt->max_block = OS_DATA_SIZE;
5828 tpnt->timeout = OSST_TIMEOUT;
5829 tpnt->long_timeout = OSST_LONG_TIMEOUT;
5830
5831 /* Recognize OnStream tapes */
5832 /* We don't need to test for OnStream, as this has been done in detect () */
5833 tpnt->os_fw_rev = osst_parse_firmware_rev (SDp->rev);
5834 tpnt->omit_blklims = 1;
5835
5836 tpnt->poll = (strncmp(SDp->model, "DI-", 3) == 0) ||
5837 (strncmp(SDp->model, "FW-", 3) == 0) || OSST_FW_NEED_POLL(tpnt->os_fw_rev,SDp);
5838 tpnt->frame_in_buffer = 0;
5839 tpnt->header_ok = 0;
5840 tpnt->linux_media = 0;
5841 tpnt->header_cache = NULL;
5842
5843 for (i=0; i < ST_NBR_MODES; i++) {
5844 STm = &(tpnt->modes[i]);
5845 STm->defined = 0;
5846 STm->sysv = OSST_SYSV;
5847 STm->defaults_for_writes = 0;
5848 STm->do_async_writes = OSST_ASYNC_WRITES;
5849 STm->do_buffer_writes = OSST_BUFFER_WRITES;
5850 STm->do_read_ahead = OSST_READ_AHEAD;
5851 STm->default_compression = ST_DONT_TOUCH;
5852 STm->default_blksize = 512;
5853 STm->default_density = (-1); /* No forced density */
5854 }
5855
5856 for (i=0; i < ST_NBR_PARTITIONS; i++) {
5857 STps = &(tpnt->ps[i]);
5858 STps->rw = ST_IDLE;
5859 STps->eof = ST_NOEOF;
5860 STps->at_sm = 0;
5861 STps->last_block_valid = 0;
5862 STps->drv_block = (-1);
5863 STps->drv_file = (-1);
5864 }
5865
5866 tpnt->current_mode = 0;
5867 tpnt->modes[0].defined = 1;
5868 tpnt->modes[2].defined = 1;
5869 tpnt->density_changed = tpnt->compression_changed = tpnt->blksize_changed = 0;
5870
Matthias Kaehlcke4390e602007-08-10 14:50:44 -07005871 mutex_init(&tpnt->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005872 osst_nr_dev++;
5873 write_unlock(&os_scsi_tapes_lock);
Jeff Garzik37e03332006-10-04 05:23:04 -04005874
Linus Torvalds1da177e2005-04-16 15:20:36 -07005875 {
5876 char name[8];
Jeff Garzik37e03332006-10-04 05:23:04 -04005877
Linus Torvalds1da177e2005-04-16 15:20:36 -07005878 /* Rewind entry */
Jeff Garzik37e03332006-10-04 05:23:04 -04005879 err = osst_sysfs_add(MKDEV(OSST_MAJOR, dev_num), dev, tpnt, tape_name(tpnt));
5880 if (err)
5881 goto out_free_buffer;
5882
Linus Torvalds1da177e2005-04-16 15:20:36 -07005883 /* No-rewind entry */
5884 snprintf(name, 8, "%s%s", "n", tape_name(tpnt));
Jeff Garzik37e03332006-10-04 05:23:04 -04005885 err = osst_sysfs_add(MKDEV(OSST_MAJOR, dev_num + 128), dev, tpnt, name);
5886 if (err)
5887 goto out_free_sysfs1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005888 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005889
James Bottomley80e23ba2005-10-29 09:42:17 -05005890 sdev_printk(KERN_INFO, SDp,
James Bottomley9ccfc752005-10-02 11:45:08 -05005891 "osst :I: Attached OnStream %.5s tape as %s\n",
5892 SDp->model, tape_name(tpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005893
5894 return 0;
5895
Jeff Garzik37e03332006-10-04 05:23:04 -04005896out_free_sysfs1:
5897 osst_sysfs_destroy(MKDEV(OSST_MAJOR, dev_num));
5898out_free_buffer:
5899 kfree(buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005900out_put_disk:
5901 put_disk(drive);
Jeff Garzik37e03332006-10-04 05:23:04 -04005902 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005903};
5904
5905static int osst_remove(struct device *dev)
5906{
5907 struct scsi_device * SDp = to_scsi_device(dev);
5908 struct osst_tape * tpnt;
Greg KH5e3c34c2006-01-18 16:17:46 -08005909 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005910
5911 if ((SDp->type != TYPE_TAPE) || (osst_nr_dev <= 0))
5912 return 0;
5913
5914 write_lock(&os_scsi_tapes_lock);
5915 for(i=0; i < osst_max_dev; i++) {
5916 if((tpnt = os_scsi_tapes[i]) && (tpnt->device == SDp)) {
5917 osst_sysfs_destroy(MKDEV(OSST_MAJOR, i));
5918 osst_sysfs_destroy(MKDEV(OSST_MAJOR, i+128));
5919 tpnt->device = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005920 put_disk(tpnt->drive);
5921 os_scsi_tapes[i] = NULL;
5922 osst_nr_dev--;
5923 write_unlock(&os_scsi_tapes_lock);
Jesper Juhlf91012102005-09-10 00:26:54 -07005924 vfree(tpnt->header_cache);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005925 if (tpnt->buffer) {
5926 normalize_buffer(tpnt->buffer);
5927 kfree(tpnt->buffer);
5928 }
5929 kfree(tpnt);
5930 return 0;
5931 }
5932 }
5933 write_unlock(&os_scsi_tapes_lock);
5934 return 0;
5935}
5936
5937static int __init init_osst(void)
5938{
Jeff Garzik37e03332006-10-04 05:23:04 -04005939 int err;
5940
Linus Torvalds1da177e2005-04-16 15:20:36 -07005941 printk(KERN_INFO "osst :I: Tape driver with OnStream support version %s\nosst :I: %s\n", osst_version, cvsid);
5942
5943 validate_options();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005944
Jeff Garzik37e03332006-10-04 05:23:04 -04005945 err = osst_sysfs_init();
5946 if (err)
5947 return err;
5948
5949 err = register_chrdev(OSST_MAJOR, "osst", &osst_fops);
5950 if (err < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005951 printk(KERN_ERR "osst :E: Unable to register major %d for OnStream tapes\n", OSST_MAJOR);
Jeff Garzik37e03332006-10-04 05:23:04 -04005952 goto err_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005953 }
Jeff Garzik37e03332006-10-04 05:23:04 -04005954
5955 err = scsi_register_driver(&osst_template.gendrv);
5956 if (err)
5957 goto err_out_chrdev;
5958
Robert P. J. Day405ae7d2007-02-17 19:13:42 +01005959 err = osst_create_sysfs_files(&osst_template.gendrv);
Jeff Garzik37e03332006-10-04 05:23:04 -04005960 if (err)
5961 goto err_out_scsidrv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005962
5963 return 0;
Jeff Garzik37e03332006-10-04 05:23:04 -04005964
5965err_out_scsidrv:
5966 scsi_unregister_driver(&osst_template.gendrv);
5967err_out_chrdev:
5968 unregister_chrdev(OSST_MAJOR, "osst");
5969err_out:
5970 osst_sysfs_cleanup();
5971 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005972}
5973
5974static void __exit exit_osst (void)
5975{
5976 int i;
5977 struct osst_tape * STp;
5978
Robert P. J. Day405ae7d2007-02-17 19:13:42 +01005979 osst_remove_sysfs_files(&osst_template.gendrv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005980 scsi_unregister_driver(&osst_template.gendrv);
5981 unregister_chrdev(OSST_MAJOR, "osst");
5982 osst_sysfs_cleanup();
5983
5984 if (os_scsi_tapes) {
5985 for (i=0; i < osst_max_dev; ++i) {
5986 if (!(STp = os_scsi_tapes[i])) continue;
5987 /* This is defensive, supposed to happen during detach */
Jesper Juhlf91012102005-09-10 00:26:54 -07005988 vfree(STp->header_cache);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005989 if (STp->buffer) {
5990 normalize_buffer(STp->buffer);
5991 kfree(STp->buffer);
5992 }
5993 put_disk(STp->drive);
5994 kfree(STp);
5995 }
5996 kfree(os_scsi_tapes);
5997 }
5998 printk(KERN_INFO "osst :I: Unloaded.\n");
5999}
6000
6001module_init(init_osst);
6002module_exit(exit_osst);