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