blob: e8196c55b633bcedb6cb6f52e2badf5e2867c164 [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>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090041#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070042#include <linux/init.h>
43#include <linux/string.h>
44#include <linux/errno.h>
45#include <linux/mtio.h>
46#include <linux/ioctl.h>
47#include <linux/fcntl.h>
48#include <linux/spinlock.h>
49#include <linux/vmalloc.h>
50#include <linux/blkdev.h>
51#include <linux/moduleparam.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070052#include <linux/delay.h>
Marcelo Feitoza Parisi60c904a2006-03-28 01:56:47 -080053#include <linux/jiffies.h>
Arnd Bergmannc45d15d2010-06-02 14:28:52 +020054#include <linux/mutex.h>
Linus Torvalds7c0f6ba2016-12-24 11:46:01 -080055#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070056#include <asm/dma.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070057
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
Arnd Bergmannc45d15d2010-06-02 14:28:52 +020082static DEFINE_MUTEX(osst_int_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -070083static int max_dev = 0;
84static int write_threshold_kbs = 0;
85static int max_sg_segs = 0;
86
87#ifdef MODULE
88MODULE_AUTHOR("Willem Riede");
89MODULE_DESCRIPTION("OnStream {DI-|FW-|SC-|USB}{30|50} Tape Driver");
90MODULE_LICENSE("GPL");
Rene Hermanf018fa52006-03-08 00:14:20 -080091MODULE_ALIAS_CHARDEV_MAJOR(OSST_MAJOR);
Michael Tokarevd7b8bcb2006-10-27 16:02:37 +040092MODULE_ALIAS_SCSI_DEVICE(TYPE_TAPE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070093
94module_param(max_dev, int, 0444);
95MODULE_PARM_DESC(max_dev, "Maximum number of OnStream Tape Drives to attach (4)");
96
97module_param(write_threshold_kbs, int, 0644);
98MODULE_PARM_DESC(write_threshold_kbs, "Asynchronous write threshold (KB; 32)");
99
100module_param(max_sg_segs, int, 0644);
101MODULE_PARM_DESC(max_sg_segs, "Maximum number of scatter/gather segments to use (9)");
102#else
103static struct osst_dev_parm {
104 char *name;
105 int *val;
106} parms[] __initdata = {
107 { "max_dev", &max_dev },
108 { "write_threshold_kbs", &write_threshold_kbs },
109 { "max_sg_segs", &max_sg_segs }
110};
111#endif
112
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113/* Some default definitions have been moved to osst_options.h */
114#define OSST_BUFFER_SIZE (OSST_BUFFER_BLOCKS * ST_KILOBYTE)
115#define OSST_WRITE_THRESHOLD (OSST_WRITE_THRESHOLD_BLOCKS * ST_KILOBYTE)
116
117/* The buffer size should fit into the 24 bits for length in the
118 6-byte SCSI read and write commands. */
119#if OSST_BUFFER_SIZE >= (2 << 24 - 1)
120#error "Buffer size should not exceed (2 << 24 - 1) bytes!"
121#endif
122
123#if DEBUG
124static int debugging = 1;
125/* uncomment define below to test error recovery */
126// #define OSST_INJECT_ERRORS 1
127#endif
128
129/* Do not retry! The drive firmware already retries when appropriate,
130 and when it tries to tell us something, we had better listen... */
131#define MAX_RETRIES 0
132
133#define NO_TAPE NOT_READY
134
135#define OSST_WAIT_POSITION_COMPLETE (HZ > 200 ? HZ / 200 : 1)
136#define OSST_WAIT_WRITE_COMPLETE (HZ / 12)
137#define OSST_WAIT_LONG_WRITE_COMPLETE (HZ / 2)
138
139#define OSST_TIMEOUT (200 * HZ)
140#define OSST_LONG_TIMEOUT (1800 * HZ)
141
142#define TAPE_NR(x) (iminor(x) & ~(-1 << ST_MODE_SHIFT))
143#define TAPE_MODE(x) ((iminor(x) & ST_MODE_MASK) >> ST_MODE_SHIFT)
144#define TAPE_REWIND(x) ((iminor(x) & 0x80) == 0)
145#define TAPE_IS_RAW(x) (TAPE_MODE(x) & (ST_NBR_MODES >> 1))
146
147/* Internal ioctl to set both density (uppermost 8 bits) and blocksize (lower
148 24 bits) */
149#define SET_DENS_AND_BLK 0x10001
150
151static int osst_buffer_size = OSST_BUFFER_SIZE;
152static int osst_write_threshold = OSST_WRITE_THRESHOLD;
153static int osst_max_sg_segs = OSST_MAX_SG;
154static int osst_max_dev = OSST_MAX_TAPES;
155static int osst_nr_dev;
156
157static struct osst_tape **os_scsi_tapes = NULL;
158static DEFINE_RWLOCK(os_scsi_tapes_lock);
159
160static int modes_defined = 0;
161
162static struct osst_buffer *new_tape_buffer(int, int, int);
163static int enlarge_buffer(struct osst_buffer *, int);
164static void normalize_buffer(struct osst_buffer *);
165static int append_to_buffer(const char __user *, struct osst_buffer *, int);
166static int from_buffer(struct osst_buffer *, char __user *, int);
167static int osst_zero_buffer_tail(struct osst_buffer *);
168static int osst_copy_to_buffer(struct osst_buffer *, unsigned char *);
169static int osst_copy_from_buffer(struct osst_buffer *, unsigned char *);
170
171static int osst_probe(struct device *);
172static int osst_remove(struct device *);
173
174static struct scsi_driver osst_template = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175 .gendrv = {
176 .name = "osst",
Christoph Hellwig3af6b352014-11-12 18:34:51 +0100177 .owner = THIS_MODULE,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178 .probe = osst_probe,
179 .remove = osst_remove,
180 }
181};
182
Willem Riede5e6575c2006-02-11 14:46:56 -0500183static int osst_int_ioctl(struct osst_tape *STp, struct osst_request ** aSRpnt,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184 unsigned int cmd_in, unsigned long arg);
185
Willem Riede5e6575c2006-02-11 14:46:56 -0500186static int osst_set_frame_position(struct osst_tape *STp, struct osst_request ** aSRpnt, int frame, int skip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187
Willem Riede5e6575c2006-02-11 14:46:56 -0500188static int osst_get_frame_position(struct osst_tape *STp, struct osst_request ** aSRpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189
Willem Riede5e6575c2006-02-11 14:46:56 -0500190static int osst_flush_write_buffer(struct osst_tape *STp, struct osst_request ** aSRpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191
Willem Riede5e6575c2006-02-11 14:46:56 -0500192static int osst_write_error_recovery(struct osst_tape * STp, struct osst_request ** aSRpnt, int pending);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193
194static inline char *tape_name(struct osst_tape *tape)
195{
196 return tape->drive->disk_name;
197}
198
199/* Routines that handle the interaction with mid-layer SCSI routines */
200
Willem Riede5e6575c2006-02-11 14:46:56 -0500201
202/* Normalize Sense */
203static void osst_analyze_sense(struct osst_request *SRpnt, struct st_cmdstatus *s)
204{
205 const u8 *ucp;
206 const u8 *sense = SRpnt->sense;
207
208 s->have_sense = scsi_normalize_sense(SRpnt->sense,
209 SCSI_SENSE_BUFFERSIZE, &s->sense_hdr);
210 s->flags = 0;
211
212 if (s->have_sense) {
213 s->deferred = 0;
214 s->remainder_valid =
215 scsi_get_sense_info_fld(sense, SCSI_SENSE_BUFFERSIZE, &s->uremainder64);
216 switch (sense[0] & 0x7f) {
217 case 0x71:
218 s->deferred = 1;
219 case 0x70:
220 s->fixed_format = 1;
221 s->flags = sense[2] & 0xe0;
222 break;
223 case 0x73:
224 s->deferred = 1;
225 case 0x72:
226 s->fixed_format = 0;
227 ucp = scsi_sense_desc_find(sense, SCSI_SENSE_BUFFERSIZE, 4);
228 s->flags = ucp ? (ucp[3] & 0xe0) : 0;
229 break;
230 }
231 }
232}
233
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234/* Convert the result to success code */
Willem Riede5e6575c2006-02-11 14:46:56 -0500235static int osst_chk_result(struct osst_tape * STp, struct osst_request * SRpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236{
237 char *name = tape_name(STp);
Willem Riede5e6575c2006-02-11 14:46:56 -0500238 int result = SRpnt->result;
239 u8 * sense = SRpnt->sense, scode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240#if DEBUG
241 const char *stp;
242#endif
Willem Riede5e6575c2006-02-11 14:46:56 -0500243 struct st_cmdstatus *cmdstatp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244
Willem Riede5e6575c2006-02-11 14:46:56 -0500245 if (!result)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246 return 0;
Willem Riede5e6575c2006-02-11 14:46:56 -0500247
248 cmdstatp = &STp->buffer->cmdstat;
249 osst_analyze_sense(SRpnt, cmdstatp);
250
251 if (cmdstatp->have_sense)
252 scode = STp->buffer->cmdstat.sense_hdr.sense_key;
253 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254 scode = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255#if DEBUG
256 if (debugging) {
Willem Riede5e6575c2006-02-11 14:46:56 -0500257 printk(OSST_DEB_MSG "%s:D: Error: %x, cmd: %x %x %x %x %x %x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 name, result,
Willem Riede5e6575c2006-02-11 14:46:56 -0500259 SRpnt->cmd[0], SRpnt->cmd[1], SRpnt->cmd[2],
260 SRpnt->cmd[3], SRpnt->cmd[4], SRpnt->cmd[5]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261 if (scode) printk(OSST_DEB_MSG "%s:D: Sense: %02x, ASC: %02x, ASCQ: %02x\n",
Hannes Reinecked811b842014-10-24 14:26:45 +0200262 name, scode, sense[12], sense[13]);
Willem Riede5e6575c2006-02-11 14:46:56 -0500263 if (cmdstatp->have_sense)
Hannes Reinecked811b842014-10-24 14:26:45 +0200264 __scsi_print_sense(STp->device, name,
265 SRpnt->sense, SCSI_SENSE_BUFFERSIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266 }
267 else
268#endif
Willem Riede5e6575c2006-02-11 14:46:56 -0500269 if (cmdstatp->have_sense && (
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 scode != NO_SENSE &&
271 scode != RECOVERED_ERROR &&
272/* scode != UNIT_ATTENTION && */
273 scode != BLANK_CHECK &&
274 scode != VOLUME_OVERFLOW &&
Willem Riede5e6575c2006-02-11 14:46:56 -0500275 SRpnt->cmd[0] != MODE_SENSE &&
276 SRpnt->cmd[0] != TEST_UNIT_READY)) { /* Abnormal conditions for tape */
277 if (cmdstatp->have_sense) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278 printk(KERN_WARNING "%s:W: Command with sense data:\n", name);
Hannes Reinecked811b842014-10-24 14:26:45 +0200279 __scsi_print_sense(STp->device, name,
280 SRpnt->sense, SCSI_SENSE_BUFFERSIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281 }
282 else {
283 static int notyetprinted = 1;
284
285 printk(KERN_WARNING
James Bottomleya4976d62009-01-25 15:09:42 -0600286 "%s:W: Warning %x (driver bt 0x%x, host bt 0x%x).\n",
287 name, result, driver_byte(result),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 host_byte(result));
289 if (notyetprinted) {
290 notyetprinted = 0;
291 printk(KERN_INFO
292 "%s:I: This warning may be caused by your scsi controller,\n", name);
293 printk(KERN_INFO
294 "%s:I: it has been reported with some Buslogic cards.\n", name);
295 }
296 }
297 }
298 STp->pos_unknown |= STp->device->was_reset;
299
Willem Riede5e6575c2006-02-11 14:46:56 -0500300 if (cmdstatp->have_sense && scode == RECOVERED_ERROR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 STp->recover_count++;
302 STp->recover_erreg++;
303#if DEBUG
304 if (debugging) {
Willem Riede5e6575c2006-02-11 14:46:56 -0500305 if (SRpnt->cmd[0] == READ_6)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306 stp = "read";
Willem Riede5e6575c2006-02-11 14:46:56 -0500307 else if (SRpnt->cmd[0] == WRITE_6)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308 stp = "write";
309 else
310 stp = "ioctl";
311 printk(OSST_DEB_MSG "%s:D: Recovered %s error (%d).\n", name, stp,
312 STp->recover_count);
313 }
314#endif
315 if ((sense[2] & 0xe0) == 0)
316 return 0;
317 }
318 return (-EIO);
319}
320
321
322/* Wakeup from interrupt */
FUJITA Tomonori26243042008-12-14 00:55:18 +0900323static void osst_end_async(struct request *req, int update)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324{
FUJITA Tomonori26243042008-12-14 00:55:18 +0900325 struct osst_request *SRpnt = req->end_io_data;
Willem Riede5e6575c2006-02-11 14:46:56 -0500326 struct osst_tape *STp = SRpnt->stp;
FUJITA Tomonori26243042008-12-14 00:55:18 +0900327 struct rq_map_data *mdata = &SRpnt->stp->buffer->map_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328
FUJITA Tomonori26243042008-12-14 00:55:18 +0900329 STp->buffer->cmdstat.midlevel_result = SRpnt->result = req->errors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330#if DEBUG
331 STp->write_pending = 0;
332#endif
Willem Riede5e6575c2006-02-11 14:46:56 -0500333 if (SRpnt->waiting)
334 complete(SRpnt->waiting);
FUJITA Tomonori26243042008-12-14 00:55:18 +0900335
336 if (SRpnt->bio) {
337 kfree(mdata->pages);
338 blk_rq_unmap_user(SRpnt->bio);
339 }
340
341 __blk_put_request(req->q, req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342}
343
Willem Riede5e6575c2006-02-11 14:46:56 -0500344/* osst_request memory management */
345static struct osst_request *osst_allocate_request(void)
346{
347 return kzalloc(sizeof(struct osst_request), GFP_KERNEL);
348}
349
350static void osst_release_request(struct osst_request *streq)
351{
352 kfree(streq);
353}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354
FUJITA Tomonori26243042008-12-14 00:55:18 +0900355static int osst_execute(struct osst_request *SRpnt, const unsigned char *cmd,
356 int cmd_len, int data_direction, void *buffer, unsigned bufflen,
357 int use_sg, int timeout, int retries)
358{
359 struct request *req;
360 struct page **pages = NULL;
361 struct rq_map_data *mdata = &SRpnt->stp->buffer->map_data;
362
363 int err = 0;
364 int write = (data_direction == DMA_TO_DEVICE);
365
366 req = blk_get_request(SRpnt->stp->device->request_queue, write, GFP_KERNEL);
Joe Lawrencea492f072014-08-28 08:15:21 -0600367 if (IS_ERR(req))
FUJITA Tomonori26243042008-12-14 00:55:18 +0900368 return DRIVER_ERROR << 24;
369
Jens Axboef27b0872014-06-06 07:57:37 -0600370 blk_rq_set_block_pc(req);
Christoph Hellwige8064022016-10-20 15:12:13 +0200371 req->rq_flags |= RQF_QUIET;
FUJITA Tomonori26243042008-12-14 00:55:18 +0900372
373 SRpnt->bio = NULL;
374
375 if (use_sg) {
376 struct scatterlist *sg, *sgl = (struct scatterlist *)buffer;
377 int i;
378
379 pages = kzalloc(use_sg * sizeof(struct page *), GFP_KERNEL);
380 if (!pages)
381 goto free_req;
382
383 for_each_sg(sgl, sg, use_sg, i)
384 pages[i] = sg_page(sg);
385
386 mdata->null_mapped = 1;
387
388 mdata->page_order = get_order(sgl[0].length);
389 mdata->nr_entries =
390 DIV_ROUND_UP(bufflen, PAGE_SIZE << mdata->page_order);
391 mdata->offset = 0;
392
393 err = blk_rq_map_user(req->q, req, mdata, NULL, bufflen, GFP_KERNEL);
394 if (err) {
395 kfree(pages);
396 goto free_req;
397 }
398 SRpnt->bio = req->bio;
399 mdata->pages = pages;
400
401 } else if (bufflen) {
402 err = blk_rq_map_kern(req->q, req, buffer, bufflen, GFP_KERNEL);
403 if (err)
404 goto free_req;
405 }
406
407 req->cmd_len = cmd_len;
408 memset(req->cmd, 0, BLK_MAX_CDB); /* ATAPI hates garbage after CDB */
409 memcpy(req->cmd, cmd, req->cmd_len);
410 req->sense = SRpnt->sense;
411 req->sense_len = 0;
412 req->timeout = timeout;
413 req->retries = retries;
414 req->end_io_data = SRpnt;
415
416 blk_execute_rq_nowait(req->q, NULL, req, 1, osst_end_async);
417 return 0;
418free_req:
419 blk_put_request(req);
420 return DRIVER_ERROR << 24;
421}
422
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423/* Do the scsi command. Waits until command performed if do_wait is true.
424 Otherwise osst_write_behind_check() is used to check that the command
425 has finished. */
Willem Riede5e6575c2006-02-11 14:46:56 -0500426static struct osst_request * osst_do_scsi(struct osst_request *SRpnt, struct osst_tape *STp,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 unsigned char *cmd, int bytes, int direction, int timeout, int retries, int do_wait)
428{
429 unsigned char *bp;
Willem Riede5e6575c2006-02-11 14:46:56 -0500430 unsigned short use_sg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431#ifdef OSST_INJECT_ERRORS
432 static int inject = 0;
433 static int repeat = 0;
434#endif
Willem Riede5e6575c2006-02-11 14:46:56 -0500435 struct completion *waiting;
436
437 /* if async, make sure there's no command outstanding */
438 if (!do_wait && ((STp->buffer)->last_SRpnt)) {
439 printk(KERN_ERR "%s: Async command already active.\n",
440 tape_name(STp));
441 if (signal_pending(current))
442 (STp->buffer)->syscall_result = (-EINTR);
443 else
444 (STp->buffer)->syscall_result = (-EBUSY);
445 return NULL;
446 }
447
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 if (SRpnt == NULL) {
Willem Riede5e6575c2006-02-11 14:46:56 -0500449 SRpnt = osst_allocate_request();
450 if (SRpnt == NULL) {
451 printk(KERN_ERR "%s: Can't allocate SCSI request.\n",
452 tape_name(STp));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453 if (signal_pending(current))
454 (STp->buffer)->syscall_result = (-EINTR);
455 else
456 (STp->buffer)->syscall_result = (-EBUSY);
457 return NULL;
458 }
Willem Riede5e6575c2006-02-11 14:46:56 -0500459 SRpnt->stp = STp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 }
461
Willem Riede5e6575c2006-02-11 14:46:56 -0500462 /* If async IO, set last_SRpnt. This ptr tells write_behind_check
463 which IO is outstanding. It's nulled out when the IO completes. */
464 if (!do_wait)
465 (STp->buffer)->last_SRpnt = SRpnt;
466
467 waiting = &STp->wait;
468 init_completion(waiting);
469 SRpnt->waiting = waiting;
470
471 use_sg = (bytes > STp->buffer->sg[0].length) ? STp->buffer->use_sg : 0;
472 if (use_sg) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473 bp = (char *)&(STp->buffer->sg[0]);
Willem Riede5e6575c2006-02-11 14:46:56 -0500474 if (STp->buffer->sg_segs < use_sg)
475 use_sg = STp->buffer->sg_segs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476 }
477 else
478 bp = (STp->buffer)->b_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479
Willem Riede5e6575c2006-02-11 14:46:56 -0500480 memcpy(SRpnt->cmd, cmd, sizeof(SRpnt->cmd));
481 STp->buffer->cmdstat.have_sense = 0;
482 STp->buffer->syscall_result = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483
FUJITA Tomonori26243042008-12-14 00:55:18 +0900484 if (osst_execute(SRpnt, cmd, COMMAND_SIZE(cmd[0]), direction, bp, bytes,
485 use_sg, timeout, retries))
Willem Riede5e6575c2006-02-11 14:46:56 -0500486 /* could not allocate the buffer or request was too large */
487 (STp->buffer)->syscall_result = (-EBUSY);
488 else if (do_wait) {
489 wait_for_completion(waiting);
490 SRpnt->waiting = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 STp->buffer->syscall_result = osst_chk_result(STp, SRpnt);
492#ifdef OSST_INJECT_ERRORS
493 if (STp->buffer->syscall_result == 0 &&
494 cmd[0] == READ_6 &&
495 cmd[4] &&
496 ( (++ inject % 83) == 29 ||
497 (STp->first_frame_position == 240
498 /* or STp->read_error_frame to fail again on the block calculated above */ &&
499 ++repeat < 3))) {
500 printk(OSST_DEB_MSG "%s:D: Injecting read error\n", tape_name(STp));
501 STp->buffer->last_result_fatal = 1;
502 }
503#endif
504 }
505 return SRpnt;
506}
507
508
509/* Handle the write-behind checking (downs the semaphore) */
510static void osst_write_behind_check(struct osst_tape *STp)
511{
512 struct osst_buffer * STbuffer;
513
514 STbuffer = STp->buffer;
515
516#if DEBUG
517 if (STp->write_pending)
518 STp->nbr_waits++;
519 else
520 STp->nbr_finished++;
521#endif
522 wait_for_completion(&(STp->wait));
Willem Riede5e6575c2006-02-11 14:46:56 -0500523 STp->buffer->last_SRpnt->waiting = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524
525 STp->buffer->syscall_result = osst_chk_result(STp, STp->buffer->last_SRpnt);
526
Willem Riede5e6575c2006-02-11 14:46:56 -0500527 if (STp->buffer->syscall_result)
528 STp->buffer->syscall_result =
529 osst_write_error_recovery(STp, &(STp->buffer->last_SRpnt), 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 else
531 STp->first_frame_position++;
532
Willem Riede5e6575c2006-02-11 14:46:56 -0500533 osst_release_request(STp->buffer->last_SRpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534
535 if (STbuffer->writing < STbuffer->buffer_bytes)
536 printk(KERN_WARNING "osst :A: write_behind_check: something left in buffer!\n");
537
Willem Riede5e6575c2006-02-11 14:46:56 -0500538 STbuffer->last_SRpnt = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 STbuffer->buffer_bytes -= STbuffer->writing;
540 STbuffer->writing = 0;
541
542 return;
543}
544
545
546
547/* Onstream specific Routines */
548/*
549 * Initialize the OnStream AUX
550 */
551static void osst_init_aux(struct osst_tape * STp, int frame_type, int frame_seq_number,
552 int logical_blk_num, int blk_sz, int blk_cnt)
553{
554 os_aux_t *aux = STp->buffer->aux;
555 os_partition_t *par = &aux->partition;
556 os_dat_t *dat = &aux->dat;
557
558 if (STp->raw) return;
559
560 memset(aux, 0, sizeof(*aux));
561 aux->format_id = htonl(0);
562 memcpy(aux->application_sig, "LIN4", 4);
563 aux->hdwr = htonl(0);
564 aux->frame_type = frame_type;
565
566 switch (frame_type) {
567 case OS_FRAME_TYPE_HEADER:
568 aux->update_frame_cntr = htonl(STp->update_frame_cntr);
569 par->partition_num = OS_CONFIG_PARTITION;
570 par->par_desc_ver = OS_PARTITION_VERSION;
571 par->wrt_pass_cntr = htons(0xffff);
572 /* 0-4 = reserved, 5-9 = header, 2990-2994 = header, 2995-2999 = reserved */
573 par->first_frame_ppos = htonl(0);
574 par->last_frame_ppos = htonl(0xbb7);
575 aux->frame_seq_num = htonl(0);
576 aux->logical_blk_num_high = htonl(0);
577 aux->logical_blk_num = htonl(0);
578 aux->next_mark_ppos = htonl(STp->first_mark_ppos);
579 break;
580 case OS_FRAME_TYPE_DATA:
581 case OS_FRAME_TYPE_MARKER:
582 dat->dat_sz = 8;
583 dat->reserved1 = 0;
584 dat->entry_cnt = 1;
585 dat->reserved3 = 0;
586 dat->dat_list[0].blk_sz = htonl(blk_sz);
587 dat->dat_list[0].blk_cnt = htons(blk_cnt);
588 dat->dat_list[0].flags = frame_type==OS_FRAME_TYPE_MARKER?
589 OS_DAT_FLAGS_MARK:OS_DAT_FLAGS_DATA;
590 dat->dat_list[0].reserved = 0;
591 case OS_FRAME_TYPE_EOD:
592 aux->update_frame_cntr = htonl(0);
593 par->partition_num = OS_DATA_PARTITION;
594 par->par_desc_ver = OS_PARTITION_VERSION;
595 par->wrt_pass_cntr = htons(STp->wrt_pass_cntr);
596 par->first_frame_ppos = htonl(STp->first_data_ppos);
597 par->last_frame_ppos = htonl(STp->capacity);
598 aux->frame_seq_num = htonl(frame_seq_number);
599 aux->logical_blk_num_high = htonl(0);
600 aux->logical_blk_num = htonl(logical_blk_num);
601 break;
602 default: ; /* probably FILL */
603 }
Al Viro95389b82007-02-09 16:39:45 +0000604 aux->filemark_cnt = htonl(STp->filemark_cnt);
605 aux->phys_fm = htonl(0xffffffff);
606 aux->last_mark_ppos = htonl(STp->last_mark_ppos);
607 aux->last_mark_lbn = htonl(STp->last_mark_lbn);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608}
609
610/*
611 * Verify that we have the correct tape frame
612 */
613static int osst_verify_frame(struct osst_tape * STp, int frame_seq_number, int quiet)
614{
615 char * name = tape_name(STp);
616 os_aux_t * aux = STp->buffer->aux;
617 os_partition_t * par = &(aux->partition);
618 struct st_partstat * STps = &(STp->ps[STp->partition]);
619 int blk_cnt, blk_sz, i;
620
621 if (STp->raw) {
622 if (STp->buffer->syscall_result) {
623 for (i=0; i < STp->buffer->sg_segs; i++)
Jens Axboe45711f12007-10-22 21:19:53 +0200624 memset(page_address(sg_page(&STp->buffer->sg[i])),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 0, STp->buffer->sg[i].length);
626 strcpy(STp->buffer->b_data, "READ ERROR ON FRAME");
627 } else
628 STp->buffer->buffer_bytes = OS_FRAME_SIZE;
629 return 1;
630 }
631 if (STp->buffer->syscall_result) {
632#if DEBUG
633 printk(OSST_DEB_MSG "%s:D: Skipping frame, read error\n", name);
634#endif
635 return 0;
636 }
637 if (ntohl(aux->format_id) != 0) {
638#if DEBUG
639 printk(OSST_DEB_MSG "%s:D: Skipping frame, format_id %u\n", name, ntohl(aux->format_id));
640#endif
641 goto err_out;
642 }
643 if (memcmp(aux->application_sig, STp->application_sig, 4) != 0 &&
644 (memcmp(aux->application_sig, "LIN3", 4) != 0 || STp->linux_media_version != 4)) {
645#if DEBUG
646 printk(OSST_DEB_MSG "%s:D: Skipping frame, incorrect application signature\n", name);
647#endif
648 goto err_out;
649 }
650 if (par->partition_num != OS_DATA_PARTITION) {
651 if (!STp->linux_media || STp->linux_media_version != 2) {
652#if DEBUG
653 printk(OSST_DEB_MSG "%s:D: Skipping frame, partition num %d\n",
654 name, par->partition_num);
655#endif
656 goto err_out;
657 }
658 }
659 if (par->par_desc_ver != OS_PARTITION_VERSION) {
660#if DEBUG
661 printk(OSST_DEB_MSG "%s:D: Skipping frame, partition version %d\n", name, par->par_desc_ver);
662#endif
663 goto err_out;
664 }
665 if (ntohs(par->wrt_pass_cntr) != STp->wrt_pass_cntr) {
666#if DEBUG
667 printk(OSST_DEB_MSG "%s:D: Skipping frame, wrt_pass_cntr %d (expected %d)\n",
668 name, ntohs(par->wrt_pass_cntr), STp->wrt_pass_cntr);
669#endif
670 goto err_out;
671 }
672 if (aux->frame_type != OS_FRAME_TYPE_DATA &&
673 aux->frame_type != OS_FRAME_TYPE_EOD &&
674 aux->frame_type != OS_FRAME_TYPE_MARKER) {
Ilpo Järvinenccd14432007-10-23 13:42:04 -0700675 if (!quiet) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676#if DEBUG
677 printk(OSST_DEB_MSG "%s:D: Skipping frame, frame type %x\n", name, aux->frame_type);
678#endif
Ilpo Järvinenccd14432007-10-23 13:42:04 -0700679 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 goto err_out;
681 }
682 if (aux->frame_type == OS_FRAME_TYPE_EOD &&
683 STp->first_frame_position < STp->eod_frame_ppos) {
684 printk(KERN_INFO "%s:I: Skipping premature EOD frame %d\n", name,
685 STp->first_frame_position);
686 goto err_out;
687 }
688 if (frame_seq_number != -1 && ntohl(aux->frame_seq_num) != frame_seq_number) {
Ilpo Järvinenccd14432007-10-23 13:42:04 -0700689 if (!quiet) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690#if DEBUG
691 printk(OSST_DEB_MSG "%s:D: Skipping frame, sequence number %u (expected %d)\n",
692 name, ntohl(aux->frame_seq_num), frame_seq_number);
693#endif
Ilpo Järvinenccd14432007-10-23 13:42:04 -0700694 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 goto err_out;
696 }
697 if (aux->frame_type == OS_FRAME_TYPE_MARKER) {
698 STps->eof = ST_FM_HIT;
699
700 i = ntohl(aux->filemark_cnt);
701 if (STp->header_cache != NULL && i < OS_FM_TAB_MAX && (i > STp->filemark_cnt ||
702 STp->first_frame_position - 1 != ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[i]))) {
703#if DEBUG
704 printk(OSST_DEB_MSG "%s:D: %s filemark %d at frame pos %d\n", name,
705 STp->header_cache->dat_fm_tab.fm_tab_ent[i] == 0?"Learned":"Corrected",
706 i, STp->first_frame_position - 1);
707#endif
708 STp->header_cache->dat_fm_tab.fm_tab_ent[i] = htonl(STp->first_frame_position - 1);
709 if (i >= STp->filemark_cnt)
710 STp->filemark_cnt = i+1;
711 }
712 }
713 if (aux->frame_type == OS_FRAME_TYPE_EOD) {
714 STps->eof = ST_EOD_1;
715 STp->frame_in_buffer = 1;
716 }
717 if (aux->frame_type == OS_FRAME_TYPE_DATA) {
718 blk_cnt = ntohs(aux->dat.dat_list[0].blk_cnt);
719 blk_sz = ntohl(aux->dat.dat_list[0].blk_sz);
720 STp->buffer->buffer_bytes = blk_cnt * blk_sz;
721 STp->buffer->read_pointer = 0;
722 STp->frame_in_buffer = 1;
723
724 /* See what block size was used to write file */
725 if (STp->block_size != blk_sz && blk_sz > 0) {
726 printk(KERN_INFO
727 "%s:I: File was written with block size %d%c, currently %d%c, adjusted to match.\n",
728 name, blk_sz<1024?blk_sz:blk_sz/1024,blk_sz<1024?'b':'k',
729 STp->block_size<1024?STp->block_size:STp->block_size/1024,
730 STp->block_size<1024?'b':'k');
731 STp->block_size = blk_sz;
732 STp->buffer->buffer_blocks = OS_DATA_SIZE / blk_sz;
733 }
734 STps->eof = ST_NOEOF;
735 }
736 STp->frame_seq_number = ntohl(aux->frame_seq_num);
737 STp->logical_blk_num = ntohl(aux->logical_blk_num);
738 return 1;
739
740err_out:
741 if (STp->read_error_frame == 0)
742 STp->read_error_frame = STp->first_frame_position - 1;
743 return 0;
744}
745
746/*
747 * Wait for the unit to become Ready
748 */
Willem Riede5e6575c2006-02-11 14:46:56 -0500749static int osst_wait_ready(struct osst_tape * STp, struct osst_request ** aSRpnt,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 unsigned timeout, int initial_delay)
751{
752 unsigned char cmd[MAX_COMMAND_SIZE];
Willem Riede5e6575c2006-02-11 14:46:56 -0500753 struct osst_request * SRpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 unsigned long startwait = jiffies;
755#if DEBUG
756 int dbg = debugging;
757 char * name = tape_name(STp);
758
759 printk(OSST_DEB_MSG "%s:D: Reached onstream wait ready\n", name);
760#endif
761
762 if (initial_delay > 0)
763 msleep(jiffies_to_msecs(initial_delay));
764
765 memset(cmd, 0, MAX_COMMAND_SIZE);
766 cmd[0] = TEST_UNIT_READY;
767
768 SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1);
769 *aSRpnt = SRpnt;
770 if (!SRpnt) return (-EBUSY);
771
772 while ( STp->buffer->syscall_result && time_before(jiffies, startwait + timeout*HZ) &&
Willem Riede5e6575c2006-02-11 14:46:56 -0500773 (( SRpnt->sense[2] == 2 && SRpnt->sense[12] == 4 &&
774 (SRpnt->sense[13] == 1 || SRpnt->sense[13] == 8) ) ||
775 ( SRpnt->sense[2] == 6 && SRpnt->sense[12] == 0x28 &&
776 SRpnt->sense[13] == 0 ) )) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777#if DEBUG
778 if (debugging) {
779 printk(OSST_DEB_MSG "%s:D: Sleeping in onstream wait ready\n", name);
780 printk(OSST_DEB_MSG "%s:D: Turning off debugging for a while\n", name);
781 debugging = 0;
782 }
783#endif
784 msleep(100);
785
786 memset(cmd, 0, MAX_COMMAND_SIZE);
787 cmd[0] = TEST_UNIT_READY;
788
789 SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1);
790 }
791 *aSRpnt = SRpnt;
792#if DEBUG
793 debugging = dbg;
794#endif
795 if ( STp->buffer->syscall_result &&
796 osst_write_error_recovery(STp, aSRpnt, 0) ) {
797#if DEBUG
798 printk(OSST_DEB_MSG "%s:D: Abnormal exit from onstream wait ready\n", name);
799 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 -0500800 STp->buffer->syscall_result, SRpnt->sense[0], SRpnt->sense[2],
801 SRpnt->sense[12], SRpnt->sense[13]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802#endif
803 return (-EIO);
804 }
805#if DEBUG
806 printk(OSST_DEB_MSG "%s:D: Normal exit from onstream wait ready\n", name);
807#endif
808 return 0;
809}
810
811/*
812 * Wait for a tape to be inserted in the unit
813 */
Willem Riede5e6575c2006-02-11 14:46:56 -0500814static int osst_wait_for_medium(struct osst_tape * STp, struct osst_request ** aSRpnt, unsigned timeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815{
816 unsigned char cmd[MAX_COMMAND_SIZE];
Willem Riede5e6575c2006-02-11 14:46:56 -0500817 struct osst_request * SRpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 unsigned long startwait = jiffies;
819#if DEBUG
820 int dbg = debugging;
821 char * name = tape_name(STp);
822
823 printk(OSST_DEB_MSG "%s:D: Reached onstream wait for medium\n", name);
824#endif
825
826 memset(cmd, 0, MAX_COMMAND_SIZE);
827 cmd[0] = TEST_UNIT_READY;
828
829 SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1);
830 *aSRpnt = SRpnt;
831 if (!SRpnt) return (-EBUSY);
832
833 while ( STp->buffer->syscall_result && time_before(jiffies, startwait + timeout*HZ) &&
Willem Riede5e6575c2006-02-11 14:46:56 -0500834 SRpnt->sense[2] == 2 && SRpnt->sense[12] == 0x3a && SRpnt->sense[13] == 0 ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835#if DEBUG
836 if (debugging) {
837 printk(OSST_DEB_MSG "%s:D: Sleeping in onstream wait medium\n", name);
838 printk(OSST_DEB_MSG "%s:D: Turning off debugging for a while\n", name);
839 debugging = 0;
840 }
841#endif
842 msleep(100);
843
844 memset(cmd, 0, MAX_COMMAND_SIZE);
845 cmd[0] = TEST_UNIT_READY;
846
847 SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1);
848 }
849 *aSRpnt = SRpnt;
850#if DEBUG
851 debugging = dbg;
852#endif
Willem Riede5e6575c2006-02-11 14:46:56 -0500853 if ( STp->buffer->syscall_result && SRpnt->sense[2] != 2 &&
854 SRpnt->sense[12] != 4 && SRpnt->sense[13] == 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855#if DEBUG
856 printk(OSST_DEB_MSG "%s:D: Abnormal exit from onstream wait medium\n", name);
857 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 -0500858 STp->buffer->syscall_result, SRpnt->sense[0], SRpnt->sense[2],
859 SRpnt->sense[12], SRpnt->sense[13]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860#endif
861 return 0;
862 }
863#if DEBUG
864 printk(OSST_DEB_MSG "%s:D: Normal exit from onstream wait medium\n", name);
865#endif
866 return 1;
867}
868
Willem Riede5e6575c2006-02-11 14:46:56 -0500869static int osst_position_tape_and_confirm(struct osst_tape * STp, struct osst_request ** aSRpnt, int frame)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870{
871 int retval;
872
873 osst_wait_ready(STp, aSRpnt, 15 * 60, 0); /* TODO - can this catch a write error? */
874 retval = osst_set_frame_position(STp, aSRpnt, frame, 0);
875 if (retval) return (retval);
876 osst_wait_ready(STp, aSRpnt, 15 * 60, OSST_WAIT_POSITION_COMPLETE);
877 return (osst_get_frame_position(STp, aSRpnt));
878}
879
880/*
881 * Wait for write(s) to complete
882 */
Willem Riede5e6575c2006-02-11 14:46:56 -0500883static int osst_flush_drive_buffer(struct osst_tape * STp, struct osst_request ** aSRpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884{
885 unsigned char cmd[MAX_COMMAND_SIZE];
Willem Riede5e6575c2006-02-11 14:46:56 -0500886 struct osst_request * SRpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887 int result = 0;
888 int delay = OSST_WAIT_WRITE_COMPLETE;
889#if DEBUG
890 char * name = tape_name(STp);
891
892 printk(OSST_DEB_MSG "%s:D: Reached onstream flush drive buffer (write filemark)\n", name);
893#endif
894
895 memset(cmd, 0, MAX_COMMAND_SIZE);
896 cmd[0] = WRITE_FILEMARKS;
897 cmd[1] = 1;
898
899 SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1);
900 *aSRpnt = SRpnt;
901 if (!SRpnt) return (-EBUSY);
902 if (STp->buffer->syscall_result) {
Willem Riede5e6575c2006-02-11 14:46:56 -0500903 if ((SRpnt->sense[2] & 0x0f) == 2 && SRpnt->sense[12] == 4) {
904 if (SRpnt->sense[13] == 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 delay = OSST_WAIT_LONG_WRITE_COMPLETE;
906 }
907 } else
908 result = osst_write_error_recovery(STp, aSRpnt, 0);
909 }
910 result |= osst_wait_ready(STp, aSRpnt, 5 * 60, delay);
911 STp->ps[STp->partition].rw = OS_WRITING_COMPLETE;
912
913 return (result);
914}
915
916#define OSST_POLL_PER_SEC 10
Willem Riede5e6575c2006-02-11 14:46:56 -0500917static 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 -0700918{
919 unsigned long startwait = jiffies;
920 char * name = tape_name(STp);
921#if DEBUG
922 char notyetprinted = 1;
923#endif
924 if (minlast >= 0 && STp->ps[STp->partition].rw != ST_READING)
925 printk(KERN_ERR "%s:A: Waiting for frame without having initialized read!\n", name);
926
927 while (time_before (jiffies, startwait + to*HZ))
928 {
929 int result;
930 result = osst_get_frame_position(STp, aSRpnt);
931 if (result == -EIO)
932 if ((result = osst_write_error_recovery(STp, aSRpnt, 0)) == 0)
933 return 0; /* successful recovery leaves drive ready for frame */
934 if (result < 0) break;
935 if (STp->first_frame_position == curr &&
936 ((minlast < 0 &&
937 (signed)STp->last_frame_position > (signed)curr + minlast) ||
938 (minlast >= 0 && STp->cur_frames > minlast)
939 ) && result >= 0)
940 {
941#if DEBUG
Marcelo Feitoza Parisi60c904a2006-03-28 01:56:47 -0800942 if (debugging || time_after_eq(jiffies, startwait + 2*HZ/OSST_POLL_PER_SEC))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943 printk (OSST_DEB_MSG
944 "%s:D: Succ wait f fr %i (>%i): %i-%i %i (%i): %3li.%li s\n",
945 name, curr, curr+minlast, STp->first_frame_position,
946 STp->last_frame_position, STp->cur_frames,
947 result, (jiffies-startwait)/HZ,
948 (((jiffies-startwait)%HZ)*10)/HZ);
949#endif
950 return 0;
951 }
952#if DEBUG
Marcelo Feitoza Parisi60c904a2006-03-28 01:56:47 -0800953 if (time_after_eq(jiffies, startwait + 2*HZ/OSST_POLL_PER_SEC) && notyetprinted)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954 {
955 printk (OSST_DEB_MSG "%s:D: Wait for frame %i (>%i): %i-%i %i (%i)\n",
956 name, curr, curr+minlast, STp->first_frame_position,
957 STp->last_frame_position, STp->cur_frames, result);
958 notyetprinted--;
959 }
960#endif
961 msleep(1000 / OSST_POLL_PER_SEC);
962 }
963#if DEBUG
964 printk (OSST_DEB_MSG "%s:D: Fail wait f fr %i (>%i): %i-%i %i: %3li.%li s\n",
965 name, curr, curr+minlast, STp->first_frame_position,
966 STp->last_frame_position, STp->cur_frames,
967 (jiffies-startwait)/HZ, (((jiffies-startwait)%HZ)*10)/HZ);
968#endif
969 return -EBUSY;
970}
971
Willem Riede5e6575c2006-02-11 14:46:56 -0500972static int osst_recover_wait_frame(struct osst_tape * STp, struct osst_request ** aSRpnt, int writing)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973{
Willem Riede5e6575c2006-02-11 14:46:56 -0500974 struct osst_request * SRpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975 unsigned char cmd[MAX_COMMAND_SIZE];
976 unsigned long startwait = jiffies;
977 int retval = 1;
978 char * name = tape_name(STp);
979
980 if (writing) {
981 char mybuf[24];
982 char * olddata = STp->buffer->b_data;
983 int oldsize = STp->buffer->buffer_size;
984
985 /* write zero fm then read pos - if shows write error, try to recover - if no progress, wait */
986
987 memset(cmd, 0, MAX_COMMAND_SIZE);
988 cmd[0] = WRITE_FILEMARKS;
989 cmd[1] = 1;
990 SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, DMA_NONE, STp->timeout,
991 MAX_RETRIES, 1);
992
993 while (retval && time_before (jiffies, startwait + 5*60*HZ)) {
994
Willem Riede5e6575c2006-02-11 14:46:56 -0500995 if (STp->buffer->syscall_result && (SRpnt->sense[2] & 0x0f) != 2) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996
997 /* some failure - not just not-ready */
998 retval = osst_write_error_recovery(STp, aSRpnt, 0);
999 break;
1000 }
Nishanth Aravamudana9a30472005-11-07 01:01:20 -08001001 schedule_timeout_interruptible(HZ / OSST_POLL_PER_SEC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002
1003 STp->buffer->b_data = mybuf; STp->buffer->buffer_size = 24;
1004 memset(cmd, 0, MAX_COMMAND_SIZE);
1005 cmd[0] = READ_POSITION;
1006
1007 SRpnt = osst_do_scsi(SRpnt, STp, cmd, 20, DMA_FROM_DEVICE, STp->timeout,
1008 MAX_RETRIES, 1);
1009
1010 retval = ( STp->buffer->syscall_result || (STp->buffer)->b_data[15] > 25 );
1011 STp->buffer->b_data = olddata; STp->buffer->buffer_size = oldsize;
1012 }
1013 if (retval)
1014 printk(KERN_ERR "%s:E: Device did not succeed to write buffered data\n", name);
1015 } else
1016 /* TODO - figure out which error conditions can be handled */
1017 if (STp->buffer->syscall_result)
1018 printk(KERN_WARNING
1019 "%s:W: Recover_wait_frame(read) cannot handle %02x:%02x:%02x\n", name,
Willem Riede5e6575c2006-02-11 14:46:56 -05001020 (*aSRpnt)->sense[ 2] & 0x0f,
1021 (*aSRpnt)->sense[12],
1022 (*aSRpnt)->sense[13]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023
1024 return retval;
1025}
1026
1027/*
1028 * Read the next OnStream tape frame at the current location
1029 */
Willem Riede5e6575c2006-02-11 14:46:56 -05001030static int osst_read_frame(struct osst_tape * STp, struct osst_request ** aSRpnt, int timeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031{
1032 unsigned char cmd[MAX_COMMAND_SIZE];
Willem Riede5e6575c2006-02-11 14:46:56 -05001033 struct osst_request * SRpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034 int retval = 0;
1035#if DEBUG
1036 os_aux_t * aux = STp->buffer->aux;
1037 char * name = tape_name(STp);
1038#endif
1039
1040 if (STp->poll)
1041 if (osst_wait_frame (STp, aSRpnt, STp->first_frame_position, 0, timeout))
1042 retval = osst_recover_wait_frame(STp, aSRpnt, 0);
1043
1044 memset(cmd, 0, MAX_COMMAND_SIZE);
1045 cmd[0] = READ_6;
1046 cmd[1] = 1;
1047 cmd[4] = 1;
1048
1049#if DEBUG
1050 if (debugging)
1051 printk(OSST_DEB_MSG "%s:D: Reading frame from OnStream tape\n", name);
1052#endif
1053 SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, OS_FRAME_SIZE, DMA_FROM_DEVICE,
1054 STp->timeout, MAX_RETRIES, 1);
1055 *aSRpnt = SRpnt;
1056 if (!SRpnt)
1057 return (-EBUSY);
1058
1059 if ((STp->buffer)->syscall_result) {
1060 retval = 1;
1061 if (STp->read_error_frame == 0) {
1062 STp->read_error_frame = STp->first_frame_position;
1063#if DEBUG
1064 printk(OSST_DEB_MSG "%s:D: Recording read error at %d\n", name, STp->read_error_frame);
1065#endif
1066 }
1067#if DEBUG
1068 if (debugging)
1069 printk(OSST_DEB_MSG "%s:D: Sense: %2x %2x %2x %2x %2x %2x %2x %2x\n",
1070 name,
Willem Riede5e6575c2006-02-11 14:46:56 -05001071 SRpnt->sense[0], SRpnt->sense[1],
1072 SRpnt->sense[2], SRpnt->sense[3],
1073 SRpnt->sense[4], SRpnt->sense[5],
1074 SRpnt->sense[6], SRpnt->sense[7]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075#endif
1076 }
1077 else
1078 STp->first_frame_position++;
1079#if DEBUG
1080 if (debugging) {
1081 char sig[8]; int i;
1082 for (i=0;i<4;i++)
1083 sig[i] = aux->application_sig[i]<32?'^':aux->application_sig[i];
1084 sig[4] = '\0';
1085 printk(OSST_DEB_MSG
1086 "%s:D: AUX: %s UpdFrCt#%d Wpass#%d %s FrSeq#%d LogBlk#%d Qty=%d Sz=%d\n", name, sig,
1087 ntohl(aux->update_frame_cntr), ntohs(aux->partition.wrt_pass_cntr),
1088 aux->frame_type==1?"EOD":aux->frame_type==2?"MARK":
1089 aux->frame_type==8?"HEADR":aux->frame_type==0x80?"DATA":"FILL",
1090 ntohl(aux->frame_seq_num), ntohl(aux->logical_blk_num),
1091 ntohs(aux->dat.dat_list[0].blk_cnt), ntohl(aux->dat.dat_list[0].blk_sz) );
1092 if (aux->frame_type==2)
1093 printk(OSST_DEB_MSG "%s:D: mark_cnt=%d, last_mark_ppos=%d, last_mark_lbn=%d\n", name,
1094 ntohl(aux->filemark_cnt), ntohl(aux->last_mark_ppos), ntohl(aux->last_mark_lbn));
1095 printk(OSST_DEB_MSG "%s:D: Exit read frame from OnStream tape with code %d\n", name, retval);
1096 }
1097#endif
1098 return (retval);
1099}
1100
Willem Riede5e6575c2006-02-11 14:46:56 -05001101static int osst_initiate_read(struct osst_tape * STp, struct osst_request ** aSRpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102{
1103 struct st_partstat * STps = &(STp->ps[STp->partition]);
Willem Riede5e6575c2006-02-11 14:46:56 -05001104 struct osst_request * SRpnt ;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 unsigned char cmd[MAX_COMMAND_SIZE];
1106 int retval = 0;
1107 char * name = tape_name(STp);
1108
1109 if (STps->rw != ST_READING) { /* Initialize read operation */
1110 if (STps->rw == ST_WRITING || STp->dirty) {
1111 STp->write_type = OS_WRITE_DATA;
1112 osst_flush_write_buffer(STp, aSRpnt);
1113 osst_flush_drive_buffer(STp, aSRpnt);
1114 }
1115 STps->rw = ST_READING;
1116 STp->frame_in_buffer = 0;
1117
1118 /*
1119 * Issue a read 0 command to get the OnStream drive
1120 * read frames into its buffer.
1121 */
1122 memset(cmd, 0, MAX_COMMAND_SIZE);
1123 cmd[0] = READ_6;
1124 cmd[1] = 1;
1125
1126#if DEBUG
1127 printk(OSST_DEB_MSG "%s:D: Start Read Ahead on OnStream tape\n", name);
1128#endif
1129 SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1);
1130 *aSRpnt = SRpnt;
1131 if ((retval = STp->buffer->syscall_result))
1132 printk(KERN_WARNING "%s:W: Error starting read ahead\n", name);
1133 }
1134
1135 return retval;
1136}
1137
Willem Riede5e6575c2006-02-11 14:46:56 -05001138static int osst_get_logical_frame(struct osst_tape * STp, struct osst_request ** aSRpnt,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139 int frame_seq_number, int quiet)
1140{
1141 struct st_partstat * STps = &(STp->ps[STp->partition]);
1142 char * name = tape_name(STp);
1143 int cnt = 0,
1144 bad = 0,
1145 past = 0,
1146 x,
1147 position;
1148
1149 /*
1150 * If we want just any frame (-1) and there is a frame in the buffer, return it
1151 */
1152 if (frame_seq_number == -1 && STp->frame_in_buffer) {
1153#if DEBUG
1154 printk(OSST_DEB_MSG "%s:D: Frame %d still in buffer\n", name, STp->frame_seq_number);
1155#endif
1156 return (STps->eof);
1157 }
1158 /*
1159 * Search and wait for the next logical tape frame
1160 */
1161 while (1) {
1162 if (cnt++ > 400) {
1163 printk(KERN_ERR "%s:E: Couldn't find logical frame %d, aborting\n",
1164 name, frame_seq_number);
1165 if (STp->read_error_frame) {
1166 osst_set_frame_position(STp, aSRpnt, STp->read_error_frame, 0);
1167#if DEBUG
1168 printk(OSST_DEB_MSG "%s:D: Repositioning tape to bad frame %d\n",
1169 name, STp->read_error_frame);
1170#endif
1171 STp->read_error_frame = 0;
1172 STp->abort_count++;
1173 }
1174 return (-EIO);
1175 }
1176#if DEBUG
1177 if (debugging)
1178 printk(OSST_DEB_MSG "%s:D: Looking for frame %d, attempt %d\n",
1179 name, frame_seq_number, cnt);
1180#endif
1181 if ( osst_initiate_read(STp, aSRpnt)
1182 || ( (!STp->frame_in_buffer) && osst_read_frame(STp, aSRpnt, 30) ) ) {
1183 if (STp->raw)
1184 return (-EIO);
1185 position = osst_get_frame_position(STp, aSRpnt);
1186 if (position >= 0xbae && position < 0xbb8)
1187 position = 0xbb8;
1188 else if (position > STp->eod_frame_ppos || ++bad == 10) {
1189 position = STp->read_error_frame - 1;
1190 bad = 0;
1191 }
1192 else {
1193 position += 29;
1194 cnt += 19;
1195 }
1196#if DEBUG
1197 printk(OSST_DEB_MSG "%s:D: Bad frame detected, positioning tape to block %d\n",
1198 name, position);
1199#endif
1200 osst_set_frame_position(STp, aSRpnt, position, 0);
1201 continue;
1202 }
1203 if (osst_verify_frame(STp, frame_seq_number, quiet))
1204 break;
1205 if (osst_verify_frame(STp, -1, quiet)) {
1206 x = ntohl(STp->buffer->aux->frame_seq_num);
1207 if (STp->fast_open) {
1208 printk(KERN_WARNING
1209 "%s:W: Found logical frame %d instead of %d after fast open\n",
1210 name, x, frame_seq_number);
1211 STp->header_ok = 0;
1212 STp->read_error_frame = 0;
1213 return (-EIO);
1214 }
1215 if (x > frame_seq_number) {
1216 if (++past > 3) {
1217 /* positioning backwards did not bring us to the desired frame */
1218 position = STp->read_error_frame - 1;
1219 }
1220 else {
1221 position = osst_get_frame_position(STp, aSRpnt)
1222 + frame_seq_number - x - 1;
1223
1224 if (STp->first_frame_position >= 3000 && position < 3000)
1225 position -= 10;
1226 }
1227#if DEBUG
1228 printk(OSST_DEB_MSG
1229 "%s:D: Found logical frame %d while looking for %d: back up %d\n",
1230 name, x, frame_seq_number,
1231 STp->first_frame_position - position);
1232#endif
1233 osst_set_frame_position(STp, aSRpnt, position, 0);
1234 cnt += 10;
1235 }
1236 else
1237 past = 0;
1238 }
1239 if (osst_get_frame_position(STp, aSRpnt) == 0xbaf) {
1240#if DEBUG
1241 printk(OSST_DEB_MSG "%s:D: Skipping config partition\n", name);
1242#endif
1243 osst_set_frame_position(STp, aSRpnt, 0xbb8, 0);
1244 cnt--;
1245 }
1246 STp->frame_in_buffer = 0;
1247 }
1248 if (cnt > 1) {
1249 STp->recover_count++;
1250 STp->recover_erreg++;
1251 printk(KERN_WARNING "%s:I: Don't worry, Read error at position %d recovered\n",
1252 name, STp->read_error_frame);
1253 }
1254 STp->read_count++;
1255
1256#if DEBUG
1257 if (debugging || STps->eof)
1258 printk(OSST_DEB_MSG
1259 "%s:D: Exit get logical frame (%d=>%d) from OnStream tape with code %d\n",
1260 name, frame_seq_number, STp->frame_seq_number, STps->eof);
1261#endif
1262 STp->fast_open = 0;
1263 STp->read_error_frame = 0;
1264 return (STps->eof);
1265}
1266
Willem Riede5e6575c2006-02-11 14:46:56 -05001267static int osst_seek_logical_blk(struct osst_tape * STp, struct osst_request ** aSRpnt, int logical_blk_num)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268{
1269 struct st_partstat * STps = &(STp->ps[STp->partition]);
1270 char * name = tape_name(STp);
1271 int retries = 0;
1272 int frame_seq_estimate, ppos_estimate, move;
1273
1274 if (logical_blk_num < 0) logical_blk_num = 0;
1275#if DEBUG
1276 printk(OSST_DEB_MSG "%s:D: Seeking logical block %d (now at %d, size %d%c)\n",
1277 name, logical_blk_num, STp->logical_blk_num,
1278 STp->block_size<1024?STp->block_size:STp->block_size/1024,
1279 STp->block_size<1024?'b':'k');
1280#endif
1281 /* Do we know where we are? */
1282 if (STps->drv_block >= 0) {
1283 move = logical_blk_num - STp->logical_blk_num;
1284 if (move < 0) move -= (OS_DATA_SIZE / STp->block_size) - 1;
1285 move /= (OS_DATA_SIZE / STp->block_size);
1286 frame_seq_estimate = STp->frame_seq_number + move;
1287 } else
1288 frame_seq_estimate = logical_blk_num * STp->block_size / OS_DATA_SIZE;
1289
1290 if (frame_seq_estimate < 2980) ppos_estimate = frame_seq_estimate + 10;
1291 else ppos_estimate = frame_seq_estimate + 20;
1292 while (++retries < 10) {
1293 if (ppos_estimate > STp->eod_frame_ppos-2) {
1294 frame_seq_estimate += STp->eod_frame_ppos - 2 - ppos_estimate;
1295 ppos_estimate = STp->eod_frame_ppos - 2;
1296 }
1297 if (frame_seq_estimate < 0) {
1298 frame_seq_estimate = 0;
1299 ppos_estimate = 10;
1300 }
1301 osst_set_frame_position(STp, aSRpnt, ppos_estimate, 0);
1302 if (osst_get_logical_frame(STp, aSRpnt, frame_seq_estimate, 1) >= 0) {
1303 /* we've located the estimated frame, now does it have our block? */
1304 if (logical_blk_num < STp->logical_blk_num ||
1305 logical_blk_num >= STp->logical_blk_num + ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt)) {
1306 if (STps->eof == ST_FM_HIT)
1307 move = logical_blk_num < STp->logical_blk_num? -2 : 1;
1308 else {
1309 move = logical_blk_num - STp->logical_blk_num;
1310 if (move < 0) move -= (OS_DATA_SIZE / STp->block_size) - 1;
1311 move /= (OS_DATA_SIZE / STp->block_size);
1312 }
1313 if (!move) move = logical_blk_num > STp->logical_blk_num ? 1 : -1;
1314#if DEBUG
1315 printk(OSST_DEB_MSG
1316 "%s:D: Seek retry %d at ppos %d fsq %d (est %d) lbn %d (need %d) move %d\n",
1317 name, retries, ppos_estimate, STp->frame_seq_number, frame_seq_estimate,
1318 STp->logical_blk_num, logical_blk_num, move);
1319#endif
1320 frame_seq_estimate += move;
1321 ppos_estimate += move;
1322 continue;
1323 } else {
1324 STp->buffer->read_pointer = (logical_blk_num - STp->logical_blk_num) * STp->block_size;
1325 STp->buffer->buffer_bytes -= STp->buffer->read_pointer;
1326 STp->logical_blk_num = logical_blk_num;
1327#if DEBUG
1328 printk(OSST_DEB_MSG
1329 "%s:D: Seek success at ppos %d fsq %d in_buf %d, bytes %d, ptr %d*%d\n",
1330 name, ppos_estimate, STp->frame_seq_number, STp->frame_in_buffer,
1331 STp->buffer->buffer_bytes, STp->buffer->read_pointer / STp->block_size,
1332 STp->block_size);
1333#endif
1334 STps->drv_file = ntohl(STp->buffer->aux->filemark_cnt);
1335 if (STps->eof == ST_FM_HIT) {
1336 STps->drv_file++;
1337 STps->drv_block = 0;
1338 } else {
1339 STps->drv_block = ntohl(STp->buffer->aux->last_mark_lbn)?
1340 STp->logical_blk_num -
1341 (STps->drv_file ? ntohl(STp->buffer->aux->last_mark_lbn) + 1 : 0):
1342 -1;
1343 }
1344 STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD:ST_NOEOF;
1345 return 0;
1346 }
1347 }
1348 if (osst_get_logical_frame(STp, aSRpnt, -1, 1) < 0)
1349 goto error;
1350 /* we are not yet at the estimated frame, adjust our estimate of its physical position */
1351#if DEBUG
1352 printk(OSST_DEB_MSG "%s:D: Seek retry %d at ppos %d fsq %d (est %d) lbn %d (need %d)\n",
1353 name, retries, ppos_estimate, STp->frame_seq_number, frame_seq_estimate,
1354 STp->logical_blk_num, logical_blk_num);
1355#endif
1356 if (frame_seq_estimate != STp->frame_seq_number)
1357 ppos_estimate += frame_seq_estimate - STp->frame_seq_number;
1358 else
1359 break;
1360 }
1361error:
1362 printk(KERN_ERR "%s:E: Couldn't seek to logical block %d (at %d), %d retries\n",
1363 name, logical_blk_num, STp->logical_blk_num, retries);
1364 return (-EIO);
1365}
1366
1367/* The values below are based on the OnStream frame payload size of 32K == 2**15,
1368 * that is, OSST_FRAME_SHIFT + OSST_SECTOR_SHIFT must be 15. With a minimum block
1369 * size of 512 bytes, we need to be able to resolve 32K/512 == 64 == 2**6 positions
Lucas De Marchi25985ed2011-03-30 22:57:33 -03001370 * inside each frame. Finally, OSST_SECTOR_MASK == 2**OSST_FRAME_SHIFT - 1.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371 */
1372#define OSST_FRAME_SHIFT 6
1373#define OSST_SECTOR_SHIFT 9
1374#define OSST_SECTOR_MASK 0x03F
1375
Willem Riede5e6575c2006-02-11 14:46:56 -05001376static int osst_get_sector(struct osst_tape * STp, struct osst_request ** aSRpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377{
1378 int sector;
1379#if DEBUG
1380 char * name = tape_name(STp);
1381
1382 printk(OSST_DEB_MSG
1383 "%s:D: Positioned at ppos %d, frame %d, lbn %d, file %d, blk %d, %cptr %d, eof %d\n",
1384 name, STp->first_frame_position, STp->frame_seq_number, STp->logical_blk_num,
1385 STp->ps[STp->partition].drv_file, STp->ps[STp->partition].drv_block,
1386 STp->ps[STp->partition].rw == ST_WRITING?'w':'r',
1387 STp->ps[STp->partition].rw == ST_WRITING?STp->buffer->buffer_bytes:
1388 STp->buffer->read_pointer, STp->ps[STp->partition].eof);
1389#endif
1390 /* do we know where we are inside a file? */
1391 if (STp->ps[STp->partition].drv_block >= 0) {
1392 sector = (STp->frame_in_buffer ? STp->first_frame_position-1 :
1393 STp->first_frame_position) << OSST_FRAME_SHIFT;
1394 if (STp->ps[STp->partition].rw == ST_WRITING)
1395 sector |= (STp->buffer->buffer_bytes >> OSST_SECTOR_SHIFT) & OSST_SECTOR_MASK;
1396 else
1397 sector |= (STp->buffer->read_pointer >> OSST_SECTOR_SHIFT) & OSST_SECTOR_MASK;
1398 } else {
1399 sector = osst_get_frame_position(STp, aSRpnt);
1400 if (sector > 0)
1401 sector <<= OSST_FRAME_SHIFT;
1402 }
1403 return sector;
1404}
1405
Willem Riede5e6575c2006-02-11 14:46:56 -05001406static int osst_seek_sector(struct osst_tape * STp, struct osst_request ** aSRpnt, int sector)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407{
1408 struct st_partstat * STps = &(STp->ps[STp->partition]);
1409 int frame = sector >> OSST_FRAME_SHIFT,
1410 offset = (sector & OSST_SECTOR_MASK) << OSST_SECTOR_SHIFT,
1411 r;
1412#if DEBUG
1413 char * name = tape_name(STp);
1414
1415 printk(OSST_DEB_MSG "%s:D: Seeking sector %d in frame %d at offset %d\n",
1416 name, sector, frame, offset);
1417#endif
1418 if (frame < 0 || frame >= STp->capacity) return (-ENXIO);
1419
1420 if (frame <= STp->first_data_ppos) {
1421 STp->frame_seq_number = STp->logical_blk_num = STps->drv_file = STps->drv_block = 0;
1422 return (osst_set_frame_position(STp, aSRpnt, frame, 0));
1423 }
1424 r = osst_set_frame_position(STp, aSRpnt, offset?frame:frame-1, 0);
1425 if (r < 0) return r;
1426
1427 r = osst_get_logical_frame(STp, aSRpnt, -1, 1);
1428 if (r < 0) return r;
1429
1430 if (osst_get_frame_position(STp, aSRpnt) != (offset?frame+1:frame)) return (-EIO);
1431
1432 if (offset) {
1433 STp->logical_blk_num += offset / STp->block_size;
1434 STp->buffer->read_pointer = offset;
1435 STp->buffer->buffer_bytes -= offset;
1436 } else {
1437 STp->frame_seq_number++;
1438 STp->frame_in_buffer = 0;
1439 STp->logical_blk_num += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
1440 STp->buffer->buffer_bytes = STp->buffer->read_pointer = 0;
1441 }
1442 STps->drv_file = ntohl(STp->buffer->aux->filemark_cnt);
1443 if (STps->eof == ST_FM_HIT) {
1444 STps->drv_file++;
1445 STps->drv_block = 0;
1446 } else {
1447 STps->drv_block = ntohl(STp->buffer->aux->last_mark_lbn)?
1448 STp->logical_blk_num -
1449 (STps->drv_file ? ntohl(STp->buffer->aux->last_mark_lbn) + 1 : 0):
1450 -1;
1451 }
1452 STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD:ST_NOEOF;
1453#if DEBUG
1454 printk(OSST_DEB_MSG
1455 "%s:D: Now positioned at ppos %d, frame %d, lbn %d, file %d, blk %d, rptr %d, eof %d\n",
1456 name, STp->first_frame_position, STp->frame_seq_number, STp->logical_blk_num,
1457 STps->drv_file, STps->drv_block, STp->buffer->read_pointer, STps->eof);
1458#endif
1459 return 0;
1460}
1461
1462/*
1463 * Read back the drive's internal buffer contents, as a part
1464 * of the write error recovery mechanism for old OnStream
1465 * firmware revisions.
1466 * Precondition for this function to work: all frames in the
1467 * drive's buffer must be of one type (DATA, MARK or EOD)!
1468 */
Willem Riede5e6575c2006-02-11 14:46:56 -05001469static int osst_read_back_buffer_and_rewrite(struct osst_tape * STp, struct osst_request ** aSRpnt,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001470 unsigned int frame, unsigned int skip, int pending)
1471{
Willem Riede5e6575c2006-02-11 14:46:56 -05001472 struct osst_request * SRpnt = * aSRpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473 unsigned char * buffer, * p;
1474 unsigned char cmd[MAX_COMMAND_SIZE];
1475 int flag, new_frame, i;
1476 int nframes = STp->cur_frames;
1477 int blks_per_frame = ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
1478 int frame_seq_number = ntohl(STp->buffer->aux->frame_seq_num)
1479 - (nframes + pending - 1);
1480 int logical_blk_num = ntohl(STp->buffer->aux->logical_blk_num)
1481 - (nframes + pending - 1) * blks_per_frame;
1482 char * name = tape_name(STp);
1483 unsigned long startwait = jiffies;
1484#if DEBUG
1485 int dbg = debugging;
1486#endif
1487
Jesper Juhl20999732010-11-09 00:09:25 +01001488 if ((buffer = vmalloc((nframes + 1) * OS_DATA_SIZE)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489 return (-EIO);
1490
1491 printk(KERN_INFO "%s:I: Reading back %d frames from drive buffer%s\n",
1492 name, nframes, pending?" and one that was pending":"");
1493
1494 osst_copy_from_buffer(STp->buffer, (p = &buffer[nframes * OS_DATA_SIZE]));
1495#if DEBUG
1496 if (pending && debugging)
1497 printk(OSST_DEB_MSG "%s:D: Pending frame %d (lblk %d), data %02x %02x %02x %02x\n",
1498 name, frame_seq_number + nframes,
1499 logical_blk_num + nframes * blks_per_frame,
1500 p[0], p[1], p[2], p[3]);
1501#endif
1502 for (i = 0, p = buffer; i < nframes; i++, p += OS_DATA_SIZE) {
1503
1504 memset(cmd, 0, MAX_COMMAND_SIZE);
1505 cmd[0] = 0x3C; /* Buffer Read */
1506 cmd[1] = 6; /* Retrieve Faulty Block */
1507 cmd[7] = 32768 >> 8;
1508 cmd[8] = 32768 & 0xff;
1509
1510 SRpnt = osst_do_scsi(SRpnt, STp, cmd, OS_FRAME_SIZE, DMA_FROM_DEVICE,
1511 STp->timeout, MAX_RETRIES, 1);
1512
1513 if ((STp->buffer)->syscall_result || !SRpnt) {
1514 printk(KERN_ERR "%s:E: Failed to read frame back from OnStream buffer\n", name);
Jesper Juhlf91012102005-09-10 00:26:54 -07001515 vfree(buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516 *aSRpnt = SRpnt;
1517 return (-EIO);
1518 }
1519 osst_copy_from_buffer(STp->buffer, p);
1520#if DEBUG
1521 if (debugging)
1522 printk(OSST_DEB_MSG "%s:D: Read back logical frame %d, data %02x %02x %02x %02x\n",
1523 name, frame_seq_number + i, p[0], p[1], p[2], p[3]);
1524#endif
1525 }
1526 *aSRpnt = SRpnt;
1527 osst_get_frame_position(STp, aSRpnt);
1528
1529#if DEBUG
1530 printk(OSST_DEB_MSG "%s:D: Frames left in buffer: %d\n", name, STp->cur_frames);
1531#endif
1532 /* Write synchronously so we can be sure we're OK again and don't have to recover recursively */
1533 /* In the header we don't actually re-write the frames that fail, just the ones after them */
1534
1535 for (flag=1, new_frame=frame, p=buffer, i=0; i < nframes + pending; ) {
1536
1537 if (flag) {
1538 if (STp->write_type == OS_WRITE_HEADER) {
1539 i += skip;
1540 p += skip * OS_DATA_SIZE;
1541 }
1542 else if (new_frame < 2990 && new_frame+skip+nframes+pending >= 2990)
1543 new_frame = 3000-i;
1544 else
1545 new_frame += skip;
1546#if DEBUG
1547 printk(OSST_DEB_MSG "%s:D: Position to frame %d, write fseq %d\n",
1548 name, new_frame+i, frame_seq_number+i);
1549#endif
1550 osst_set_frame_position(STp, aSRpnt, new_frame + i, 0);
1551 osst_wait_ready(STp, aSRpnt, 60, OSST_WAIT_POSITION_COMPLETE);
1552 osst_get_frame_position(STp, aSRpnt);
1553 SRpnt = * aSRpnt;
1554
1555 if (new_frame > frame + 1000) {
1556 printk(KERN_ERR "%s:E: Failed to find writable tape media\n", name);
Jesper Juhlf91012102005-09-10 00:26:54 -07001557 vfree(buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558 return (-EIO);
1559 }
1560 if ( i >= nframes + pending ) break;
1561 flag = 0;
1562 }
1563 osst_copy_to_buffer(STp->buffer, p);
1564 /*
1565 * IMPORTANT: for error recovery to work, _never_ queue frames with mixed frame type!
1566 */
1567 osst_init_aux(STp, STp->buffer->aux->frame_type, frame_seq_number+i,
1568 logical_blk_num + i*blks_per_frame,
1569 ntohl(STp->buffer->aux->dat.dat_list[0].blk_sz), blks_per_frame);
1570 memset(cmd, 0, MAX_COMMAND_SIZE);
1571 cmd[0] = WRITE_6;
1572 cmd[1] = 1;
1573 cmd[4] = 1;
1574
1575#if DEBUG
1576 if (debugging)
1577 printk(OSST_DEB_MSG
1578 "%s:D: About to write frame %d, seq %d, lbn %d, data %02x %02x %02x %02x\n",
1579 name, new_frame+i, frame_seq_number+i, logical_blk_num + i*blks_per_frame,
1580 p[0], p[1], p[2], p[3]);
1581#endif
1582 SRpnt = osst_do_scsi(SRpnt, STp, cmd, OS_FRAME_SIZE, DMA_TO_DEVICE,
1583 STp->timeout, MAX_RETRIES, 1);
1584
1585 if (STp->buffer->syscall_result)
1586 flag = 1;
1587 else {
1588 p += OS_DATA_SIZE; i++;
1589
1590 /* if we just sent the last frame, wait till all successfully written */
1591 if ( i == nframes + pending ) {
1592#if DEBUG
1593 printk(OSST_DEB_MSG "%s:D: Check re-write successful\n", name);
1594#endif
1595 memset(cmd, 0, MAX_COMMAND_SIZE);
1596 cmd[0] = WRITE_FILEMARKS;
1597 cmd[1] = 1;
1598 SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE,
1599 STp->timeout, MAX_RETRIES, 1);
1600#if DEBUG
1601 if (debugging) {
1602 printk(OSST_DEB_MSG "%s:D: Sleeping in re-write wait ready\n", name);
1603 printk(OSST_DEB_MSG "%s:D: Turning off debugging for a while\n", name);
1604 debugging = 0;
1605 }
1606#endif
1607 flag = STp->buffer->syscall_result;
1608 while ( !flag && time_before(jiffies, startwait + 60*HZ) ) {
1609
1610 memset(cmd, 0, MAX_COMMAND_SIZE);
1611 cmd[0] = TEST_UNIT_READY;
1612
1613 SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE, STp->timeout,
1614 MAX_RETRIES, 1);
1615
Willem Riede5e6575c2006-02-11 14:46:56 -05001616 if (SRpnt->sense[2] == 2 && SRpnt->sense[12] == 4 &&
1617 (SRpnt->sense[13] == 1 || SRpnt->sense[13] == 8)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618 /* in the process of becoming ready */
1619 msleep(100);
1620 continue;
1621 }
1622 if (STp->buffer->syscall_result)
1623 flag = 1;
1624 break;
1625 }
1626#if DEBUG
1627 debugging = dbg;
1628 printk(OSST_DEB_MSG "%s:D: Wait re-write finished\n", name);
1629#endif
1630 }
1631 }
1632 *aSRpnt = SRpnt;
1633 if (flag) {
Willem Riede5e6575c2006-02-11 14:46:56 -05001634 if ((SRpnt->sense[ 2] & 0x0f) == 13 &&
1635 SRpnt->sense[12] == 0 &&
1636 SRpnt->sense[13] == 2) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001637 printk(KERN_ERR "%s:E: Volume overflow in write error recovery\n", name);
Jesper Juhlf91012102005-09-10 00:26:54 -07001638 vfree(buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639 return (-EIO); /* hit end of tape = fail */
1640 }
Willem Riede5e6575c2006-02-11 14:46:56 -05001641 i = ((SRpnt->sense[3] << 24) |
1642 (SRpnt->sense[4] << 16) |
1643 (SRpnt->sense[5] << 8) |
1644 SRpnt->sense[6] ) - new_frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645 p = &buffer[i * OS_DATA_SIZE];
1646#if DEBUG
1647 printk(OSST_DEB_MSG "%s:D: Additional write error at %d\n", name, new_frame+i);
1648#endif
1649 osst_get_frame_position(STp, aSRpnt);
1650#if DEBUG
1651 printk(OSST_DEB_MSG "%s:D: reported frame positions: host = %d, tape = %d, buffer = %d\n",
1652 name, STp->first_frame_position, STp->last_frame_position, STp->cur_frames);
1653#endif
1654 }
1655 }
1656 if (flag) {
1657 /* error recovery did not successfully complete */
1658 printk(KERN_ERR "%s:D: Write error recovery failed in %s\n", name,
1659 STp->write_type == OS_WRITE_HEADER?"header":"body");
1660 }
1661 if (!pending)
1662 osst_copy_to_buffer(STp->buffer, p); /* so buffer content == at entry in all cases */
Jesper Juhlf91012102005-09-10 00:26:54 -07001663 vfree(buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664 return 0;
1665}
1666
Willem Riede5e6575c2006-02-11 14:46:56 -05001667static int osst_reposition_and_retry(struct osst_tape * STp, struct osst_request ** aSRpnt,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668 unsigned int frame, unsigned int skip, int pending)
1669{
1670 unsigned char cmd[MAX_COMMAND_SIZE];
Willem Riede5e6575c2006-02-11 14:46:56 -05001671 struct osst_request * SRpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672 char * name = tape_name(STp);
1673 int expected = 0;
1674 int attempts = 1000 / skip;
1675 int flag = 1;
1676 unsigned long startwait = jiffies;
1677#if DEBUG
1678 int dbg = debugging;
1679#endif
1680
1681 while (attempts && time_before(jiffies, startwait + 60*HZ)) {
1682 if (flag) {
1683#if DEBUG
1684 debugging = dbg;
1685#endif
1686 if (frame < 2990 && frame+skip+STp->cur_frames+pending >= 2990)
1687 frame = 3000-skip;
1688 expected = frame+skip+STp->cur_frames+pending;
1689#if DEBUG
1690 printk(OSST_DEB_MSG "%s:D: Position to fppos %d, re-write from fseq %d\n",
1691 name, frame+skip, STp->frame_seq_number-STp->cur_frames-pending);
1692#endif
1693 osst_set_frame_position(STp, aSRpnt, frame + skip, 1);
1694 flag = 0;
1695 attempts--;
Nishanth Aravamudana9a30472005-11-07 01:01:20 -08001696 schedule_timeout_interruptible(msecs_to_jiffies(100));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697 }
1698 if (osst_get_frame_position(STp, aSRpnt) < 0) { /* additional write error */
1699#if DEBUG
1700 printk(OSST_DEB_MSG "%s:D: Addl error, host %d, tape %d, buffer %d\n",
1701 name, STp->first_frame_position,
1702 STp->last_frame_position, STp->cur_frames);
1703#endif
1704 frame = STp->last_frame_position;
1705 flag = 1;
1706 continue;
1707 }
1708 if (pending && STp->cur_frames < 50) {
1709
1710 memset(cmd, 0, MAX_COMMAND_SIZE);
1711 cmd[0] = WRITE_6;
1712 cmd[1] = 1;
1713 cmd[4] = 1;
1714#if DEBUG
1715 printk(OSST_DEB_MSG "%s:D: About to write pending fseq %d at fppos %d\n",
1716 name, STp->frame_seq_number-1, STp->first_frame_position);
1717#endif
1718 SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, OS_FRAME_SIZE, DMA_TO_DEVICE,
1719 STp->timeout, MAX_RETRIES, 1);
1720 *aSRpnt = SRpnt;
1721
1722 if (STp->buffer->syscall_result) { /* additional write error */
Willem Riede5e6575c2006-02-11 14:46:56 -05001723 if ((SRpnt->sense[ 2] & 0x0f) == 13 &&
1724 SRpnt->sense[12] == 0 &&
1725 SRpnt->sense[13] == 2) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726 printk(KERN_ERR
1727 "%s:E: Volume overflow in write error recovery\n",
1728 name);
1729 break; /* hit end of tape = fail */
1730 }
1731 flag = 1;
1732 }
1733 else
1734 pending = 0;
1735
1736 continue;
1737 }
1738 if (STp->cur_frames == 0) {
1739#if DEBUG
1740 debugging = dbg;
1741 printk(OSST_DEB_MSG "%s:D: Wait re-write finished\n", name);
1742#endif
1743 if (STp->first_frame_position != expected) {
1744 printk(KERN_ERR "%s:A: Actual position %d - expected %d\n",
1745 name, STp->first_frame_position, expected);
1746 return (-EIO);
1747 }
1748 return 0;
1749 }
1750#if DEBUG
1751 if (debugging) {
1752 printk(OSST_DEB_MSG "%s:D: Sleeping in re-write wait ready\n", name);
1753 printk(OSST_DEB_MSG "%s:D: Turning off debugging for a while\n", name);
1754 debugging = 0;
1755 }
1756#endif
Nishanth Aravamudana9a30472005-11-07 01:01:20 -08001757 schedule_timeout_interruptible(msecs_to_jiffies(100));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758 }
1759 printk(KERN_ERR "%s:E: Failed to find valid tape media\n", name);
1760#if DEBUG
1761 debugging = dbg;
1762#endif
1763 return (-EIO);
1764}
1765
1766/*
1767 * Error recovery algorithm for the OnStream tape.
1768 */
1769
Willem Riede5e6575c2006-02-11 14:46:56 -05001770static int osst_write_error_recovery(struct osst_tape * STp, struct osst_request ** aSRpnt, int pending)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771{
Willem Riede5e6575c2006-02-11 14:46:56 -05001772 struct osst_request * SRpnt = * aSRpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773 struct st_partstat * STps = & STp->ps[STp->partition];
1774 char * name = tape_name(STp);
1775 int retval = 0;
1776 int rw_state;
1777 unsigned int frame, skip;
1778
1779 rw_state = STps->rw;
1780
Willem Riede5e6575c2006-02-11 14:46:56 -05001781 if ((SRpnt->sense[ 2] & 0x0f) != 3
1782 || SRpnt->sense[12] != 12
1783 || SRpnt->sense[13] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001784#if DEBUG
1785 printk(OSST_DEB_MSG "%s:D: Write error recovery cannot handle %02x:%02x:%02x\n", name,
Willem Riede5e6575c2006-02-11 14:46:56 -05001786 SRpnt->sense[2], SRpnt->sense[12], SRpnt->sense[13]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787#endif
1788 return (-EIO);
1789 }
Willem Riede5e6575c2006-02-11 14:46:56 -05001790 frame = (SRpnt->sense[3] << 24) |
1791 (SRpnt->sense[4] << 16) |
1792 (SRpnt->sense[5] << 8) |
1793 SRpnt->sense[6];
1794 skip = SRpnt->sense[9];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795
1796#if DEBUG
1797 printk(OSST_DEB_MSG "%s:D: Detected physical bad frame at %u, advised to skip %d\n", name, frame, skip);
1798#endif
1799 osst_get_frame_position(STp, aSRpnt);
1800#if DEBUG
1801 printk(OSST_DEB_MSG "%s:D: reported frame positions: host = %d, tape = %d\n",
1802 name, STp->first_frame_position, STp->last_frame_position);
1803#endif
1804 switch (STp->write_type) {
1805 case OS_WRITE_DATA:
1806 case OS_WRITE_EOD:
1807 case OS_WRITE_NEW_MARK:
1808 printk(KERN_WARNING
1809 "%s:I: Relocating %d buffered logical frames from position %u to %u\n",
1810 name, STp->cur_frames, frame, (frame + skip > 3000 && frame < 3000)?3000:frame + skip);
1811 if (STp->os_fw_rev >= 10600)
1812 retval = osst_reposition_and_retry(STp, aSRpnt, frame, skip, pending);
1813 else
1814 retval = osst_read_back_buffer_and_rewrite(STp, aSRpnt, frame, skip, pending);
1815 printk(KERN_WARNING "%s:%s: %sWrite error%srecovered\n", name,
1816 retval?"E" :"I",
1817 retval?"" :"Don't worry, ",
1818 retval?" not ":" ");
1819 break;
1820 case OS_WRITE_LAST_MARK:
1821 printk(KERN_ERR "%s:E: Bad frame in update last marker, fatal\n", name);
1822 osst_set_frame_position(STp, aSRpnt, frame + STp->cur_frames + pending, 0);
1823 retval = -EIO;
1824 break;
1825 case OS_WRITE_HEADER:
1826 printk(KERN_WARNING "%s:I: Bad frame in header partition, skipped\n", name);
1827 retval = osst_read_back_buffer_and_rewrite(STp, aSRpnt, frame, 1, pending);
1828 break;
1829 default:
1830 printk(KERN_INFO "%s:I: Bad frame in filler, ignored\n", name);
1831 osst_set_frame_position(STp, aSRpnt, frame + STp->cur_frames + pending, 0);
1832 }
1833 osst_get_frame_position(STp, aSRpnt);
1834#if DEBUG
1835 printk(OSST_DEB_MSG "%s:D: Positioning complete, cur_frames %d, pos %d, tape pos %d\n",
1836 name, STp->cur_frames, STp->first_frame_position, STp->last_frame_position);
1837 printk(OSST_DEB_MSG "%s:D: next logical frame to write: %d\n", name, STp->logical_blk_num);
1838#endif
1839 if (retval == 0) {
1840 STp->recover_count++;
1841 STp->recover_erreg++;
1842 } else
1843 STp->abort_count++;
1844
1845 STps->rw = rw_state;
1846 return retval;
1847}
1848
Willem Riede5e6575c2006-02-11 14:46:56 -05001849static int osst_space_over_filemarks_backward(struct osst_tape * STp, struct osst_request ** aSRpnt,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850 int mt_op, int mt_count)
1851{
1852 char * name = tape_name(STp);
1853 int cnt;
1854 int last_mark_ppos = -1;
1855
1856#if DEBUG
1857 printk(OSST_DEB_MSG "%s:D: Reached space_over_filemarks_backwards %d %d\n", name, mt_op, mt_count);
1858#endif
1859 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
1860#if DEBUG
1861 printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks_bwd\n", name);
1862#endif
1863 return -EIO;
1864 }
1865 if (STp->linux_media_version >= 4) {
1866 /*
1867 * direct lookup in header filemark list
1868 */
1869 cnt = ntohl(STp->buffer->aux->filemark_cnt);
1870 if (STp->header_ok &&
1871 STp->header_cache != NULL &&
1872 (cnt - mt_count) >= 0 &&
1873 (cnt - mt_count) < OS_FM_TAB_MAX &&
1874 (cnt - mt_count) < STp->filemark_cnt &&
1875 STp->header_cache->dat_fm_tab.fm_tab_ent[cnt-1] == STp->buffer->aux->last_mark_ppos)
1876
1877 last_mark_ppos = ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[cnt - mt_count]);
1878#if DEBUG
1879 if (STp->header_cache == NULL || (cnt - mt_count) < 0 || (cnt - mt_count) >= OS_FM_TAB_MAX)
1880 printk(OSST_DEB_MSG "%s:D: Filemark lookup fail due to %s\n", name,
1881 STp->header_cache == NULL?"lack of header cache":"count out of range");
1882 else
1883 printk(OSST_DEB_MSG "%s:D: Filemark lookup: prev mark %d (%s), skip %d to %d\n",
1884 name, cnt,
1885 ((cnt == -1 && ntohl(STp->buffer->aux->last_mark_ppos) == -1) ||
1886 (STp->header_cache->dat_fm_tab.fm_tab_ent[cnt-1] ==
1887 STp->buffer->aux->last_mark_ppos))?"match":"error",
1888 mt_count, last_mark_ppos);
1889#endif
1890 if (last_mark_ppos > 10 && last_mark_ppos < STp->eod_frame_ppos) {
1891 osst_position_tape_and_confirm(STp, aSRpnt, last_mark_ppos);
1892 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
1893#if DEBUG
1894 printk(OSST_DEB_MSG
1895 "%s:D: Couldn't get logical blk num in space_filemarks\n", name);
1896#endif
1897 return (-EIO);
1898 }
1899 if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
1900 printk(KERN_WARNING "%s:W: Expected to find marker at ppos %d, not found\n",
1901 name, last_mark_ppos);
1902 return (-EIO);
1903 }
1904 goto found;
1905 }
1906#if DEBUG
1907 printk(OSST_DEB_MSG "%s:D: Reverting to scan filemark backwards\n", name);
1908#endif
1909 }
1910 cnt = 0;
1911 while (cnt != mt_count) {
1912 last_mark_ppos = ntohl(STp->buffer->aux->last_mark_ppos);
1913 if (last_mark_ppos == -1)
1914 return (-EIO);
1915#if DEBUG
1916 printk(OSST_DEB_MSG "%s:D: Positioning to last mark at %d\n", name, last_mark_ppos);
1917#endif
1918 osst_position_tape_and_confirm(STp, aSRpnt, last_mark_ppos);
1919 cnt++;
1920 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
1921#if DEBUG
1922 printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks\n", name);
1923#endif
1924 return (-EIO);
1925 }
1926 if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
1927 printk(KERN_WARNING "%s:W: Expected to find marker at ppos %d, not found\n",
1928 name, last_mark_ppos);
1929 return (-EIO);
1930 }
1931 }
1932found:
1933 if (mt_op == MTBSFM) {
1934 STp->frame_seq_number++;
1935 STp->frame_in_buffer = 0;
1936 STp->buffer->buffer_bytes = 0;
1937 STp->buffer->read_pointer = 0;
1938 STp->logical_blk_num += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
1939 }
1940 return 0;
1941}
1942
1943/*
1944 * ADRL 1.1 compatible "slow" space filemarks fwd version
1945 *
1946 * Just scans for the filemark sequentially.
1947 */
Willem Riede5e6575c2006-02-11 14:46:56 -05001948static int osst_space_over_filemarks_forward_slow(struct osst_tape * STp, struct osst_request ** aSRpnt,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949 int mt_op, int mt_count)
1950{
1951 int cnt = 0;
1952#if DEBUG
1953 char * name = tape_name(STp);
1954
1955 printk(OSST_DEB_MSG "%s:D: Reached space_over_filemarks_forward_slow %d %d\n", name, mt_op, mt_count);
1956#endif
1957 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
1958#if DEBUG
1959 printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks_fwd\n", name);
1960#endif
1961 return (-EIO);
1962 }
1963 while (1) {
1964 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
1965#if DEBUG
1966 printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks\n", name);
1967#endif
1968 return (-EIO);
1969 }
1970 if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_MARKER)
1971 cnt++;
1972 if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_EOD) {
1973#if DEBUG
1974 printk(OSST_DEB_MSG "%s:D: space_fwd: EOD reached\n", name);
1975#endif
1976 if (STp->first_frame_position > STp->eod_frame_ppos+1) {
1977#if DEBUG
1978 printk(OSST_DEB_MSG "%s:D: EOD position corrected (%d=>%d)\n",
1979 name, STp->eod_frame_ppos, STp->first_frame_position-1);
1980#endif
1981 STp->eod_frame_ppos = STp->first_frame_position-1;
1982 }
1983 return (-EIO);
1984 }
1985 if (cnt == mt_count)
1986 break;
1987 STp->frame_in_buffer = 0;
1988 }
1989 if (mt_op == MTFSF) {
1990 STp->frame_seq_number++;
1991 STp->frame_in_buffer = 0;
1992 STp->buffer->buffer_bytes = 0;
1993 STp->buffer->read_pointer = 0;
1994 STp->logical_blk_num += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
1995 }
1996 return 0;
1997}
1998
1999/*
2000 * Fast linux specific version of OnStream FSF
2001 */
Willem Riede5e6575c2006-02-11 14:46:56 -05002002static int osst_space_over_filemarks_forward_fast(struct osst_tape * STp, struct osst_request ** aSRpnt,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003 int mt_op, int mt_count)
2004{
2005 char * name = tape_name(STp);
2006 int cnt = 0,
2007 next_mark_ppos = -1;
2008
2009#if DEBUG
2010 printk(OSST_DEB_MSG "%s:D: Reached space_over_filemarks_forward_fast %d %d\n", name, mt_op, mt_count);
2011#endif
2012 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
2013#if DEBUG
2014 printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks_fwd\n", name);
2015#endif
2016 return (-EIO);
2017 }
2018
2019 if (STp->linux_media_version >= 4) {
2020 /*
2021 * direct lookup in header filemark list
2022 */
2023 cnt = ntohl(STp->buffer->aux->filemark_cnt) - 1;
2024 if (STp->header_ok &&
2025 STp->header_cache != NULL &&
2026 (cnt + mt_count) < OS_FM_TAB_MAX &&
2027 (cnt + mt_count) < STp->filemark_cnt &&
2028 ((cnt == -1 && ntohl(STp->buffer->aux->last_mark_ppos) == -1) ||
2029 (STp->header_cache->dat_fm_tab.fm_tab_ent[cnt] == STp->buffer->aux->last_mark_ppos)))
2030
2031 next_mark_ppos = ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[cnt + mt_count]);
2032#if DEBUG
2033 if (STp->header_cache == NULL || (cnt + mt_count) >= OS_FM_TAB_MAX)
2034 printk(OSST_DEB_MSG "%s:D: Filemark lookup fail due to %s\n", name,
2035 STp->header_cache == NULL?"lack of header cache":"count out of range");
2036 else
2037 printk(OSST_DEB_MSG "%s:D: Filemark lookup: prev mark %d (%s), skip %d to %d\n",
2038 name, cnt,
2039 ((cnt == -1 && ntohl(STp->buffer->aux->last_mark_ppos) == -1) ||
2040 (STp->header_cache->dat_fm_tab.fm_tab_ent[cnt] ==
2041 STp->buffer->aux->last_mark_ppos))?"match":"error",
2042 mt_count, next_mark_ppos);
2043#endif
2044 if (next_mark_ppos <= 10 || next_mark_ppos > STp->eod_frame_ppos) {
2045#if DEBUG
2046 printk(OSST_DEB_MSG "%s:D: Reverting to slow filemark space\n", name);
2047#endif
2048 return osst_space_over_filemarks_forward_slow(STp, aSRpnt, mt_op, mt_count);
2049 } else {
2050 osst_position_tape_and_confirm(STp, aSRpnt, next_mark_ppos);
2051 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
2052#if DEBUG
2053 printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks\n",
2054 name);
2055#endif
2056 return (-EIO);
2057 }
2058 if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
2059 printk(KERN_WARNING "%s:W: Expected to find marker at ppos %d, not found\n",
2060 name, next_mark_ppos);
2061 return (-EIO);
2062 }
2063 if (ntohl(STp->buffer->aux->filemark_cnt) != cnt + mt_count) {
2064 printk(KERN_WARNING "%s:W: Expected to find marker %d at ppos %d, not %d\n",
2065 name, cnt+mt_count, next_mark_ppos,
2066 ntohl(STp->buffer->aux->filemark_cnt));
2067 return (-EIO);
2068 }
2069 }
2070 } else {
2071 /*
2072 * Find nearest (usually previous) marker, then jump from marker to marker
2073 */
2074 while (1) {
2075 if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_MARKER)
2076 break;
2077 if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_EOD) {
2078#if DEBUG
2079 printk(OSST_DEB_MSG "%s:D: space_fwd: EOD reached\n", name);
2080#endif
2081 return (-EIO);
2082 }
2083 if (ntohl(STp->buffer->aux->filemark_cnt) == 0) {
2084 if (STp->first_mark_ppos == -1) {
2085#if DEBUG
2086 printk(OSST_DEB_MSG "%s:D: Reverting to slow filemark space\n", name);
2087#endif
2088 return osst_space_over_filemarks_forward_slow(STp, aSRpnt, mt_op, mt_count);
2089 }
2090 osst_position_tape_and_confirm(STp, aSRpnt, STp->first_mark_ppos);
2091 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
2092#if DEBUG
2093 printk(OSST_DEB_MSG
2094 "%s:D: Couldn't get logical blk num in space_filemarks_fwd_fast\n",
2095 name);
2096#endif
2097 return (-EIO);
2098 }
2099 if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
2100 printk(KERN_WARNING "%s:W: Expected to find filemark at %d\n",
2101 name, STp->first_mark_ppos);
2102 return (-EIO);
2103 }
2104 } else {
2105 if (osst_space_over_filemarks_backward(STp, aSRpnt, MTBSF, 1) < 0)
2106 return (-EIO);
2107 mt_count++;
2108 }
2109 }
2110 cnt++;
2111 while (cnt != mt_count) {
2112 next_mark_ppos = ntohl(STp->buffer->aux->next_mark_ppos);
2113 if (!next_mark_ppos || next_mark_ppos > STp->eod_frame_ppos) {
2114#if DEBUG
2115 printk(OSST_DEB_MSG "%s:D: Reverting to slow filemark space\n", name);
2116#endif
2117 return osst_space_over_filemarks_forward_slow(STp, aSRpnt, mt_op, mt_count - cnt);
2118 }
2119#if DEBUG
2120 else printk(OSST_DEB_MSG "%s:D: Positioning to next mark at %d\n", name, next_mark_ppos);
2121#endif
2122 osst_position_tape_and_confirm(STp, aSRpnt, next_mark_ppos);
2123 cnt++;
2124 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
2125#if DEBUG
2126 printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks\n",
2127 name);
2128#endif
2129 return (-EIO);
2130 }
2131 if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
2132 printk(KERN_WARNING "%s:W: Expected to find marker at ppos %d, not found\n",
2133 name, next_mark_ppos);
2134 return (-EIO);
2135 }
2136 }
2137 }
2138 if (mt_op == MTFSF) {
2139 STp->frame_seq_number++;
2140 STp->frame_in_buffer = 0;
2141 STp->buffer->buffer_bytes = 0;
2142 STp->buffer->read_pointer = 0;
2143 STp->logical_blk_num += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
2144 }
2145 return 0;
2146}
2147
2148/*
2149 * In debug mode, we want to see as many errors as possible
2150 * to test the error recovery mechanism.
2151 */
2152#if DEBUG
Willem Riede5e6575c2006-02-11 14:46:56 -05002153static void osst_set_retries(struct osst_tape * STp, struct osst_request ** aSRpnt, int retries)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002154{
2155 unsigned char cmd[MAX_COMMAND_SIZE];
Willem Riede5e6575c2006-02-11 14:46:56 -05002156 struct osst_request * SRpnt = * aSRpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002157 char * name = tape_name(STp);
2158
2159 memset(cmd, 0, MAX_COMMAND_SIZE);
2160 cmd[0] = MODE_SELECT;
2161 cmd[1] = 0x10;
2162 cmd[4] = NUMBER_RETRIES_PAGE_LENGTH + MODE_HEADER_LENGTH;
2163
2164 (STp->buffer)->b_data[0] = cmd[4] - 1;
2165 (STp->buffer)->b_data[1] = 0; /* Medium Type - ignoring */
2166 (STp->buffer)->b_data[2] = 0; /* Reserved */
2167 (STp->buffer)->b_data[3] = 0; /* Block Descriptor Length */
2168 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 0] = NUMBER_RETRIES_PAGE | (1 << 7);
2169 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 1] = 2;
2170 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] = 4;
2171 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] = retries;
2172
2173 if (debugging)
2174 printk(OSST_DEB_MSG "%s:D: Setting number of retries on OnStream tape to %d\n", name, retries);
2175
2176 SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_TO_DEVICE, STp->timeout, 0, 1);
2177 *aSRpnt = SRpnt;
2178
2179 if ((STp->buffer)->syscall_result)
2180 printk (KERN_ERR "%s:D: Couldn't set retries to %d\n", name, retries);
2181}
2182#endif
2183
2184
Willem Riede5e6575c2006-02-11 14:46:56 -05002185static int osst_write_filemark(struct osst_tape * STp, struct osst_request ** aSRpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002186{
2187 int result;
2188 int this_mark_ppos = STp->first_frame_position;
2189 int this_mark_lbn = STp->logical_blk_num;
2190#if DEBUG
2191 char * name = tape_name(STp);
2192#endif
2193
2194 if (STp->raw) return 0;
2195
2196 STp->write_type = OS_WRITE_NEW_MARK;
2197#if DEBUG
2198 printk(OSST_DEB_MSG "%s:D: Writing Filemark %i at fppos %d (fseq %d, lblk %d)\n",
2199 name, STp->filemark_cnt, this_mark_ppos, STp->frame_seq_number, this_mark_lbn);
2200#endif
2201 STp->dirty = 1;
2202 result = osst_flush_write_buffer(STp, aSRpnt);
2203 result |= osst_flush_drive_buffer(STp, aSRpnt);
2204 STp->last_mark_ppos = this_mark_ppos;
2205 STp->last_mark_lbn = this_mark_lbn;
2206 if (STp->header_cache != NULL && STp->filemark_cnt < OS_FM_TAB_MAX)
2207 STp->header_cache->dat_fm_tab.fm_tab_ent[STp->filemark_cnt] = htonl(this_mark_ppos);
2208 if (STp->filemark_cnt++ == 0)
2209 STp->first_mark_ppos = this_mark_ppos;
2210 return result;
2211}
2212
Willem Riede5e6575c2006-02-11 14:46:56 -05002213static int osst_write_eod(struct osst_tape * STp, struct osst_request ** aSRpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002214{
2215 int result;
2216#if DEBUG
2217 char * name = tape_name(STp);
2218#endif
2219
2220 if (STp->raw) return 0;
2221
2222 STp->write_type = OS_WRITE_EOD;
2223 STp->eod_frame_ppos = STp->first_frame_position;
2224#if DEBUG
2225 printk(OSST_DEB_MSG "%s:D: Writing EOD at fppos %d (fseq %d, lblk %d)\n", name,
2226 STp->eod_frame_ppos, STp->frame_seq_number, STp->logical_blk_num);
2227#endif
2228 STp->dirty = 1;
2229
2230 result = osst_flush_write_buffer(STp, aSRpnt);
2231 result |= osst_flush_drive_buffer(STp, aSRpnt);
2232 STp->eod_frame_lfa = --(STp->frame_seq_number);
2233 return result;
2234}
2235
Willem Riede5e6575c2006-02-11 14:46:56 -05002236static int osst_write_filler(struct osst_tape * STp, struct osst_request ** aSRpnt, int where, int count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002237{
2238 char * name = tape_name(STp);
2239
2240#if DEBUG
2241 printk(OSST_DEB_MSG "%s:D: Reached onstream write filler group %d\n", name, where);
2242#endif
2243 osst_wait_ready(STp, aSRpnt, 60 * 5, 0);
2244 osst_set_frame_position(STp, aSRpnt, where, 0);
2245 STp->write_type = OS_WRITE_FILLER;
2246 while (count--) {
2247 memcpy(STp->buffer->b_data, "Filler", 6);
2248 STp->buffer->buffer_bytes = 6;
2249 STp->dirty = 1;
2250 if (osst_flush_write_buffer(STp, aSRpnt)) {
2251 printk(KERN_INFO "%s:I: Couldn't write filler frame\n", name);
2252 return (-EIO);
2253 }
2254 }
2255#if DEBUG
2256 printk(OSST_DEB_MSG "%s:D: Exiting onstream write filler group\n", name);
2257#endif
2258 return osst_flush_drive_buffer(STp, aSRpnt);
2259}
2260
Willem Riede5e6575c2006-02-11 14:46:56 -05002261static int __osst_write_header(struct osst_tape * STp, struct osst_request ** aSRpnt, int where, int count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002262{
2263 char * name = tape_name(STp);
2264 int result;
2265
2266#if DEBUG
2267 printk(OSST_DEB_MSG "%s:D: Reached onstream write header group %d\n", name, where);
2268#endif
2269 osst_wait_ready(STp, aSRpnt, 60 * 5, 0);
2270 osst_set_frame_position(STp, aSRpnt, where, 0);
2271 STp->write_type = OS_WRITE_HEADER;
2272 while (count--) {
2273 osst_copy_to_buffer(STp->buffer, (unsigned char *)STp->header_cache);
2274 STp->buffer->buffer_bytes = sizeof(os_header_t);
2275 STp->dirty = 1;
2276 if (osst_flush_write_buffer(STp, aSRpnt)) {
2277 printk(KERN_INFO "%s:I: Couldn't write header frame\n", name);
2278 return (-EIO);
2279 }
2280 }
2281 result = osst_flush_drive_buffer(STp, aSRpnt);
2282#if DEBUG
2283 printk(OSST_DEB_MSG "%s:D: Write onstream header group %s\n", name, result?"failed":"done");
2284#endif
2285 return result;
2286}
2287
Willem Riede5e6575c2006-02-11 14:46:56 -05002288static int osst_write_header(struct osst_tape * STp, struct osst_request ** aSRpnt, int locate_eod)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002289{
2290 os_header_t * header;
2291 int result;
2292 char * name = tape_name(STp);
2293
2294#if DEBUG
2295 printk(OSST_DEB_MSG "%s:D: Writing tape header\n", name);
2296#endif
2297 if (STp->raw) return 0;
2298
2299 if (STp->header_cache == NULL) {
Jesper Juhl20999732010-11-09 00:09:25 +01002300 if ((STp->header_cache = vmalloc(sizeof(os_header_t))) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002301 printk(KERN_ERR "%s:E: Failed to allocate header cache\n", name);
2302 return (-ENOMEM);
2303 }
2304 memset(STp->header_cache, 0, sizeof(os_header_t));
2305#if DEBUG
2306 printk(OSST_DEB_MSG "%s:D: Allocated and cleared memory for header cache\n", name);
2307#endif
2308 }
2309 if (STp->header_ok) STp->update_frame_cntr++;
2310 else STp->update_frame_cntr = 0;
2311
2312 header = STp->header_cache;
2313 strcpy(header->ident_str, "ADR_SEQ");
2314 header->major_rev = 1;
2315 header->minor_rev = 4;
2316 header->ext_trk_tb_off = htons(17192);
2317 header->pt_par_num = 1;
2318 header->partition[0].partition_num = OS_DATA_PARTITION;
2319 header->partition[0].par_desc_ver = OS_PARTITION_VERSION;
2320 header->partition[0].wrt_pass_cntr = htons(STp->wrt_pass_cntr);
2321 header->partition[0].first_frame_ppos = htonl(STp->first_data_ppos);
2322 header->partition[0].last_frame_ppos = htonl(STp->capacity);
2323 header->partition[0].eod_frame_ppos = htonl(STp->eod_frame_ppos);
2324 header->cfg_col_width = htonl(20);
2325 header->dat_col_width = htonl(1500);
2326 header->qfa_col_width = htonl(0);
2327 header->ext_track_tb.nr_stream_part = 1;
2328 header->ext_track_tb.et_ent_sz = 32;
2329 header->ext_track_tb.dat_ext_trk_ey.et_part_num = 0;
2330 header->ext_track_tb.dat_ext_trk_ey.fmt = 1;
2331 header->ext_track_tb.dat_ext_trk_ey.fm_tab_off = htons(17736);
2332 header->ext_track_tb.dat_ext_trk_ey.last_hlb_hi = 0;
2333 header->ext_track_tb.dat_ext_trk_ey.last_hlb = htonl(STp->eod_frame_lfa);
2334 header->ext_track_tb.dat_ext_trk_ey.last_pp = htonl(STp->eod_frame_ppos);
2335 header->dat_fm_tab.fm_part_num = 0;
2336 header->dat_fm_tab.fm_tab_ent_sz = 4;
2337 header->dat_fm_tab.fm_tab_ent_cnt = htons(STp->filemark_cnt<OS_FM_TAB_MAX?
2338 STp->filemark_cnt:OS_FM_TAB_MAX);
2339
2340 result = __osst_write_header(STp, aSRpnt, 0xbae, 5);
2341 if (STp->update_frame_cntr == 0)
2342 osst_write_filler(STp, aSRpnt, 0xbb3, 5);
2343 result &= __osst_write_header(STp, aSRpnt, 5, 5);
2344
2345 if (locate_eod) {
2346#if DEBUG
2347 printk(OSST_DEB_MSG "%s:D: Locating back to eod frame addr %d\n", name, STp->eod_frame_ppos);
2348#endif
2349 osst_set_frame_position(STp, aSRpnt, STp->eod_frame_ppos, 0);
2350 }
2351 if (result)
2352 printk(KERN_ERR "%s:E: Write header failed\n", name);
2353 else {
2354 memcpy(STp->application_sig, "LIN4", 4);
2355 STp->linux_media = 1;
2356 STp->linux_media_version = 4;
2357 STp->header_ok = 1;
2358 }
2359 return result;
2360}
2361
Willem Riede5e6575c2006-02-11 14:46:56 -05002362static int osst_reset_header(struct osst_tape * STp, struct osst_request ** aSRpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002363{
2364 if (STp->header_cache != NULL)
2365 memset(STp->header_cache, 0, sizeof(os_header_t));
2366
2367 STp->logical_blk_num = STp->frame_seq_number = 0;
2368 STp->frame_in_buffer = 0;
2369 STp->eod_frame_ppos = STp->first_data_ppos = 0x0000000A;
2370 STp->filemark_cnt = 0;
2371 STp->first_mark_ppos = STp->last_mark_ppos = STp->last_mark_lbn = -1;
2372 return osst_write_header(STp, aSRpnt, 1);
2373}
2374
Willem Riede5e6575c2006-02-11 14:46:56 -05002375static int __osst_analyze_headers(struct osst_tape * STp, struct osst_request ** aSRpnt, int ppos)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002376{
2377 char * name = tape_name(STp);
2378 os_header_t * header;
2379 os_aux_t * aux;
2380 char id_string[8];
2381 int linux_media_version,
2382 update_frame_cntr;
2383
2384 if (STp->raw)
2385 return 1;
2386
2387 if (ppos == 5 || ppos == 0xbae || STp->buffer->syscall_result) {
2388 if (osst_set_frame_position(STp, aSRpnt, ppos, 0))
2389 printk(KERN_WARNING "%s:W: Couldn't position tape\n", name);
2390 osst_wait_ready(STp, aSRpnt, 60 * 15, 0);
2391 if (osst_initiate_read (STp, aSRpnt)) {
2392 printk(KERN_WARNING "%s:W: Couldn't initiate read\n", name);
2393 return 0;
2394 }
2395 }
2396 if (osst_read_frame(STp, aSRpnt, 180)) {
2397#if DEBUG
2398 printk(OSST_DEB_MSG "%s:D: Couldn't read header frame\n", name);
2399#endif
2400 return 0;
2401 }
2402 header = (os_header_t *) STp->buffer->b_data; /* warning: only first segment addressable */
2403 aux = STp->buffer->aux;
2404 if (aux->frame_type != OS_FRAME_TYPE_HEADER) {
2405#if DEBUG
2406 printk(OSST_DEB_MSG "%s:D: Skipping non-header frame (%d)\n", name, ppos);
2407#endif
2408 return 0;
2409 }
2410 if (ntohl(aux->frame_seq_num) != 0 ||
2411 ntohl(aux->logical_blk_num) != 0 ||
2412 aux->partition.partition_num != OS_CONFIG_PARTITION ||
2413 ntohl(aux->partition.first_frame_ppos) != 0 ||
2414 ntohl(aux->partition.last_frame_ppos) != 0xbb7 ) {
2415#if DEBUG
2416 printk(OSST_DEB_MSG "%s:D: Invalid header frame (%d,%d,%d,%d,%d)\n", name,
2417 ntohl(aux->frame_seq_num), ntohl(aux->logical_blk_num),
2418 aux->partition.partition_num, ntohl(aux->partition.first_frame_ppos),
2419 ntohl(aux->partition.last_frame_ppos));
2420#endif
2421 return 0;
2422 }
2423 if (strncmp(header->ident_str, "ADR_SEQ", 7) != 0 &&
2424 strncmp(header->ident_str, "ADR-SEQ", 7) != 0) {
2425 strlcpy(id_string, header->ident_str, 8);
2426#if DEBUG
2427 printk(OSST_DEB_MSG "%s:D: Invalid header identification string %s\n", name, id_string);
2428#endif
2429 return 0;
2430 }
2431 update_frame_cntr = ntohl(aux->update_frame_cntr);
2432 if (update_frame_cntr < STp->update_frame_cntr) {
2433#if DEBUG
2434 printk(OSST_DEB_MSG "%s:D: Skipping frame %d with update_frame_counter %d<%d\n",
2435 name, ppos, update_frame_cntr, STp->update_frame_cntr);
2436#endif
2437 return 0;
2438 }
2439 if (header->major_rev != 1 || header->minor_rev != 4 ) {
2440#if DEBUG
2441 printk(OSST_DEB_MSG "%s:D: %s revision %d.%d detected (1.4 supported)\n",
2442 name, (header->major_rev != 1 || header->minor_rev < 2 ||
2443 header->minor_rev > 4 )? "Invalid" : "Warning:",
2444 header->major_rev, header->minor_rev);
2445#endif
2446 if (header->major_rev != 1 || header->minor_rev < 2 || header->minor_rev > 4)
2447 return 0;
2448 }
2449#if DEBUG
2450 if (header->pt_par_num != 1)
2451 printk(KERN_INFO "%s:W: %d partitions defined, only one supported\n",
2452 name, header->pt_par_num);
2453#endif
2454 memcpy(id_string, aux->application_sig, 4);
2455 id_string[4] = 0;
2456 if (memcmp(id_string, "LIN", 3) == 0) {
2457 STp->linux_media = 1;
2458 linux_media_version = id_string[3] - '0';
2459 if (linux_media_version != 4)
2460 printk(KERN_INFO "%s:I: Linux media version %d detected (current 4)\n",
2461 name, linux_media_version);
2462 } else {
2463 printk(KERN_WARNING "%s:W: Non Linux media detected (%s)\n", name, id_string);
2464 return 0;
2465 }
2466 if (linux_media_version < STp->linux_media_version) {
2467#if DEBUG
2468 printk(OSST_DEB_MSG "%s:D: Skipping frame %d with linux_media_version %d\n",
2469 name, ppos, linux_media_version);
2470#endif
2471 return 0;
2472 }
2473 if (linux_media_version > STp->linux_media_version) {
2474#if DEBUG
2475 printk(OSST_DEB_MSG "%s:D: Frame %d sets linux_media_version to %d\n",
2476 name, ppos, linux_media_version);
2477#endif
2478 memcpy(STp->application_sig, id_string, 5);
2479 STp->linux_media_version = linux_media_version;
2480 STp->update_frame_cntr = -1;
2481 }
2482 if (update_frame_cntr > STp->update_frame_cntr) {
2483#if DEBUG
2484 printk(OSST_DEB_MSG "%s:D: Frame %d sets update_frame_counter to %d\n",
2485 name, ppos, update_frame_cntr);
2486#endif
2487 if (STp->header_cache == NULL) {
Jesper Juhl20999732010-11-09 00:09:25 +01002488 if ((STp->header_cache = vmalloc(sizeof(os_header_t))) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002489 printk(KERN_ERR "%s:E: Failed to allocate header cache\n", name);
2490 return 0;
2491 }
2492#if DEBUG
2493 printk(OSST_DEB_MSG "%s:D: Allocated memory for header cache\n", name);
2494#endif
2495 }
2496 osst_copy_from_buffer(STp->buffer, (unsigned char *)STp->header_cache);
2497 header = STp->header_cache; /* further accesses from cached (full) copy */
2498
2499 STp->wrt_pass_cntr = ntohs(header->partition[0].wrt_pass_cntr);
2500 STp->first_data_ppos = ntohl(header->partition[0].first_frame_ppos);
2501 STp->eod_frame_ppos = ntohl(header->partition[0].eod_frame_ppos);
2502 STp->eod_frame_lfa = ntohl(header->ext_track_tb.dat_ext_trk_ey.last_hlb);
2503 STp->filemark_cnt = ntohl(aux->filemark_cnt);
2504 STp->first_mark_ppos = ntohl(aux->next_mark_ppos);
2505 STp->last_mark_ppos = ntohl(aux->last_mark_ppos);
2506 STp->last_mark_lbn = ntohl(aux->last_mark_lbn);
2507 STp->update_frame_cntr = update_frame_cntr;
2508#if DEBUG
2509 printk(OSST_DEB_MSG "%s:D: Detected write pass %d, update frame counter %d, filemark counter %d\n",
2510 name, STp->wrt_pass_cntr, STp->update_frame_cntr, STp->filemark_cnt);
2511 printk(OSST_DEB_MSG "%s:D: first data frame on tape = %d, last = %d, eod frame = %d\n", name,
2512 STp->first_data_ppos,
2513 ntohl(header->partition[0].last_frame_ppos),
2514 ntohl(header->partition[0].eod_frame_ppos));
2515 printk(OSST_DEB_MSG "%s:D: first mark on tape = %d, last = %d, eod frame = %d\n",
2516 name, STp->first_mark_ppos, STp->last_mark_ppos, STp->eod_frame_ppos);
2517#endif
2518 if (header->minor_rev < 4 && STp->linux_media_version == 4) {
2519#if DEBUG
2520 printk(OSST_DEB_MSG "%s:D: Moving filemark list to ADR 1.4 location\n", name);
2521#endif
2522 memcpy((void *)header->dat_fm_tab.fm_tab_ent,
2523 (void *)header->old_filemark_list, sizeof(header->dat_fm_tab.fm_tab_ent));
2524 memset((void *)header->old_filemark_list, 0, sizeof(header->old_filemark_list));
2525 }
2526 if (header->minor_rev == 4 &&
2527 (header->ext_trk_tb_off != htons(17192) ||
2528 header->partition[0].partition_num != OS_DATA_PARTITION ||
2529 header->partition[0].par_desc_ver != OS_PARTITION_VERSION ||
2530 header->partition[0].last_frame_ppos != htonl(STp->capacity) ||
2531 header->cfg_col_width != htonl(20) ||
2532 header->dat_col_width != htonl(1500) ||
2533 header->qfa_col_width != htonl(0) ||
2534 header->ext_track_tb.nr_stream_part != 1 ||
2535 header->ext_track_tb.et_ent_sz != 32 ||
2536 header->ext_track_tb.dat_ext_trk_ey.et_part_num != OS_DATA_PARTITION ||
2537 header->ext_track_tb.dat_ext_trk_ey.fmt != 1 ||
2538 header->ext_track_tb.dat_ext_trk_ey.fm_tab_off != htons(17736) ||
2539 header->ext_track_tb.dat_ext_trk_ey.last_hlb_hi != 0 ||
2540 header->ext_track_tb.dat_ext_trk_ey.last_pp != htonl(STp->eod_frame_ppos) ||
2541 header->dat_fm_tab.fm_part_num != OS_DATA_PARTITION ||
2542 header->dat_fm_tab.fm_tab_ent_sz != 4 ||
2543 header->dat_fm_tab.fm_tab_ent_cnt !=
2544 htons(STp->filemark_cnt<OS_FM_TAB_MAX?STp->filemark_cnt:OS_FM_TAB_MAX)))
2545 printk(KERN_WARNING "%s:W: Failed consistency check ADR 1.4 format\n", name);
2546
2547 }
2548
2549 return 1;
2550}
2551
Willem Riede5e6575c2006-02-11 14:46:56 -05002552static int osst_analyze_headers(struct osst_tape * STp, struct osst_request ** aSRpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002553{
2554 int position, ppos;
2555 int first, last;
2556 int valid = 0;
2557 char * name = tape_name(STp);
2558
2559 position = osst_get_frame_position(STp, aSRpnt);
2560
2561 if (STp->raw) {
2562 STp->header_ok = STp->linux_media = 1;
2563 STp->linux_media_version = 0;
2564 return 1;
2565 }
2566 STp->header_ok = STp->linux_media = STp->linux_media_version = 0;
2567 STp->wrt_pass_cntr = STp->update_frame_cntr = -1;
2568 STp->eod_frame_ppos = STp->first_data_ppos = -1;
2569 STp->first_mark_ppos = STp->last_mark_ppos = STp->last_mark_lbn = -1;
2570#if DEBUG
2571 printk(OSST_DEB_MSG "%s:D: Reading header\n", name);
2572#endif
2573
2574 /* optimization for speed - if we are positioned at ppos 10, read second group first */
2575 /* TODO try the ADR 1.1 locations for the second group if we have no valid one yet... */
2576
2577 first = position==10?0xbae: 5;
2578 last = position==10?0xbb3:10;
2579
2580 for (ppos = first; ppos < last; ppos++)
2581 if (__osst_analyze_headers(STp, aSRpnt, ppos))
2582 valid = 1;
2583
2584 first = position==10? 5:0xbae;
2585 last = position==10?10:0xbb3;
2586
2587 for (ppos = first; ppos < last; ppos++)
2588 if (__osst_analyze_headers(STp, aSRpnt, ppos))
2589 valid = 1;
2590
2591 if (!valid) {
2592 printk(KERN_ERR "%s:E: Failed to find valid ADRL header, new media?\n", name);
2593 STp->eod_frame_ppos = STp->first_data_ppos = 0;
2594 osst_set_frame_position(STp, aSRpnt, 10, 0);
2595 return 0;
2596 }
2597 if (position <= STp->first_data_ppos) {
2598 position = STp->first_data_ppos;
2599 STp->ps[0].drv_file = STp->ps[0].drv_block = STp->frame_seq_number = STp->logical_blk_num = 0;
2600 }
2601 osst_set_frame_position(STp, aSRpnt, position, 0);
2602 STp->header_ok = 1;
2603
2604 return 1;
2605}
2606
Willem Riede5e6575c2006-02-11 14:46:56 -05002607static int osst_verify_position(struct osst_tape * STp, struct osst_request ** aSRpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002608{
2609 int frame_position = STp->first_frame_position;
2610 int frame_seq_numbr = STp->frame_seq_number;
2611 int logical_blk_num = STp->logical_blk_num;
2612 int halfway_frame = STp->frame_in_buffer;
2613 int read_pointer = STp->buffer->read_pointer;
2614 int prev_mark_ppos = -1;
2615 int actual_mark_ppos, i, n;
2616#if DEBUG
2617 char * name = tape_name(STp);
2618
2619 printk(OSST_DEB_MSG "%s:D: Verify that the tape is really the one we think before writing\n", name);
2620#endif
2621 osst_set_frame_position(STp, aSRpnt, frame_position - 1, 0);
2622 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
2623#if DEBUG
2624 printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in verify_position\n", name);
2625#endif
2626 return (-EIO);
2627 }
2628 if (STp->linux_media_version >= 4) {
2629 for (i=0; i<STp->filemark_cnt; i++)
2630 if ((n=ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[i])) < frame_position)
2631 prev_mark_ppos = n;
2632 } else
2633 prev_mark_ppos = frame_position - 1; /* usually - we don't really know */
2634 actual_mark_ppos = STp->buffer->aux->frame_type == OS_FRAME_TYPE_MARKER ?
2635 frame_position - 1 : ntohl(STp->buffer->aux->last_mark_ppos);
2636 if (frame_position != STp->first_frame_position ||
2637 frame_seq_numbr != STp->frame_seq_number + (halfway_frame?0:1) ||
2638 prev_mark_ppos != actual_mark_ppos ) {
2639#if DEBUG
2640 printk(OSST_DEB_MSG "%s:D: Block mismatch: fppos %d-%d, fseq %d-%d, mark %d-%d\n", name,
2641 STp->first_frame_position, frame_position,
2642 STp->frame_seq_number + (halfway_frame?0:1),
2643 frame_seq_numbr, actual_mark_ppos, prev_mark_ppos);
2644#endif
2645 return (-EIO);
2646 }
2647 if (halfway_frame) {
2648 /* prepare buffer for append and rewrite on top of original */
2649 osst_set_frame_position(STp, aSRpnt, frame_position - 1, 0);
2650 STp->buffer->buffer_bytes = read_pointer;
2651 STp->ps[STp->partition].rw = ST_WRITING;
2652 STp->dirty = 1;
2653 }
2654 STp->frame_in_buffer = halfway_frame;
2655 STp->frame_seq_number = frame_seq_numbr;
2656 STp->logical_blk_num = logical_blk_num;
2657 return 0;
2658}
2659
2660/* Acc. to OnStream, the vers. numbering is the following:
2661 * X.XX for released versions (X=digit),
2662 * XXXY for unreleased versions (Y=letter)
2663 * Ordering 1.05 < 106A < 106B < ... < 106a < ... < 1.06
2664 * This fn makes monoton numbers out of this scheme ...
2665 */
2666static unsigned int osst_parse_firmware_rev (const char * str)
2667{
2668 if (str[1] == '.') {
2669 return (str[0]-'0')*10000
2670 +(str[2]-'0')*1000
2671 +(str[3]-'0')*100;
2672 } else {
2673 return (str[0]-'0')*10000
2674 +(str[1]-'0')*1000
2675 +(str[2]-'0')*100 - 100
2676 +(str[3]-'@');
2677 }
2678}
2679
2680/*
2681 * Configure the OnStream SCII tape drive for default operation
2682 */
Willem Riede5e6575c2006-02-11 14:46:56 -05002683static int osst_configure_onstream(struct osst_tape *STp, struct osst_request ** aSRpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002684{
2685 unsigned char cmd[MAX_COMMAND_SIZE];
2686 char * name = tape_name(STp);
Willem Riede5e6575c2006-02-11 14:46:56 -05002687 struct osst_request * SRpnt = * aSRpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002688 osst_mode_parameter_header_t * header;
2689 osst_block_size_page_t * bs;
2690 osst_capabilities_page_t * cp;
2691 osst_tape_paramtr_page_t * prm;
2692 int drive_buffer_size;
2693
2694 if (STp->ready != ST_READY) {
2695#if DEBUG
2696 printk(OSST_DEB_MSG "%s:D: Not Ready\n", name);
2697#endif
2698 return (-EIO);
2699 }
2700
2701 if (STp->os_fw_rev < 10600) {
2702 printk(KERN_INFO "%s:I: Old OnStream firmware revision detected (%s),\n", name, STp->device->rev);
2703 printk(KERN_INFO "%s:I: an upgrade to version 1.06 or above is recommended\n", name);
2704 }
2705
2706 /*
2707 * Configure 32.5KB (data+aux) frame size.
2708 * Get the current frame size from the block size mode page
2709 */
2710 memset(cmd, 0, MAX_COMMAND_SIZE);
2711 cmd[0] = MODE_SENSE;
2712 cmd[1] = 8;
2713 cmd[2] = BLOCK_SIZE_PAGE;
2714 cmd[4] = BLOCK_SIZE_PAGE_LENGTH + MODE_HEADER_LENGTH;
2715
2716 SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_FROM_DEVICE, STp->timeout, 0, 1);
2717 if (SRpnt == NULL) {
2718#if DEBUG
2719 printk(OSST_DEB_MSG "osst :D: Busy\n");
2720#endif
2721 return (-EBUSY);
2722 }
2723 *aSRpnt = SRpnt;
2724 if ((STp->buffer)->syscall_result != 0) {
2725 printk (KERN_ERR "%s:E: Can't get tape block size mode page\n", name);
2726 return (-EIO);
2727 }
2728
2729 header = (osst_mode_parameter_header_t *) (STp->buffer)->b_data;
2730 bs = (osst_block_size_page_t *) ((STp->buffer)->b_data + sizeof(osst_mode_parameter_header_t) + header->bdl);
2731
2732#if DEBUG
2733 printk(OSST_DEB_MSG "%s:D: 32KB play back: %s\n", name, bs->play32 ? "Yes" : "No");
2734 printk(OSST_DEB_MSG "%s:D: 32.5KB play back: %s\n", name, bs->play32_5 ? "Yes" : "No");
2735 printk(OSST_DEB_MSG "%s:D: 32KB record: %s\n", name, bs->record32 ? "Yes" : "No");
2736 printk(OSST_DEB_MSG "%s:D: 32.5KB record: %s\n", name, bs->record32_5 ? "Yes" : "No");
2737#endif
2738
2739 /*
2740 * Configure default auto columns mode, 32.5KB transfer mode
2741 */
2742 bs->one = 1;
2743 bs->play32 = 0;
2744 bs->play32_5 = 1;
2745 bs->record32 = 0;
2746 bs->record32_5 = 1;
2747
2748 memset(cmd, 0, MAX_COMMAND_SIZE);
2749 cmd[0] = MODE_SELECT;
2750 cmd[1] = 0x10;
2751 cmd[4] = BLOCK_SIZE_PAGE_LENGTH + MODE_HEADER_LENGTH;
2752
2753 SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_TO_DEVICE, STp->timeout, 0, 1);
2754 *aSRpnt = SRpnt;
2755 if ((STp->buffer)->syscall_result != 0) {
2756 printk (KERN_ERR "%s:E: Couldn't set tape block size mode page\n", name);
2757 return (-EIO);
2758 }
2759
2760#if DEBUG
2761 printk(KERN_INFO "%s:D: Drive Block Size changed to 32.5K\n", name);
2762 /*
2763 * In debug mode, we want to see as many errors as possible
2764 * to test the error recovery mechanism.
2765 */
2766 osst_set_retries(STp, aSRpnt, 0);
2767 SRpnt = * aSRpnt;
2768#endif
2769
2770 /*
2771 * Set vendor name to 'LIN4' for "Linux support version 4".
2772 */
2773
2774 memset(cmd, 0, MAX_COMMAND_SIZE);
2775 cmd[0] = MODE_SELECT;
2776 cmd[1] = 0x10;
2777 cmd[4] = VENDOR_IDENT_PAGE_LENGTH + MODE_HEADER_LENGTH;
2778
2779 header->mode_data_length = VENDOR_IDENT_PAGE_LENGTH + MODE_HEADER_LENGTH - 1;
2780 header->medium_type = 0; /* Medium Type - ignoring */
2781 header->dsp = 0; /* Reserved */
2782 header->bdl = 0; /* Block Descriptor Length */
2783
2784 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 0] = VENDOR_IDENT_PAGE | (1 << 7);
2785 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 1] = 6;
2786 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] = 'L';
2787 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] = 'I';
2788 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 4] = 'N';
2789 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 5] = '4';
2790 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 6] = 0;
2791 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 7] = 0;
2792
2793 SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_TO_DEVICE, STp->timeout, 0, 1);
2794 *aSRpnt = SRpnt;
2795
2796 if ((STp->buffer)->syscall_result != 0) {
2797 printk (KERN_ERR "%s:E: Couldn't set vendor name to %s\n", name,
2798 (char *) ((STp->buffer)->b_data + MODE_HEADER_LENGTH + 2));
2799 return (-EIO);
2800 }
2801
2802 memset(cmd, 0, MAX_COMMAND_SIZE);
2803 cmd[0] = MODE_SENSE;
2804 cmd[1] = 8;
2805 cmd[2] = CAPABILITIES_PAGE;
2806 cmd[4] = CAPABILITIES_PAGE_LENGTH + MODE_HEADER_LENGTH;
2807
2808 SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_FROM_DEVICE, STp->timeout, 0, 1);
2809 *aSRpnt = SRpnt;
2810
2811 if ((STp->buffer)->syscall_result != 0) {
2812 printk (KERN_ERR "%s:E: Can't get capabilities page\n", name);
2813 return (-EIO);
2814 }
2815
2816 header = (osst_mode_parameter_header_t *) (STp->buffer)->b_data;
2817 cp = (osst_capabilities_page_t *) ((STp->buffer)->b_data +
2818 sizeof(osst_mode_parameter_header_t) + header->bdl);
2819
2820 drive_buffer_size = ntohs(cp->buffer_size) / 2;
2821
2822 memset(cmd, 0, MAX_COMMAND_SIZE);
2823 cmd[0] = MODE_SENSE;
2824 cmd[1] = 8;
2825 cmd[2] = TAPE_PARAMTR_PAGE;
2826 cmd[4] = TAPE_PARAMTR_PAGE_LENGTH + MODE_HEADER_LENGTH;
2827
2828 SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_FROM_DEVICE, STp->timeout, 0, 1);
2829 *aSRpnt = SRpnt;
2830
2831 if ((STp->buffer)->syscall_result != 0) {
2832 printk (KERN_ERR "%s:E: Can't get tape parameter page\n", name);
2833 return (-EIO);
2834 }
2835
2836 header = (osst_mode_parameter_header_t *) (STp->buffer)->b_data;
2837 prm = (osst_tape_paramtr_page_t *) ((STp->buffer)->b_data +
2838 sizeof(osst_mode_parameter_header_t) + header->bdl);
2839
2840 STp->density = prm->density;
2841 STp->capacity = ntohs(prm->segtrk) * ntohs(prm->trks);
2842#if DEBUG
2843 printk(OSST_DEB_MSG "%s:D: Density %d, tape length: %dMB, drive buffer size: %dKB\n",
2844 name, STp->density, STp->capacity / 32, drive_buffer_size);
2845#endif
2846
2847 return 0;
2848
2849}
2850
2851
2852/* Step over EOF if it has been inadvertently crossed (ioctl not used because
2853 it messes up the block number). */
Willem Riede5e6575c2006-02-11 14:46:56 -05002854static int cross_eof(struct osst_tape *STp, struct osst_request ** aSRpnt, int forward)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002855{
2856 int result;
2857 char * name = tape_name(STp);
2858
2859#if DEBUG
2860 if (debugging)
2861 printk(OSST_DEB_MSG "%s:D: Stepping over filemark %s.\n",
2862 name, forward ? "forward" : "backward");
2863#endif
2864
2865 if (forward) {
2866 /* assumes that the filemark is already read by the drive, so this is low cost */
2867 result = osst_space_over_filemarks_forward_slow(STp, aSRpnt, MTFSF, 1);
2868 }
2869 else
2870 /* assumes this is only called if we just read the filemark! */
2871 result = osst_seek_logical_blk(STp, aSRpnt, STp->logical_blk_num - 1);
2872
2873 if (result < 0)
2874 printk(KERN_WARNING "%s:W: Stepping over filemark %s failed.\n",
2875 name, forward ? "forward" : "backward");
2876
2877 return result;
2878}
2879
2880
2881/* Get the tape position. */
2882
Willem Riede5e6575c2006-02-11 14:46:56 -05002883static int osst_get_frame_position(struct osst_tape *STp, struct osst_request ** aSRpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002884{
2885 unsigned char scmd[MAX_COMMAND_SIZE];
Willem Riede5e6575c2006-02-11 14:46:56 -05002886 struct osst_request * SRpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002887 int result = 0;
2888 char * name = tape_name(STp);
2889
2890 /* KG: We want to be able to use it for checking Write Buffer availability
2891 * and thus don't want to risk to overwrite anything. Exchange buffers ... */
2892 char mybuf[24];
2893 char * olddata = STp->buffer->b_data;
2894 int oldsize = STp->buffer->buffer_size;
2895
2896 if (STp->ready != ST_READY) return (-EIO);
2897
2898 memset (scmd, 0, MAX_COMMAND_SIZE);
2899 scmd[0] = READ_POSITION;
2900
2901 STp->buffer->b_data = mybuf; STp->buffer->buffer_size = 24;
2902 SRpnt = osst_do_scsi(*aSRpnt, STp, scmd, 20, DMA_FROM_DEVICE,
2903 STp->timeout, MAX_RETRIES, 1);
2904 if (!SRpnt) {
2905 STp->buffer->b_data = olddata; STp->buffer->buffer_size = oldsize;
2906 return (-EBUSY);
2907 }
2908 *aSRpnt = SRpnt;
2909
2910 if (STp->buffer->syscall_result)
Willem Riede5e6575c2006-02-11 14:46:56 -05002911 result = ((SRpnt->sense[2] & 0x0f) == 3) ? -EIO : -EINVAL; /* 3: Write Error */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002912
2913 if (result == -EINVAL)
2914 printk(KERN_ERR "%s:E: Can't read tape position.\n", name);
2915 else {
2916 if (result == -EIO) { /* re-read position - this needs to preserve media errors */
2917 unsigned char mysense[16];
Willem Riede5e6575c2006-02-11 14:46:56 -05002918 memcpy (mysense, SRpnt->sense, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002919 memset (scmd, 0, MAX_COMMAND_SIZE);
2920 scmd[0] = READ_POSITION;
2921 STp->buffer->b_data = mybuf; STp->buffer->buffer_size = 24;
2922 SRpnt = osst_do_scsi(SRpnt, STp, scmd, 20, DMA_FROM_DEVICE,
2923 STp->timeout, MAX_RETRIES, 1);
2924#if DEBUG
2925 printk(OSST_DEB_MSG "%s:D: Reread position, reason=[%02x:%02x:%02x], result=[%s%02x:%02x:%02x]\n",
2926 name, mysense[2], mysense[12], mysense[13], STp->buffer->syscall_result?"":"ok:",
Willem Riede5e6575c2006-02-11 14:46:56 -05002927 SRpnt->sense[2],SRpnt->sense[12],SRpnt->sense[13]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002928#endif
2929 if (!STp->buffer->syscall_result)
Willem Riede5e6575c2006-02-11 14:46:56 -05002930 memcpy (SRpnt->sense, mysense, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002931 else
2932 printk(KERN_WARNING "%s:W: Double error in get position\n", name);
2933 }
2934 STp->first_frame_position = ((STp->buffer)->b_data[4] << 24)
2935 + ((STp->buffer)->b_data[5] << 16)
2936 + ((STp->buffer)->b_data[6] << 8)
2937 + (STp->buffer)->b_data[7];
2938 STp->last_frame_position = ((STp->buffer)->b_data[ 8] << 24)
2939 + ((STp->buffer)->b_data[ 9] << 16)
2940 + ((STp->buffer)->b_data[10] << 8)
2941 + (STp->buffer)->b_data[11];
2942 STp->cur_frames = (STp->buffer)->b_data[15];
2943#if DEBUG
2944 if (debugging) {
2945 printk(OSST_DEB_MSG "%s:D: Drive Positions: host %d, tape %d%s, buffer %d\n", name,
2946 STp->first_frame_position, STp->last_frame_position,
2947 ((STp->buffer)->b_data[0]&0x80)?" (BOP)":
2948 ((STp->buffer)->b_data[0]&0x40)?" (EOP)":"",
2949 STp->cur_frames);
2950 }
2951#endif
2952 if (STp->cur_frames == 0 && STp->first_frame_position != STp->last_frame_position) {
2953#if DEBUG
2954 printk(OSST_DEB_MSG "%s:D: Correcting read position %d, %d, %d\n", name,
2955 STp->first_frame_position, STp->last_frame_position, STp->cur_frames);
2956#endif
2957 STp->first_frame_position = STp->last_frame_position;
2958 }
2959 }
2960 STp->buffer->b_data = olddata; STp->buffer->buffer_size = oldsize;
2961
2962 return (result == 0 ? STp->first_frame_position : result);
2963}
2964
2965
2966/* Set the tape block */
Willem Riede5e6575c2006-02-11 14:46:56 -05002967static int osst_set_frame_position(struct osst_tape *STp, struct osst_request ** aSRpnt, int ppos, int skip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002968{
2969 unsigned char scmd[MAX_COMMAND_SIZE];
Willem Riede5e6575c2006-02-11 14:46:56 -05002970 struct osst_request * SRpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002971 struct st_partstat * STps;
2972 int result = 0;
2973 int pp = (ppos == 3000 && !skip)? 0 : ppos;
2974 char * name = tape_name(STp);
2975
2976 if (STp->ready != ST_READY) return (-EIO);
2977
2978 STps = &(STp->ps[STp->partition]);
2979
2980 if (ppos < 0 || ppos > STp->capacity) {
2981 printk(KERN_WARNING "%s:W: Reposition request %d out of range\n", name, ppos);
2982 pp = ppos = ppos < 0 ? 0 : (STp->capacity - 1);
2983 result = (-EINVAL);
2984 }
2985
2986 do {
2987#if DEBUG
2988 if (debugging)
2989 printk(OSST_DEB_MSG "%s:D: Setting ppos to %d.\n", name, pp);
2990#endif
2991 memset (scmd, 0, MAX_COMMAND_SIZE);
2992 scmd[0] = SEEK_10;
2993 scmd[1] = 1;
2994 scmd[3] = (pp >> 24);
2995 scmd[4] = (pp >> 16);
2996 scmd[5] = (pp >> 8);
2997 scmd[6] = pp;
2998 if (skip)
2999 scmd[9] = 0x80;
3000
3001 SRpnt = osst_do_scsi(*aSRpnt, STp, scmd, 0, DMA_NONE, STp->long_timeout,
3002 MAX_RETRIES, 1);
3003 if (!SRpnt)
3004 return (-EBUSY);
3005 *aSRpnt = SRpnt;
3006
3007 if ((STp->buffer)->syscall_result != 0) {
3008#if DEBUG
3009 printk(OSST_DEB_MSG "%s:D: SEEK command from %d to %d failed.\n",
3010 name, STp->first_frame_position, pp);
3011#endif
3012 result = (-EIO);
3013 }
3014 if (pp != ppos)
3015 osst_wait_ready(STp, aSRpnt, 5 * 60, OSST_WAIT_POSITION_COMPLETE);
3016 } while ((pp != ppos) && (pp = ppos));
3017 STp->first_frame_position = STp->last_frame_position = ppos;
3018 STps->eof = ST_NOEOF;
3019 STps->at_sm = 0;
3020 STps->rw = ST_IDLE;
3021 STp->frame_in_buffer = 0;
3022 return result;
3023}
3024
Willem Riede5e6575c2006-02-11 14:46:56 -05003025static int osst_write_trailer(struct osst_tape *STp, struct osst_request ** aSRpnt, int leave_at_EOT)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003026{
3027 struct st_partstat * STps = &(STp->ps[STp->partition]);
3028 int result = 0;
3029
3030 if (STp->write_type != OS_WRITE_NEW_MARK) {
3031 /* true unless the user wrote the filemark for us */
3032 result = osst_flush_drive_buffer(STp, aSRpnt);
3033 if (result < 0) goto out;
3034 result = osst_write_filemark(STp, aSRpnt);
3035 if (result < 0) goto out;
3036
3037 if (STps->drv_file >= 0)
3038 STps->drv_file++ ;
3039 STps->drv_block = 0;
3040 }
3041 result = osst_write_eod(STp, aSRpnt);
3042 osst_write_header(STp, aSRpnt, leave_at_EOT);
3043
3044 STps->eof = ST_FM;
3045out:
3046 return result;
3047}
3048
3049/* osst versions of st functions - augmented and stripped to suit OnStream only */
3050
3051/* Flush the write buffer (never need to write if variable blocksize). */
Willem Riede5e6575c2006-02-11 14:46:56 -05003052static int osst_flush_write_buffer(struct osst_tape *STp, struct osst_request ** aSRpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003053{
3054 int offset, transfer, blks = 0;
3055 int result = 0;
3056 unsigned char cmd[MAX_COMMAND_SIZE];
Willem Riede5e6575c2006-02-11 14:46:56 -05003057 struct osst_request * SRpnt = *aSRpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003058 struct st_partstat * STps;
3059 char * name = tape_name(STp);
3060
3061 if ((STp->buffer)->writing) {
3062 if (SRpnt == (STp->buffer)->last_SRpnt)
3063#if DEBUG
3064 { printk(OSST_DEB_MSG
Willem Riede5e6575c2006-02-11 14:46:56 -05003065 "%s:D: aSRpnt points to osst_request that write_behind_check will release -- cleared\n", name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003066#endif
3067 *aSRpnt = SRpnt = NULL;
3068#if DEBUG
3069 } else if (SRpnt)
3070 printk(OSST_DEB_MSG
Willem Riede5e6575c2006-02-11 14:46:56 -05003071 "%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 -07003072#endif
3073 osst_write_behind_check(STp);
3074 if ((STp->buffer)->syscall_result) {
3075#if DEBUG
3076 if (debugging)
3077 printk(OSST_DEB_MSG "%s:D: Async write error (flush) %x.\n",
3078 name, (STp->buffer)->midlevel_result);
3079#endif
3080 if ((STp->buffer)->midlevel_result == INT_MAX)
3081 return (-ENOSPC);
3082 return (-EIO);
3083 }
3084 }
3085
3086 result = 0;
3087 if (STp->dirty == 1) {
3088
3089 STp->write_count++;
3090 STps = &(STp->ps[STp->partition]);
3091 STps->rw = ST_WRITING;
3092 offset = STp->buffer->buffer_bytes;
3093 blks = (offset + STp->block_size - 1) / STp->block_size;
3094 transfer = OS_FRAME_SIZE;
3095
3096 if (offset < OS_DATA_SIZE)
3097 osst_zero_buffer_tail(STp->buffer);
3098
3099 if (STp->poll)
3100 if (osst_wait_frame (STp, aSRpnt, STp->first_frame_position, -50, 120))
3101 result = osst_recover_wait_frame(STp, aSRpnt, 1);
3102
3103 memset(cmd, 0, MAX_COMMAND_SIZE);
3104 cmd[0] = WRITE_6;
3105 cmd[1] = 1;
3106 cmd[4] = 1;
3107
3108 switch (STp->write_type) {
3109 case OS_WRITE_DATA:
3110#if DEBUG
3111 if (debugging)
3112 printk(OSST_DEB_MSG "%s:D: Writing %d blocks to frame %d, lblks %d-%d\n",
3113 name, blks, STp->frame_seq_number,
3114 STp->logical_blk_num - blks, STp->logical_blk_num - 1);
3115#endif
3116 osst_init_aux(STp, OS_FRAME_TYPE_DATA, STp->frame_seq_number++,
3117 STp->logical_blk_num - blks, STp->block_size, blks);
3118 break;
3119 case OS_WRITE_EOD:
3120 osst_init_aux(STp, OS_FRAME_TYPE_EOD, STp->frame_seq_number++,
3121 STp->logical_blk_num, 0, 0);
3122 break;
3123 case OS_WRITE_NEW_MARK:
3124 osst_init_aux(STp, OS_FRAME_TYPE_MARKER, STp->frame_seq_number++,
3125 STp->logical_blk_num++, 0, blks=1);
3126 break;
3127 case OS_WRITE_HEADER:
3128 osst_init_aux(STp, OS_FRAME_TYPE_HEADER, 0, 0, 0, blks=0);
3129 break;
3130 default: /* probably FILLER */
3131 osst_init_aux(STp, OS_FRAME_TYPE_FILL, 0, 0, 0, 0);
3132 }
3133#if DEBUG
3134 if (debugging)
Lucas De Marchi25985ed2011-03-30 22:57:33 -03003135 printk(OSST_DEB_MSG "%s:D: Flushing %d bytes, Transferring %d bytes in %d lblocks.\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003136 name, offset, transfer, blks);
3137#endif
3138
3139 SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, transfer, DMA_TO_DEVICE,
3140 STp->timeout, MAX_RETRIES, 1);
3141 *aSRpnt = SRpnt;
3142 if (!SRpnt)
3143 return (-EBUSY);
3144
3145 if ((STp->buffer)->syscall_result != 0) {
3146#if DEBUG
3147 printk(OSST_DEB_MSG
3148 "%s:D: write sense [0]=0x%02x [2]=%02x [12]=%02x [13]=%02x\n",
Willem Riede5e6575c2006-02-11 14:46:56 -05003149 name, SRpnt->sense[0], SRpnt->sense[2],
3150 SRpnt->sense[12], SRpnt->sense[13]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003151#endif
Willem Riede5e6575c2006-02-11 14:46:56 -05003152 if ((SRpnt->sense[0] & 0x70) == 0x70 &&
3153 (SRpnt->sense[2] & 0x40) && /* FIXME - SC-30 drive doesn't assert EOM bit */
3154 (SRpnt->sense[2] & 0x0f) == NO_SENSE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003155 STp->dirty = 0;
3156 (STp->buffer)->buffer_bytes = 0;
3157 result = (-ENOSPC);
3158 }
3159 else {
3160 if (osst_write_error_recovery(STp, aSRpnt, 1)) {
3161 printk(KERN_ERR "%s:E: Error on flush write.\n", name);
3162 result = (-EIO);
3163 }
3164 }
3165 STps->drv_block = (-1); /* FIXME - even if write recovery succeeds? */
3166 }
3167 else {
3168 STp->first_frame_position++;
3169 STp->dirty = 0;
3170 (STp->buffer)->buffer_bytes = 0;
3171 }
3172 }
3173#if DEBUG
3174 printk(OSST_DEB_MSG "%s:D: Exit flush write buffer with code %d\n", name, result);
3175#endif
3176 return result;
3177}
3178
3179
3180/* Flush the tape buffer. The tape will be positioned correctly unless
3181 seek_next is true. */
Willem Riede5e6575c2006-02-11 14:46:56 -05003182static int osst_flush_buffer(struct osst_tape * STp, struct osst_request ** aSRpnt, int seek_next)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003183{
3184 struct st_partstat * STps;
3185 int backspace = 0, result = 0;
3186#if DEBUG
3187 char * name = tape_name(STp);
3188#endif
3189
3190 /*
3191 * If there was a bus reset, block further access
3192 * to this device.
3193 */
3194 if( STp->pos_unknown)
3195 return (-EIO);
3196
3197 if (STp->ready != ST_READY)
3198 return 0;
3199
3200 STps = &(STp->ps[STp->partition]);
3201 if (STps->rw == ST_WRITING || STp->dirty) { /* Writing */
3202 STp->write_type = OS_WRITE_DATA;
3203 return osst_flush_write_buffer(STp, aSRpnt);
3204 }
3205 if (STp->block_size == 0)
3206 return 0;
3207
3208#if DEBUG
3209 printk(OSST_DEB_MSG "%s:D: Reached flush (read) buffer\n", name);
3210#endif
3211
3212 if (!STp->can_bsr) {
3213 backspace = ((STp->buffer)->buffer_bytes + (STp->buffer)->read_pointer) / STp->block_size -
3214 ((STp->buffer)->read_pointer + STp->block_size - 1 ) / STp->block_size ;
3215 (STp->buffer)->buffer_bytes = 0;
3216 (STp->buffer)->read_pointer = 0;
3217 STp->frame_in_buffer = 0; /* FIXME is this relevant w. OSST? */
3218 }
3219
3220 if (!seek_next) {
3221 if (STps->eof == ST_FM_HIT) {
3222 result = cross_eof(STp, aSRpnt, 0); /* Back over the EOF hit */
3223 if (!result)
3224 STps->eof = ST_NOEOF;
3225 else {
3226 if (STps->drv_file >= 0)
3227 STps->drv_file++;
3228 STps->drv_block = 0;
3229 }
3230 }
3231 if (!result && backspace > 0) /* TODO -- design and run a test case for this */
3232 result = osst_seek_logical_blk(STp, aSRpnt, STp->logical_blk_num - backspace);
3233 }
3234 else if (STps->eof == ST_FM_HIT) {
3235 if (STps->drv_file >= 0)
3236 STps->drv_file++;
3237 STps->drv_block = 0;
3238 STps->eof = ST_NOEOF;
3239 }
3240
3241 return result;
3242}
3243
Willem Riede5e6575c2006-02-11 14:46:56 -05003244static int osst_write_frame(struct osst_tape * STp, struct osst_request ** aSRpnt, int synchronous)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003245{
3246 unsigned char cmd[MAX_COMMAND_SIZE];
Willem Riede5e6575c2006-02-11 14:46:56 -05003247 struct osst_request * SRpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003248 int blks;
3249#if DEBUG
3250 char * name = tape_name(STp);
3251#endif
3252
3253 if ((!STp-> raw) && (STp->first_frame_position == 0xbae)) { /* _must_ preserve buffer! */
3254#if DEBUG
3255 printk(OSST_DEB_MSG "%s:D: Reaching config partition.\n", name);
3256#endif
3257 if (osst_flush_drive_buffer(STp, aSRpnt) < 0) {
3258 return (-EIO);
3259 }
3260 /* error recovery may have bumped us past the header partition */
3261 if (osst_get_frame_position(STp, aSRpnt) < 0xbb8) {
3262#if DEBUG
3263 printk(OSST_DEB_MSG "%s:D: Skipping over config partition.\n", name);
3264#endif
3265 osst_position_tape_and_confirm(STp, aSRpnt, 0xbb8);
3266 }
3267 }
3268
3269 if (STp->poll)
3270 if (osst_wait_frame (STp, aSRpnt, STp->first_frame_position, -48, 120))
3271 if (osst_recover_wait_frame(STp, aSRpnt, 1))
3272 return (-EIO);
3273
3274// osst_build_stats(STp, &SRpnt);
3275
3276 STp->ps[STp->partition].rw = ST_WRITING;
3277 STp->write_type = OS_WRITE_DATA;
3278
3279 memset(cmd, 0, MAX_COMMAND_SIZE);
3280 cmd[0] = WRITE_6;
3281 cmd[1] = 1;
3282 cmd[4] = 1; /* one frame at a time... */
3283 blks = STp->buffer->buffer_bytes / STp->block_size;
3284#if DEBUG
3285 if (debugging)
3286 printk(OSST_DEB_MSG "%s:D: Writing %d blocks to frame %d, lblks %d-%d\n", name, blks,
3287 STp->frame_seq_number, STp->logical_blk_num - blks, STp->logical_blk_num - 1);
3288#endif
3289 osst_init_aux(STp, OS_FRAME_TYPE_DATA, STp->frame_seq_number++,
3290 STp->logical_blk_num - blks, STp->block_size, blks);
3291
3292#if DEBUG
3293 if (!synchronous)
3294 STp->write_pending = 1;
3295#endif
3296 SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, OS_FRAME_SIZE, DMA_TO_DEVICE, STp->timeout,
3297 MAX_RETRIES, synchronous);
3298 if (!SRpnt)
3299 return (-EBUSY);
3300 *aSRpnt = SRpnt;
3301
3302 if (synchronous) {
3303 if (STp->buffer->syscall_result != 0) {
3304#if DEBUG
3305 if (debugging)
3306 printk(OSST_DEB_MSG "%s:D: Error on write:\n", name);
3307#endif
Willem Riede5e6575c2006-02-11 14:46:56 -05003308 if ((SRpnt->sense[0] & 0x70) == 0x70 &&
3309 (SRpnt->sense[2] & 0x40)) {
3310 if ((SRpnt->sense[2] & 0x0f) == VOLUME_OVERFLOW)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003311 return (-ENOSPC);
3312 }
3313 else {
3314 if (osst_write_error_recovery(STp, aSRpnt, 1))
3315 return (-EIO);
3316 }
3317 }
3318 else
3319 STp->first_frame_position++;
3320 }
3321
3322 STp->write_count++;
3323
3324 return 0;
3325}
3326
Willem Riede5e6575c2006-02-11 14:46:56 -05003327/* Lock or unlock the drive door. Don't use when struct osst_request allocated. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003328static int do_door_lock(struct osst_tape * STp, int do_lock)
3329{
Christoph Hellwig2b3b3d62014-10-11 16:00:33 +02003330 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003331
Linus Torvalds1da177e2005-04-16 15:20:36 -07003332#if DEBUG
3333 printk(OSST_DEB_MSG "%s:D: %socking drive door.\n", tape_name(STp), do_lock ? "L" : "Unl");
3334#endif
Christoph Hellwig2b3b3d62014-10-11 16:00:33 +02003335
3336 retval = scsi_set_medium_removal(STp->device,
3337 do_lock ? SCSI_REMOVAL_PREVENT : SCSI_REMOVAL_ALLOW);
3338 if (!retval)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003339 STp->door_locked = do_lock ? ST_LOCKED_EXPLICIT : ST_UNLOCKED;
Christoph Hellwig2b3b3d62014-10-11 16:00:33 +02003340 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07003341 STp->door_locked = ST_LOCK_FAILS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003342 return retval;
3343}
3344
3345/* Set the internal state after reset */
3346static void reset_state(struct osst_tape *STp)
3347{
3348 int i;
3349 struct st_partstat *STps;
3350
3351 STp->pos_unknown = 0;
3352 for (i = 0; i < ST_NBR_PARTITIONS; i++) {
3353 STps = &(STp->ps[i]);
3354 STps->rw = ST_IDLE;
3355 STps->eof = ST_NOEOF;
3356 STps->at_sm = 0;
3357 STps->last_block_valid = 0;
3358 STps->drv_block = -1;
3359 STps->drv_file = -1;
3360 }
3361}
3362
3363
3364/* Entry points to osst */
3365
3366/* Write command */
3367static ssize_t osst_write(struct file * filp, const char __user * buf, size_t count, loff_t *ppos)
3368{
3369 ssize_t total, retval = 0;
3370 ssize_t i, do_count, blks, transfer;
3371 int write_threshold;
3372 int doing_write = 0;
3373 const char __user * b_point;
Willem Riede5e6575c2006-02-11 14:46:56 -05003374 struct osst_request * SRpnt = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003375 struct st_modedef * STm;
3376 struct st_partstat * STps;
3377 struct osst_tape * STp = filp->private_data;
3378 char * name = tape_name(STp);
3379
3380
Matthias Kaehlcke4390e602007-08-10 14:50:44 -07003381 if (mutex_lock_interruptible(&STp->lock))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003382 return (-ERESTARTSYS);
3383
3384 /*
3385 * If we are in the middle of error recovery, don't let anyone
3386 * else try and use this device. Also, if error recovery fails, it
3387 * may try and take the device offline, in which case all further
3388 * access to the device is prohibited.
3389 */
3390 if( !scsi_block_when_processing_errors(STp->device) ) {
3391 retval = (-ENXIO);
3392 goto out;
3393 }
3394
3395 if (STp->ready != ST_READY) {
3396 if (STp->ready == ST_NO_TAPE)
3397 retval = (-ENOMEDIUM);
3398 else
3399 retval = (-EIO);
3400 goto out;
3401 }
3402 STm = &(STp->modes[STp->current_mode]);
3403 if (!STm->defined) {
3404 retval = (-ENXIO);
3405 goto out;
3406 }
3407 if (count == 0)
3408 goto out;
3409
3410 /*
3411 * If there was a bus reset, block further access
3412 * to this device.
3413 */
3414 if (STp->pos_unknown) {
3415 retval = (-EIO);
3416 goto out;
3417 }
3418
3419#if DEBUG
3420 if (!STp->in_use) {
3421 printk(OSST_DEB_MSG "%s:D: Incorrect device.\n", name);
3422 retval = (-EIO);
3423 goto out;
3424 }
3425#endif
3426
3427 if (STp->write_prot) {
3428 retval = (-EACCES);
3429 goto out;
3430 }
3431
3432 /* Write must be integral number of blocks */
3433 if (STp->block_size != 0 && (count % STp->block_size) != 0) {
3434 printk(KERN_ERR "%s:E: Write (%Zd bytes) not multiple of tape block size (%d%c).\n",
3435 name, count, STp->block_size<1024?
3436 STp->block_size:STp->block_size/1024, STp->block_size<1024?'b':'k');
3437 retval = (-EINVAL);
3438 goto out;
3439 }
3440
3441 if (STp->first_frame_position >= STp->capacity - OSST_EOM_RESERVE) {
3442 printk(KERN_ERR "%s:E: Write truncated at EOM early warning (frame %d).\n",
3443 name, STp->first_frame_position);
3444 retval = (-ENOSPC);
3445 goto out;
3446 }
3447
3448 if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED && !do_door_lock(STp, 1))
3449 STp->door_locked = ST_LOCKED_AUTO;
3450
3451 STps = &(STp->ps[STp->partition]);
3452
3453 if (STps->rw == ST_READING) {
3454#if DEBUG
3455 printk(OSST_DEB_MSG "%s:D: Switching from read to write at file %d, block %d\n", name,
3456 STps->drv_file, STps->drv_block);
3457#endif
3458 retval = osst_flush_buffer(STp, &SRpnt, 0);
3459 if (retval)
3460 goto out;
3461 STps->rw = ST_IDLE;
3462 }
3463 if (STps->rw != ST_WRITING) {
3464 /* Are we totally rewriting this tape? */
3465 if (!STp->header_ok ||
3466 (STp->first_frame_position == STp->first_data_ppos && STps->drv_block < 0) ||
3467 (STps->drv_file == 0 && STps->drv_block == 0)) {
3468 STp->wrt_pass_cntr++;
3469#if DEBUG
3470 printk(OSST_DEB_MSG "%s:D: Allocating next write pass counter: %d\n",
3471 name, STp->wrt_pass_cntr);
3472#endif
3473 osst_reset_header(STp, &SRpnt);
3474 STps->drv_file = STps->drv_block = 0;
3475 }
3476 /* Do we know where we'll be writing on the tape? */
3477 else {
3478 if ((STp->fast_open && osst_verify_position(STp, &SRpnt)) ||
3479 STps->drv_file < 0 || STps->drv_block < 0) {
3480 if (STp->first_frame_position == STp->eod_frame_ppos) { /* at EOD */
3481 STps->drv_file = STp->filemark_cnt;
3482 STps->drv_block = 0;
3483 }
3484 else {
3485 /* We have no idea where the tape is positioned - give up */
3486#if DEBUG
3487 printk(OSST_DEB_MSG
3488 "%s:D: Cannot write at indeterminate position.\n", name);
3489#endif
3490 retval = (-EIO);
3491 goto out;
3492 }
3493 }
3494 if ((STps->drv_file + STps->drv_block) > 0 && STps->drv_file < STp->filemark_cnt) {
3495 STp->filemark_cnt = STps->drv_file;
3496 STp->last_mark_ppos =
3497 ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[STp->filemark_cnt-1]);
3498 printk(KERN_WARNING
3499 "%s:W: Overwriting file %d with old write pass counter %d\n",
3500 name, STps->drv_file, STp->wrt_pass_cntr);
3501 printk(KERN_WARNING
3502 "%s:W: may lead to stale data being accepted on reading back!\n",
3503 name);
3504#if DEBUG
3505 printk(OSST_DEB_MSG
3506 "%s:D: resetting filemark count to %d and last mark ppos,lbn to %d,%d\n",
3507 name, STp->filemark_cnt, STp->last_mark_ppos, STp->last_mark_lbn);
3508#endif
3509 }
3510 }
3511 STp->fast_open = 0;
3512 }
3513 if (!STp->header_ok) {
3514#if DEBUG
3515 printk(OSST_DEB_MSG "%s:D: Write cannot proceed without valid headers\n", name);
3516#endif
3517 retval = (-EIO);
3518 goto out;
3519 }
3520
3521 if ((STp->buffer)->writing) {
3522if (SRpnt) printk(KERN_ERR "%s:A: Not supposed to have SRpnt at line %d\n", name, __LINE__);
3523 osst_write_behind_check(STp);
3524 if ((STp->buffer)->syscall_result) {
3525#if DEBUG
3526 if (debugging)
3527 printk(OSST_DEB_MSG "%s:D: Async write error (write) %x.\n", name,
3528 (STp->buffer)->midlevel_result);
3529#endif
3530 if ((STp->buffer)->midlevel_result == INT_MAX)
3531 STps->eof = ST_EOM_OK;
3532 else
3533 STps->eof = ST_EOM_ERROR;
3534 }
3535 }
3536 if (STps->eof == ST_EOM_OK) {
3537 retval = (-ENOSPC);
3538 goto out;
3539 }
3540 else if (STps->eof == ST_EOM_ERROR) {
3541 retval = (-EIO);
3542 goto out;
3543 }
3544
3545 /* Check the buffer readability in cases where copy_user might catch
3546 the problems after some tape movement. */
3547 if ((copy_from_user(&i, buf, 1) != 0 ||
3548 copy_from_user(&i, buf + count - 1, 1) != 0)) {
3549 retval = (-EFAULT);
3550 goto out;
3551 }
3552
3553 if (!STm->do_buffer_writes) {
3554 write_threshold = 1;
3555 }
3556 else
3557 write_threshold = (STp->buffer)->buffer_blocks * STp->block_size;
3558 if (!STm->do_async_writes)
3559 write_threshold--;
3560
3561 total = count;
3562#if DEBUG
3563 if (debugging)
3564 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 -05003565 name, (int) count, STps->drv_file, STps->drv_block,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003566 STp->logical_blk_num, STp->frame_seq_number, STp->first_frame_position);
3567#endif
3568 b_point = buf;
3569 while ((STp->buffer)->buffer_bytes + count > write_threshold)
3570 {
3571 doing_write = 1;
3572 do_count = (STp->buffer)->buffer_blocks * STp->block_size -
3573 (STp->buffer)->buffer_bytes;
3574 if (do_count > count)
3575 do_count = count;
3576
3577 i = append_to_buffer(b_point, STp->buffer, do_count);
3578 if (i) {
3579 retval = i;
3580 goto out;
3581 }
3582
3583 blks = do_count / STp->block_size;
3584 STp->logical_blk_num += blks; /* logical_blk_num is incremented as data is moved from user */
3585
3586 i = osst_write_frame(STp, &SRpnt, 1);
3587
3588 if (i == (-ENOSPC)) {
3589 transfer = STp->buffer->writing; /* FIXME -- check this logic */
3590 if (transfer <= do_count) {
Jan Bluncke1c54b62010-05-26 14:44:44 -07003591 *ppos += do_count - transfer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003592 count -= do_count - transfer;
3593 if (STps->drv_block >= 0) {
3594 STps->drv_block += (do_count - transfer) / STp->block_size;
3595 }
3596 STps->eof = ST_EOM_OK;
3597 retval = (-ENOSPC); /* EOM within current request */
3598#if DEBUG
3599 if (debugging)
3600 printk(OSST_DEB_MSG "%s:D: EOM with %d bytes unwritten.\n",
Willem Riede5e6575c2006-02-11 14:46:56 -05003601 name, (int) transfer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003602#endif
3603 }
3604 else {
3605 STps->eof = ST_EOM_ERROR;
3606 STps->drv_block = (-1); /* Too cautious? */
3607 retval = (-EIO); /* EOM for old data */
3608#if DEBUG
3609 if (debugging)
3610 printk(OSST_DEB_MSG "%s:D: EOM with lost data.\n", name);
3611#endif
3612 }
3613 }
3614 else
3615 retval = i;
3616
3617 if (retval < 0) {
3618 if (SRpnt != NULL) {
Willem Riede5e6575c2006-02-11 14:46:56 -05003619 osst_release_request(SRpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003620 SRpnt = NULL;
3621 }
3622 STp->buffer->buffer_bytes = 0;
3623 STp->dirty = 0;
3624 if (count < total)
3625 retval = total - count;
3626 goto out;
3627 }
3628
Jan Bluncke1c54b62010-05-26 14:44:44 -07003629 *ppos += do_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003630 b_point += do_count;
3631 count -= do_count;
3632 if (STps->drv_block >= 0) {
3633 STps->drv_block += blks;
3634 }
3635 STp->buffer->buffer_bytes = 0;
3636 STp->dirty = 0;
3637 } /* end while write threshold exceeded */
3638
3639 if (count != 0) {
3640 STp->dirty = 1;
3641 i = append_to_buffer(b_point, STp->buffer, count);
3642 if (i) {
3643 retval = i;
3644 goto out;
3645 }
3646 blks = count / STp->block_size;
3647 STp->logical_blk_num += blks;
3648 if (STps->drv_block >= 0) {
3649 STps->drv_block += blks;
3650 }
Jan Bluncke1c54b62010-05-26 14:44:44 -07003651 *ppos += count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003652 count = 0;
3653 }
3654
3655 if (doing_write && (STp->buffer)->syscall_result != 0) {
3656 retval = (STp->buffer)->syscall_result;
3657 goto out;
3658 }
3659
3660 if (STm->do_async_writes && ((STp->buffer)->buffer_bytes >= STp->write_threshold)) {
3661 /* Schedule an asynchronous write */
3662 (STp->buffer)->writing = ((STp->buffer)->buffer_bytes /
3663 STp->block_size) * STp->block_size;
3664 STp->dirty = !((STp->buffer)->writing ==
3665 (STp->buffer)->buffer_bytes);
3666
3667 i = osst_write_frame(STp, &SRpnt, 0);
3668 if (i < 0) {
3669 retval = (-EIO);
3670 goto out;
3671 }
3672 SRpnt = NULL; /* Prevent releasing this request! */
3673 }
3674 STps->at_sm &= (total == 0);
3675 if (total > 0)
3676 STps->eof = ST_NOEOF;
3677
3678 retval = total;
3679
3680out:
Willem Riede5e6575c2006-02-11 14:46:56 -05003681 if (SRpnt != NULL) osst_release_request(SRpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003682
Matthias Kaehlcke4390e602007-08-10 14:50:44 -07003683 mutex_unlock(&STp->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003684
3685 return retval;
3686}
3687
3688
3689/* Read command */
3690static ssize_t osst_read(struct file * filp, char __user * buf, size_t count, loff_t *ppos)
3691{
3692 ssize_t total, retval = 0;
3693 ssize_t i, transfer;
3694 int special;
3695 struct st_modedef * STm;
3696 struct st_partstat * STps;
Willem Riede5e6575c2006-02-11 14:46:56 -05003697 struct osst_request * SRpnt = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003698 struct osst_tape * STp = filp->private_data;
3699 char * name = tape_name(STp);
3700
3701
Matthias Kaehlcke4390e602007-08-10 14:50:44 -07003702 if (mutex_lock_interruptible(&STp->lock))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003703 return (-ERESTARTSYS);
3704
3705 /*
3706 * If we are in the middle of error recovery, don't let anyone
3707 * else try and use this device. Also, if error recovery fails, it
3708 * may try and take the device offline, in which case all further
3709 * access to the device is prohibited.
3710 */
3711 if( !scsi_block_when_processing_errors(STp->device) ) {
3712 retval = (-ENXIO);
3713 goto out;
3714 }
3715
3716 if (STp->ready != ST_READY) {
3717 if (STp->ready == ST_NO_TAPE)
3718 retval = (-ENOMEDIUM);
3719 else
3720 retval = (-EIO);
3721 goto out;
3722 }
3723 STm = &(STp->modes[STp->current_mode]);
3724 if (!STm->defined) {
3725 retval = (-ENXIO);
3726 goto out;
3727 }
3728#if DEBUG
3729 if (!STp->in_use) {
3730 printk(OSST_DEB_MSG "%s:D: Incorrect device.\n", name);
3731 retval = (-EIO);
3732 goto out;
3733 }
3734#endif
3735 /* Must have initialized medium */
3736 if (!STp->header_ok) {
3737 retval = (-EIO);
3738 goto out;
3739 }
3740
3741 if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED && !do_door_lock(STp, 1))
3742 STp->door_locked = ST_LOCKED_AUTO;
3743
3744 STps = &(STp->ps[STp->partition]);
3745 if (STps->rw == ST_WRITING) {
3746 retval = osst_flush_buffer(STp, &SRpnt, 0);
3747 if (retval)
3748 goto out;
3749 STps->rw = ST_IDLE;
3750 /* FIXME -- this may leave the tape without EOD and up2date headers */
3751 }
3752
3753 if ((count % STp->block_size) != 0) {
3754 printk(KERN_WARNING
3755 "%s:W: Read (%Zd bytes) not multiple of tape block size (%d%c).\n", name, count,
3756 STp->block_size<1024?STp->block_size:STp->block_size/1024, STp->block_size<1024?'b':'k');
3757 }
3758
3759#if DEBUG
3760 if (debugging && STps->eof != ST_NOEOF)
3761 printk(OSST_DEB_MSG "%s:D: EOF/EOM flag up (%d). Bytes %d\n", name,
3762 STps->eof, (STp->buffer)->buffer_bytes);
3763#endif
3764 if ((STp->buffer)->buffer_bytes == 0 &&
3765 STps->eof >= ST_EOD_1) {
3766 if (STps->eof < ST_EOD) {
3767 STps->eof += 1;
3768 retval = 0;
3769 goto out;
3770 }
3771 retval = (-EIO); /* EOM or Blank Check */
3772 goto out;
3773 }
3774
3775 /* Check the buffer writability before any tape movement. Don't alter
3776 buffer data. */
3777 if (copy_from_user(&i, buf, 1) != 0 ||
3778 copy_to_user (buf, &i, 1) != 0 ||
3779 copy_from_user(&i, buf + count - 1, 1) != 0 ||
3780 copy_to_user (buf + count - 1, &i, 1) != 0) {
3781 retval = (-EFAULT);
3782 goto out;
3783 }
3784
3785 /* Loop until enough data in buffer or a special condition found */
3786 for (total = 0, special = 0; total < count - STp->block_size + 1 && !special; ) {
3787
3788 /* Get new data if the buffer is empty */
3789 if ((STp->buffer)->buffer_bytes == 0) {
3790 if (STps->eof == ST_FM_HIT)
3791 break;
3792 special = osst_get_logical_frame(STp, &SRpnt, STp->frame_seq_number, 0);
3793 if (special < 0) { /* No need to continue read */
3794 STp->frame_in_buffer = 0;
3795 retval = special;
3796 goto out;
3797 }
3798 }
3799
3800 /* Move the data from driver buffer to user buffer */
3801 if ((STp->buffer)->buffer_bytes > 0) {
3802#if DEBUG
3803 if (debugging && STps->eof != ST_NOEOF)
3804 printk(OSST_DEB_MSG "%s:D: EOF up (%d). Left %d, needed %d.\n", name,
Willem Riede5e6575c2006-02-11 14:46:56 -05003805 STps->eof, (STp->buffer)->buffer_bytes, (int) (count - total));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003806#endif
3807 /* force multiple of block size, note block_size may have been adjusted */
3808 transfer = (((STp->buffer)->buffer_bytes < count - total ?
3809 (STp->buffer)->buffer_bytes : count - total)/
3810 STp->block_size) * STp->block_size;
3811
3812 if (transfer == 0) {
3813 printk(KERN_WARNING
Lucas De Marchi25985ed2011-03-30 22:57:33 -03003814 "%s:W: Nothing can be transferred, requested %Zd, tape block size (%d%c).\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003815 name, count, STp->block_size < 1024?
3816 STp->block_size:STp->block_size/1024,
3817 STp->block_size<1024?'b':'k');
3818 break;
3819 }
3820 i = from_buffer(STp->buffer, buf, transfer);
3821 if (i) {
3822 retval = i;
3823 goto out;
3824 }
3825 STp->logical_blk_num += transfer / STp->block_size;
3826 STps->drv_block += transfer / STp->block_size;
Jan Bluncke1c54b62010-05-26 14:44:44 -07003827 *ppos += transfer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003828 buf += transfer;
3829 total += transfer;
3830 }
3831
3832 if ((STp->buffer)->buffer_bytes == 0) {
3833#if DEBUG
3834 if (debugging)
3835 printk(OSST_DEB_MSG "%s:D: Finished with frame %d\n",
3836 name, STp->frame_seq_number);
3837#endif
3838 STp->frame_in_buffer = 0;
3839 STp->frame_seq_number++; /* frame to look for next time */
3840 }
3841 } /* for (total = 0, special = 0; total < count && !special; ) */
3842
3843 /* Change the eof state if no data from tape or buffer */
3844 if (total == 0) {
3845 if (STps->eof == ST_FM_HIT) {
3846 STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD_2:ST_FM;
3847 STps->drv_block = 0;
3848 if (STps->drv_file >= 0)
3849 STps->drv_file++;
3850 }
3851 else if (STps->eof == ST_EOD_1) {
3852 STps->eof = ST_EOD_2;
3853 if (STps->drv_block > 0 && STps->drv_file >= 0)
3854 STps->drv_file++;
3855 STps->drv_block = 0;
3856 }
3857 else if (STps->eof == ST_EOD_2)
3858 STps->eof = ST_EOD;
3859 }
3860 else if (STps->eof == ST_FM)
3861 STps->eof = ST_NOEOF;
3862
3863 retval = total;
3864
3865out:
Willem Riede5e6575c2006-02-11 14:46:56 -05003866 if (SRpnt != NULL) osst_release_request(SRpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003867
Matthias Kaehlcke4390e602007-08-10 14:50:44 -07003868 mutex_unlock(&STp->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003869
3870 return retval;
3871}
3872
3873
3874/* Set the driver options */
3875static void osst_log_options(struct osst_tape *STp, struct st_modedef *STm, char *name)
3876{
3877 printk(KERN_INFO
3878"%s:I: Mode %d options: buffer writes: %d, async writes: %d, read ahead: %d\n",
3879 name, STp->current_mode, STm->do_buffer_writes, STm->do_async_writes,
3880 STm->do_read_ahead);
3881 printk(KERN_INFO
3882"%s:I: can bsr: %d, two FMs: %d, fast mteom: %d, auto lock: %d,\n",
3883 name, STp->can_bsr, STp->two_fm, STp->fast_mteom, STp->do_auto_lock);
3884 printk(KERN_INFO
3885"%s:I: defs for wr: %d, no block limits: %d, partitions: %d, s2 log: %d\n",
3886 name, STm->defaults_for_writes, STp->omit_blklims, STp->can_partitions,
3887 STp->scsi2_logical);
3888 printk(KERN_INFO
3889"%s:I: sysv: %d\n", name, STm->sysv);
3890#if DEBUG
3891 printk(KERN_INFO
3892 "%s:D: debugging: %d\n",
3893 name, debugging);
3894#endif
3895}
3896
3897
3898static int osst_set_options(struct osst_tape *STp, long options)
3899{
3900 int value;
3901 long code;
3902 struct st_modedef * STm;
3903 char * name = tape_name(STp);
3904
3905 STm = &(STp->modes[STp->current_mode]);
3906 if (!STm->defined) {
3907 memcpy(STm, &(STp->modes[0]), sizeof(*STm));
3908 modes_defined = 1;
3909#if DEBUG
3910 if (debugging)
3911 printk(OSST_DEB_MSG "%s:D: Initialized mode %d definition from mode 0\n",
3912 name, STp->current_mode);
3913#endif
3914 }
3915
3916 code = options & MT_ST_OPTIONS;
3917 if (code == MT_ST_BOOLEANS) {
3918 STm->do_buffer_writes = (options & MT_ST_BUFFER_WRITES) != 0;
3919 STm->do_async_writes = (options & MT_ST_ASYNC_WRITES) != 0;
3920 STm->defaults_for_writes = (options & MT_ST_DEF_WRITES) != 0;
3921 STm->do_read_ahead = (options & MT_ST_READ_AHEAD) != 0;
3922 STp->two_fm = (options & MT_ST_TWO_FM) != 0;
3923 STp->fast_mteom = (options & MT_ST_FAST_MTEOM) != 0;
3924 STp->do_auto_lock = (options & MT_ST_AUTO_LOCK) != 0;
3925 STp->can_bsr = (options & MT_ST_CAN_BSR) != 0;
3926 STp->omit_blklims = (options & MT_ST_NO_BLKLIMS) != 0;
3927 if ((STp->device)->scsi_level >= SCSI_2)
3928 STp->can_partitions = (options & MT_ST_CAN_PARTITIONS) != 0;
3929 STp->scsi2_logical = (options & MT_ST_SCSI2LOGICAL) != 0;
3930 STm->sysv = (options & MT_ST_SYSV) != 0;
3931#if DEBUG
3932 debugging = (options & MT_ST_DEBUGGING) != 0;
3933#endif
3934 osst_log_options(STp, STm, name);
3935 }
3936 else if (code == MT_ST_SETBOOLEANS || code == MT_ST_CLEARBOOLEANS) {
3937 value = (code == MT_ST_SETBOOLEANS);
3938 if ((options & MT_ST_BUFFER_WRITES) != 0)
3939 STm->do_buffer_writes = value;
3940 if ((options & MT_ST_ASYNC_WRITES) != 0)
3941 STm->do_async_writes = value;
3942 if ((options & MT_ST_DEF_WRITES) != 0)
3943 STm->defaults_for_writes = value;
3944 if ((options & MT_ST_READ_AHEAD) != 0)
3945 STm->do_read_ahead = value;
3946 if ((options & MT_ST_TWO_FM) != 0)
3947 STp->two_fm = value;
3948 if ((options & MT_ST_FAST_MTEOM) != 0)
3949 STp->fast_mteom = value;
3950 if ((options & MT_ST_AUTO_LOCK) != 0)
3951 STp->do_auto_lock = value;
3952 if ((options & MT_ST_CAN_BSR) != 0)
3953 STp->can_bsr = value;
3954 if ((options & MT_ST_NO_BLKLIMS) != 0)
3955 STp->omit_blklims = value;
3956 if ((STp->device)->scsi_level >= SCSI_2 &&
3957 (options & MT_ST_CAN_PARTITIONS) != 0)
3958 STp->can_partitions = value;
3959 if ((options & MT_ST_SCSI2LOGICAL) != 0)
3960 STp->scsi2_logical = value;
3961 if ((options & MT_ST_SYSV) != 0)
3962 STm->sysv = value;
3963#if DEBUG
3964 if ((options & MT_ST_DEBUGGING) != 0)
3965 debugging = value;
3966#endif
3967 osst_log_options(STp, STm, name);
3968 }
3969 else if (code == MT_ST_WRITE_THRESHOLD) {
3970 value = (options & ~MT_ST_OPTIONS) * ST_KILOBYTE;
3971 if (value < 1 || value > osst_buffer_size) {
3972 printk(KERN_WARNING "%s:W: Write threshold %d too small or too large.\n",
3973 name, value);
3974 return (-EIO);
3975 }
3976 STp->write_threshold = value;
3977 printk(KERN_INFO "%s:I: Write threshold set to %d bytes.\n",
3978 name, value);
3979 }
3980 else if (code == MT_ST_DEF_BLKSIZE) {
3981 value = (options & ~MT_ST_OPTIONS);
3982 if (value == ~MT_ST_OPTIONS) {
3983 STm->default_blksize = (-1);
3984 printk(KERN_INFO "%s:I: Default block size disabled.\n", name);
3985 }
3986 else {
3987 if (value < 512 || value > OS_DATA_SIZE || OS_DATA_SIZE % value) {
3988 printk(KERN_WARNING "%s:W: Default block size cannot be set to %d.\n",
3989 name, value);
3990 return (-EINVAL);
3991 }
3992 STm->default_blksize = value;
3993 printk(KERN_INFO "%s:I: Default block size set to %d bytes.\n",
3994 name, STm->default_blksize);
3995 }
3996 }
3997 else if (code == MT_ST_TIMEOUTS) {
3998 value = (options & ~MT_ST_OPTIONS);
3999 if ((value & MT_ST_SET_LONG_TIMEOUT) != 0) {
4000 STp->long_timeout = (value & ~MT_ST_SET_LONG_TIMEOUT) * HZ;
4001 printk(KERN_INFO "%s:I: Long timeout set to %d seconds.\n", name,
4002 (value & ~MT_ST_SET_LONG_TIMEOUT));
4003 }
4004 else {
4005 STp->timeout = value * HZ;
4006 printk(KERN_INFO "%s:I: Normal timeout set to %d seconds.\n", name, value);
4007 }
4008 }
4009 else if (code == MT_ST_DEF_OPTIONS) {
4010 code = (options & ~MT_ST_CLEAR_DEFAULT);
4011 value = (options & MT_ST_CLEAR_DEFAULT);
4012 if (code == MT_ST_DEF_DENSITY) {
4013 if (value == MT_ST_CLEAR_DEFAULT) {
4014 STm->default_density = (-1);
4015 printk(KERN_INFO "%s:I: Density default disabled.\n", name);
4016 }
4017 else {
4018 STm->default_density = value & 0xff;
4019 printk(KERN_INFO "%s:I: Density default set to %x\n",
4020 name, STm->default_density);
4021 }
4022 }
4023 else if (code == MT_ST_DEF_DRVBUFFER) {
4024 if (value == MT_ST_CLEAR_DEFAULT) {
4025 STp->default_drvbuffer = 0xff;
4026 printk(KERN_INFO "%s:I: Drive buffer default disabled.\n", name);
4027 }
4028 else {
4029 STp->default_drvbuffer = value & 7;
4030 printk(KERN_INFO "%s:I: Drive buffer default set to %x\n",
4031 name, STp->default_drvbuffer);
4032 }
4033 }
4034 else if (code == MT_ST_DEF_COMPRESSION) {
4035 if (value == MT_ST_CLEAR_DEFAULT) {
4036 STm->default_compression = ST_DONT_TOUCH;
4037 printk(KERN_INFO "%s:I: Compression default disabled.\n", name);
4038 }
4039 else {
4040 STm->default_compression = (value & 1 ? ST_YES : ST_NO);
4041 printk(KERN_INFO "%s:I: Compression default set to %x\n",
4042 name, (value & 1));
4043 }
4044 }
4045 }
4046 else
4047 return (-EIO);
4048
4049 return 0;
4050}
4051
4052
4053/* Internal ioctl function */
Willem Riede5e6575c2006-02-11 14:46:56 -05004054static int osst_int_ioctl(struct osst_tape * STp, struct osst_request ** aSRpnt,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004055 unsigned int cmd_in, unsigned long arg)
4056{
4057 int timeout;
4058 long ltmp;
4059 int i, ioctl_result;
4060 int chg_eof = 1;
4061 unsigned char cmd[MAX_COMMAND_SIZE];
Willem Riede5e6575c2006-02-11 14:46:56 -05004062 struct osst_request * SRpnt = * aSRpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004063 struct st_partstat * STps;
4064 int fileno, blkno, at_sm, frame_seq_numbr, logical_blk_num;
4065 int datalen = 0, direction = DMA_NONE;
4066 char * name = tape_name(STp);
4067
4068 if (STp->ready != ST_READY && cmd_in != MTLOAD) {
4069 if (STp->ready == ST_NO_TAPE)
4070 return (-ENOMEDIUM);
4071 else
4072 return (-EIO);
4073 }
4074 timeout = STp->long_timeout;
4075 STps = &(STp->ps[STp->partition]);
4076 fileno = STps->drv_file;
4077 blkno = STps->drv_block;
4078 at_sm = STps->at_sm;
4079 frame_seq_numbr = STp->frame_seq_number;
4080 logical_blk_num = STp->logical_blk_num;
4081
4082 memset(cmd, 0, MAX_COMMAND_SIZE);
4083 switch (cmd_in) {
4084 case MTFSFM:
4085 chg_eof = 0; /* Changed from the FSF after this */
4086 case MTFSF:
4087 if (STp->raw)
4088 return (-EIO);
4089 if (STp->linux_media)
4090 ioctl_result = osst_space_over_filemarks_forward_fast(STp, &SRpnt, cmd_in, arg);
4091 else
4092 ioctl_result = osst_space_over_filemarks_forward_slow(STp, &SRpnt, cmd_in, arg);
4093 if (fileno >= 0)
4094 fileno += arg;
4095 blkno = 0;
4096 at_sm &= (arg == 0);
4097 goto os_bypass;
4098
4099 case MTBSF:
4100 chg_eof = 0; /* Changed from the FSF after this */
4101 case MTBSFM:
4102 if (STp->raw)
4103 return (-EIO);
4104 ioctl_result = osst_space_over_filemarks_backward(STp, &SRpnt, cmd_in, arg);
4105 if (fileno >= 0)
4106 fileno -= arg;
4107 blkno = (-1); /* We can't know the block number */
4108 at_sm &= (arg == 0);
4109 goto os_bypass;
4110
4111 case MTFSR:
4112 case MTBSR:
4113#if DEBUG
4114 if (debugging)
4115 printk(OSST_DEB_MSG "%s:D: Skipping %lu blocks %s from logical block %d\n",
4116 name, arg, cmd_in==MTFSR?"forward":"backward", logical_blk_num);
4117#endif
4118 if (cmd_in == MTFSR) {
4119 logical_blk_num += arg;
4120 if (blkno >= 0) blkno += arg;
4121 }
4122 else {
4123 logical_blk_num -= arg;
4124 if (blkno >= 0) blkno -= arg;
4125 }
4126 ioctl_result = osst_seek_logical_blk(STp, &SRpnt, logical_blk_num);
4127 fileno = STps->drv_file;
4128 blkno = STps->drv_block;
4129 at_sm &= (arg == 0);
4130 goto os_bypass;
4131
4132 case MTFSS:
4133 cmd[0] = SPACE;
4134 cmd[1] = 0x04; /* Space Setmarks */ /* FIXME -- OS can't do this? */
4135 cmd[2] = (arg >> 16);
4136 cmd[3] = (arg >> 8);
4137 cmd[4] = arg;
4138#if DEBUG
4139 if (debugging)
4140 printk(OSST_DEB_MSG "%s:D: Spacing tape forward %d setmarks.\n", name,
4141 cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
4142#endif
4143 if (arg != 0) {
4144 blkno = fileno = (-1);
4145 at_sm = 1;
4146 }
4147 break;
4148 case MTBSS:
4149 cmd[0] = SPACE;
4150 cmd[1] = 0x04; /* Space Setmarks */ /* FIXME -- OS can't do this? */
4151 ltmp = (-arg);
4152 cmd[2] = (ltmp >> 16);
4153 cmd[3] = (ltmp >> 8);
4154 cmd[4] = ltmp;
4155#if DEBUG
4156 if (debugging) {
4157 if (cmd[2] & 0x80)
4158 ltmp = 0xff000000;
4159 ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4];
4160 printk(OSST_DEB_MSG "%s:D: Spacing tape backward %ld setmarks.\n",
4161 name, (-ltmp));
4162 }
4163#endif
4164 if (arg != 0) {
4165 blkno = fileno = (-1);
4166 at_sm = 1;
4167 }
4168 break;
4169 case MTWEOF:
4170 if ((STps->rw == ST_WRITING || STp->dirty) && !STp->pos_unknown) {
4171 STp->write_type = OS_WRITE_DATA;
4172 ioctl_result = osst_flush_write_buffer(STp, &SRpnt);
4173 } else
4174 ioctl_result = 0;
4175#if DEBUG
4176 if (debugging)
4177 printk(OSST_DEB_MSG "%s:D: Writing %ld filemark(s).\n", name, arg);
4178#endif
4179 for (i=0; i<arg; i++)
4180 ioctl_result |= osst_write_filemark(STp, &SRpnt);
4181 if (fileno >= 0) fileno += arg;
4182 if (blkno >= 0) blkno = 0;
4183 goto os_bypass;
4184
4185 case MTWSM:
4186 if (STp->write_prot)
4187 return (-EACCES);
4188 if (!STp->raw)
4189 return 0;
4190 cmd[0] = WRITE_FILEMARKS; /* FIXME -- need OS version */
4191 if (cmd_in == MTWSM)
4192 cmd[1] = 2;
4193 cmd[2] = (arg >> 16);
4194 cmd[3] = (arg >> 8);
4195 cmd[4] = arg;
4196 timeout = STp->timeout;
4197#if DEBUG
4198 if (debugging)
4199 printk(OSST_DEB_MSG "%s:D: Writing %d setmark(s).\n", name,
4200 cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
4201#endif
4202 if (fileno >= 0)
4203 fileno += arg;
4204 blkno = 0;
4205 at_sm = (cmd_in == MTWSM);
4206 break;
4207 case MTOFFL:
4208 case MTLOAD:
4209 case MTUNLOAD:
4210 case MTRETEN:
4211 cmd[0] = START_STOP;
4212 cmd[1] = 1; /* Don't wait for completion */
4213 if (cmd_in == MTLOAD) {
4214 if (STp->ready == ST_NO_TAPE)
4215 cmd[4] = 4; /* open tray */
4216 else
4217 cmd[4] = 1; /* load */
4218 }
4219 if (cmd_in == MTRETEN)
4220 cmd[4] = 3; /* retension then mount */
4221 if (cmd_in == MTOFFL)
4222 cmd[4] = 4; /* rewind then eject */
4223 timeout = STp->timeout;
4224#if DEBUG
4225 if (debugging) {
4226 switch (cmd_in) {
4227 case MTUNLOAD:
4228 printk(OSST_DEB_MSG "%s:D: Unloading tape.\n", name);
4229 break;
4230 case MTLOAD:
4231 printk(OSST_DEB_MSG "%s:D: Loading tape.\n", name);
4232 break;
4233 case MTRETEN:
4234 printk(OSST_DEB_MSG "%s:D: Retensioning tape.\n", name);
4235 break;
4236 case MTOFFL:
4237 printk(OSST_DEB_MSG "%s:D: Ejecting tape.\n", name);
4238 break;
4239 }
4240 }
4241#endif
4242 fileno = blkno = at_sm = frame_seq_numbr = logical_blk_num = 0 ;
4243 break;
4244 case MTNOP:
4245#if DEBUG
4246 if (debugging)
4247 printk(OSST_DEB_MSG "%s:D: No-op on tape.\n", name);
4248#endif
4249 return 0; /* Should do something ? */
4250 break;
4251 case MTEOM:
4252#if DEBUG
4253 if (debugging)
4254 printk(OSST_DEB_MSG "%s:D: Spacing to end of recorded medium.\n", name);
4255#endif
4256 if ((osst_position_tape_and_confirm(STp, &SRpnt, STp->eod_frame_ppos) < 0) ||
4257 (osst_get_logical_frame(STp, &SRpnt, -1, 0) < 0)) {
4258 ioctl_result = -EIO;
4259 goto os_bypass;
4260 }
4261 if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_EOD) {
4262#if DEBUG
4263 printk(OSST_DEB_MSG "%s:D: No EOD frame found where expected.\n", name);
4264#endif
4265 ioctl_result = -EIO;
4266 goto os_bypass;
4267 }
4268 ioctl_result = osst_set_frame_position(STp, &SRpnt, STp->eod_frame_ppos, 0);
4269 fileno = STp->filemark_cnt;
4270 blkno = at_sm = 0;
4271 goto os_bypass;
4272
4273 case MTERASE:
4274 if (STp->write_prot)
4275 return (-EACCES);
4276 ioctl_result = osst_reset_header(STp, &SRpnt);
4277 i = osst_write_eod(STp, &SRpnt);
4278 if (i < ioctl_result) ioctl_result = i;
4279 i = osst_position_tape_and_confirm(STp, &SRpnt, STp->eod_frame_ppos);
4280 if (i < ioctl_result) ioctl_result = i;
4281 fileno = blkno = at_sm = 0 ;
4282 goto os_bypass;
4283
4284 case MTREW:
4285 cmd[0] = REZERO_UNIT; /* rewind */
4286 cmd[1] = 1;
4287#if DEBUG
4288 if (debugging)
4289 printk(OSST_DEB_MSG "%s:D: Rewinding tape, Immed=%d.\n", name, cmd[1]);
4290#endif
4291 fileno = blkno = at_sm = frame_seq_numbr = logical_blk_num = 0 ;
4292 break;
4293
4294 case MTSETBLK: /* Set block length */
4295 if ((STps->drv_block == 0 ) &&
4296 !STp->dirty &&
4297 ((STp->buffer)->buffer_bytes == 0) &&
4298 ((arg & MT_ST_BLKSIZE_MASK) >= 512 ) &&
4299 ((arg & MT_ST_BLKSIZE_MASK) <= OS_DATA_SIZE) &&
4300 !(OS_DATA_SIZE % (arg & MT_ST_BLKSIZE_MASK)) ) {
4301 /*
4302 * Only allowed to change the block size if you opened the
4303 * device at the beginning of a file before writing anything.
4304 * Note, that when reading, changing block_size is futile,
4305 * as the size used when writing overrides it.
4306 */
4307 STp->block_size = (arg & MT_ST_BLKSIZE_MASK);
4308 printk(KERN_INFO "%s:I: Block size set to %d bytes.\n",
4309 name, STp->block_size);
4310 return 0;
4311 }
4312 case MTSETDENSITY: /* Set tape density */
4313 case MTSETDRVBUFFER: /* Set drive buffering */
4314 case SET_DENS_AND_BLK: /* Set density and block size */
4315 chg_eof = 0;
4316 if (STp->dirty || (STp->buffer)->buffer_bytes != 0)
4317 return (-EIO); /* Not allowed if data in buffer */
4318 if ((cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) &&
4319 (arg & MT_ST_BLKSIZE_MASK) != 0 &&
4320 (arg & MT_ST_BLKSIZE_MASK) != STp->block_size ) {
4321 printk(KERN_WARNING "%s:W: Illegal to set block size to %d%s.\n",
4322 name, (int)(arg & MT_ST_BLKSIZE_MASK),
4323 (OS_DATA_SIZE % (arg & MT_ST_BLKSIZE_MASK))?"":" now");
4324 return (-EINVAL);
4325 }
4326 return 0; /* FIXME silently ignore if block size didn't change */
4327
4328 default:
4329 return (-ENOSYS);
4330 }
4331
4332 SRpnt = osst_do_scsi(SRpnt, STp, cmd, datalen, direction, timeout, MAX_RETRIES, 1);
4333
4334 ioctl_result = (STp->buffer)->syscall_result;
4335
4336 if (!SRpnt) {
4337#if DEBUG
4338 printk(OSST_DEB_MSG "%s:D: Couldn't exec scsi cmd for IOCTL\n", name);
4339#endif
4340 return ioctl_result;
4341 }
4342
4343 if (!ioctl_result) { /* SCSI command successful */
4344 STp->frame_seq_number = frame_seq_numbr;
4345 STp->logical_blk_num = logical_blk_num;
4346 }
4347
4348os_bypass:
4349#if DEBUG
4350 if (debugging)
4351 printk(OSST_DEB_MSG "%s:D: IOCTL (%d) Result=%d\n", name, cmd_in, ioctl_result);
4352#endif
4353
4354 if (!ioctl_result) { /* success */
4355
4356 if (cmd_in == MTFSFM) {
4357 fileno--;
4358 blkno--;
4359 }
4360 if (cmd_in == MTBSFM) {
4361 fileno++;
4362 blkno++;
4363 }
4364 STps->drv_block = blkno;
4365 STps->drv_file = fileno;
4366 STps->at_sm = at_sm;
4367
4368 if (cmd_in == MTEOM)
4369 STps->eof = ST_EOD;
4370 else if ((cmd_in == MTFSFM || cmd_in == MTBSF) && STps->eof == ST_FM_HIT) {
4371 ioctl_result = osst_seek_logical_blk(STp, &SRpnt, STp->logical_blk_num-1);
4372 STps->drv_block++;
4373 STp->logical_blk_num++;
4374 STp->frame_seq_number++;
4375 STp->frame_in_buffer = 0;
4376 STp->buffer->read_pointer = 0;
4377 }
4378 else if (cmd_in == MTFSF)
4379 STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD:ST_FM;
4380 else if (chg_eof)
4381 STps->eof = ST_NOEOF;
4382
4383 if (cmd_in == MTOFFL || cmd_in == MTUNLOAD)
4384 STp->rew_at_close = 0;
4385 else if (cmd_in == MTLOAD) {
4386 for (i=0; i < ST_NBR_PARTITIONS; i++) {
4387 STp->ps[i].rw = ST_IDLE;
4388 STp->ps[i].last_block_valid = 0;/* FIXME - where else is this field maintained? */
4389 }
4390 STp->partition = 0;
4391 }
4392
4393 if (cmd_in == MTREW) {
4394 ioctl_result = osst_position_tape_and_confirm(STp, &SRpnt, STp->first_data_ppos);
4395 if (ioctl_result > 0)
4396 ioctl_result = 0;
4397 }
4398
4399 } else if (cmd_in == MTBSF || cmd_in == MTBSFM ) {
4400 if (osst_position_tape_and_confirm(STp, &SRpnt, STp->first_data_ppos) < 0)
4401 STps->drv_file = STps->drv_block = -1;
4402 else
4403 STps->drv_file = STps->drv_block = 0;
4404 STps->eof = ST_NOEOF;
4405 } else if (cmd_in == MTFSF || cmd_in == MTFSFM) {
4406 if (osst_position_tape_and_confirm(STp, &SRpnt, STp->eod_frame_ppos) < 0)
4407 STps->drv_file = STps->drv_block = -1;
4408 else {
4409 STps->drv_file = STp->filemark_cnt;
4410 STps->drv_block = 0;
4411 }
4412 STps->eof = ST_EOD;
4413 } else if (cmd_in == MTBSR || cmd_in == MTFSR || cmd_in == MTWEOF || cmd_in == MTEOM) {
4414 STps->drv_file = STps->drv_block = (-1);
4415 STps->eof = ST_NOEOF;
4416 STp->header_ok = 0;
4417 } else if (cmd_in == MTERASE) {
4418 STp->header_ok = 0;
4419 } else if (SRpnt) { /* SCSI command was not completely successful. */
Willem Riede5e6575c2006-02-11 14:46:56 -05004420 if (SRpnt->sense[2] & 0x40) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004421 STps->eof = ST_EOM_OK;
4422 STps->drv_block = 0;
4423 }
4424 if (chg_eof)
4425 STps->eof = ST_NOEOF;
4426
Willem Riede5e6575c2006-02-11 14:46:56 -05004427 if ((SRpnt->sense[2] & 0x0f) == BLANK_CHECK)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004428 STps->eof = ST_EOD;
4429
4430 if (cmd_in == MTLOAD && osst_wait_for_medium(STp, &SRpnt, 60))
4431 ioctl_result = osst_wait_ready(STp, &SRpnt, 5 * 60, OSST_WAIT_POSITION_COMPLETE);
4432 }
4433 *aSRpnt = SRpnt;
4434
4435 return ioctl_result;
4436}
4437
4438
4439/* Open the device */
Jonathan Corbet647d87b2008-05-15 12:23:19 -06004440static int __os_scsi_tape_open(struct inode * inode, struct file * filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004441{
4442 unsigned short flags;
4443 int i, b_size, new_session = 0, retval = 0;
4444 unsigned char cmd[MAX_COMMAND_SIZE];
Willem Riede5e6575c2006-02-11 14:46:56 -05004445 struct osst_request * SRpnt = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004446 struct osst_tape * STp;
4447 struct st_modedef * STm;
4448 struct st_partstat * STps;
4449 char * name;
4450 int dev = TAPE_NR(inode);
4451 int mode = TAPE_MODE(inode);
4452
4453 /*
4454 * We really want to do nonseekable_open(inode, filp); here, but some
4455 * versions of tar incorrectly call lseek on tapes and bail out if that
4456 * fails. So we disallow pread() and pwrite(), but permit lseeks.
4457 */
4458 filp->f_mode &= ~(FMODE_PREAD | FMODE_PWRITE);
4459
4460 write_lock(&os_scsi_tapes_lock);
4461 if (dev >= osst_max_dev || os_scsi_tapes == NULL ||
4462 (STp = os_scsi_tapes[dev]) == NULL || !STp->device) {
4463 write_unlock(&os_scsi_tapes_lock);
4464 return (-ENXIO);
4465 }
4466
4467 name = tape_name(STp);
4468
4469 if (STp->in_use) {
4470 write_unlock(&os_scsi_tapes_lock);
4471#if DEBUG
4472 printk(OSST_DEB_MSG "%s:D: Device already in use.\n", name);
4473#endif
4474 return (-EBUSY);
4475 }
4476 if (scsi_device_get(STp->device)) {
4477 write_unlock(&os_scsi_tapes_lock);
4478#if DEBUG
4479 printk(OSST_DEB_MSG "%s:D: Failed scsi_device_get.\n", name);
4480#endif
4481 return (-ENXIO);
4482 }
4483 filp->private_data = STp;
4484 STp->in_use = 1;
4485 write_unlock(&os_scsi_tapes_lock);
4486 STp->rew_at_close = TAPE_REWIND(inode);
4487
4488 if( !scsi_block_when_processing_errors(STp->device) ) {
4489 return -ENXIO;
4490 }
4491
4492 if (mode != STp->current_mode) {
4493#if DEBUG
4494 if (debugging)
4495 printk(OSST_DEB_MSG "%s:D: Mode change from %d to %d.\n",
4496 name, STp->current_mode, mode);
4497#endif
4498 new_session = 1;
4499 STp->current_mode = mode;
4500 }
4501 STm = &(STp->modes[STp->current_mode]);
4502
4503 flags = filp->f_flags;
4504 STp->write_prot = ((flags & O_ACCMODE) == O_RDONLY);
4505
4506 STp->raw = TAPE_IS_RAW(inode);
4507 if (STp->raw)
4508 STp->header_ok = 0;
4509
4510 /* Allocate data segments for this device's tape buffer */
4511 if (!enlarge_buffer(STp->buffer, STp->restr_dma)) {
4512 printk(KERN_ERR "%s:E: Unable to allocate memory segments for tape buffer.\n", name);
4513 retval = (-EOVERFLOW);
4514 goto err_out;
4515 }
4516 if (STp->buffer->buffer_size >= OS_FRAME_SIZE) {
4517 for (i = 0, b_size = 0;
4518 (i < STp->buffer->sg_segs) && ((b_size + STp->buffer->sg[i].length) <= OS_DATA_SIZE);
4519 b_size += STp->buffer->sg[i++].length);
Jens Axboe45711f12007-10-22 21:19:53 +02004520 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 -07004521#if DEBUG
4522 printk(OSST_DEB_MSG "%s:D: b_data points to %p in segment 0 at %p\n", name,
4523 STp->buffer->b_data, page_address(STp->buffer->sg[0].page));
4524 printk(OSST_DEB_MSG "%s:D: AUX points to %p in segment %d at %p\n", name,
4525 STp->buffer->aux, i, page_address(STp->buffer->sg[i].page));
4526#endif
4527 } else {
4528 STp->buffer->aux = NULL; /* this had better never happen! */
4529 printk(KERN_NOTICE "%s:A: Framesize %d too large for buffer.\n", name, OS_FRAME_SIZE);
4530 retval = (-EIO);
4531 goto err_out;
4532 }
4533 STp->buffer->writing = 0;
4534 STp->buffer->syscall_result = 0;
4535 STp->dirty = 0;
4536 for (i=0; i < ST_NBR_PARTITIONS; i++) {
4537 STps = &(STp->ps[i]);
4538 STps->rw = ST_IDLE;
4539 }
4540 STp->ready = ST_READY;
4541#if DEBUG
4542 STp->nbr_waits = STp->nbr_finished = 0;
4543#endif
4544
4545 memset (cmd, 0, MAX_COMMAND_SIZE);
4546 cmd[0] = TEST_UNIT_READY;
4547
4548 SRpnt = osst_do_scsi(NULL, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1);
4549 if (!SRpnt) {
4550 retval = (STp->buffer)->syscall_result; /* FIXME - valid? */
4551 goto err_out;
4552 }
Willem Riede5e6575c2006-02-11 14:46:56 -05004553 if ((SRpnt->sense[0] & 0x70) == 0x70 &&
4554 (SRpnt->sense[2] & 0x0f) == NOT_READY &&
4555 SRpnt->sense[12] == 4 ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004556#if DEBUG
Willem Riede5e6575c2006-02-11 14:46:56 -05004557 printk(OSST_DEB_MSG "%s:D: Unit not ready, cause %x\n", name, SRpnt->sense[13]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004558#endif
4559 if (filp->f_flags & O_NONBLOCK) {
4560 retval = -EAGAIN;
4561 goto err_out;
4562 }
Willem Riede5e6575c2006-02-11 14:46:56 -05004563 if (SRpnt->sense[13] == 2) { /* initialize command required (LOAD) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004564 memset (cmd, 0, MAX_COMMAND_SIZE);
4565 cmd[0] = START_STOP;
4566 cmd[1] = 1;
4567 cmd[4] = 1;
4568 SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE,
4569 STp->timeout, MAX_RETRIES, 1);
4570 }
Willem Riede5e6575c2006-02-11 14:46:56 -05004571 osst_wait_ready(STp, &SRpnt, (SRpnt->sense[13]==1?15:3) * 60, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004572 }
Willem Riede5e6575c2006-02-11 14:46:56 -05004573 if ((SRpnt->sense[0] & 0x70) == 0x70 &&
4574 (SRpnt->sense[2] & 0x0f) == UNIT_ATTENTION) { /* New media? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004575#if DEBUG
4576 printk(OSST_DEB_MSG "%s:D: Unit wants attention\n", name);
4577#endif
4578 STp->header_ok = 0;
4579
4580 for (i=0; i < 10; i++) {
4581
4582 memset (cmd, 0, MAX_COMMAND_SIZE);
4583 cmd[0] = TEST_UNIT_READY;
4584
4585 SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE,
4586 STp->timeout, MAX_RETRIES, 1);
Willem Riede5e6575c2006-02-11 14:46:56 -05004587 if ((SRpnt->sense[0] & 0x70) != 0x70 ||
4588 (SRpnt->sense[2] & 0x0f) != UNIT_ATTENTION)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004589 break;
4590 }
4591
4592 STp->pos_unknown = 0;
4593 STp->partition = STp->new_partition = 0;
4594 if (STp->can_partitions)
4595 STp->nbr_partitions = 1; /* This guess will be updated later if necessary */
4596 for (i=0; i < ST_NBR_PARTITIONS; i++) {
4597 STps = &(STp->ps[i]);
4598 STps->rw = ST_IDLE; /* FIXME - seems to be redundant... */
4599 STps->eof = ST_NOEOF;
4600 STps->at_sm = 0;
4601 STps->last_block_valid = 0;
4602 STps->drv_block = 0;
4603 STps->drv_file = 0 ;
4604 }
4605 new_session = 1;
4606 STp->recover_count = 0;
4607 STp->abort_count = 0;
4608 }
4609 /*
4610 * if we have valid headers from before, and the drive/tape seem untouched,
4611 * open without reconfiguring and re-reading the headers
4612 */
4613 if (!STp->buffer->syscall_result && STp->header_ok &&
Willem Riede5e6575c2006-02-11 14:46:56 -05004614 !SRpnt->result && SRpnt->sense[0] == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004615
4616 memset(cmd, 0, MAX_COMMAND_SIZE);
4617 cmd[0] = MODE_SENSE;
4618 cmd[1] = 8;
4619 cmd[2] = VENDOR_IDENT_PAGE;
4620 cmd[4] = VENDOR_IDENT_PAGE_LENGTH + MODE_HEADER_LENGTH;
4621
4622 SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_FROM_DEVICE, STp->timeout, 0, 1);
4623
4624 if (STp->buffer->syscall_result ||
4625 STp->buffer->b_data[MODE_HEADER_LENGTH + 2] != 'L' ||
4626 STp->buffer->b_data[MODE_HEADER_LENGTH + 3] != 'I' ||
4627 STp->buffer->b_data[MODE_HEADER_LENGTH + 4] != 'N' ||
4628 STp->buffer->b_data[MODE_HEADER_LENGTH + 5] != '4' ) {
4629#if DEBUG
4630 printk(OSST_DEB_MSG "%s:D: Signature was changed to %c%c%c%c\n", name,
4631 STp->buffer->b_data[MODE_HEADER_LENGTH + 2],
4632 STp->buffer->b_data[MODE_HEADER_LENGTH + 3],
4633 STp->buffer->b_data[MODE_HEADER_LENGTH + 4],
4634 STp->buffer->b_data[MODE_HEADER_LENGTH + 5]);
4635#endif
4636 STp->header_ok = 0;
4637 }
4638 i = STp->first_frame_position;
4639 if (STp->header_ok && i == osst_get_frame_position(STp, &SRpnt)) {
4640 if (STp->door_locked == ST_UNLOCKED) {
4641 if (do_door_lock(STp, 1))
4642 printk(KERN_INFO "%s:I: Can't lock drive door\n", name);
4643 else
4644 STp->door_locked = ST_LOCKED_AUTO;
4645 }
4646 if (!STp->frame_in_buffer) {
4647 STp->block_size = (STm->default_blksize > 0) ?
4648 STm->default_blksize : OS_DATA_SIZE;
4649 STp->buffer->buffer_bytes = STp->buffer->read_pointer = 0;
4650 }
4651 STp->buffer->buffer_blocks = OS_DATA_SIZE / STp->block_size;
4652 STp->fast_open = 1;
Willem Riede5e6575c2006-02-11 14:46:56 -05004653 osst_release_request(SRpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004654 return 0;
4655 }
4656#if DEBUG
4657 if (i != STp->first_frame_position)
4658 printk(OSST_DEB_MSG "%s:D: Tape position changed from %d to %d\n",
4659 name, i, STp->first_frame_position);
4660#endif
4661 STp->header_ok = 0;
4662 }
4663 STp->fast_open = 0;
4664
4665 if ((STp->buffer)->syscall_result != 0 && /* in all error conditions except no medium */
Willem Riede5e6575c2006-02-11 14:46:56 -05004666 (SRpnt->sense[2] != 2 || SRpnt->sense[12] != 0x3A) ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004667
4668 memset(cmd, 0, MAX_COMMAND_SIZE);
4669 cmd[0] = MODE_SELECT;
4670 cmd[1] = 0x10;
4671 cmd[4] = 4 + MODE_HEADER_LENGTH;
4672
4673 (STp->buffer)->b_data[0] = cmd[4] - 1;
4674 (STp->buffer)->b_data[1] = 0; /* Medium Type - ignoring */
4675 (STp->buffer)->b_data[2] = 0; /* Reserved */
4676 (STp->buffer)->b_data[3] = 0; /* Block Descriptor Length */
4677 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 0] = 0x3f;
4678 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 1] = 1;
4679 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] = 2;
4680 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] = 3;
4681
4682#if DEBUG
4683 printk(OSST_DEB_MSG "%s:D: Applying soft reset\n", name);
4684#endif
4685 SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_TO_DEVICE, STp->timeout, 0, 1);
4686
4687 STp->header_ok = 0;
4688
4689 for (i=0; i < 10; i++) {
4690
4691 memset (cmd, 0, MAX_COMMAND_SIZE);
4692 cmd[0] = TEST_UNIT_READY;
4693
4694 SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE,
4695 STp->timeout, MAX_RETRIES, 1);
Willem Riede5e6575c2006-02-11 14:46:56 -05004696 if ((SRpnt->sense[0] & 0x70) != 0x70 ||
4697 (SRpnt->sense[2] & 0x0f) == NOT_READY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004698 break;
4699
Willem Riede5e6575c2006-02-11 14:46:56 -05004700 if ((SRpnt->sense[2] & 0x0f) == UNIT_ATTENTION) {
Andrew Morton6e2037b2011-05-23 15:29:13 -07004701 int j;
4702
Linus Torvalds1da177e2005-04-16 15:20:36 -07004703 STp->pos_unknown = 0;
4704 STp->partition = STp->new_partition = 0;
4705 if (STp->can_partitions)
4706 STp->nbr_partitions = 1; /* This guess will be updated later if necessary */
Roel Kluina061f572011-05-23 15:29:12 -07004707 for (j = 0; j < ST_NBR_PARTITIONS; j++) {
4708 STps = &(STp->ps[j]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004709 STps->rw = ST_IDLE;
4710 STps->eof = ST_NOEOF;
4711 STps->at_sm = 0;
4712 STps->last_block_valid = 0;
4713 STps->drv_block = 0;
4714 STps->drv_file = 0 ;
4715 }
4716 new_session = 1;
4717 }
4718 }
4719 }
4720
4721 if (osst_wait_ready(STp, &SRpnt, 15 * 60, 0)) /* FIXME - not allowed with NOBLOCK */
4722 printk(KERN_INFO "%s:I: Device did not become Ready in open\n", name);
4723
4724 if ((STp->buffer)->syscall_result != 0) {
4725 if ((STp->device)->scsi_level >= SCSI_2 &&
Willem Riede5e6575c2006-02-11 14:46:56 -05004726 (SRpnt->sense[0] & 0x70) == 0x70 &&
4727 (SRpnt->sense[2] & 0x0f) == NOT_READY &&
4728 SRpnt->sense[12] == 0x3a) { /* Check ASC */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004729 STp->ready = ST_NO_TAPE;
4730 } else
4731 STp->ready = ST_NOT_READY;
Willem Riede5e6575c2006-02-11 14:46:56 -05004732 osst_release_request(SRpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004733 SRpnt = NULL;
4734 STp->density = 0; /* Clear the erroneous "residue" */
4735 STp->write_prot = 0;
4736 STp->block_size = 0;
4737 STp->ps[0].drv_file = STp->ps[0].drv_block = (-1);
4738 STp->partition = STp->new_partition = 0;
4739 STp->door_locked = ST_UNLOCKED;
4740 return 0;
4741 }
4742
4743 osst_configure_onstream(STp, &SRpnt);
4744
4745 STp->block_size = STp->raw ? OS_FRAME_SIZE : (
4746 (STm->default_blksize > 0) ? STm->default_blksize : OS_DATA_SIZE);
4747 STp->buffer->buffer_blocks = STp->raw ? 1 : OS_DATA_SIZE / STp->block_size;
4748 STp->buffer->buffer_bytes =
4749 STp->buffer->read_pointer =
4750 STp->frame_in_buffer = 0;
4751
4752#if DEBUG
4753 if (debugging)
4754 printk(OSST_DEB_MSG "%s:D: Block size: %d, frame size: %d, buffer size: %d (%d blocks).\n",
4755 name, STp->block_size, OS_FRAME_SIZE, (STp->buffer)->buffer_size,
4756 (STp->buffer)->buffer_blocks);
4757#endif
4758
4759 if (STp->drv_write_prot) {
4760 STp->write_prot = 1;
4761#if DEBUG
4762 if (debugging)
4763 printk(OSST_DEB_MSG "%s:D: Write protected\n", name);
4764#endif
4765 if ((flags & O_ACCMODE) == O_WRONLY || (flags & O_ACCMODE) == O_RDWR) {
4766 retval = (-EROFS);
4767 goto err_out;
4768 }
4769 }
4770
4771 if (new_session) { /* Change the drive parameters for the new mode */
4772#if DEBUG
4773 if (debugging)
4774 printk(OSST_DEB_MSG "%s:D: New Session\n", name);
4775#endif
4776 STp->density_changed = STp->blksize_changed = 0;
4777 STp->compression_changed = 0;
4778 }
4779
4780 /*
4781 * properly position the tape and check the ADR headers
4782 */
4783 if (STp->door_locked == ST_UNLOCKED) {
4784 if (do_door_lock(STp, 1))
4785 printk(KERN_INFO "%s:I: Can't lock drive door\n", name);
4786 else
4787 STp->door_locked = ST_LOCKED_AUTO;
4788 }
4789
4790 osst_analyze_headers(STp, &SRpnt);
4791
Willem Riede5e6575c2006-02-11 14:46:56 -05004792 osst_release_request(SRpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004793 SRpnt = NULL;
4794
4795 return 0;
4796
4797err_out:
4798 if (SRpnt != NULL)
Willem Riede5e6575c2006-02-11 14:46:56 -05004799 osst_release_request(SRpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004800 normalize_buffer(STp->buffer);
4801 STp->header_ok = 0;
4802 STp->in_use = 0;
4803 scsi_device_put(STp->device);
4804
4805 return retval;
4806}
4807
Jonathan Corbet647d87b2008-05-15 12:23:19 -06004808/* BKL pushdown: spaghetti avoidance wrapper */
4809static int os_scsi_tape_open(struct inode * inode, struct file * filp)
4810{
4811 int ret;
4812
Arnd Bergmannc45d15d2010-06-02 14:28:52 +02004813 mutex_lock(&osst_int_mutex);
Jonathan Corbet647d87b2008-05-15 12:23:19 -06004814 ret = __os_scsi_tape_open(inode, filp);
Arnd Bergmannc45d15d2010-06-02 14:28:52 +02004815 mutex_unlock(&osst_int_mutex);
Jonathan Corbet647d87b2008-05-15 12:23:19 -06004816 return ret;
4817}
4818
4819
Linus Torvalds1da177e2005-04-16 15:20:36 -07004820
4821/* Flush the tape buffer before close */
Miklos Szeredi75e1fcc2006-06-23 02:05:12 -07004822static int os_scsi_tape_flush(struct file * filp, fl_owner_t id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004823{
4824 int result = 0, result2;
4825 struct osst_tape * STp = filp->private_data;
4826 struct st_modedef * STm = &(STp->modes[STp->current_mode]);
4827 struct st_partstat * STps = &(STp->ps[STp->partition]);
Willem Riede5e6575c2006-02-11 14:46:56 -05004828 struct osst_request * SRpnt = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004829 char * name = tape_name(STp);
4830
4831 if (file_count(filp) > 1)
4832 return 0;
4833
4834 if ((STps->rw == ST_WRITING || STp->dirty) && !STp->pos_unknown) {
4835 STp->write_type = OS_WRITE_DATA;
4836 result = osst_flush_write_buffer(STp, &SRpnt);
4837 if (result != 0 && result != (-ENOSPC))
4838 goto out;
4839 }
4840 if ( STps->rw >= ST_WRITING && !STp->pos_unknown) {
4841
4842#if DEBUG
4843 if (debugging) {
4844 printk(OSST_DEB_MSG "%s:D: File length %ld bytes.\n",
4845 name, (long)(filp->f_pos));
4846 printk(OSST_DEB_MSG "%s:D: Async write waits %d, finished %d.\n",
4847 name, STp->nbr_waits, STp->nbr_finished);
4848 }
4849#endif
4850 result = osst_write_trailer(STp, &SRpnt, !(STp->rew_at_close));
4851#if DEBUG
4852 if (debugging)
4853 printk(OSST_DEB_MSG "%s:D: Buffer flushed, %d EOF(s) written\n",
4854 name, 1+STp->two_fm);
4855#endif
4856 }
4857 else if (!STp->rew_at_close) {
4858 STps = &(STp->ps[STp->partition]);
4859 if (!STm->sysv || STps->rw != ST_READING) {
4860 if (STp->can_bsr)
4861 result = osst_flush_buffer(STp, &SRpnt, 0); /* this is the default path */
4862 else if (STps->eof == ST_FM_HIT) {
4863 result = cross_eof(STp, &SRpnt, 0);
4864 if (result) {
4865 if (STps->drv_file >= 0)
4866 STps->drv_file++;
4867 STps->drv_block = 0;
4868 STps->eof = ST_FM;
4869 }
4870 else
4871 STps->eof = ST_NOEOF;
4872 }
4873 }
4874 else if ((STps->eof == ST_NOEOF &&
4875 !(result = cross_eof(STp, &SRpnt, 1))) ||
4876 STps->eof == ST_FM_HIT) {
4877 if (STps->drv_file >= 0)
4878 STps->drv_file++;
4879 STps->drv_block = 0;
4880 STps->eof = ST_FM;
4881 }
4882 }
4883
4884out:
4885 if (STp->rew_at_close) {
4886 result2 = osst_position_tape_and_confirm(STp, &SRpnt, STp->first_data_ppos);
4887 STps->drv_file = STps->drv_block = STp->frame_seq_number = STp->logical_blk_num = 0;
4888 if (result == 0 && result2 < 0)
4889 result = result2;
4890 }
Willem Riede5e6575c2006-02-11 14:46:56 -05004891 if (SRpnt) osst_release_request(SRpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004892
4893 if (STp->abort_count || STp->recover_count) {
4894 printk(KERN_INFO "%s:I:", name);
4895 if (STp->abort_count)
4896 printk(" %d unrecovered errors", STp->abort_count);
4897 if (STp->recover_count)
4898 printk(" %d recovered errors", STp->recover_count);
4899 if (STp->write_count)
4900 printk(" in %d frames written", STp->write_count);
4901 if (STp->read_count)
4902 printk(" in %d frames read", STp->read_count);
4903 printk("\n");
4904 STp->recover_count = 0;
4905 STp->abort_count = 0;
4906 }
4907 STp->write_count = 0;
4908 STp->read_count = 0;
4909
4910 return result;
4911}
4912
4913
4914/* Close the device and release it */
4915static int os_scsi_tape_close(struct inode * inode, struct file * filp)
4916{
4917 int result = 0;
4918 struct osst_tape * STp = filp->private_data;
4919
4920 if (STp->door_locked == ST_LOCKED_AUTO)
4921 do_door_lock(STp, 0);
4922
4923 if (STp->raw)
4924 STp->header_ok = 0;
4925
4926 normalize_buffer(STp->buffer);
4927 write_lock(&os_scsi_tapes_lock);
4928 STp->in_use = 0;
4929 write_unlock(&os_scsi_tapes_lock);
4930
4931 scsi_device_put(STp->device);
4932
4933 return result;
4934}
4935
4936
4937/* The ioctl command */
Arnd Bergmannf4927c42010-04-27 00:24:01 +02004938static long osst_ioctl(struct file * file,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004939 unsigned int cmd_in, unsigned long arg)
4940{
Eric Sesterhenn45223fd2006-09-25 16:59:08 -07004941 int i, cmd_nr, cmd_type, blk, retval = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004942 struct st_modedef * STm;
4943 struct st_partstat * STps;
Willem Riede5e6575c2006-02-11 14:46:56 -05004944 struct osst_request * SRpnt = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004945 struct osst_tape * STp = file->private_data;
4946 char * name = tape_name(STp);
4947 void __user * p = (void __user *)arg;
4948
Arnd Bergmannc45d15d2010-06-02 14:28:52 +02004949 mutex_lock(&osst_int_mutex);
Arnd Bergmannf4927c42010-04-27 00:24:01 +02004950 if (mutex_lock_interruptible(&STp->lock)) {
Arnd Bergmannc45d15d2010-06-02 14:28:52 +02004951 mutex_unlock(&osst_int_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004952 return -ERESTARTSYS;
Arnd Bergmannf4927c42010-04-27 00:24:01 +02004953 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004954
4955#if DEBUG
4956 if (debugging && !STp->in_use) {
4957 printk(OSST_DEB_MSG "%s:D: Incorrect device.\n", name);
4958 retval = (-EIO);
4959 goto out;
4960 }
4961#endif
4962 STm = &(STp->modes[STp->current_mode]);
4963 STps = &(STp->ps[STp->partition]);
4964
4965 /*
4966 * If we are in the middle of error recovery, don't let anyone
4967 * else try and use this device. Also, if error recovery fails, it
4968 * may try and take the device offline, in which case all further
4969 * access to the device is prohibited.
4970 */
Christoph Hellwig906d15f2014-10-11 16:25:31 +02004971 retval = scsi_ioctl_block_when_processing_errors(STp->device, cmd_in,
4972 file->f_flags & O_NDELAY);
4973 if (retval)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004974 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004975
4976 cmd_type = _IOC_TYPE(cmd_in);
4977 cmd_nr = _IOC_NR(cmd_in);
4978#if DEBUG
4979 printk(OSST_DEB_MSG "%s:D: Ioctl %d,%d in %s mode\n", name,
4980 cmd_type, cmd_nr, STp->raw?"raw":"normal");
4981#endif
4982 if (cmd_type == _IOC_TYPE(MTIOCTOP) && cmd_nr == _IOC_NR(MTIOCTOP)) {
4983 struct mtop mtc;
4984 int auto_weof = 0;
4985
4986 if (_IOC_SIZE(cmd_in) != sizeof(mtc)) {
4987 retval = (-EINVAL);
4988 goto out;
4989 }
4990
4991 i = copy_from_user((char *) &mtc, p, sizeof(struct mtop));
4992 if (i) {
4993 retval = (-EFAULT);
4994 goto out;
4995 }
4996
4997 if (mtc.mt_op == MTSETDRVBUFFER && !capable(CAP_SYS_ADMIN)) {
4998 printk(KERN_WARNING "%s:W: MTSETDRVBUFFER only allowed for root.\n", name);
4999 retval = (-EPERM);
5000 goto out;
5001 }
5002
5003 if (!STm->defined && (mtc.mt_op != MTSETDRVBUFFER && (mtc.mt_count & MT_ST_OPTIONS) == 0)) {
5004 retval = (-ENXIO);
5005 goto out;
5006 }
5007
5008 if (!STp->pos_unknown) {
5009
5010 if (STps->eof == ST_FM_HIT) {
5011 if (mtc.mt_op == MTFSF || mtc.mt_op == MTFSFM|| mtc.mt_op == MTEOM) {
5012 mtc.mt_count -= 1;
5013 if (STps->drv_file >= 0)
5014 STps->drv_file += 1;
5015 }
5016 else if (mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM) {
5017 mtc.mt_count += 1;
5018 if (STps->drv_file >= 0)
5019 STps->drv_file += 1;
5020 }
5021 }
5022
5023 if (mtc.mt_op == MTSEEK) {
5024 /* Old position must be restored if partition will be changed */
5025 i = !STp->can_partitions || (STp->new_partition != STp->partition);
5026 }
5027 else {
5028 i = mtc.mt_op == MTREW || mtc.mt_op == MTOFFL ||
5029 mtc.mt_op == MTRETEN || mtc.mt_op == MTEOM ||
5030 mtc.mt_op == MTLOCK || mtc.mt_op == MTLOAD ||
5031 mtc.mt_op == MTFSF || mtc.mt_op == MTFSFM ||
5032 mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM ||
5033 mtc.mt_op == MTCOMPRESSION;
5034 }
5035 i = osst_flush_buffer(STp, &SRpnt, i);
5036 if (i < 0) {
5037 retval = i;
5038 goto out;
5039 }
5040 }
5041 else {
5042 /*
5043 * If there was a bus reset, block further access
5044 * to this device. If the user wants to rewind the tape,
5045 * then reset the flag and allow access again.
5046 */
5047 if(mtc.mt_op != MTREW &&
5048 mtc.mt_op != MTOFFL &&
5049 mtc.mt_op != MTRETEN &&
5050 mtc.mt_op != MTERASE &&
5051 mtc.mt_op != MTSEEK &&
5052 mtc.mt_op != MTEOM) {
5053 retval = (-EIO);
5054 goto out;
5055 }
5056 reset_state(STp);
5057 /* remove this when the midlevel properly clears was_reset */
5058 STp->device->was_reset = 0;
5059 }
5060
5061 if (mtc.mt_op != MTCOMPRESSION && mtc.mt_op != MTLOCK &&
5062 mtc.mt_op != MTNOP && mtc.mt_op != MTSETBLK &&
5063 mtc.mt_op != MTSETDENSITY && mtc.mt_op != MTSETDRVBUFFER &&
5064 mtc.mt_op != MTMKPART && mtc.mt_op != MTSETPART &&
5065 mtc.mt_op != MTWEOF && mtc.mt_op != MTWSM ) {
5066
5067 /*
5068 * The user tells us to move to another position on the tape.
5069 * If we were appending to the tape content, that would leave
5070 * the tape without proper end, in that case write EOD and
5071 * update the header to reflect its position.
5072 */
5073#if DEBUG
5074 printk(KERN_WARNING "%s:D: auto_weod %s at ffp=%d,efp=%d,fsn=%d,lbn=%d,fn=%d,bn=%d\n", name,
5075 STps->rw >= ST_WRITING ? "write" : STps->rw == ST_READING ? "read" : "idle",
5076 STp->first_frame_position, STp->eod_frame_ppos, STp->frame_seq_number,
5077 STp->logical_blk_num, STps->drv_file, STps->drv_block );
5078#endif
5079 if (STps->rw >= ST_WRITING && STp->first_frame_position >= STp->eod_frame_ppos) {
5080 auto_weof = ((STp->write_type != OS_WRITE_NEW_MARK) &&
5081 !(mtc.mt_op == MTREW || mtc.mt_op == MTOFFL));
5082 i = osst_write_trailer(STp, &SRpnt,
5083 !(mtc.mt_op == MTREW || mtc.mt_op == MTOFFL));
5084#if DEBUG
5085 printk(KERN_WARNING "%s:D: post trailer xeof=%d,ffp=%d,efp=%d,fsn=%d,lbn=%d,fn=%d,bn=%d\n",
5086 name, auto_weof, STp->first_frame_position, STp->eod_frame_ppos,
5087 STp->frame_seq_number, STp->logical_blk_num, STps->drv_file, STps->drv_block );
5088#endif
5089 if (i < 0) {
5090 retval = i;
5091 goto out;
5092 }
5093 }
5094 STps->rw = ST_IDLE;
5095 }
5096
5097 if (mtc.mt_op == MTOFFL && STp->door_locked != ST_UNLOCKED)
5098 do_door_lock(STp, 0); /* Ignore result! */
5099
5100 if (mtc.mt_op == MTSETDRVBUFFER &&
5101 (mtc.mt_count & MT_ST_OPTIONS) != 0) {
5102 retval = osst_set_options(STp, mtc.mt_count);
5103 goto out;
5104 }
5105
5106 if (mtc.mt_op == MTSETPART) {
5107 if (mtc.mt_count >= STp->nbr_partitions)
5108 retval = -EINVAL;
5109 else {
5110 STp->new_partition = mtc.mt_count;
5111 retval = 0;
5112 }
5113 goto out;
5114 }
5115
5116 if (mtc.mt_op == MTMKPART) {
5117 if (!STp->can_partitions) {
5118 retval = (-EINVAL);
5119 goto out;
5120 }
5121 if ((i = osst_int_ioctl(STp, &SRpnt, MTREW, 0)) < 0 /*||
5122 (i = partition_tape(inode, mtc.mt_count)) < 0*/) {
5123 retval = i;
5124 goto out;
5125 }
5126 for (i=0; i < ST_NBR_PARTITIONS; i++) {
5127 STp->ps[i].rw = ST_IDLE;
5128 STp->ps[i].at_sm = 0;
5129 STp->ps[i].last_block_valid = 0;
5130 }
5131 STp->partition = STp->new_partition = 0;
5132 STp->nbr_partitions = 1; /* Bad guess ?-) */
5133 STps->drv_block = STps->drv_file = 0;
5134 retval = 0;
5135 goto out;
5136 }
5137
5138 if (mtc.mt_op == MTSEEK) {
5139 if (STp->raw)
5140 i = osst_set_frame_position(STp, &SRpnt, mtc.mt_count, 0);
5141 else
5142 i = osst_seek_sector(STp, &SRpnt, mtc.mt_count);
5143 if (!STp->can_partitions)
5144 STp->ps[0].rw = ST_IDLE;
5145 retval = i;
5146 goto out;
5147 }
5148
5149 if (mtc.mt_op == MTLOCK || mtc.mt_op == MTUNLOCK) {
5150 retval = do_door_lock(STp, (mtc.mt_op == MTLOCK));
5151 goto out;
5152 }
5153
5154 if (auto_weof)
5155 cross_eof(STp, &SRpnt, 0);
5156
5157 if (mtc.mt_op == MTCOMPRESSION)
5158 retval = -EINVAL; /* OnStream drives don't have compression hardware */
5159 else
5160 /* MTBSF MTBSFM MTBSR MTBSS MTEOM MTERASE MTFSF MTFSFB MTFSR MTFSS
5161 * MTLOAD MTOFFL MTRESET MTRETEN MTREW MTUNLOAD MTWEOF MTWSM */
5162 retval = osst_int_ioctl(STp, &SRpnt, mtc.mt_op, mtc.mt_count);
5163 goto out;
5164 }
5165
5166 if (!STm->defined) {
5167 retval = (-ENXIO);
5168 goto out;
5169 }
5170
5171 if ((i = osst_flush_buffer(STp, &SRpnt, 0)) < 0) {
5172 retval = i;
5173 goto out;
5174 }
5175
5176 if (cmd_type == _IOC_TYPE(MTIOCGET) && cmd_nr == _IOC_NR(MTIOCGET)) {
5177 struct mtget mt_status;
5178
5179 if (_IOC_SIZE(cmd_in) != sizeof(struct mtget)) {
5180 retval = (-EINVAL);
5181 goto out;
5182 }
5183
5184 mt_status.mt_type = MT_ISONSTREAM_SC;
5185 mt_status.mt_erreg = STp->recover_erreg << MT_ST_SOFTERR_SHIFT;
5186 mt_status.mt_dsreg =
5187 ((STp->block_size << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK) |
5188 ((STp->density << MT_ST_DENSITY_SHIFT) & MT_ST_DENSITY_MASK);
5189 mt_status.mt_blkno = STps->drv_block;
5190 mt_status.mt_fileno = STps->drv_file;
5191 if (STp->block_size != 0) {
5192 if (STps->rw == ST_WRITING)
5193 mt_status.mt_blkno += (STp->buffer)->buffer_bytes / STp->block_size;
5194 else if (STps->rw == ST_READING)
5195 mt_status.mt_blkno -= ((STp->buffer)->buffer_bytes +
5196 STp->block_size - 1) / STp->block_size;
5197 }
5198
5199 mt_status.mt_gstat = 0;
5200 if (STp->drv_write_prot)
5201 mt_status.mt_gstat |= GMT_WR_PROT(0xffffffff);
5202 if (mt_status.mt_blkno == 0) {
5203 if (mt_status.mt_fileno == 0)
5204 mt_status.mt_gstat |= GMT_BOT(0xffffffff);
5205 else
5206 mt_status.mt_gstat |= GMT_EOF(0xffffffff);
5207 }
5208 mt_status.mt_resid = STp->partition;
5209 if (STps->eof == ST_EOM_OK || STps->eof == ST_EOM_ERROR)
5210 mt_status.mt_gstat |= GMT_EOT(0xffffffff);
5211 else if (STps->eof >= ST_EOM_OK)
5212 mt_status.mt_gstat |= GMT_EOD(0xffffffff);
5213 if (STp->density == 1)
5214 mt_status.mt_gstat |= GMT_D_800(0xffffffff);
5215 else if (STp->density == 2)
5216 mt_status.mt_gstat |= GMT_D_1600(0xffffffff);
5217 else if (STp->density == 3)
5218 mt_status.mt_gstat |= GMT_D_6250(0xffffffff);
5219 if (STp->ready == ST_READY)
5220 mt_status.mt_gstat |= GMT_ONLINE(0xffffffff);
5221 if (STp->ready == ST_NO_TAPE)
5222 mt_status.mt_gstat |= GMT_DR_OPEN(0xffffffff);
5223 if (STps->at_sm)
5224 mt_status.mt_gstat |= GMT_SM(0xffffffff);
5225 if (STm->do_async_writes || (STm->do_buffer_writes && STp->block_size != 0) ||
5226 STp->drv_buffer != 0)
5227 mt_status.mt_gstat |= GMT_IM_REP_EN(0xffffffff);
5228
5229 i = copy_to_user(p, &mt_status, sizeof(struct mtget));
5230 if (i) {
5231 retval = (-EFAULT);
5232 goto out;
5233 }
5234
5235 STp->recover_erreg = 0; /* Clear after read */
5236 retval = 0;
5237 goto out;
5238 } /* End of MTIOCGET */
5239
5240 if (cmd_type == _IOC_TYPE(MTIOCPOS) && cmd_nr == _IOC_NR(MTIOCPOS)) {
5241 struct mtpos mt_pos;
5242
5243 if (_IOC_SIZE(cmd_in) != sizeof(struct mtpos)) {
5244 retval = (-EINVAL);
5245 goto out;
5246 }
5247 if (STp->raw)
5248 blk = osst_get_frame_position(STp, &SRpnt);
5249 else
5250 blk = osst_get_sector(STp, &SRpnt);
5251 if (blk < 0) {
5252 retval = blk;
5253 goto out;
5254 }
5255 mt_pos.mt_blkno = blk;
5256 i = copy_to_user(p, &mt_pos, sizeof(struct mtpos));
5257 if (i)
5258 retval = -EFAULT;
5259 goto out;
5260 }
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
Arnd Bergmannf4927c42010-04-27 00:24:01 +02005265 retval = scsi_ioctl(STp->device, cmd_in, p);
Arnd Bergmannc45d15d2010-06-02 14:28:52 +02005266 mutex_unlock(&osst_int_mutex);
Arnd Bergmannf4927c42010-04-27 00:24:01 +02005267 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005268
5269out:
Willem Riede5e6575c2006-02-11 14:46:56 -05005270 if (SRpnt) osst_release_request(SRpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005271
Matthias Kaehlcke4390e602007-08-10 14:50:44 -07005272 mutex_unlock(&STp->lock);
Arnd Bergmannc45d15d2010-06-02 14:28:52 +02005273 mutex_unlock(&osst_int_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005274
5275 return retval;
5276}
5277
5278#ifdef CONFIG_COMPAT
5279static long osst_compat_ioctl(struct file * file, unsigned int cmd_in, unsigned long arg)
5280{
5281 struct osst_tape *STp = file->private_data;
5282 struct scsi_device *sdev = STp->device;
5283 int ret = -ENOIOCTLCMD;
5284 if (sdev->host->hostt->compat_ioctl) {
5285
5286 ret = sdev->host->hostt->compat_ioctl(sdev, cmd_in, (void __user *)arg);
5287
5288 }
5289 return ret;
5290}
5291#endif
5292
5293
5294
5295/* Memory handling routines */
5296
5297/* Try to allocate a new tape buffer skeleton. Caller must not hold os_scsi_tapes_lock */
5298static struct osst_buffer * new_tape_buffer( int from_initialization, int need_dma, int max_sg )
5299{
Al Viroc53033f2005-10-21 03:22:08 -04005300 int i;
5301 gfp_t priority;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005302 struct osst_buffer *tb;
5303
5304 if (from_initialization)
5305 priority = GFP_ATOMIC;
5306 else
5307 priority = GFP_KERNEL;
5308
5309 i = sizeof(struct osst_buffer) + (osst_max_sg_segs - 1) * sizeof(struct scatterlist);
Jeff Garzik37e03332006-10-04 05:23:04 -04005310 tb = kzalloc(i, priority);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005311 if (!tb) {
5312 printk(KERN_NOTICE "osst :I: Can't allocate new tape buffer.\n");
5313 return NULL;
5314 }
Jeff Garzik37e03332006-10-04 05:23:04 -04005315
Linus Torvalds1da177e2005-04-16 15:20:36 -07005316 tb->sg_segs = tb->orig_sg_segs = 0;
5317 tb->use_sg = max_sg;
5318 tb->in_use = 1;
5319 tb->dma = need_dma;
5320 tb->buffer_size = 0;
5321#if DEBUG
5322 if (debugging)
5323 printk(OSST_DEB_MSG
5324 "osst :D: Allocated tape buffer skeleton (%d bytes, %d segments, dma: %d).\n",
5325 i, max_sg, need_dma);
5326#endif
5327 return tb;
5328}
5329
5330/* Try to allocate a temporary (while a user has the device open) enlarged tape buffer */
5331static int enlarge_buffer(struct osst_buffer *STbuffer, int need_dma)
5332{
Al Viroc53033f2005-10-21 03:22:08 -04005333 int segs, nbr, max_segs, b_size, order, got;
5334 gfp_t priority;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005335
5336 if (STbuffer->buffer_size >= OS_FRAME_SIZE)
5337 return 1;
5338
5339 if (STbuffer->sg_segs) {
5340 printk(KERN_WARNING "osst :A: Buffer not previously normalized.\n");
5341 normalize_buffer(STbuffer);
5342 }
5343 /* See how many segments we can use -- need at least two */
5344 nbr = max_segs = STbuffer->use_sg;
5345 if (nbr <= 2)
5346 return 0;
5347
5348 priority = GFP_KERNEL /* | __GFP_NOWARN */;
5349 if (need_dma)
5350 priority |= GFP_DMA;
5351
5352 /* Try to allocate the first segment up to OS_DATA_SIZE and the others
5353 big enough to reach the goal (code assumes no segments in place) */
5354 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 +02005355 struct page *page = alloc_pages(priority, order);
5356
Linus Torvalds1da177e2005-04-16 15:20:36 -07005357 STbuffer->sg[0].offset = 0;
Jens Axboe45711f12007-10-22 21:19:53 +02005358 if (page != NULL) {
Jens Axboe642f1492007-10-24 11:20:47 +02005359 sg_set_page(&STbuffer->sg[0], page, b_size, 0);
Jens Axboe45711f12007-10-22 21:19:53 +02005360 STbuffer->b_data = page_address(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005361 break;
5362 }
5363 }
Jens Axboe45711f12007-10-22 21:19:53 +02005364 if (sg_page(&STbuffer->sg[0]) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005365 printk(KERN_NOTICE "osst :I: Can't allocate tape buffer main segment.\n");
5366 return 0;
5367 }
5368 /* Got initial segment of 'bsize,order', continue with same size if possible, except for AUX */
5369 for (segs=STbuffer->sg_segs=1, got=b_size;
5370 segs < max_segs && got < OS_FRAME_SIZE; ) {
Jens Axboe45711f12007-10-22 21:19:53 +02005371 struct page *page = alloc_pages(priority, (OS_FRAME_SIZE - got <= PAGE_SIZE) ? 0 : order);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005372 STbuffer->sg[segs].offset = 0;
Jens Axboe45711f12007-10-22 21:19:53 +02005373 if (page == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005374 printk(KERN_WARNING "osst :W: Failed to enlarge buffer to %d bytes.\n",
5375 OS_FRAME_SIZE);
5376#if DEBUG
5377 STbuffer->buffer_size = got;
5378#endif
5379 normalize_buffer(STbuffer);
5380 return 0;
5381 }
Jens Axboe642f1492007-10-24 11:20:47 +02005382 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 -07005383 got += STbuffer->sg[segs].length;
5384 STbuffer->buffer_size = got;
5385 STbuffer->sg_segs = ++segs;
5386 }
5387#if DEBUG
5388 if (debugging) {
5389 printk(OSST_DEB_MSG
5390 "osst :D: Expanded tape buffer (%d bytes, %d->%d segments, dma: %d, at: %p).\n",
5391 got, STbuffer->orig_sg_segs, STbuffer->sg_segs, need_dma, STbuffer->b_data);
5392 printk(OSST_DEB_MSG
5393 "osst :D: segment sizes: first %d at %p, last %d bytes at %p.\n",
5394 STbuffer->sg[0].length, page_address(STbuffer->sg[0].page),
5395 STbuffer->sg[segs-1].length, page_address(STbuffer->sg[segs-1].page));
5396 }
5397#endif
5398
5399 return 1;
5400}
5401
5402
5403/* Release the segments */
5404static void normalize_buffer(struct osst_buffer *STbuffer)
5405{
5406 int i, order, b_size;
5407
5408 for (i=0; i < STbuffer->sg_segs; i++) {
5409
5410 for (b_size = PAGE_SIZE, order = 0;
5411 b_size < STbuffer->sg[i].length;
5412 b_size *= 2, order++);
5413
Jens Axboe45711f12007-10-22 21:19:53 +02005414 __free_pages(sg_page(&STbuffer->sg[i]), order);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005415 STbuffer->buffer_size -= STbuffer->sg[i].length;
5416 }
5417#if DEBUG
5418 if (debugging && STbuffer->orig_sg_segs < STbuffer->sg_segs)
5419 printk(OSST_DEB_MSG "osst :D: Buffer at %p normalized to %d bytes (segs %d).\n",
5420 STbuffer->b_data, STbuffer->buffer_size, STbuffer->sg_segs);
5421#endif
5422 STbuffer->sg_segs = STbuffer->orig_sg_segs = 0;
5423}
5424
5425
5426/* Move data from the user buffer to the tape buffer. Returns zero (success) or
5427 negative error code. */
5428static int append_to_buffer(const char __user *ubp, struct osst_buffer *st_bp, int do_count)
5429{
5430 int i, cnt, res, offset;
5431
5432 for (i=0, offset=st_bp->buffer_bytes;
5433 i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++)
5434 offset -= st_bp->sg[i].length;
5435 if (i == st_bp->sg_segs) { /* Should never happen */
5436 printk(KERN_WARNING "osst :A: Append_to_buffer offset overflow.\n");
5437 return (-EIO);
5438 }
5439 for ( ; i < st_bp->sg_segs && do_count > 0; i++) {
5440 cnt = st_bp->sg[i].length - offset < do_count ?
5441 st_bp->sg[i].length - offset : do_count;
Jens Axboe45711f12007-10-22 21:19:53 +02005442 res = copy_from_user(page_address(sg_page(&st_bp->sg[i])) + offset, ubp, cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005443 if (res)
5444 return (-EFAULT);
5445 do_count -= cnt;
5446 st_bp->buffer_bytes += cnt;
5447 ubp += cnt;
5448 offset = 0;
5449 }
5450 if (do_count) { /* Should never happen */
5451 printk(KERN_WARNING "osst :A: Append_to_buffer overflow (left %d).\n",
5452 do_count);
5453 return (-EIO);
5454 }
5455 return 0;
5456}
5457
5458
5459/* Move data from the tape buffer to the user buffer. Returns zero (success) or
5460 negative error code. */
5461static int from_buffer(struct osst_buffer *st_bp, char __user *ubp, int do_count)
5462{
5463 int i, cnt, res, offset;
5464
5465 for (i=0, offset=st_bp->read_pointer;
5466 i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++)
5467 offset -= st_bp->sg[i].length;
5468 if (i == st_bp->sg_segs) { /* Should never happen */
5469 printk(KERN_WARNING "osst :A: From_buffer offset overflow.\n");
5470 return (-EIO);
5471 }
5472 for ( ; i < st_bp->sg_segs && do_count > 0; i++) {
5473 cnt = st_bp->sg[i].length - offset < do_count ?
5474 st_bp->sg[i].length - offset : do_count;
Jens Axboe45711f12007-10-22 21:19:53 +02005475 res = copy_to_user(ubp, page_address(sg_page(&st_bp->sg[i])) + offset, cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005476 if (res)
5477 return (-EFAULT);
5478 do_count -= cnt;
5479 st_bp->buffer_bytes -= cnt;
5480 st_bp->read_pointer += cnt;
5481 ubp += cnt;
5482 offset = 0;
5483 }
5484 if (do_count) { /* Should never happen */
5485 printk(KERN_WARNING "osst :A: From_buffer overflow (left %d).\n", do_count);
5486 return (-EIO);
5487 }
5488 return 0;
5489}
5490
5491/* Sets the tail of the buffer after fill point to zero.
5492 Returns zero (success) or negative error code. */
5493static int osst_zero_buffer_tail(struct osst_buffer *st_bp)
5494{
5495 int i, offset, do_count, cnt;
5496
5497 for (i = 0, offset = st_bp->buffer_bytes;
5498 i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++)
5499 offset -= st_bp->sg[i].length;
5500 if (i == st_bp->sg_segs) { /* Should never happen */
5501 printk(KERN_WARNING "osst :A: Zero_buffer offset overflow.\n");
5502 return (-EIO);
5503 }
5504 for (do_count = OS_DATA_SIZE - st_bp->buffer_bytes;
5505 i < st_bp->sg_segs && do_count > 0; i++) {
5506 cnt = st_bp->sg[i].length - offset < do_count ?
5507 st_bp->sg[i].length - offset : do_count ;
Jens Axboe45711f12007-10-22 21:19:53 +02005508 memset(page_address(sg_page(&st_bp->sg[i])) + offset, 0, cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005509 do_count -= cnt;
5510 offset = 0;
5511 }
5512 if (do_count) { /* Should never happen */
5513 printk(KERN_WARNING "osst :A: Zero_buffer overflow (left %d).\n", do_count);
5514 return (-EIO);
5515 }
5516 return 0;
5517}
5518
5519/* Copy a osst 32K chunk of memory into the buffer.
5520 Returns zero (success) or negative error code. */
5521static int osst_copy_to_buffer(struct osst_buffer *st_bp, unsigned char *ptr)
5522{
5523 int i, cnt, do_count = OS_DATA_SIZE;
5524
5525 for (i = 0; i < st_bp->sg_segs && do_count > 0; i++) {
5526 cnt = st_bp->sg[i].length < do_count ?
5527 st_bp->sg[i].length : do_count ;
Jens Axboe45711f12007-10-22 21:19:53 +02005528 memcpy(page_address(sg_page(&st_bp->sg[i])), ptr, cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005529 do_count -= cnt;
5530 ptr += cnt;
5531 }
5532 if (do_count || i != st_bp->sg_segs-1) { /* Should never happen */
5533 printk(KERN_WARNING "osst :A: Copy_to_buffer overflow (left %d at sg %d).\n",
5534 do_count, i);
5535 return (-EIO);
5536 }
5537 return 0;
5538}
5539
5540/* Copy a osst 32K chunk of memory from the buffer.
5541 Returns zero (success) or negative error code. */
5542static int osst_copy_from_buffer(struct osst_buffer *st_bp, unsigned char *ptr)
5543{
5544 int i, cnt, do_count = OS_DATA_SIZE;
5545
5546 for (i = 0; i < st_bp->sg_segs && do_count > 0; i++) {
5547 cnt = st_bp->sg[i].length < do_count ?
5548 st_bp->sg[i].length : do_count ;
Jens Axboe45711f12007-10-22 21:19:53 +02005549 memcpy(ptr, page_address(sg_page(&st_bp->sg[i])), cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005550 do_count -= cnt;
5551 ptr += cnt;
5552 }
5553 if (do_count || i != st_bp->sg_segs-1) { /* Should never happen */
5554 printk(KERN_WARNING "osst :A: Copy_from_buffer overflow (left %d at sg %d).\n",
5555 do_count, i);
5556 return (-EIO);
5557 }
5558 return 0;
5559}
5560
5561
5562/* Module housekeeping */
5563
5564static void validate_options (void)
5565{
5566 if (max_dev > 0)
5567 osst_max_dev = max_dev;
5568 if (write_threshold_kbs > 0)
5569 osst_write_threshold = write_threshold_kbs * ST_KILOBYTE;
5570 if (osst_write_threshold > osst_buffer_size)
5571 osst_write_threshold = osst_buffer_size;
5572 if (max_sg_segs >= OSST_FIRST_SG)
5573 osst_max_sg_segs = max_sg_segs;
5574#if DEBUG
5575 printk(OSST_DEB_MSG "osst :D: max tapes %d, write threshold %d, max s/g segs %d.\n",
5576 osst_max_dev, osst_write_threshold, osst_max_sg_segs);
5577#endif
5578}
5579
5580#ifndef MODULE
5581/* Set the boot options. Syntax: osst=xxx,yyy,...
5582 where xxx is write threshold in 1024 byte blocks,
5583 and yyy is number of s/g segments to use. */
5584static int __init osst_setup (char *str)
5585{
5586 int i, ints[5];
5587 char *stp;
5588
5589 stp = get_options(str, ARRAY_SIZE(ints), ints);
Tobias Klauser6391a112006-06-08 22:23:48 -07005590
Linus Torvalds1da177e2005-04-16 15:20:36 -07005591 if (ints[0] > 0) {
5592 for (i = 0; i < ints[0] && i < ARRAY_SIZE(parms); i++)
5593 *parms[i].val = ints[i + 1];
5594 } else {
5595 while (stp != NULL) {
5596 for (i = 0; i < ARRAY_SIZE(parms); i++) {
5597 int len = strlen(parms[i].name);
5598 if (!strncmp(stp, parms[i].name, len) &&
5599 (*(stp + len) == ':' || *(stp + len) == '=')) {
5600 *parms[i].val =
5601 simple_strtoul(stp + len + 1, NULL, 0);
5602 break;
5603 }
5604 }
Tobias Klauser6391a112006-06-08 22:23:48 -07005605 if (i >= ARRAY_SIZE(parms))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005606 printk(KERN_INFO "osst :I: Illegal parameter in '%s'\n",
5607 stp);
5608 stp = strchr(stp, ',');
5609 if (stp)
5610 stp++;
5611 }
5612 }
5613
5614 return 1;
5615}
5616
5617__setup("osst=", osst_setup);
5618
5619#endif
5620
Arjan van de Ven00977a52007-02-12 00:55:34 -08005621static const struct file_operations osst_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005622 .owner = THIS_MODULE,
5623 .read = osst_read,
5624 .write = osst_write,
Arnd Bergmannf4927c42010-04-27 00:24:01 +02005625 .unlocked_ioctl = osst_ioctl,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005626#ifdef CONFIG_COMPAT
5627 .compat_ioctl = osst_compat_ioctl,
5628#endif
5629 .open = os_scsi_tape_open,
5630 .flush = os_scsi_tape_flush,
5631 .release = os_scsi_tape_close,
Jan Blunck889e5fb2010-05-26 14:44:50 -07005632 .llseek = noop_llseek,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005633};
5634
5635static int osst_supports(struct scsi_device * SDp)
5636{
5637 struct osst_support_data {
5638 char *vendor;
5639 char *model;
5640 char *rev;
5641 char *driver_hint; /* Name of the correct driver, NULL if unknown */
5642 };
5643
5644static struct osst_support_data support_list[] = {
5645 /* {"XXX", "Yy-", "", NULL}, example */
5646 SIGS_FROM_OSST,
5647 {NULL, }};
5648
5649 struct osst_support_data *rp;
5650
5651 /* We are willing to drive OnStream SC-x0 as well as the
5652 * * IDE, ParPort, FireWire, USB variants, if accessible by
5653 * * emulation layer (ide-scsi, usb-storage, ...) */
5654
5655 for (rp=&(support_list[0]); rp->vendor != NULL; rp++)
5656 if (!strncmp(rp->vendor, SDp->vendor, strlen(rp->vendor)) &&
5657 !strncmp(rp->model, SDp->model, strlen(rp->model)) &&
5658 !strncmp(rp->rev, SDp->rev, strlen(rp->rev)))
5659 return 1;
5660 return 0;
5661}
5662
5663/*
5664 * sysfs support for osst driver parameter information
5665 */
5666
5667static ssize_t osst_version_show(struct device_driver *ddd, char *buf)
5668{
5669 return snprintf(buf, PAGE_SIZE, "%s\n", osst_version);
5670}
5671
5672static DRIVER_ATTR(version, S_IRUGO, osst_version_show, NULL);
5673
Robert P. J. Day405ae7d2007-02-17 19:13:42 +01005674static int osst_create_sysfs_files(struct device_driver *sysfs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005675{
Robert P. J. Day405ae7d2007-02-17 19:13:42 +01005676 return driver_create_file(sysfs, &driver_attr_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005677}
5678
Robert P. J. Day405ae7d2007-02-17 19:13:42 +01005679static void osst_remove_sysfs_files(struct device_driver *sysfs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005680{
Robert P. J. Day405ae7d2007-02-17 19:13:42 +01005681 driver_remove_file(sysfs, &driver_attr_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005682}
5683
5684/*
5685 * sysfs support for accessing ADR header information
5686 */
5687
Tony Jonesee959b02008-02-22 00:13:36 +01005688static ssize_t osst_adr_rev_show(struct device *dev,
5689 struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005690{
Tony Jonesee959b02008-02-22 00:13:36 +01005691 struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005692 ssize_t l = 0;
5693
5694 if (STp && STp->header_ok && STp->linux_media)
5695 l = snprintf(buf, PAGE_SIZE, "%d.%d\n", STp->header_cache->major_rev, STp->header_cache->minor_rev);
5696 return l;
5697}
5698
Tony Jonesee959b02008-02-22 00:13:36 +01005699DEVICE_ATTR(ADR_rev, S_IRUGO, osst_adr_rev_show, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005700
Tony Jonesee959b02008-02-22 00:13:36 +01005701static ssize_t osst_linux_media_version_show(struct device *dev,
5702 struct device_attribute *attr,
5703 char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005704{
Tony Jonesee959b02008-02-22 00:13:36 +01005705 struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005706 ssize_t l = 0;
5707
5708 if (STp && STp->header_ok && STp->linux_media)
5709 l = snprintf(buf, PAGE_SIZE, "LIN%d\n", STp->linux_media_version);
5710 return l;
5711}
5712
Tony Jonesee959b02008-02-22 00:13:36 +01005713DEVICE_ATTR(media_version, S_IRUGO, osst_linux_media_version_show, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005714
Tony Jonesee959b02008-02-22 00:13:36 +01005715static ssize_t osst_capacity_show(struct device *dev,
5716 struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005717{
Tony Jonesee959b02008-02-22 00:13:36 +01005718 struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005719 ssize_t l = 0;
5720
5721 if (STp && STp->header_ok && STp->linux_media)
5722 l = snprintf(buf, PAGE_SIZE, "%d\n", STp->capacity);
5723 return l;
5724}
5725
Tony Jonesee959b02008-02-22 00:13:36 +01005726DEVICE_ATTR(capacity, S_IRUGO, osst_capacity_show, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005727
Tony Jonesee959b02008-02-22 00:13:36 +01005728static ssize_t osst_first_data_ppos_show(struct device *dev,
5729 struct device_attribute *attr,
5730 char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005731{
Tony Jonesee959b02008-02-22 00:13:36 +01005732 struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005733 ssize_t l = 0;
5734
5735 if (STp && STp->header_ok && STp->linux_media)
5736 l = snprintf(buf, PAGE_SIZE, "%d\n", STp->first_data_ppos);
5737 return l;
5738}
5739
Tony Jonesee959b02008-02-22 00:13:36 +01005740DEVICE_ATTR(BOT_frame, S_IRUGO, osst_first_data_ppos_show, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005741
Tony Jonesee959b02008-02-22 00:13:36 +01005742static ssize_t osst_eod_frame_ppos_show(struct device *dev,
5743 struct device_attribute *attr,
5744 char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005745{
Tony Jonesee959b02008-02-22 00:13:36 +01005746 struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005747 ssize_t l = 0;
5748
5749 if (STp && STp->header_ok && STp->linux_media)
5750 l = snprintf(buf, PAGE_SIZE, "%d\n", STp->eod_frame_ppos);
5751 return l;
5752}
5753
Tony Jonesee959b02008-02-22 00:13:36 +01005754DEVICE_ATTR(EOD_frame, S_IRUGO, osst_eod_frame_ppos_show, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005755
Tony Jonesee959b02008-02-22 00:13:36 +01005756static ssize_t osst_filemark_cnt_show(struct device *dev,
5757 struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005758{
Tony Jonesee959b02008-02-22 00:13:36 +01005759 struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005760 ssize_t l = 0;
5761
5762 if (STp && STp->header_ok && STp->linux_media)
5763 l = snprintf(buf, PAGE_SIZE, "%d\n", STp->filemark_cnt);
5764 return l;
5765}
5766
Tony Jonesee959b02008-02-22 00:13:36 +01005767DEVICE_ATTR(file_count, S_IRUGO, osst_filemark_cnt_show, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005768
gregkh@suse.ded2538782005-03-23 09:55:22 -08005769static struct class *osst_sysfs_class;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005770
Jeff Garzik37e03332006-10-04 05:23:04 -04005771static int osst_sysfs_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005772{
gregkh@suse.ded2538782005-03-23 09:55:22 -08005773 osst_sysfs_class = class_create(THIS_MODULE, "onstream_tape");
Jeff Garzik37e03332006-10-04 05:23:04 -04005774 if (IS_ERR(osst_sysfs_class)) {
5775 printk(KERN_ERR "osst :W: Unable to register sysfs class\n");
5776 return PTR_ERR(osst_sysfs_class);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005777 }
Jeff Garzik37e03332006-10-04 05:23:04 -04005778
5779 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005780}
5781
5782static void osst_sysfs_destroy(dev_t dev)
5783{
Tony Jonesee959b02008-02-22 00:13:36 +01005784 device_destroy(osst_sysfs_class, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005785}
5786
Jeff Garzik37e03332006-10-04 05:23:04 -04005787static int osst_sysfs_add(dev_t dev, struct device *device, struct osst_tape * STp, char * name)
5788{
Tony Jonesee959b02008-02-22 00:13:36 +01005789 struct device *osst_member;
Jeff Garzik37e03332006-10-04 05:23:04 -04005790 int err;
5791
Greg Kroah-Hartmand73a1a672008-07-21 20:03:34 -07005792 osst_member = device_create(osst_sysfs_class, device, dev, STp,
5793 "%s", name);
Tony Jonesee959b02008-02-22 00:13:36 +01005794 if (IS_ERR(osst_member)) {
Jeff Garzik37e03332006-10-04 05:23:04 -04005795 printk(KERN_WARNING "osst :W: Unable to add sysfs class member %s\n", name);
Tony Jonesee959b02008-02-22 00:13:36 +01005796 return PTR_ERR(osst_member);
Jeff Garzik37e03332006-10-04 05:23:04 -04005797 }
5798
Tony Jonesee959b02008-02-22 00:13:36 +01005799 err = device_create_file(osst_member, &dev_attr_ADR_rev);
Jeff Garzik37e03332006-10-04 05:23:04 -04005800 if (err)
5801 goto err_out;
Tony Jonesee959b02008-02-22 00:13:36 +01005802 err = device_create_file(osst_member, &dev_attr_media_version);
Jeff Garzik37e03332006-10-04 05:23:04 -04005803 if (err)
5804 goto err_out;
Tony Jonesee959b02008-02-22 00:13:36 +01005805 err = device_create_file(osst_member, &dev_attr_capacity);
Jeff Garzik37e03332006-10-04 05:23:04 -04005806 if (err)
5807 goto err_out;
Tony Jonesee959b02008-02-22 00:13:36 +01005808 err = device_create_file(osst_member, &dev_attr_BOT_frame);
Jeff Garzik37e03332006-10-04 05:23:04 -04005809 if (err)
5810 goto err_out;
Tony Jonesee959b02008-02-22 00:13:36 +01005811 err = device_create_file(osst_member, &dev_attr_EOD_frame);
Jeff Garzik37e03332006-10-04 05:23:04 -04005812 if (err)
5813 goto err_out;
Tony Jonesee959b02008-02-22 00:13:36 +01005814 err = device_create_file(osst_member, &dev_attr_file_count);
Jeff Garzik37e03332006-10-04 05:23:04 -04005815 if (err)
5816 goto err_out;
5817
5818 return 0;
5819
5820err_out:
5821 osst_sysfs_destroy(dev);
5822 return err;
5823}
5824
Linus Torvalds1da177e2005-04-16 15:20:36 -07005825static void osst_sysfs_cleanup(void)
5826{
Jeff Garzik37e03332006-10-04 05:23:04 -04005827 class_destroy(osst_sysfs_class);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005828}
5829
5830/*
5831 * osst startup / cleanup code
5832 */
5833
5834static int osst_probe(struct device *dev)
5835{
5836 struct scsi_device * SDp = to_scsi_device(dev);
5837 struct osst_tape * tpnt;
5838 struct st_modedef * STm;
5839 struct st_partstat * STps;
5840 struct osst_buffer * buffer;
5841 struct gendisk * drive;
Jeff Garzik37e03332006-10-04 05:23:04 -04005842 int i, dev_num, err = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005843
5844 if (SDp->type != TYPE_TAPE || !osst_supports(SDp))
5845 return -ENODEV;
5846
5847 drive = alloc_disk(1);
5848 if (!drive) {
5849 printk(KERN_ERR "osst :E: Out of memory. Device not attached.\n");
5850 return -ENODEV;
5851 }
5852
5853 /* if this is the first attach, build the infrastructure */
5854 write_lock(&os_scsi_tapes_lock);
5855 if (os_scsi_tapes == NULL) {
Jesper Juhl20999732010-11-09 00:09:25 +01005856 os_scsi_tapes = kmalloc(osst_max_dev * sizeof(struct osst_tape *), GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005857 if (os_scsi_tapes == NULL) {
5858 write_unlock(&os_scsi_tapes_lock);
5859 printk(KERN_ERR "osst :E: Unable to allocate array for OnStream SCSI tapes.\n");
5860 goto out_put_disk;
5861 }
5862 for (i=0; i < osst_max_dev; ++i) os_scsi_tapes[i] = NULL;
5863 }
5864
5865 if (osst_nr_dev >= osst_max_dev) {
5866 write_unlock(&os_scsi_tapes_lock);
5867 printk(KERN_ERR "osst :E: Too many tape devices (max. %d).\n", osst_max_dev);
5868 goto out_put_disk;
5869 }
5870
5871 /* find a free minor number */
Roel Kluinef3f7cc2010-08-10 18:01:10 -07005872 for (i = 0; i < osst_max_dev && os_scsi_tapes[i]; i++)
5873 ;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005874 if(i >= osst_max_dev) panic ("Scsi_devices corrupt (osst)");
5875 dev_num = i;
5876
5877 /* allocate a struct osst_tape for this device */
Mariusz Kozlowskibbfbbbc2007-08-11 10:13:24 +02005878 tpnt = kzalloc(sizeof(struct osst_tape), GFP_ATOMIC);
5879 if (!tpnt) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005880 write_unlock(&os_scsi_tapes_lock);
5881 printk(KERN_ERR "osst :E: Can't allocate device descriptor, device not attached.\n");
5882 goto out_put_disk;
5883 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005884
5885 /* allocate a buffer for this device */
5886 i = SDp->host->sg_tablesize;
5887 if (osst_max_sg_segs < i)
5888 i = osst_max_sg_segs;
5889 buffer = new_tape_buffer(1, SDp->host->unchecked_isa_dma, i);
5890 if (buffer == NULL) {
5891 write_unlock(&os_scsi_tapes_lock);
5892 printk(KERN_ERR "osst :E: Unable to allocate a tape buffer, device not attached.\n");
5893 kfree(tpnt);
5894 goto out_put_disk;
5895 }
5896 os_scsi_tapes[dev_num] = tpnt;
5897 tpnt->buffer = buffer;
5898 tpnt->device = SDp;
5899 drive->private_data = &tpnt->driver;
5900 sprintf(drive->disk_name, "osst%d", dev_num);
5901 tpnt->driver = &osst_template;
5902 tpnt->drive = drive;
5903 tpnt->in_use = 0;
5904 tpnt->capacity = 0xfffff;
5905 tpnt->dirty = 0;
5906 tpnt->drv_buffer = 1; /* Try buffering if no mode sense */
5907 tpnt->restr_dma = (SDp->host)->unchecked_isa_dma;
5908 tpnt->density = 0;
5909 tpnt->do_auto_lock = OSST_AUTO_LOCK;
5910 tpnt->can_bsr = OSST_IN_FILE_POS;
5911 tpnt->can_partitions = 0;
5912 tpnt->two_fm = OSST_TWO_FM;
5913 tpnt->fast_mteom = OSST_FAST_MTEOM;
5914 tpnt->scsi2_logical = OSST_SCSI2LOGICAL; /* FIXME */
5915 tpnt->write_threshold = osst_write_threshold;
5916 tpnt->default_drvbuffer = 0xff; /* No forced buffering */
5917 tpnt->partition = 0;
5918 tpnt->new_partition = 0;
5919 tpnt->nbr_partitions = 0;
5920 tpnt->min_block = 512;
5921 tpnt->max_block = OS_DATA_SIZE;
5922 tpnt->timeout = OSST_TIMEOUT;
5923 tpnt->long_timeout = OSST_LONG_TIMEOUT;
5924
5925 /* Recognize OnStream tapes */
5926 /* We don't need to test for OnStream, as this has been done in detect () */
5927 tpnt->os_fw_rev = osst_parse_firmware_rev (SDp->rev);
5928 tpnt->omit_blklims = 1;
5929
5930 tpnt->poll = (strncmp(SDp->model, "DI-", 3) == 0) ||
5931 (strncmp(SDp->model, "FW-", 3) == 0) || OSST_FW_NEED_POLL(tpnt->os_fw_rev,SDp);
5932 tpnt->frame_in_buffer = 0;
5933 tpnt->header_ok = 0;
5934 tpnt->linux_media = 0;
5935 tpnt->header_cache = NULL;
5936
5937 for (i=0; i < ST_NBR_MODES; i++) {
5938 STm = &(tpnt->modes[i]);
5939 STm->defined = 0;
5940 STm->sysv = OSST_SYSV;
5941 STm->defaults_for_writes = 0;
5942 STm->do_async_writes = OSST_ASYNC_WRITES;
5943 STm->do_buffer_writes = OSST_BUFFER_WRITES;
5944 STm->do_read_ahead = OSST_READ_AHEAD;
5945 STm->default_compression = ST_DONT_TOUCH;
5946 STm->default_blksize = 512;
5947 STm->default_density = (-1); /* No forced density */
5948 }
5949
5950 for (i=0; i < ST_NBR_PARTITIONS; i++) {
5951 STps = &(tpnt->ps[i]);
5952 STps->rw = ST_IDLE;
5953 STps->eof = ST_NOEOF;
5954 STps->at_sm = 0;
5955 STps->last_block_valid = 0;
5956 STps->drv_block = (-1);
5957 STps->drv_file = (-1);
5958 }
5959
5960 tpnt->current_mode = 0;
5961 tpnt->modes[0].defined = 1;
5962 tpnt->modes[2].defined = 1;
5963 tpnt->density_changed = tpnt->compression_changed = tpnt->blksize_changed = 0;
5964
Matthias Kaehlcke4390e602007-08-10 14:50:44 -07005965 mutex_init(&tpnt->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005966 osst_nr_dev++;
5967 write_unlock(&os_scsi_tapes_lock);
Jeff Garzik37e03332006-10-04 05:23:04 -04005968
Linus Torvalds1da177e2005-04-16 15:20:36 -07005969 {
5970 char name[8];
Jeff Garzik37e03332006-10-04 05:23:04 -04005971
Linus Torvalds1da177e2005-04-16 15:20:36 -07005972 /* Rewind entry */
Jeff Garzik37e03332006-10-04 05:23:04 -04005973 err = osst_sysfs_add(MKDEV(OSST_MAJOR, dev_num), dev, tpnt, tape_name(tpnt));
5974 if (err)
5975 goto out_free_buffer;
5976
Linus Torvalds1da177e2005-04-16 15:20:36 -07005977 /* No-rewind entry */
5978 snprintf(name, 8, "%s%s", "n", tape_name(tpnt));
Jeff Garzik37e03332006-10-04 05:23:04 -04005979 err = osst_sysfs_add(MKDEV(OSST_MAJOR, dev_num + 128), dev, tpnt, name);
5980 if (err)
5981 goto out_free_sysfs1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005982 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005983
James Bottomley80e23ba2005-10-29 09:42:17 -05005984 sdev_printk(KERN_INFO, SDp,
James Bottomley9ccfc752005-10-02 11:45:08 -05005985 "osst :I: Attached OnStream %.5s tape as %s\n",
5986 SDp->model, tape_name(tpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005987
5988 return 0;
5989
Jeff Garzik37e03332006-10-04 05:23:04 -04005990out_free_sysfs1:
5991 osst_sysfs_destroy(MKDEV(OSST_MAJOR, dev_num));
5992out_free_buffer:
5993 kfree(buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005994out_put_disk:
5995 put_disk(drive);
Jeff Garzik37e03332006-10-04 05:23:04 -04005996 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005997};
5998
5999static int osst_remove(struct device *dev)
6000{
6001 struct scsi_device * SDp = to_scsi_device(dev);
6002 struct osst_tape * tpnt;
Greg KH5e3c34c2006-01-18 16:17:46 -08006003 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006004
6005 if ((SDp->type != TYPE_TAPE) || (osst_nr_dev <= 0))
6006 return 0;
6007
6008 write_lock(&os_scsi_tapes_lock);
6009 for(i=0; i < osst_max_dev; i++) {
6010 if((tpnt = os_scsi_tapes[i]) && (tpnt->device == SDp)) {
6011 osst_sysfs_destroy(MKDEV(OSST_MAJOR, i));
6012 osst_sysfs_destroy(MKDEV(OSST_MAJOR, i+128));
6013 tpnt->device = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006014 put_disk(tpnt->drive);
6015 os_scsi_tapes[i] = NULL;
6016 osst_nr_dev--;
6017 write_unlock(&os_scsi_tapes_lock);
Jesper Juhlf91012102005-09-10 00:26:54 -07006018 vfree(tpnt->header_cache);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006019 if (tpnt->buffer) {
6020 normalize_buffer(tpnt->buffer);
6021 kfree(tpnt->buffer);
6022 }
6023 kfree(tpnt);
6024 return 0;
6025 }
6026 }
6027 write_unlock(&os_scsi_tapes_lock);
6028 return 0;
6029}
6030
6031static int __init init_osst(void)
6032{
Jeff Garzik37e03332006-10-04 05:23:04 -04006033 int err;
6034
Linus Torvalds1da177e2005-04-16 15:20:36 -07006035 printk(KERN_INFO "osst :I: Tape driver with OnStream support version %s\nosst :I: %s\n", osst_version, cvsid);
6036
6037 validate_options();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006038
Jeff Garzik37e03332006-10-04 05:23:04 -04006039 err = osst_sysfs_init();
6040 if (err)
6041 return err;
6042
6043 err = register_chrdev(OSST_MAJOR, "osst", &osst_fops);
6044 if (err < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006045 printk(KERN_ERR "osst :E: Unable to register major %d for OnStream tapes\n", OSST_MAJOR);
Jeff Garzik37e03332006-10-04 05:23:04 -04006046 goto err_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006047 }
Jeff Garzik37e03332006-10-04 05:23:04 -04006048
6049 err = scsi_register_driver(&osst_template.gendrv);
6050 if (err)
6051 goto err_out_chrdev;
6052
Robert P. J. Day405ae7d2007-02-17 19:13:42 +01006053 err = osst_create_sysfs_files(&osst_template.gendrv);
Jeff Garzik37e03332006-10-04 05:23:04 -04006054 if (err)
6055 goto err_out_scsidrv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006056
6057 return 0;
Jeff Garzik37e03332006-10-04 05:23:04 -04006058
6059err_out_scsidrv:
6060 scsi_unregister_driver(&osst_template.gendrv);
6061err_out_chrdev:
6062 unregister_chrdev(OSST_MAJOR, "osst");
6063err_out:
6064 osst_sysfs_cleanup();
6065 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006066}
6067
6068static void __exit exit_osst (void)
6069{
6070 int i;
6071 struct osst_tape * STp;
6072
Robert P. J. Day405ae7d2007-02-17 19:13:42 +01006073 osst_remove_sysfs_files(&osst_template.gendrv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006074 scsi_unregister_driver(&osst_template.gendrv);
6075 unregister_chrdev(OSST_MAJOR, "osst");
6076 osst_sysfs_cleanup();
6077
6078 if (os_scsi_tapes) {
6079 for (i=0; i < osst_max_dev; ++i) {
6080 if (!(STp = os_scsi_tapes[i])) continue;
6081 /* This is defensive, supposed to happen during detach */
Jesper Juhlf91012102005-09-10 00:26:54 -07006082 vfree(STp->header_cache);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006083 if (STp->buffer) {
6084 normalize_buffer(STp->buffer);
6085 kfree(STp->buffer);
6086 }
6087 put_disk(STp->drive);
6088 kfree(STp);
6089 }
6090 kfree(os_scsi_tapes);
6091 }
6092 printk(KERN_INFO "osst :I: Unloaded.\n");
6093}
6094
6095module_init(init_osst);
6096module_exit(exit_osst);