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