MOXA linux-2.6.x / linux-2.6.9-uc0 from sdlinux-moxaart.tgz
[linux-2.6.9-moxart.git] / drivers / scsi / osst.c
blobfb74a2f64cd51528a2d5d5b020d4f38e1db730a0
1 /*
2 SCSI Tape Driver for Linux version 1.1 and newer. See the accompanying
3 file Documentation/scsi/st.txt for more information.
5 History:
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
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.
16 Copyright 1992 - 2002 Kai Makisara / Willem Riede
17 email Kai.Makisara@metla.fi / osst@riede.org
19 $Header: /cvsroot/osst/Driver/osst.c,v 1.70 2003/12/23 14:22:12 wriede Exp $
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
26 static const char * cvsid = "$Id: osst.c,v 1.70 2003/12/23 14:22:12 wriede Exp $";
27 const char * osst_version = "0.99.1";
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)
34 #include <linux/module.h>
36 #include <linux/fs.h>
37 #include <linux/kernel.h>
38 #include <linux/sched.h>
39 #include <linux/mm.h>
40 #include <linux/init.h>
41 #include <linux/string.h>
42 #include <linux/errno.h>
43 #include <linux/mtio.h>
44 #include <linux/ioctl.h>
45 #include <linux/fcntl.h>
46 #include <linux/spinlock.h>
47 #include <linux/vmalloc.h>
48 #include <linux/blkdev.h>
49 #include <linux/devfs_fs_kernel.h>
50 #include <asm/uaccess.h>
51 #include <asm/dma.h>
52 #include <asm/system.h>
54 /* The driver prints some debugging information on the console if DEBUG
55 is defined and non-zero. */
56 #define DEBUG 0
58 /* The message level for the debug messages is currently set to KERN_NOTICE
59 so that people can easily see the messages. Later when the debugging messages
60 in the drivers are more widely classified, this may be changed to KERN_DEBUG. */
61 #define OSST_DEB_MSG KERN_NOTICE
63 #include "scsi.h"
64 #include <scsi/scsi_host.h>
65 #include <scsi/scsi_driver.h>
66 #include <scsi/scsi_ioctl.h>
68 #define ST_KILOBYTE 1024
70 #include "st.h"
71 #include "osst.h"
72 #include "osst_options.h"
73 #include "osst_detect.h"
75 static int max_dev = 0;
76 static int write_threshold_kbs = 0;
77 static int max_sg_segs = 0;
79 #ifdef MODULE
80 MODULE_AUTHOR("Willem Riede");
81 MODULE_DESCRIPTION("OnStream {DI-|FW-|SC-|USB}{30|50} Tape Driver");
82 MODULE_LICENSE("GPL");
84 MODULE_PARM(max_dev, "i");
85 MODULE_PARM_DESC(max_dev, "Maximum number of OnStream Tape Drives to attach (4)");
87 MODULE_PARM(write_threshold_kbs, "i");
88 MODULE_PARM_DESC(write_threshold_kbs, "Asynchronous write threshold (KB; 32)");
90 MODULE_PARM(max_sg_segs, "i");
91 MODULE_PARM_DESC(max_sg_segs, "Maximum number of scatter/gather segments to use (9)");
92 #else
93 static struct osst_dev_parm {
94 char *name;
95 int *val;
96 } parms[] __initdata = {
97 { "max_dev", &max_dev },
98 { "write_threshold_kbs", &write_threshold_kbs },
99 { "max_sg_segs", &max_sg_segs }
101 #endif
103 static char *osst_formats[ST_NBR_MODES] ={"", "l", "m", "a"};
105 /* Some default definitions have been moved to osst_options.h */
106 #define OSST_BUFFER_SIZE (OSST_BUFFER_BLOCKS * ST_KILOBYTE)
107 #define OSST_WRITE_THRESHOLD (OSST_WRITE_THRESHOLD_BLOCKS * ST_KILOBYTE)
109 /* The buffer size should fit into the 24 bits for length in the
110 6-byte SCSI read and write commands. */
111 #if OSST_BUFFER_SIZE >= (2 << 24 - 1)
112 #error "Buffer size should not exceed (2 << 24 - 1) bytes!"
113 #endif
115 #if DEBUG
116 static int debugging = 1;
117 /* uncomment define below to test error recovery */
118 // #define OSST_INJECT_ERRORS 1
119 #endif
121 #define MAX_RETRIES 2
122 #define MAX_READ_RETRIES 0
123 #define MAX_WRITE_RETRIES 0
124 #define MAX_READY_RETRIES 0
125 #define NO_TAPE NOT_READY
127 #define OSST_WAIT_POSITION_COMPLETE (HZ > 200 ? HZ / 200 : 1)
128 #define OSST_WAIT_WRITE_COMPLETE (HZ / 12)
129 #define OSST_WAIT_LONG_WRITE_COMPLETE (HZ / 2)
131 #define OSST_TIMEOUT (200 * HZ)
132 #define OSST_LONG_TIMEOUT (1800 * HZ)
134 #define TAPE_NR(x) (iminor(x) & ~(-1 << ST_MODE_SHIFT))
135 #define TAPE_MODE(x) ((iminor(x) & ST_MODE_MASK) >> ST_MODE_SHIFT)
136 #define TAPE_REWIND(x) ((iminor(x) & 0x80) == 0)
137 #define TAPE_IS_RAW(x) (TAPE_MODE(x) & (ST_NBR_MODES >> 1))
139 /* Internal ioctl to set both density (uppermost 8 bits) and blocksize (lower
140 24 bits) */
141 #define SET_DENS_AND_BLK 0x10001
143 static int osst_buffer_size = OSST_BUFFER_SIZE;
144 static int osst_write_threshold = OSST_WRITE_THRESHOLD;
145 static int osst_max_sg_segs = OSST_MAX_SG;
146 static int osst_max_dev = OSST_MAX_TAPES;
147 static int osst_nr_dev;
149 static OS_Scsi_Tape **os_scsi_tapes = NULL;
150 static rwlock_t os_scsi_tapes_lock = RW_LOCK_UNLOCKED;
152 static int modes_defined = FALSE;
154 static OSST_buffer *new_tape_buffer(int, int, int);
155 static int enlarge_buffer(OSST_buffer *, int);
156 static void normalize_buffer(OSST_buffer *);
157 static int append_to_buffer(const char __user *, OSST_buffer *, int);
158 static int from_buffer(OSST_buffer *, char __user *, int);
159 static int osst_zero_buffer_tail(OSST_buffer *);
160 static int osst_copy_to_buffer(OSST_buffer *, unsigned char *);
161 static int osst_copy_from_buffer(OSST_buffer *, unsigned char *);
163 static int osst_probe(struct device *);
164 static int osst_remove(struct device *);
166 struct scsi_driver osst_template = {
167 .owner = THIS_MODULE,
168 .gendrv = {
169 .name = "osst",
170 .probe = osst_probe,
171 .remove = osst_remove,
175 static int osst_int_ioctl(OS_Scsi_Tape *STp, Scsi_Request ** aSRpnt, unsigned int cmd_in,unsigned long arg);
177 static int osst_set_frame_position(OS_Scsi_Tape *STp, Scsi_Request ** aSRpnt, int frame, int skip);
179 static int osst_get_frame_position(OS_Scsi_Tape *STp, Scsi_Request ** aSRpnt);
181 static int osst_flush_write_buffer(OS_Scsi_Tape *STp, Scsi_Request ** aSRpnt);
183 static int osst_write_error_recovery(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int pending);
185 static inline char *tape_name(OS_Scsi_Tape *tape)
187 return tape->drive->disk_name;
190 /* Routines that handle the interaction with mid-layer SCSI routines */
192 /* Convert the result to success code */
193 static int osst_chk_result(OS_Scsi_Tape * STp, Scsi_Request * SRpnt)
195 char *name = tape_name(STp);
196 int result = SRpnt->sr_result;
197 unsigned char * sense = SRpnt->sr_sense_buffer, scode;
198 #if DEBUG
199 const char *stp;
200 #endif
202 if (!result) {
203 sense[0] = 0; /* We don't have sense data if this byte is zero */
204 return 0;
206 if ((driver_byte(result) & DRIVER_MASK) == DRIVER_SENSE)
207 scode = sense[2] & 0x0f;
208 else {
209 sense[0] = 0; /* We don't have sense data if this byte is zero */
210 scode = 0;
212 #if DEBUG
213 if (debugging) {
214 printk(OSST_DEB_MSG "%s:D: Error: %x, cmd: %x %x %x %x %x %x Len: %d\n",
215 name, result,
216 SRpnt->sr_cmnd[0], SRpnt->sr_cmnd[1], SRpnt->sr_cmnd[2],
217 SRpnt->sr_cmnd[3], SRpnt->sr_cmnd[4], SRpnt->sr_cmnd[5],
218 SRpnt->sr_bufflen);
219 if (scode) printk(OSST_DEB_MSG "%s:D: Sense: %02x, ASC: %02x, ASCQ: %02x\n",
220 name, scode, sense[12], sense[13]);
221 if (driver_byte(result) & DRIVER_SENSE)
222 print_req_sense("osst ", SRpnt);
224 // else
225 #endif
226 if (!(driver_byte(result) & DRIVER_SENSE) ||
227 ((sense[0] & 0x70) == 0x70 &&
228 scode != NO_SENSE &&
229 scode != RECOVERED_ERROR &&
230 /* scode != UNIT_ATTENTION && */
231 scode != BLANK_CHECK &&
232 scode != VOLUME_OVERFLOW &&
233 SRpnt->sr_cmnd[0] != MODE_SENSE &&
234 SRpnt->sr_cmnd[0] != TEST_UNIT_READY)) { /* Abnormal conditions for tape */
235 if (driver_byte(result) & DRIVER_SENSE) {
236 printk(KERN_WARNING "%s:W: Command with sense data: ", name);
237 print_req_sense("osst:", SRpnt);
239 else {
240 static int notyetprinted = 1;
242 printk(KERN_WARNING
243 "%s:W: Warning %x (sugg. bt 0x%x, driver bt 0x%x, host bt 0x%x).\n",
244 name, result, suggestion(result), driver_byte(result) & DRIVER_MASK,
245 host_byte(result));
246 if (notyetprinted) {
247 notyetprinted = 0;
248 printk(KERN_INFO
249 "%s:I: This warning may be caused by your scsi controller,\n", name);
250 printk(KERN_INFO
251 "%s:I: it has been reported with some Buslogic cards.\n", name);
255 STp->pos_unknown |= STp->device->was_reset;
257 if ((sense[0] & 0x70) == 0x70 &&
258 scode == RECOVERED_ERROR) {
259 STp->recover_count++;
260 STp->recover_erreg++;
261 #if DEBUG
262 if (debugging) {
263 if (SRpnt->sr_cmnd[0] == READ_6)
264 stp = "read";
265 else if (SRpnt->sr_cmnd[0] == WRITE_6)
266 stp = "write";
267 else
268 stp = "ioctl";
269 printk(OSST_DEB_MSG "%s:D: Recovered %s error (%d).\n", name, stp,
270 STp->recover_count);
272 #endif
273 if ((sense[2] & 0xe0) == 0)
274 return 0;
276 return (-EIO);
280 /* Wakeup from interrupt */
281 static void osst_sleep_done (Scsi_Cmnd * SCpnt)
283 OS_Scsi_Tape * STp = container_of(SCpnt->request->rq_disk->private_data, OS_Scsi_Tape, driver);
285 if ((STp->buffer)->writing &&
286 (SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
287 (SCpnt->sense_buffer[2] & 0x40)) {
288 /* EOM at write-behind, has all been written? */
289 if ((SCpnt->sense_buffer[2] & 0x0f) == VOLUME_OVERFLOW)
290 STp->buffer->midlevel_result = SCpnt->result; /* Error */
291 else
292 STp->buffer->midlevel_result = INT_MAX; /* OK */
294 else
295 STp->buffer->midlevel_result = SCpnt->result;
296 SCpnt->request->rq_status = RQ_SCSI_DONE;
297 STp->buffer->last_SRpnt = SCpnt->sc_request;
299 #if DEBUG
300 STp->write_pending = 0;
301 #endif
302 complete(SCpnt->request->waiting);
306 /* Do the scsi command. Waits until command performed if do_wait is true.
307 Otherwise osst_write_behind_check() is used to check that the command
308 has finished. */
309 static Scsi_Request * osst_do_scsi(Scsi_Request *SRpnt, OS_Scsi_Tape *STp,
310 unsigned char *cmd, int bytes, int direction, int timeout, int retries, int do_wait)
312 unsigned char *bp;
313 #ifdef OSST_INJECT_ERRORS
314 static int inject = 0;
315 static int repeat = 0;
316 #endif
317 if (SRpnt == NULL) {
318 if ((SRpnt = scsi_allocate_request(STp->device, GFP_ATOMIC)) == NULL) {
319 printk(KERN_ERR "%s:E: Can't get SCSI request.\n", tape_name(STp));
320 if (signal_pending(current))
321 (STp->buffer)->syscall_result = (-EINTR);
322 else
323 (STp->buffer)->syscall_result = (-EBUSY);
324 return NULL;
328 init_completion(&STp->wait);
329 SRpnt->sr_use_sg = (bytes > (STp->buffer)->sg[0].length) ?
330 (STp->buffer)->use_sg : 0;
331 if (SRpnt->sr_use_sg) {
332 bp = (char *)&(STp->buffer->sg[0]);
333 if (STp->buffer->sg_segs < SRpnt->sr_use_sg)
334 SRpnt->sr_use_sg = STp->buffer->sg_segs;
336 else
337 bp = (STp->buffer)->b_data;
338 SRpnt->sr_data_direction = direction;
339 SRpnt->sr_cmd_len = 0;
340 SRpnt->sr_request->waiting = &(STp->wait);
341 SRpnt->sr_request->rq_status = RQ_SCSI_BUSY;
342 SRpnt->sr_request->rq_disk = STp->drive;
344 scsi_do_req(SRpnt, (void *)cmd, bp, bytes, osst_sleep_done, timeout, retries);
346 if (do_wait) {
347 wait_for_completion(SRpnt->sr_request->waiting);
348 SRpnt->sr_request->waiting = NULL;
349 STp->buffer->syscall_result = osst_chk_result(STp, SRpnt);
350 #ifdef OSST_INJECT_ERRORS
351 if (STp->buffer->syscall_result == 0 &&
352 cmd[0] == READ_6 &&
353 cmd[4] &&
354 ( (++ inject % 83) == 29 ||
355 (STp->first_frame_position == 240
356 /* or STp->read_error_frame to fail again on the block calculated above */ &&
357 ++repeat < 3))) {
358 printk(OSST_DEB_MSG "%s:D: Injecting read error\n", tape_name(STp));
359 STp->buffer->last_result_fatal = 1;
361 #endif
363 return SRpnt;
367 /* Handle the write-behind checking (downs the semaphore) */
368 static void osst_write_behind_check(OS_Scsi_Tape *STp)
370 OSST_buffer * STbuffer;
372 STbuffer = STp->buffer;
374 #if DEBUG
375 if (STp->write_pending)
376 STp->nbr_waits++;
377 else
378 STp->nbr_finished++;
379 #endif
380 wait_for_completion(&(STp->wait));
381 (STp->buffer)->last_SRpnt->sr_request->waiting = NULL;
383 STp->buffer->syscall_result = osst_chk_result(STp, STp->buffer->last_SRpnt);
385 if ((STp->buffer)->syscall_result)
386 (STp->buffer)->syscall_result =
387 osst_write_error_recovery(STp, &((STp->buffer)->last_SRpnt), 1);
388 else
389 STp->first_frame_position++;
391 scsi_release_request((STp->buffer)->last_SRpnt);
393 if (STbuffer->writing < STbuffer->buffer_bytes)
394 printk(KERN_WARNING "osst :A: write_behind_check: something left in buffer!\n");
396 STbuffer->buffer_bytes -= STbuffer->writing;
397 STbuffer->writing = 0;
399 return;
404 /* Onstream specific Routines */
406 * Initialize the OnStream AUX
408 static void osst_init_aux(OS_Scsi_Tape * STp, int frame_type, int frame_seq_number,
409 int logical_blk_num, int blk_sz, int blk_cnt)
411 os_aux_t *aux = STp->buffer->aux;
412 os_partition_t *par = &aux->partition;
413 os_dat_t *dat = &aux->dat;
415 if (STp->raw) return;
417 memset(aux, 0, sizeof(*aux));
418 aux->format_id = htonl(0);
419 memcpy(aux->application_sig, "LIN4", 4);
420 aux->hdwr = htonl(0);
421 aux->frame_type = frame_type;
423 switch (frame_type) {
424 case OS_FRAME_TYPE_HEADER:
425 aux->update_frame_cntr = htonl(STp->update_frame_cntr);
426 par->partition_num = OS_CONFIG_PARTITION;
427 par->par_desc_ver = OS_PARTITION_VERSION;
428 par->wrt_pass_cntr = htons(0xffff);
429 /* 0-4 = reserved, 5-9 = header, 2990-2994 = header, 2995-2999 = reserved */
430 par->first_frame_ppos = htonl(0);
431 par->last_frame_ppos = htonl(0xbb7);
432 aux->frame_seq_num = htonl(0);
433 aux->logical_blk_num_high = htonl(0);
434 aux->logical_blk_num = htonl(0);
435 aux->next_mark_ppos = htonl(STp->first_mark_ppos);
436 break;
437 case OS_FRAME_TYPE_DATA:
438 case OS_FRAME_TYPE_MARKER:
439 dat->dat_sz = 8;
440 dat->reserved1 = 0;
441 dat->entry_cnt = 1;
442 dat->reserved3 = 0;
443 dat->dat_list[0].blk_sz = htonl(blk_sz);
444 dat->dat_list[0].blk_cnt = htons(blk_cnt);
445 dat->dat_list[0].flags = frame_type==OS_FRAME_TYPE_MARKER?
446 OS_DAT_FLAGS_MARK:OS_DAT_FLAGS_DATA;
447 dat->dat_list[0].reserved = 0;
448 case OS_FRAME_TYPE_EOD:
449 aux->update_frame_cntr = htonl(0);
450 par->partition_num = OS_DATA_PARTITION;
451 par->par_desc_ver = OS_PARTITION_VERSION;
452 par->wrt_pass_cntr = htons(STp->wrt_pass_cntr);
453 par->first_frame_ppos = htonl(STp->first_data_ppos);
454 par->last_frame_ppos = htonl(STp->capacity);
455 aux->frame_seq_num = htonl(frame_seq_number);
456 aux->logical_blk_num_high = htonl(0);
457 aux->logical_blk_num = htonl(logical_blk_num);
458 break;
459 default: ; /* probably FILL */
461 aux->filemark_cnt = ntohl(STp->filemark_cnt);
462 aux->phys_fm = ntohl(0xffffffff);
463 aux->last_mark_ppos = ntohl(STp->last_mark_ppos);
464 aux->last_mark_lbn = ntohl(STp->last_mark_lbn);
468 * Verify that we have the correct tape frame
470 static int osst_verify_frame(OS_Scsi_Tape * STp, int frame_seq_number, int quiet)
472 char * name = tape_name(STp);
473 os_aux_t * aux = STp->buffer->aux;
474 os_partition_t * par = &(aux->partition);
475 ST_partstat * STps = &(STp->ps[STp->partition]);
476 int blk_cnt, blk_sz, i;
478 if (STp->raw) {
479 if (STp->buffer->syscall_result) {
480 for (i=0; i < STp->buffer->sg_segs; i++)
481 memset(page_address(STp->buffer->sg[i].page),
482 0, STp->buffer->sg[i].length);
483 strcpy(STp->buffer->b_data, "READ ERROR ON FRAME");
484 } else
485 STp->buffer->buffer_bytes = OS_FRAME_SIZE;
486 return 1;
488 if (STp->buffer->syscall_result) {
489 #if DEBUG
490 printk(OSST_DEB_MSG "%s:D: Skipping frame, read error\n", name);
491 #endif
492 return 0;
494 if (ntohl(aux->format_id) != 0) {
495 #if DEBUG
496 printk(OSST_DEB_MSG "%s:D: Skipping frame, format_id %u\n", name, ntohl(aux->format_id));
497 #endif
498 goto err_out;
500 if (memcmp(aux->application_sig, STp->application_sig, 4) != 0 &&
501 (memcmp(aux->application_sig, "LIN3", 4) != 0 || STp->linux_media_version != 4)) {
502 #if DEBUG
503 printk(OSST_DEB_MSG "%s:D: Skipping frame, incorrect application signature\n", name);
504 #endif
505 goto err_out;
507 if (par->partition_num != OS_DATA_PARTITION) {
508 if (!STp->linux_media || STp->linux_media_version != 2) {
509 #if DEBUG
510 printk(OSST_DEB_MSG "%s:D: Skipping frame, partition num %d\n",
511 name, par->partition_num);
512 #endif
513 goto err_out;
516 if (par->par_desc_ver != OS_PARTITION_VERSION) {
517 #if DEBUG
518 printk(OSST_DEB_MSG "%s:D: Skipping frame, partition version %d\n", name, par->par_desc_ver);
519 #endif
520 goto err_out;
522 if (ntohs(par->wrt_pass_cntr) != STp->wrt_pass_cntr) {
523 #if DEBUG
524 printk(OSST_DEB_MSG "%s:D: Skipping frame, wrt_pass_cntr %d (expected %d)\n",
525 name, ntohs(par->wrt_pass_cntr), STp->wrt_pass_cntr);
526 #endif
527 goto err_out;
529 if (aux->frame_type != OS_FRAME_TYPE_DATA &&
530 aux->frame_type != OS_FRAME_TYPE_EOD &&
531 aux->frame_type != OS_FRAME_TYPE_MARKER) {
532 if (!quiet)
533 #if DEBUG
534 printk(OSST_DEB_MSG "%s:D: Skipping frame, frame type %x\n", name, aux->frame_type);
535 #endif
536 goto err_out;
538 if (aux->frame_type == OS_FRAME_TYPE_EOD &&
539 STp->first_frame_position < STp->eod_frame_ppos) {
540 printk(KERN_INFO "%s:I: Skipping premature EOD frame %d\n", name,
541 STp->first_frame_position);
542 goto err_out;
544 if (frame_seq_number != -1 && ntohl(aux->frame_seq_num) != frame_seq_number) {
545 if (!quiet)
546 #if DEBUG
547 printk(OSST_DEB_MSG "%s:D: Skipping frame, sequence number %u (expected %d)\n",
548 name, ntohl(aux->frame_seq_num), frame_seq_number);
549 #endif
550 goto err_out;
552 if (aux->frame_type == OS_FRAME_TYPE_MARKER) {
553 STps->eof = ST_FM_HIT;
555 i = ntohl(aux->filemark_cnt);
556 if (STp->header_cache != NULL && i < OS_FM_TAB_MAX && (i > STp->filemark_cnt ||
557 STp->first_frame_position - 1 != ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[i]))) {
558 #if DEBUG
559 printk(OSST_DEB_MSG "%s:D: %s filemark %d at frame pos %d\n", name,
560 STp->header_cache->dat_fm_tab.fm_tab_ent[i] == 0?"Learned":"Corrected",
561 i, STp->first_frame_position - 1);
562 #endif
563 STp->header_cache->dat_fm_tab.fm_tab_ent[i] = htonl(STp->first_frame_position - 1);
564 if (i >= STp->filemark_cnt)
565 STp->filemark_cnt = i+1;
568 if (aux->frame_type == OS_FRAME_TYPE_EOD) {
569 STps->eof = ST_EOD_1;
570 STp->frame_in_buffer = 1;
572 if (aux->frame_type == OS_FRAME_TYPE_DATA) {
573 blk_cnt = ntohs(aux->dat.dat_list[0].blk_cnt);
574 blk_sz = ntohl(aux->dat.dat_list[0].blk_sz);
575 STp->buffer->buffer_bytes = blk_cnt * blk_sz;
576 STp->buffer->read_pointer = 0;
577 STp->frame_in_buffer = 1;
579 /* See what block size was used to write file */
580 if (STp->block_size != blk_sz && blk_sz > 0) {
581 printk(KERN_INFO
582 "%s:I: File was written with block size %d%c, currently %d%c, adjusted to match.\n",
583 name, blk_sz<1024?blk_sz:blk_sz/1024,blk_sz<1024?'b':'k',
584 STp->block_size<1024?STp->block_size:STp->block_size/1024,
585 STp->block_size<1024?'b':'k');
586 STp->block_size = blk_sz;
587 STp->buffer->buffer_blocks = OS_DATA_SIZE / blk_sz;
589 STps->eof = ST_NOEOF;
591 STp->frame_seq_number = ntohl(aux->frame_seq_num);
592 STp->logical_blk_num = ntohl(aux->logical_blk_num);
593 return 1;
595 err_out:
596 if (STp->read_error_frame == 0)
597 STp->read_error_frame = STp->first_frame_position - 1;
598 return 0;
602 * Wait for the unit to become Ready
604 static int osst_wait_ready(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, unsigned timeout, int initial_delay)
606 unsigned char cmd[MAX_COMMAND_SIZE];
607 Scsi_Request * SRpnt;
608 unsigned long startwait = jiffies;
609 #if DEBUG
610 int dbg = debugging;
611 char * name = tape_name(STp);
613 printk(OSST_DEB_MSG "%s:D: Reached onstream wait ready\n", name);
614 #endif
616 if (initial_delay > 0) {
617 set_current_state(TASK_INTERRUPTIBLE);
618 schedule_timeout(initial_delay);
621 memset(cmd, 0, MAX_COMMAND_SIZE);
622 cmd[0] = TEST_UNIT_READY;
624 SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, SCSI_DATA_NONE, STp->timeout, MAX_READY_RETRIES, TRUE);
625 *aSRpnt = SRpnt;
626 if (!SRpnt) return (-EBUSY);
628 while ( STp->buffer->syscall_result && time_before(jiffies, startwait + timeout*HZ) &&
629 (( SRpnt->sr_sense_buffer[2] == 2 && SRpnt->sr_sense_buffer[12] == 4 &&
630 (SRpnt->sr_sense_buffer[13] == 1 || SRpnt->sr_sense_buffer[13] == 8) ) ||
631 ( SRpnt->sr_sense_buffer[2] == 6 && SRpnt->sr_sense_buffer[12] == 0x28 &&
632 SRpnt->sr_sense_buffer[13] == 0 ) )) {
633 #if DEBUG
634 if (debugging) {
635 printk(OSST_DEB_MSG "%s:D: Sleeping in onstream wait ready\n", name);
636 printk(OSST_DEB_MSG "%s:D: Turning off debugging for a while\n", name);
637 debugging = 0;
639 #endif
640 set_current_state(TASK_INTERRUPTIBLE);
641 schedule_timeout(HZ / 10);
643 memset(cmd, 0, MAX_COMMAND_SIZE);
644 cmd[0] = TEST_UNIT_READY;
646 SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, SCSI_DATA_NONE, STp->timeout, MAX_READY_RETRIES, TRUE);
648 *aSRpnt = SRpnt;
649 #if DEBUG
650 debugging = dbg;
651 #endif
652 if ( STp->buffer->syscall_result &&
653 osst_write_error_recovery(STp, aSRpnt, 0) ) {
654 #if DEBUG
655 printk(OSST_DEB_MSG "%s:D: Abnormal exit from onstream wait ready\n", name);
656 printk(OSST_DEB_MSG "%s:D: Result = %d, Sense: 0=%02x, 2=%02x, 12=%02x, 13=%02x\n", name,
657 STp->buffer->syscall_result, SRpnt->sr_sense_buffer[0], SRpnt->sr_sense_buffer[2],
658 SRpnt->sr_sense_buffer[12], SRpnt->sr_sense_buffer[13]);
659 #endif
660 return (-EIO);
662 #if DEBUG
663 printk(OSST_DEB_MSG "%s:D: Normal exit from onstream wait ready\n", name);
664 #endif
665 return 0;
669 * Wait for a tape to be inserted in the unit
671 static int osst_wait_for_medium(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, unsigned timeout)
673 unsigned char cmd[MAX_COMMAND_SIZE];
674 Scsi_Request * SRpnt;
675 unsigned long startwait = jiffies;
676 #if DEBUG
677 int dbg = debugging;
678 char * name = tape_name(STp);
680 printk(OSST_DEB_MSG "%s:D: Reached onstream wait for medium\n", name);
681 #endif
683 memset(cmd, 0, MAX_COMMAND_SIZE);
684 cmd[0] = TEST_UNIT_READY;
686 SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, SCSI_DATA_NONE, STp->timeout, MAX_READY_RETRIES, TRUE);
687 *aSRpnt = SRpnt;
688 if (!SRpnt) return (-EBUSY);
690 while ( STp->buffer->syscall_result && time_before(jiffies, startwait + timeout*HZ) &&
691 SRpnt->sr_sense_buffer[2] == 2 && SRpnt->sr_sense_buffer[12] == 0x3a &&
692 SRpnt->sr_sense_buffer[13] == 0 ) {
693 #if DEBUG
694 if (debugging) {
695 printk(OSST_DEB_MSG "%s:D: Sleeping in onstream wait medium\n", name);
696 printk(OSST_DEB_MSG "%s:D: Turning off debugging for a while\n", name);
697 debugging = 0;
699 #endif
700 set_current_state(TASK_INTERRUPTIBLE);
701 schedule_timeout(HZ / 10);
703 memset(cmd, 0, MAX_COMMAND_SIZE);
704 cmd[0] = TEST_UNIT_READY;
706 SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, SCSI_DATA_NONE, STp->timeout, MAX_READY_RETRIES, TRUE);
708 *aSRpnt = SRpnt;
709 #if DEBUG
710 debugging = dbg;
711 #endif
712 if ( STp->buffer->syscall_result && SRpnt->sr_sense_buffer[2] != 2 &&
713 SRpnt->sr_sense_buffer[12] != 4 && SRpnt->sr_sense_buffer[13] == 1) {
714 #if DEBUG
715 printk(OSST_DEB_MSG "%s:D: Abnormal exit from onstream wait medium\n", name);
716 printk(OSST_DEB_MSG "%s:D: Result = %d, Sense: 0=%02x, 2=%02x, 12=%02x, 13=%02x\n", name,
717 STp->buffer->syscall_result, SRpnt->sr_sense_buffer[0], SRpnt->sr_sense_buffer[2],
718 SRpnt->sr_sense_buffer[12], SRpnt->sr_sense_buffer[13]);
719 #endif
720 return 0;
722 #if DEBUG
723 printk(OSST_DEB_MSG "%s:D: Normal exit from onstream wait medium\n", name);
724 #endif
725 return 1;
728 static int osst_position_tape_and_confirm(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int frame)
730 int retval;
732 osst_wait_ready(STp, aSRpnt, 15 * 60, 0); /* TODO - can this catch a write error? */
733 retval = osst_set_frame_position(STp, aSRpnt, frame, 0);
734 if (retval) return (retval);
735 osst_wait_ready(STp, aSRpnt, 15 * 60, OSST_WAIT_POSITION_COMPLETE);
736 return (osst_get_frame_position(STp, aSRpnt));
740 * Wait for write(s) to complete
742 static int osst_flush_drive_buffer(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt)
744 unsigned char cmd[MAX_COMMAND_SIZE];
745 Scsi_Request * SRpnt;
747 int result = 0;
748 int delay = OSST_WAIT_WRITE_COMPLETE;
749 #if DEBUG
750 char * name = tape_name(STp);
752 printk(OSST_DEB_MSG "%s:D: Reached onstream flush drive buffer (write filemark)\n", name);
753 #endif
755 memset(cmd, 0, MAX_COMMAND_SIZE);
756 cmd[0] = WRITE_FILEMARKS;
757 cmd[1] = 1;
759 SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, SCSI_DATA_NONE, STp->timeout, MAX_WRITE_RETRIES, TRUE);
760 *aSRpnt = SRpnt;
761 if (!SRpnt) return (-EBUSY);
762 if (STp->buffer->syscall_result) {
763 if ((SRpnt->sr_sense_buffer[2] & 0x0f) == 2 && SRpnt->sr_sense_buffer[12] == 4) {
764 if (SRpnt->sr_sense_buffer[13] == 8) {
765 delay = OSST_WAIT_LONG_WRITE_COMPLETE;
767 } else
768 result = osst_write_error_recovery(STp, aSRpnt, 0);
770 result |= osst_wait_ready(STp, aSRpnt, 5 * 60, delay);
771 STp->ps[STp->partition].rw = OS_WRITING_COMPLETE;
773 return (result);
776 #define OSST_POLL_PER_SEC 10
777 static int osst_wait_frame(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int curr, int minlast, int to)
779 unsigned long startwait = jiffies;
780 char * name = tape_name(STp);
781 #if DEBUG
782 char notyetprinted = 1;
783 #endif
784 if (minlast >= 0 && STp->ps[STp->partition].rw != ST_READING)
785 printk(KERN_ERR "%s:A: Waiting for frame without having initialized read!\n", name);
787 while (time_before (jiffies, startwait + to*HZ))
789 int result;
790 result = osst_get_frame_position (STp, aSRpnt);
791 if (result == -EIO)
792 if ((result = osst_write_error_recovery(STp, aSRpnt, 0)) == 0)
793 return 0; /* successful recovery leaves drive ready for frame */
794 if (result < 0) break;
795 if (STp->first_frame_position == curr &&
796 ((minlast < 0 &&
797 (signed)STp->last_frame_position > (signed)curr + minlast) ||
798 (minlast >= 0 && STp->cur_frames > minlast)
799 ) && result >= 0)
801 #if DEBUG
802 if (debugging || jiffies - startwait >= 2*HZ/OSST_POLL_PER_SEC)
803 printk (OSST_DEB_MSG
804 "%s:D: Succ wait f fr %i (>%i): %i-%i %i (%i): %3li.%li s\n",
805 name, curr, curr+minlast, STp->first_frame_position,
806 STp->last_frame_position, STp->cur_frames,
807 result, (jiffies-startwait)/HZ,
808 (((jiffies-startwait)%HZ)*10)/HZ);
809 #endif
810 return 0;
812 #if DEBUG
813 if (jiffies - startwait >= 2*HZ/OSST_POLL_PER_SEC && notyetprinted)
815 printk (OSST_DEB_MSG "%s:D: Wait for frame %i (>%i): %i-%i %i (%i)\n",
816 name, curr, curr+minlast, STp->first_frame_position,
817 STp->last_frame_position, STp->cur_frames, result);
818 notyetprinted--;
820 #endif
821 set_current_state(TASK_INTERRUPTIBLE);
822 schedule_timeout (HZ / OSST_POLL_PER_SEC);
824 #if DEBUG
825 printk (OSST_DEB_MSG "%s:D: Fail wait f fr %i (>%i): %i-%i %i: %3li.%li s\n",
826 name, curr, curr+minlast, STp->first_frame_position,
827 STp->last_frame_position, STp->cur_frames,
828 (jiffies-startwait)/HZ, (((jiffies-startwait)%HZ)*10)/HZ);
829 #endif
830 return -EBUSY;
834 * Read the next OnStream tape frame at the current location
836 static int osst_read_frame(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int timeout)
838 unsigned char cmd[MAX_COMMAND_SIZE];
839 Scsi_Request * SRpnt;
840 int retval = 0;
841 #if DEBUG
842 os_aux_t * aux = STp->buffer->aux;
843 char * name = tape_name(STp);
844 #endif
846 /* TODO: Error handling */
847 if (STp->poll)
848 retval = osst_wait_frame (STp, aSRpnt, STp->first_frame_position, 0, timeout);
850 memset(cmd, 0, MAX_COMMAND_SIZE);
851 cmd[0] = READ_6;
852 cmd[1] = 1;
853 cmd[4] = 1;
855 #if DEBUG
856 if (debugging)
857 printk(OSST_DEB_MSG "%s:D: Reading frame from OnStream tape\n", name);
858 #endif
859 SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, OS_FRAME_SIZE, SCSI_DATA_READ,
860 STp->timeout, MAX_READ_RETRIES, TRUE);
861 *aSRpnt = SRpnt;
862 if (!SRpnt)
863 return (-EBUSY);
865 if ((STp->buffer)->syscall_result) {
866 retval = 1;
867 if (STp->read_error_frame == 0) {
868 STp->read_error_frame = STp->first_frame_position;
869 #if DEBUG
870 printk(OSST_DEB_MSG "%s:D: Recording read error at %d\n", name, STp->read_error_frame);
871 #endif
873 #if DEBUG
874 if (debugging)
875 printk(OSST_DEB_MSG "%s:D: Sense: %2x %2x %2x %2x %2x %2x %2x %2x\n",
876 name,
877 SRpnt->sr_sense_buffer[0], SRpnt->sr_sense_buffer[1],
878 SRpnt->sr_sense_buffer[2], SRpnt->sr_sense_buffer[3],
879 SRpnt->sr_sense_buffer[4], SRpnt->sr_sense_buffer[5],
880 SRpnt->sr_sense_buffer[6], SRpnt->sr_sense_buffer[7]);
881 #endif
883 else
884 STp->first_frame_position++;
885 #if DEBUG
886 if (debugging) {
887 char sig[8]; int i;
888 for (i=0;i<4;i++)
889 sig[i] = aux->application_sig[i]<32?'^':aux->application_sig[i];
890 sig[4] = '\0';
891 printk(OSST_DEB_MSG
892 "%s:D: AUX: %s UpdFrCt#%d Wpass#%d %s FrSeq#%d LogBlk#%d Qty=%d Sz=%d\n", name, sig,
893 ntohl(aux->update_frame_cntr), ntohs(aux->partition.wrt_pass_cntr),
894 aux->frame_type==1?"EOD":aux->frame_type==2?"MARK":
895 aux->frame_type==8?"HEADR":aux->frame_type==0x80?"DATA":"FILL",
896 ntohl(aux->frame_seq_num), ntohl(aux->logical_blk_num),
897 ntohs(aux->dat.dat_list[0].blk_cnt), ntohl(aux->dat.dat_list[0].blk_sz) );
898 if (aux->frame_type==2)
899 printk(OSST_DEB_MSG "%s:D: mark_cnt=%d, last_mark_ppos=%d, last_mark_lbn=%d\n", name,
900 ntohl(aux->filemark_cnt), ntohl(aux->last_mark_ppos), ntohl(aux->last_mark_lbn));
901 printk(OSST_DEB_MSG "%s:D: Exit read frame from OnStream tape with code %d\n", name, retval);
903 #endif
904 return (retval);
907 static int osst_initiate_read(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt)
909 ST_partstat * STps = &(STp->ps[STp->partition]);
910 Scsi_Request * SRpnt ;
911 unsigned char cmd[MAX_COMMAND_SIZE];
912 int retval = 0;
913 #if DEBUG
914 char * name = tape_name(STp);
915 #endif
917 if (STps->rw != ST_READING) { /* Initialize read operation */
918 if (STps->rw == ST_WRITING || STp->dirty) {
919 STp->write_type = OS_WRITE_DATA;
920 osst_flush_write_buffer(STp, aSRpnt);
921 osst_flush_drive_buffer(STp, aSRpnt);
923 STps->rw = ST_READING;
924 STp->frame_in_buffer = 0;
927 * Issue a read 0 command to get the OnStream drive
928 * read frames into its buffer.
930 memset(cmd, 0, MAX_COMMAND_SIZE);
931 cmd[0] = READ_6;
932 cmd[1] = 1;
934 #if DEBUG
935 printk(OSST_DEB_MSG "%s:D: Start Read Ahead on OnStream tape\n", name);
936 #endif
937 SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, SCSI_DATA_NONE, STp->timeout, MAX_READ_RETRIES, TRUE);
938 *aSRpnt = SRpnt;
939 retval = STp->buffer->syscall_result;
942 return retval;
945 static int osst_get_logical_frame(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int frame_seq_number, int quiet)
947 ST_partstat * STps = &(STp->ps[STp->partition]);
948 char * name = tape_name(STp);
949 int cnt = 0,
950 bad = 0,
951 past = 0,
953 position;
956 * If we want just any frame (-1) and there is a frame in the buffer, return it
958 if (frame_seq_number == -1 && STp->frame_in_buffer) {
959 #if DEBUG
960 printk(OSST_DEB_MSG "%s:D: Frame %d still in buffer\n", name, STp->frame_seq_number);
961 #endif
962 return (STps->eof);
965 * Search and wait for the next logical tape frame
967 while (1) {
968 if (cnt++ > 400) {
969 printk(KERN_ERR "%s:E: Couldn't find logical frame %d, aborting\n",
970 name, frame_seq_number);
971 if (STp->read_error_frame) {
972 osst_set_frame_position(STp, aSRpnt, STp->read_error_frame, 0);
973 #if DEBUG
974 printk(OSST_DEB_MSG "%s:D: Repositioning tape to bad frame %d\n",
975 name, STp->read_error_frame);
976 #endif
977 STp->read_error_frame = 0;
979 return (-EIO);
981 #if DEBUG
982 if (debugging)
983 printk(OSST_DEB_MSG "%s:D: Looking for frame %d, attempt %d\n",
984 name, frame_seq_number, cnt);
985 #endif
986 if ( osst_initiate_read(STp, aSRpnt)
987 || ( (!STp->frame_in_buffer) && osst_read_frame(STp, aSRpnt, 30) ) ) {
988 if (STp->raw)
989 return (-EIO);
990 position = osst_get_frame_position(STp, aSRpnt);
991 if (position >= 0xbae && position < 0xbb8)
992 position = 0xbb8;
993 else if (position > STp->eod_frame_ppos || ++bad == 10) {
994 position = STp->read_error_frame - 1;
996 else {
997 position += 39;
998 cnt += 20;
1000 #if DEBUG
1001 printk(OSST_DEB_MSG "%s:D: Bad frame detected, positioning tape to block %d\n",
1002 name, position);
1003 #endif
1004 osst_set_frame_position(STp, aSRpnt, position, 0);
1005 continue;
1007 if (osst_verify_frame(STp, frame_seq_number, quiet))
1008 break;
1009 if (osst_verify_frame(STp, -1, quiet)) {
1010 x = ntohl(STp->buffer->aux->frame_seq_num);
1011 if (STp->fast_open) {
1012 printk(KERN_WARNING
1013 "%s:W: Found logical frame %d instead of %d after fast open\n",
1014 name, x, frame_seq_number);
1015 STp->header_ok = 0;
1016 STp->read_error_frame = 0;
1017 return (-EIO);
1019 if (x > frame_seq_number) {
1020 if (++past > 3) {
1021 /* positioning backwards did not bring us to the desired frame */
1022 position = STp->read_error_frame - 1;
1024 else {
1025 position = osst_get_frame_position(STp, aSRpnt)
1026 + frame_seq_number - x - 1;
1028 if (STp->first_frame_position >= 3000 && position < 3000)
1029 position -= 10;
1031 #if DEBUG
1032 printk(OSST_DEB_MSG
1033 "%s:D: Found logical frame %d while looking for %d: back up %d\n",
1034 name, x, frame_seq_number,
1035 STp->first_frame_position - position);
1036 #endif
1037 osst_set_frame_position(STp, aSRpnt, position, 0);
1038 cnt += 10;
1040 else
1041 past = 0;
1043 if (osst_get_frame_position(STp, aSRpnt) == 0xbaf) {
1044 #if DEBUG
1045 printk(OSST_DEB_MSG "%s:D: Skipping config partition\n", name);
1046 #endif
1047 osst_set_frame_position(STp, aSRpnt, 0xbb8, 0);
1048 cnt--;
1050 STp->frame_in_buffer = 0;
1052 if (cnt > 1) {
1053 STp->recover_count++;
1054 STp->recover_erreg++;
1055 printk(KERN_WARNING "%s:I: Don't worry, Read error at position %d recovered\n",
1056 name, STp->read_error_frame);
1058 STp->read_count++;
1060 #if DEBUG
1061 if (debugging || STps->eof)
1062 printk(OSST_DEB_MSG
1063 "%s:D: Exit get logical frame (%d=>%d) from OnStream tape with code %d\n",
1064 name, frame_seq_number, STp->frame_seq_number, STps->eof);
1065 #endif
1066 STp->fast_open = FALSE;
1067 STp->read_error_frame = 0;
1068 return (STps->eof);
1071 static int osst_seek_logical_blk(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int logical_blk_num)
1073 ST_partstat * STps = &(STp->ps[STp->partition]);
1074 char * name = tape_name(STp);
1075 int retries = 0;
1076 int frame_seq_estimate, ppos_estimate, move;
1078 if (logical_blk_num < 0) logical_blk_num = 0;
1079 #if DEBUG
1080 printk(OSST_DEB_MSG "%s:D: Seeking logical block %d (now at %d, size %d%c)\n",
1081 name, logical_blk_num, STp->logical_blk_num,
1082 STp->block_size<1024?STp->block_size:STp->block_size/1024,
1083 STp->block_size<1024?'b':'k');
1084 #endif
1085 /* Do we know where we are? */
1086 if (STps->drv_block >= 0) {
1087 move = logical_blk_num - STp->logical_blk_num;
1088 if (move < 0) move -= (OS_DATA_SIZE / STp->block_size) - 1;
1089 move /= (OS_DATA_SIZE / STp->block_size);
1090 frame_seq_estimate = STp->frame_seq_number + move;
1091 } else
1092 frame_seq_estimate = logical_blk_num * STp->block_size / OS_DATA_SIZE;
1094 if (frame_seq_estimate < 2980) ppos_estimate = frame_seq_estimate + 10;
1095 else ppos_estimate = frame_seq_estimate + 20;
1096 while (++retries < 10) {
1097 if (ppos_estimate > STp->eod_frame_ppos-2) {
1098 frame_seq_estimate += STp->eod_frame_ppos - 2 - ppos_estimate;
1099 ppos_estimate = STp->eod_frame_ppos - 2;
1101 if (frame_seq_estimate < 0) {
1102 frame_seq_estimate = 0;
1103 ppos_estimate = 10;
1105 osst_set_frame_position(STp, aSRpnt, ppos_estimate, 0);
1106 if (osst_get_logical_frame(STp, aSRpnt, frame_seq_estimate, 1) >= 0) {
1107 /* we've located the estimated frame, now does it have our block? */
1108 if (logical_blk_num < STp->logical_blk_num ||
1109 logical_blk_num >= STp->logical_blk_num + ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt)) {
1110 if (STps->eof == ST_FM_HIT)
1111 move = logical_blk_num < STp->logical_blk_num? -2 : 1;
1112 else {
1113 move = logical_blk_num - STp->logical_blk_num;
1114 if (move < 0) move -= (OS_DATA_SIZE / STp->block_size) - 1;
1115 move /= (OS_DATA_SIZE / STp->block_size);
1117 if (!move) move = logical_blk_num > STp->logical_blk_num ? 1 : -1;
1118 #if DEBUG
1119 printk(OSST_DEB_MSG
1120 "%s:D: Seek retry %d at ppos %d fsq %d (est %d) lbn %d (need %d) move %d\n",
1121 name, retries, ppos_estimate, STp->frame_seq_number, frame_seq_estimate,
1122 STp->logical_blk_num, logical_blk_num, move);
1123 #endif
1124 frame_seq_estimate += move;
1125 ppos_estimate += move;
1126 continue;
1127 } else {
1128 STp->buffer->read_pointer = (logical_blk_num - STp->logical_blk_num) * STp->block_size;
1129 STp->buffer->buffer_bytes -= STp->buffer->read_pointer;
1130 STp->logical_blk_num = logical_blk_num;
1131 #if DEBUG
1132 printk(OSST_DEB_MSG
1133 "%s:D: Seek success at ppos %d fsq %d in_buf %d, bytes %d, ptr %d*%d\n",
1134 name, ppos_estimate, STp->frame_seq_number, STp->frame_in_buffer,
1135 STp->buffer->buffer_bytes, STp->buffer->read_pointer / STp->block_size,
1136 STp->block_size);
1137 #endif
1138 STps->drv_file = ntohl(STp->buffer->aux->filemark_cnt);
1139 if (STps->eof == ST_FM_HIT) {
1140 STps->drv_file++;
1141 STps->drv_block = 0;
1142 } else {
1143 STps->drv_block = ntohl(STp->buffer->aux->last_mark_lbn)?
1144 STp->logical_blk_num -
1145 (STps->drv_file ? ntohl(STp->buffer->aux->last_mark_lbn) + 1 : 0):
1148 STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD:ST_NOEOF;
1149 return 0;
1152 if (osst_get_logical_frame(STp, aSRpnt, -1, 1) < 0)
1153 goto error;
1154 /* we are not yet at the estimated frame, adjust our estimate of its physical position */
1155 #if DEBUG
1156 printk(OSST_DEB_MSG "%s:D: Seek retry %d at ppos %d fsq %d (est %d) lbn %d (need %d)\n",
1157 name, retries, ppos_estimate, STp->frame_seq_number, frame_seq_estimate,
1158 STp->logical_blk_num, logical_blk_num);
1159 #endif
1160 if (frame_seq_estimate != STp->frame_seq_number)
1161 ppos_estimate += frame_seq_estimate - STp->frame_seq_number;
1162 else
1163 break;
1165 error:
1166 printk(KERN_ERR "%s:E: Couldn't seek to logical block %d (at %d), %d retries\n",
1167 name, logical_blk_num, STp->logical_blk_num, retries);
1168 return (-EIO);
1171 /* The values below are based on the OnStream frame payload size of 32K == 2**15,
1172 * that is, OSST_FRAME_SHIFT + OSST_SECTOR_SHIFT must be 15. With a minimum block
1173 * size of 512 bytes, we need to be able to resolve 32K/512 == 64 == 2**6 positions
1174 * inside each frame. Finaly, OSST_SECTOR_MASK == 2**OSST_FRAME_SHIFT - 1.
1176 #define OSST_FRAME_SHIFT 6
1177 #define OSST_SECTOR_SHIFT 9
1178 #define OSST_SECTOR_MASK 0x03F
1180 static int osst_get_sector(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt)
1182 int sector;
1183 #if DEBUG
1184 char * name = tape_name(STp);
1186 printk(OSST_DEB_MSG
1187 "%s:D: Positioned at ppos %d, frame %d, lbn %d, file %d, blk %d, %cptr %d, eof %d\n",
1188 name, STp->first_frame_position, STp->frame_seq_number, STp->logical_blk_num,
1189 STp->ps[STp->partition].drv_file, STp->ps[STp->partition].drv_block,
1190 STp->ps[STp->partition].rw == ST_WRITING?'w':'r',
1191 STp->ps[STp->partition].rw == ST_WRITING?STp->buffer->buffer_bytes:
1192 STp->buffer->read_pointer, STp->ps[STp->partition].eof);
1193 #endif
1194 /* do we know where we are inside a file? */
1195 if (STp->ps[STp->partition].drv_block >= 0) {
1196 sector = (STp->frame_in_buffer ? STp->first_frame_position-1 :
1197 STp->first_frame_position) << OSST_FRAME_SHIFT;
1198 if (STp->ps[STp->partition].rw == ST_WRITING)
1199 sector |= (STp->buffer->buffer_bytes >> OSST_SECTOR_SHIFT) & OSST_SECTOR_MASK;
1200 else
1201 sector |= (STp->buffer->read_pointer >> OSST_SECTOR_SHIFT) & OSST_SECTOR_MASK;
1202 } else {
1203 sector = osst_get_frame_position(STp, aSRpnt);
1204 if (sector > 0)
1205 sector <<= OSST_FRAME_SHIFT;
1207 return sector;
1210 static int osst_seek_sector(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int sector)
1212 ST_partstat * STps = &(STp->ps[STp->partition]);
1213 int frame = sector >> OSST_FRAME_SHIFT,
1214 offset = (sector & OSST_SECTOR_MASK) << OSST_SECTOR_SHIFT,
1216 #if DEBUG
1217 char * name = tape_name(STp);
1219 printk(OSST_DEB_MSG "%s:D: Seeking sector %d in frame %d at offset %d\n",
1220 name, sector, frame, offset);
1221 #endif
1222 if (frame < 0 || frame >= STp->capacity) return (-ENXIO);
1224 if (frame <= STp->first_data_ppos) {
1225 STp->frame_seq_number = STp->logical_blk_num = STps->drv_file = STps->drv_block = 0;
1226 return (osst_set_frame_position(STp, aSRpnt, frame, 0));
1228 r = osst_set_frame_position(STp, aSRpnt, offset?frame:frame-1, 0);
1229 if (r < 0) return r;
1231 r = osst_get_logical_frame(STp, aSRpnt, -1, 1);
1232 if (r < 0) return r;
1234 if (osst_get_frame_position(STp, aSRpnt) != (offset?frame+1:frame)) return (-EIO);
1236 if (offset) {
1237 STp->logical_blk_num += offset / STp->block_size;
1238 STp->buffer->read_pointer = offset;
1239 STp->buffer->buffer_bytes -= offset;
1240 } else {
1241 STp->frame_seq_number++;
1242 STp->frame_in_buffer = 0;
1243 STp->logical_blk_num += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
1244 STp->buffer->buffer_bytes = STp->buffer->read_pointer = 0;
1246 STps->drv_file = ntohl(STp->buffer->aux->filemark_cnt);
1247 if (STps->eof == ST_FM_HIT) {
1248 STps->drv_file++;
1249 STps->drv_block = 0;
1250 } else {
1251 STps->drv_block = ntohl(STp->buffer->aux->last_mark_lbn)?
1252 STp->logical_blk_num -
1253 (STps->drv_file ? ntohl(STp->buffer->aux->last_mark_lbn) + 1 : 0):
1256 STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD:ST_NOEOF;
1257 #if DEBUG
1258 printk(OSST_DEB_MSG
1259 "%s:D: Now positioned at ppos %d, frame %d, lbn %d, file %d, blk %d, rptr %d, eof %d\n",
1260 name, STp->first_frame_position, STp->frame_seq_number, STp->logical_blk_num,
1261 STps->drv_file, STps->drv_block, STp->buffer->read_pointer, STps->eof);
1262 #endif
1263 return 0;
1267 * Read back the drive's internal buffer contents, as a part
1268 * of the write error recovery mechanism for old OnStream
1269 * firmware revisions.
1270 * Precondition for this function to work: all frames in the
1271 * drive's buffer must be of one type (DATA, MARK or EOD)!
1273 static int osst_read_back_buffer_and_rewrite(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt,
1274 unsigned int frame, unsigned int skip, int pending)
1276 Scsi_Request * SRpnt = * aSRpnt;
1277 unsigned char * buffer, * p;
1278 unsigned char cmd[MAX_COMMAND_SIZE];
1279 int flag, new_frame, i;
1280 int nframes = STp->cur_frames;
1281 int blks_per_frame = ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
1282 int frame_seq_number = ntohl(STp->buffer->aux->frame_seq_num)
1283 - (nframes + pending - 1);
1284 int logical_blk_num = ntohl(STp->buffer->aux->logical_blk_num)
1285 - (nframes + pending - 1) * blks_per_frame;
1286 char * name = tape_name(STp);
1287 unsigned long startwait = jiffies;
1288 #if DEBUG
1289 int dbg = debugging;
1290 #endif
1292 if ((buffer = (unsigned char *)vmalloc((nframes + 1) * OS_DATA_SIZE)) == NULL)
1293 return (-EIO);
1295 printk(KERN_INFO "%s:I: Reading back %d frames from drive buffer%s\n",
1296 name, nframes, pending?" and one that was pending":"");
1298 osst_copy_from_buffer(STp->buffer, (p = &buffer[nframes * OS_DATA_SIZE]));
1299 #if DEBUG
1300 if (pending && debugging)
1301 printk(OSST_DEB_MSG "%s:D: Pending frame %d (lblk %d), data %02x %02x %02x %02x\n",
1302 name, frame_seq_number + nframes,
1303 logical_blk_num + nframes * blks_per_frame,
1304 p[0], p[1], p[2], p[3]);
1305 #endif
1306 for (i = 0, p = buffer; i < nframes; i++, p += OS_DATA_SIZE) {
1308 memset(cmd, 0, MAX_COMMAND_SIZE);
1309 cmd[0] = 0x3C; /* Buffer Read */
1310 cmd[1] = 6; /* Retrieve Faulty Block */
1311 cmd[7] = 32768 >> 8;
1312 cmd[8] = 32768 & 0xff;
1314 SRpnt = osst_do_scsi(SRpnt, STp, cmd, OS_FRAME_SIZE, SCSI_DATA_READ,
1315 STp->timeout, MAX_READ_RETRIES, TRUE);
1317 if ((STp->buffer)->syscall_result || !SRpnt) {
1318 printk(KERN_ERR "%s:E: Failed to read frame back from OnStream buffer\n", name);
1319 vfree((void *)buffer);
1320 *aSRpnt = SRpnt;
1321 return (-EIO);
1323 osst_copy_from_buffer(STp->buffer, p);
1324 #if DEBUG
1325 if (debugging)
1326 printk(OSST_DEB_MSG "%s:D: Read back logical frame %d, data %02x %02x %02x %02x\n",
1327 name, frame_seq_number + i, p[0], p[1], p[2], p[3]);
1328 #endif
1330 *aSRpnt = SRpnt;
1331 osst_get_frame_position(STp, aSRpnt);
1333 #if DEBUG
1334 printk(OSST_DEB_MSG "%s:D: Frames left in buffer: %d\n", name, STp->cur_frames);
1335 #endif
1336 /* Write synchronously so we can be sure we're OK again and don't have to recover recursively */
1337 /* In the header we don't actually re-write the frames that fail, just the ones after them */
1339 for (flag=1, new_frame=frame, p=buffer, i=0; i < nframes + pending; ) {
1341 if (flag) {
1342 if (STp->write_type == OS_WRITE_HEADER) {
1343 i += skip;
1344 p += skip * OS_DATA_SIZE;
1346 else if (new_frame < 2990 && new_frame+skip+nframes+pending >= 2990)
1347 new_frame = 3000-i;
1348 else
1349 new_frame += skip;
1350 #if DEBUG
1351 printk(OSST_DEB_MSG "%s:D: Position to frame %d, write fseq %d\n",
1352 name, new_frame+i, frame_seq_number+i);
1353 #endif
1354 osst_set_frame_position(STp, aSRpnt, new_frame + i, 0);
1355 osst_wait_ready(STp, aSRpnt, 60, OSST_WAIT_POSITION_COMPLETE);
1356 osst_get_frame_position(STp, aSRpnt);
1357 SRpnt = * aSRpnt;
1359 if (new_frame > frame + 1000) {
1360 printk(KERN_ERR "%s:E: Failed to find writable tape media\n", name);
1361 vfree((void *)buffer);
1362 return (-EIO);
1364 flag = 0;
1365 if ( i >= nframes + pending ) break;
1367 osst_copy_to_buffer(STp->buffer, p);
1369 * IMPORTANT: for error recovery to work, _never_ queue frames with mixed frame type!
1371 osst_init_aux(STp, STp->buffer->aux->frame_type, frame_seq_number+i,
1372 logical_blk_num + i*blks_per_frame,
1373 ntohl(STp->buffer->aux->dat.dat_list[0].blk_sz), blks_per_frame);
1374 memset(cmd, 0, MAX_COMMAND_SIZE);
1375 cmd[0] = WRITE_6;
1376 cmd[1] = 1;
1377 cmd[4] = 1;
1379 #if DEBUG
1380 if (debugging)
1381 printk(OSST_DEB_MSG
1382 "%s:D: About to write frame %d, seq %d, lbn %d, data %02x %02x %02x %02x\n",
1383 name, new_frame+i, frame_seq_number+i, logical_blk_num + i*blks_per_frame,
1384 p[0], p[1], p[2], p[3]);
1385 #endif
1386 SRpnt = osst_do_scsi(SRpnt, STp, cmd, OS_FRAME_SIZE, SCSI_DATA_WRITE,
1387 STp->timeout, MAX_WRITE_RETRIES, TRUE);
1389 if (STp->buffer->syscall_result)
1390 flag = 1;
1391 else {
1392 p += OS_DATA_SIZE; i++;
1394 /* if we just sent the last frame, wait till all successfully written */
1395 if ( i == nframes + pending ) {
1396 #if DEBUG
1397 printk(OSST_DEB_MSG "%s:D: Check re-write successful\n", name);
1398 #endif
1399 memset(cmd, 0, MAX_COMMAND_SIZE);
1400 cmd[0] = WRITE_FILEMARKS;
1401 cmd[1] = 1;
1402 SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, SCSI_DATA_NONE,
1403 STp->timeout, MAX_WRITE_RETRIES, TRUE);
1404 #if DEBUG
1405 if (debugging) {
1406 printk(OSST_DEB_MSG "%s:D: Sleeping in re-write wait ready\n", name);
1407 printk(OSST_DEB_MSG "%s:D: Turning off debugging for a while\n", name);
1408 debugging = 0;
1410 #endif
1411 flag = STp->buffer->syscall_result;
1412 while ( !flag && time_before(jiffies, startwait + 60*HZ) ) {
1414 memset(cmd, 0, MAX_COMMAND_SIZE);
1415 cmd[0] = TEST_UNIT_READY;
1417 SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, SCSI_DATA_NONE, STp->timeout,
1418 MAX_READY_RETRIES, TRUE);
1420 if (SRpnt->sr_sense_buffer[2] == 2 && SRpnt->sr_sense_buffer[12] == 4 &&
1421 (SRpnt->sr_sense_buffer[13] == 1 || SRpnt->sr_sense_buffer[13] == 8)) {
1422 /* in the process of becoming ready */
1423 set_current_state(TASK_INTERRUPTIBLE);
1424 schedule_timeout(HZ / 10);
1425 continue;
1427 if (STp->buffer->syscall_result)
1428 flag = 1;
1429 break;
1431 #if DEBUG
1432 debugging = dbg;
1433 printk(OSST_DEB_MSG "%s:D: Wait re-write finished\n", name);
1434 #endif
1437 *aSRpnt = SRpnt;
1438 if (flag) {
1439 if ((SRpnt->sr_sense_buffer[ 2] & 0x0f) == 13 &&
1440 SRpnt->sr_sense_buffer[12] == 0 &&
1441 SRpnt->sr_sense_buffer[13] == 2) {
1442 printk(KERN_ERR "%s:E: Volume overflow in write error recovery\n", name);
1443 vfree((void *)buffer);
1444 return (-EIO); /* hit end of tape = fail */
1446 i = ((SRpnt->sr_sense_buffer[3] << 24) |
1447 (SRpnt->sr_sense_buffer[4] << 16) |
1448 (SRpnt->sr_sense_buffer[5] << 8) |
1449 SRpnt->sr_sense_buffer[6] ) - new_frame;
1450 p = &buffer[i * OS_DATA_SIZE];
1451 #if DEBUG
1452 printk(OSST_DEB_MSG "%s:D: Additional write error at %d\n", name, new_frame+i);
1453 #endif
1454 osst_get_frame_position(STp, aSRpnt);
1455 #if DEBUG
1456 printk(OSST_DEB_MSG "%s:D: reported frame positions: host = %d, tape = %d\n",
1457 name, STp->first_frame_position, STp->last_frame_position);
1458 #endif
1461 if (!pending)
1462 osst_copy_to_buffer(STp->buffer, p); /* so buffer content == at entry in all cases */
1463 vfree((void *)buffer);
1464 return 0;
1467 static int osst_reposition_and_retry(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt,
1468 unsigned int frame, unsigned int skip, int pending)
1470 unsigned char cmd[MAX_COMMAND_SIZE];
1471 Scsi_Request * SRpnt;
1472 char * name = tape_name(STp);
1473 int expected = 0;
1474 int attempts = 1000 / skip;
1475 int flag = 1;
1476 unsigned long startwait = jiffies;
1477 #if DEBUG
1478 int dbg = debugging;
1479 #endif
1481 while (attempts && time_before(jiffies, startwait + 60*HZ)) {
1482 if (flag) {
1483 #if DEBUG
1484 debugging = dbg;
1485 #endif
1486 if (frame < 2990 && frame+skip+STp->cur_frames+pending >= 2990)
1487 frame = 3000-skip;
1488 expected = frame+skip+STp->cur_frames+pending;
1489 #if DEBUG
1490 printk(OSST_DEB_MSG "%s:D: Position to fppos %d, re-write from fseq %d\n",
1491 name, frame+skip, STp->frame_seq_number-STp->cur_frames-pending);
1492 #endif
1493 osst_set_frame_position(STp, aSRpnt, frame + skip, 1);
1494 flag = 0;
1495 attempts--;
1496 set_current_state(TASK_INTERRUPTIBLE);
1497 schedule_timeout(HZ / 10);
1499 if (osst_get_frame_position(STp, aSRpnt) < 0) { /* additional write error */
1500 #if DEBUG
1501 printk(OSST_DEB_MSG "%s:D: Addl error, host %d, tape %d, buffer %d\n",
1502 name, STp->first_frame_position,
1503 STp->last_frame_position, STp->cur_frames);
1504 #endif
1505 frame = STp->last_frame_position;
1506 flag = 1;
1507 continue;
1509 if (pending && STp->cur_frames < 50) {
1511 memset(cmd, 0, MAX_COMMAND_SIZE);
1512 cmd[0] = WRITE_6;
1513 cmd[1] = 1;
1514 cmd[4] = 1;
1515 #if DEBUG
1516 printk(OSST_DEB_MSG "%s:D: About to write pending fseq %d at fppos %d\n",
1517 name, STp->frame_seq_number-1, STp->first_frame_position);
1518 #endif
1519 SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, OS_FRAME_SIZE, SCSI_DATA_WRITE,
1520 STp->timeout, MAX_WRITE_RETRIES, TRUE);
1521 *aSRpnt = SRpnt;
1523 if (STp->buffer->syscall_result) { /* additional write error */
1524 if ((SRpnt->sr_sense_buffer[ 2] & 0x0f) == 13 &&
1525 SRpnt->sr_sense_buffer[12] == 0 &&
1526 SRpnt->sr_sense_buffer[13] == 2) {
1527 printk(KERN_ERR
1528 "%s:E: Volume overflow in write error recovery\n",
1529 name);
1530 break; /* hit end of tape = fail */
1532 flag = 1;
1534 else
1535 pending = 0;
1537 continue;
1539 if (STp->cur_frames == 0) {
1540 #if DEBUG
1541 debugging = dbg;
1542 printk(OSST_DEB_MSG "%s:D: Wait re-write finished\n", name);
1543 #endif
1544 if (STp->first_frame_position != expected) {
1545 printk(KERN_ERR "%s:A: Actual position %d - expected %d\n",
1546 name, STp->first_frame_position, expected);
1547 return (-EIO);
1549 return 0;
1551 #if DEBUG
1552 if (debugging) {
1553 printk(OSST_DEB_MSG "%s:D: Sleeping in re-write wait ready\n", name);
1554 printk(OSST_DEB_MSG "%s:D: Turning off debugging for a while\n", name);
1555 debugging = 0;
1557 #endif
1558 schedule_timeout(HZ / 10);
1560 printk(KERN_ERR "%s:E: Failed to find valid tape media\n", name);
1561 #if DEBUG
1562 debugging = dbg;
1563 #endif
1564 return (-EIO);
1568 * Error recovery algorithm for the OnStream tape.
1571 static int osst_write_error_recovery(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int pending)
1573 Scsi_Request * SRpnt = * aSRpnt;
1574 ST_partstat * STps = & STp->ps[STp->partition];
1575 char * name = tape_name(STp);
1576 int retval = 0;
1577 int rw_state;
1578 unsigned int frame, skip;
1580 rw_state = STps->rw;
1582 if ((SRpnt->sr_sense_buffer[ 2] & 0x0f) != 3
1583 || SRpnt->sr_sense_buffer[12] != 12
1584 || SRpnt->sr_sense_buffer[13] != 0) {
1585 #if DEBUG
1586 printk(OSST_DEB_MSG "%s:D: Write error recovery cannot handle %02x:%02x:%02x\n", name,
1587 SRpnt->sr_sense_buffer[2], SRpnt->sr_sense_buffer[12], SRpnt->sr_sense_buffer[13]);
1588 #endif
1589 return (-EIO);
1591 frame = (SRpnt->sr_sense_buffer[3] << 24) |
1592 (SRpnt->sr_sense_buffer[4] << 16) |
1593 (SRpnt->sr_sense_buffer[5] << 8) |
1594 SRpnt->sr_sense_buffer[6];
1595 skip = SRpnt->sr_sense_buffer[9];
1597 #if DEBUG
1598 printk(OSST_DEB_MSG "%s:D: Detected physical bad frame at %u, advised to skip %d\n", name, frame, skip);
1599 #endif
1600 osst_get_frame_position(STp, aSRpnt);
1601 #if DEBUG
1602 printk(OSST_DEB_MSG "%s:D: reported frame positions: host = %d, tape = %d\n",
1603 name, STp->first_frame_position, STp->last_frame_position);
1604 #endif
1605 switch (STp->write_type) {
1606 case OS_WRITE_DATA:
1607 case OS_WRITE_EOD:
1608 case OS_WRITE_NEW_MARK:
1609 printk(KERN_WARNING
1610 "%s:I: Relocating %d buffered logical frames from position %u to %u\n",
1611 name, STp->cur_frames, frame, (frame + skip > 3000 && frame < 3000)?3000:frame + skip);
1612 if (STp->os_fw_rev >= 10600)
1613 retval = osst_reposition_and_retry(STp, aSRpnt, frame, skip, pending);
1614 else
1615 retval = osst_read_back_buffer_and_rewrite(STp, aSRpnt, frame, skip, pending);
1616 printk(KERN_WARNING "%s:%s: %sWrite error%srecovered\n", name,
1617 retval?"E" :"I",
1618 retval?"" :"Don't worry, ",
1619 retval?" not ":" ");
1620 break;
1621 case OS_WRITE_LAST_MARK:
1622 printk(KERN_ERR "%s:E: Bad frame in update last marker, fatal\n", name);
1623 osst_set_frame_position(STp, aSRpnt, frame + STp->cur_frames + pending, 0);
1624 retval = -EIO;
1625 break;
1626 case OS_WRITE_HEADER:
1627 printk(KERN_WARNING "%s:I: Bad frame in header partition, skipped\n", name);
1628 retval = osst_read_back_buffer_and_rewrite(STp, aSRpnt, frame, 1, pending);
1629 break;
1630 default:
1631 printk(KERN_INFO "%s:I: Bad frame in filler, ignored\n", name);
1632 osst_set_frame_position(STp, aSRpnt, frame + STp->cur_frames + pending, 0);
1634 osst_get_frame_position(STp, aSRpnt);
1635 #if DEBUG
1636 printk(OSST_DEB_MSG "%s:D: Positioning complete, cur_frames %d, pos %d, tape pos %d\n",
1637 name, STp->cur_frames, STp->first_frame_position, STp->last_frame_position);
1638 printk(OSST_DEB_MSG "%s:D: next logical frame to write: %d\n", name, STp->logical_blk_num);
1639 #endif
1640 if (retval == 0) {
1641 STp->recover_count++;
1642 STp->recover_erreg++;
1644 STps->rw = rw_state;
1645 return retval;
1648 static int osst_space_over_filemarks_backward(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt,
1649 int mt_op, int mt_count)
1651 char * name = tape_name(STp);
1652 int cnt;
1653 int last_mark_ppos = -1;
1655 #if DEBUG
1656 printk(OSST_DEB_MSG "%s:D: Reached space_over_filemarks_backwards %d %d\n", name, mt_op, mt_count);
1657 #endif
1658 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
1659 #if DEBUG
1660 printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks_bwd\n", name);
1661 #endif
1662 return -EIO;
1664 if (STp->linux_media_version >= 4) {
1666 * direct lookup in header filemark list
1668 cnt = ntohl(STp->buffer->aux->filemark_cnt);
1669 if (STp->header_ok &&
1670 STp->header_cache != NULL &&
1671 (cnt - mt_count) >= 0 &&
1672 (cnt - mt_count) < OS_FM_TAB_MAX &&
1673 (cnt - mt_count) < STp->filemark_cnt &&
1674 STp->header_cache->dat_fm_tab.fm_tab_ent[cnt-1] == STp->buffer->aux->last_mark_ppos)
1676 last_mark_ppos = ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[cnt - mt_count]);
1677 #if DEBUG
1678 if (STp->header_cache == NULL || (cnt - mt_count) < 0 || (cnt - mt_count) >= OS_FM_TAB_MAX)
1679 printk(OSST_DEB_MSG "%s:D: Filemark lookup fail due to %s\n", name,
1680 STp->header_cache == NULL?"lack of header cache":"count out of range");
1681 else
1682 printk(OSST_DEB_MSG "%s:D: Filemark lookup: prev mark %d (%s), skip %d to %d\n",
1683 name, cnt,
1684 ((cnt == -1 && ntohl(STp->buffer->aux->last_mark_ppos) == -1) ||
1685 (STp->header_cache->dat_fm_tab.fm_tab_ent[cnt-1] ==
1686 STp->buffer->aux->last_mark_ppos))?"match":"error",
1687 mt_count, last_mark_ppos);
1688 #endif
1689 if (last_mark_ppos > 10 && last_mark_ppos < STp->eod_frame_ppos) {
1690 osst_position_tape_and_confirm(STp, aSRpnt, last_mark_ppos);
1691 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
1692 #if DEBUG
1693 printk(OSST_DEB_MSG
1694 "%s:D: Couldn't get logical blk num in space_filemarks\n", name);
1695 #endif
1696 return (-EIO);
1698 if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
1699 printk(KERN_WARNING "%s:W: Expected to find marker at ppos %d, not found\n",
1700 name, last_mark_ppos);
1701 return (-EIO);
1703 goto found;
1705 #if DEBUG
1706 printk(OSST_DEB_MSG "%s:D: Reverting to scan filemark backwards\n", name);
1707 #endif
1709 cnt = 0;
1710 while (cnt != mt_count) {
1711 last_mark_ppos = ntohl(STp->buffer->aux->last_mark_ppos);
1712 if (last_mark_ppos == -1)
1713 return (-EIO);
1714 #if DEBUG
1715 printk(OSST_DEB_MSG "%s:D: Positioning to last mark at %d\n", name, last_mark_ppos);
1716 #endif
1717 osst_position_tape_and_confirm(STp, aSRpnt, last_mark_ppos);
1718 cnt++;
1719 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
1720 #if DEBUG
1721 printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks\n", name);
1722 #endif
1723 return (-EIO);
1725 if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
1726 printk(KERN_WARNING "%s:W: Expected to find marker at ppos %d, not found\n",
1727 name, last_mark_ppos);
1728 return (-EIO);
1731 found:
1732 if (mt_op == MTBSFM) {
1733 STp->frame_seq_number++;
1734 STp->frame_in_buffer = 0;
1735 STp->buffer->buffer_bytes = 0;
1736 STp->buffer->read_pointer = 0;
1737 STp->logical_blk_num += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
1739 return 0;
1743 * ADRL 1.1 compatible "slow" space filemarks fwd version
1745 * Just scans for the filemark sequentially.
1747 static int osst_space_over_filemarks_forward_slow(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt,
1748 int mt_op, int mt_count)
1750 int cnt = 0;
1751 #if DEBUG
1752 char * name = tape_name(STp);
1754 printk(OSST_DEB_MSG "%s:D: Reached space_over_filemarks_forward_slow %d %d\n", name, mt_op, mt_count);
1755 #endif
1756 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
1757 #if DEBUG
1758 printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks_fwd\n", name);
1759 #endif
1760 return (-EIO);
1762 while (1) {
1763 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
1764 #if DEBUG
1765 printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks\n", name);
1766 #endif
1767 return (-EIO);
1769 if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_MARKER)
1770 cnt++;
1771 if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_EOD) {
1772 #if DEBUG
1773 printk(OSST_DEB_MSG "%s:D: space_fwd: EOD reached\n", name);
1774 #endif
1775 if (STp->first_frame_position > STp->eod_frame_ppos+1) {
1776 #if DEBUG
1777 printk(OSST_DEB_MSG "%s:D: EOD position corrected (%d=>%d)\n",
1778 name, STp->eod_frame_ppos, STp->first_frame_position-1);
1779 #endif
1780 STp->eod_frame_ppos = STp->first_frame_position-1;
1782 return (-EIO);
1784 if (cnt == mt_count)
1785 break;
1786 STp->frame_in_buffer = 0;
1788 if (mt_op == MTFSF) {
1789 STp->frame_seq_number++;
1790 STp->frame_in_buffer = 0;
1791 STp->buffer->buffer_bytes = 0;
1792 STp->buffer->read_pointer = 0;
1793 STp->logical_blk_num += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
1795 return 0;
1799 * Fast linux specific version of OnStream FSF
1801 static int osst_space_over_filemarks_forward_fast(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt,
1802 int mt_op, int mt_count)
1804 char * name = tape_name(STp);
1805 int cnt = 0,
1806 next_mark_ppos = -1;
1808 #if DEBUG
1809 printk(OSST_DEB_MSG "%s:D: Reached space_over_filemarks_forward_fast %d %d\n", name, mt_op, mt_count);
1810 #endif
1811 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
1812 #if DEBUG
1813 printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks_fwd\n", name);
1814 #endif
1815 return (-EIO);
1818 if (STp->linux_media_version >= 4) {
1820 * direct lookup in header filemark list
1822 cnt = ntohl(STp->buffer->aux->filemark_cnt) - 1;
1823 if (STp->header_ok &&
1824 STp->header_cache != NULL &&
1825 (cnt + mt_count) < OS_FM_TAB_MAX &&
1826 (cnt + mt_count) < STp->filemark_cnt &&
1827 ((cnt == -1 && ntohl(STp->buffer->aux->last_mark_ppos) == -1) ||
1828 (STp->header_cache->dat_fm_tab.fm_tab_ent[cnt] == STp->buffer->aux->last_mark_ppos)))
1830 next_mark_ppos = ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[cnt + mt_count]);
1831 #if DEBUG
1832 if (STp->header_cache == NULL || (cnt + mt_count) >= OS_FM_TAB_MAX)
1833 printk(OSST_DEB_MSG "%s:D: Filemark lookup fail due to %s\n", name,
1834 STp->header_cache == NULL?"lack of header cache":"count out of range");
1835 else
1836 printk(OSST_DEB_MSG "%s:D: Filemark lookup: prev mark %d (%s), skip %d to %d\n",
1837 name, cnt,
1838 ((cnt == -1 && ntohl(STp->buffer->aux->last_mark_ppos) == -1) ||
1839 (STp->header_cache->dat_fm_tab.fm_tab_ent[cnt] ==
1840 STp->buffer->aux->last_mark_ppos))?"match":"error",
1841 mt_count, next_mark_ppos);
1842 #endif
1843 if (next_mark_ppos <= 10 || next_mark_ppos > STp->eod_frame_ppos) {
1844 #if DEBUG
1845 printk(OSST_DEB_MSG "%s:D: Reverting to slow filemark space\n", name);
1846 #endif
1847 return osst_space_over_filemarks_forward_slow(STp, aSRpnt, mt_op, mt_count);
1848 } else {
1849 osst_position_tape_and_confirm(STp, aSRpnt, next_mark_ppos);
1850 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
1851 #if DEBUG
1852 printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks\n",
1853 name);
1854 #endif
1855 return (-EIO);
1857 if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
1858 printk(KERN_WARNING "%s:W: Expected to find marker at ppos %d, not found\n",
1859 name, next_mark_ppos);
1860 return (-EIO);
1862 if (ntohl(STp->buffer->aux->filemark_cnt) != cnt + mt_count) {
1863 printk(KERN_WARNING "%s:W: Expected to find marker %d at ppos %d, not %d\n",
1864 name, cnt+mt_count, next_mark_ppos,
1865 ntohl(STp->buffer->aux->filemark_cnt));
1866 return (-EIO);
1869 } else {
1871 * Find nearest (usually previous) marker, then jump from marker to marker
1873 while (1) {
1874 if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_MARKER)
1875 break;
1876 if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_EOD) {
1877 #if DEBUG
1878 printk(OSST_DEB_MSG "%s:D: space_fwd: EOD reached\n", name);
1879 #endif
1880 return (-EIO);
1882 if (ntohl(STp->buffer->aux->filemark_cnt) == 0) {
1883 if (STp->first_mark_ppos == -1) {
1884 #if DEBUG
1885 printk(OSST_DEB_MSG "%s:D: Reverting to slow filemark space\n", name);
1886 #endif
1887 return osst_space_over_filemarks_forward_slow(STp, aSRpnt, mt_op, mt_count);
1889 osst_position_tape_and_confirm(STp, aSRpnt, STp->first_mark_ppos);
1890 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
1891 #if DEBUG
1892 printk(OSST_DEB_MSG
1893 "%s:D: Couldn't get logical blk num in space_filemarks_fwd_fast\n",
1894 name);
1895 #endif
1896 return (-EIO);
1898 if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
1899 printk(KERN_WARNING "%s:W: Expected to find filemark at %d\n",
1900 name, STp->first_mark_ppos);
1901 return (-EIO);
1903 } else {
1904 if (osst_space_over_filemarks_backward(STp, aSRpnt, MTBSF, 1) < 0)
1905 return (-EIO);
1906 mt_count++;
1909 cnt++;
1910 while (cnt != mt_count) {
1911 next_mark_ppos = ntohl(STp->buffer->aux->next_mark_ppos);
1912 if (!next_mark_ppos || next_mark_ppos > STp->eod_frame_ppos) {
1913 #if DEBUG
1914 printk(OSST_DEB_MSG "%s:D: Reverting to slow filemark space\n", name);
1915 #endif
1916 return osst_space_over_filemarks_forward_slow(STp, aSRpnt, mt_op, mt_count - cnt);
1918 #if DEBUG
1919 else printk(OSST_DEB_MSG "%s:D: Positioning to next mark at %d\n", name, next_mark_ppos);
1920 #endif
1921 osst_position_tape_and_confirm(STp, aSRpnt, next_mark_ppos);
1922 cnt++;
1923 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
1924 #if DEBUG
1925 printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks\n",
1926 name);
1927 #endif
1928 return (-EIO);
1930 if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
1931 printk(KERN_WARNING "%s:W: Expected to find marker at ppos %d, not found\n",
1932 name, next_mark_ppos);
1933 return (-EIO);
1937 if (mt_op == MTFSF) {
1938 STp->frame_seq_number++;
1939 STp->frame_in_buffer = 0;
1940 STp->buffer->buffer_bytes = 0;
1941 STp->buffer->read_pointer = 0;
1942 STp->logical_blk_num += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
1944 return 0;
1948 * In debug mode, we want to see as many errors as possible
1949 * to test the error recovery mechanism.
1951 #if DEBUG
1952 static void osst_set_retries(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int retries)
1954 unsigned char cmd[MAX_COMMAND_SIZE];
1955 Scsi_Request * SRpnt = * aSRpnt;
1956 char * name = tape_name(STp);
1958 memset(cmd, 0, MAX_COMMAND_SIZE);
1959 cmd[0] = MODE_SELECT;
1960 cmd[1] = 0x10;
1961 cmd[4] = NUMBER_RETRIES_PAGE_LENGTH + MODE_HEADER_LENGTH;
1963 (STp->buffer)->b_data[0] = cmd[4] - 1;
1964 (STp->buffer)->b_data[1] = 0; /* Medium Type - ignoring */
1965 (STp->buffer)->b_data[2] = 0; /* Reserved */
1966 (STp->buffer)->b_data[3] = 0; /* Block Descriptor Length */
1967 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 0] = NUMBER_RETRIES_PAGE | (1 << 7);
1968 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 1] = 2;
1969 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] = 4;
1970 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] = retries;
1972 if (debugging)
1973 printk(OSST_DEB_MSG "%s:D: Setting number of retries on OnStream tape to %d\n", name, retries);
1975 SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], SCSI_DATA_WRITE, STp->timeout, 0, TRUE);
1976 *aSRpnt = SRpnt;
1978 if ((STp->buffer)->syscall_result)
1979 printk (KERN_ERR "%s:D: Couldn't set retries to %d\n", name, retries);
1981 #endif
1984 static int osst_write_filemark(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt)
1986 int result;
1987 int this_mark_ppos = STp->first_frame_position;
1988 int this_mark_lbn = STp->logical_blk_num;
1989 #if DEBUG
1990 char * name = tape_name(STp);
1991 #endif
1993 if (STp->raw) return 0;
1995 STp->write_type = OS_WRITE_NEW_MARK;
1996 #if DEBUG
1997 printk(OSST_DEB_MSG "%s:D: Writing Filemark %i at fppos %d (fseq %d, lblk %d)\n",
1998 name, STp->filemark_cnt, this_mark_ppos, STp->frame_seq_number, this_mark_lbn);
1999 #endif
2000 STp->dirty = 1;
2001 result = osst_flush_write_buffer(STp, aSRpnt);
2002 result |= osst_flush_drive_buffer(STp, aSRpnt);
2003 STp->last_mark_ppos = this_mark_ppos;
2004 STp->last_mark_lbn = this_mark_lbn;
2005 if (STp->header_cache != NULL && STp->filemark_cnt < OS_FM_TAB_MAX)
2006 STp->header_cache->dat_fm_tab.fm_tab_ent[STp->filemark_cnt] = htonl(this_mark_ppos);
2007 if (STp->filemark_cnt++ == 0)
2008 STp->first_mark_ppos = this_mark_ppos;
2009 return result;
2012 static int osst_write_eod(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt)
2014 int result;
2015 #if DEBUG
2016 char * name = tape_name(STp);
2017 #endif
2019 if (STp->raw) return 0;
2021 STp->write_type = OS_WRITE_EOD;
2022 STp->eod_frame_ppos = STp->first_frame_position;
2023 #if DEBUG
2024 printk(OSST_DEB_MSG "%s:D: Writing EOD at fppos %d (fseq %d, lblk %d)\n", name,
2025 STp->eod_frame_ppos, STp->frame_seq_number, STp->logical_blk_num);
2026 #endif
2027 STp->dirty = 1;
2029 result = osst_flush_write_buffer(STp, aSRpnt);
2030 result |= osst_flush_drive_buffer(STp, aSRpnt);
2031 STp->eod_frame_lfa = --(STp->frame_seq_number);
2032 return result;
2035 static int osst_write_filler(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int where, int count)
2037 char * name = tape_name(STp);
2039 #if DEBUG
2040 printk(OSST_DEB_MSG "%s:D: Reached onstream write filler group %d\n", name, where);
2041 #endif
2042 osst_wait_ready(STp, aSRpnt, 60 * 5, 0);
2043 osst_set_frame_position(STp, aSRpnt, where, 0);
2044 STp->write_type = OS_WRITE_FILLER;
2045 while (count--) {
2046 memcpy(STp->buffer->b_data, "Filler", 6);
2047 STp->buffer->buffer_bytes = 6;
2048 STp->dirty = 1;
2049 if (osst_flush_write_buffer(STp, aSRpnt)) {
2050 printk(KERN_INFO "%s:I: Couldn't write filler frame\n", name);
2051 return (-EIO);
2054 #if DEBUG
2055 printk(OSST_DEB_MSG "%s:D: Exiting onstream write filler group\n", name);
2056 #endif
2057 return osst_flush_drive_buffer(STp, aSRpnt);
2060 static int __osst_write_header(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int where, int count)
2062 char * name = tape_name(STp);
2063 int result;
2065 #if DEBUG
2066 printk(OSST_DEB_MSG "%s:D: Reached onstream write header group %d\n", name, where);
2067 #endif
2068 osst_wait_ready(STp, aSRpnt, 60 * 5, 0);
2069 osst_set_frame_position(STp, aSRpnt, where, 0);
2070 STp->write_type = OS_WRITE_HEADER;
2071 while (count--) {
2072 osst_copy_to_buffer(STp->buffer, (unsigned char *)STp->header_cache);
2073 STp->buffer->buffer_bytes = sizeof(os_header_t);
2074 STp->dirty = 1;
2075 if (osst_flush_write_buffer(STp, aSRpnt)) {
2076 printk(KERN_INFO "%s:I: Couldn't write header frame\n", name);
2077 return (-EIO);
2080 result = osst_flush_drive_buffer(STp, aSRpnt);
2081 #if DEBUG
2082 printk(OSST_DEB_MSG "%s:D: Write onstream header group %s\n", name, result?"failed":"done");
2083 #endif
2084 return result;
2087 static int osst_write_header(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int locate_eod)
2089 os_header_t * header;
2090 int result;
2091 char * name = tape_name(STp);
2093 #if DEBUG
2094 printk(OSST_DEB_MSG "%s:D: Writing tape header\n", name);
2095 #endif
2096 if (STp->raw) return 0;
2098 if (STp->header_cache == NULL) {
2099 if ((STp->header_cache = (os_header_t *)vmalloc(sizeof(os_header_t))) == NULL) {
2100 printk(KERN_ERR "%s:E: Failed to allocate header cache\n", name);
2101 return (-ENOMEM);
2103 memset(STp->header_cache, 0, sizeof(os_header_t));
2104 #if DEBUG
2105 printk(OSST_DEB_MSG "%s:D: Allocated and cleared memory for header cache\n", name);
2106 #endif
2108 if (STp->header_ok) STp->update_frame_cntr++;
2109 else STp->update_frame_cntr = 0;
2111 header = STp->header_cache;
2112 strcpy(header->ident_str, "ADR_SEQ");
2113 header->major_rev = 1;
2114 header->minor_rev = 4;
2115 header->ext_trk_tb_off = htons(17192);
2116 header->pt_par_num = 1;
2117 header->partition[0].partition_num = OS_DATA_PARTITION;
2118 header->partition[0].par_desc_ver = OS_PARTITION_VERSION;
2119 header->partition[0].wrt_pass_cntr = htons(STp->wrt_pass_cntr);
2120 header->partition[0].first_frame_ppos = htonl(STp->first_data_ppos);
2121 header->partition[0].last_frame_ppos = htonl(STp->capacity);
2122 header->partition[0].eod_frame_ppos = htonl(STp->eod_frame_ppos);
2123 header->cfg_col_width = htonl(20);
2124 header->dat_col_width = htonl(1500);
2125 header->qfa_col_width = htonl(0);
2126 header->ext_track_tb.nr_stream_part = 1;
2127 header->ext_track_tb.et_ent_sz = 32;
2128 header->ext_track_tb.dat_ext_trk_ey.et_part_num = 0;
2129 header->ext_track_tb.dat_ext_trk_ey.fmt = 1;
2130 header->ext_track_tb.dat_ext_trk_ey.fm_tab_off = htons(17736);
2131 header->ext_track_tb.dat_ext_trk_ey.last_hlb_hi = 0;
2132 header->ext_track_tb.dat_ext_trk_ey.last_hlb = htonl(STp->eod_frame_lfa);
2133 header->ext_track_tb.dat_ext_trk_ey.last_pp = htonl(STp->eod_frame_ppos);
2134 header->dat_fm_tab.fm_part_num = 0;
2135 header->dat_fm_tab.fm_tab_ent_sz = 4;
2136 header->dat_fm_tab.fm_tab_ent_cnt = htons(STp->filemark_cnt<OS_FM_TAB_MAX?
2137 STp->filemark_cnt:OS_FM_TAB_MAX);
2139 result = __osst_write_header(STp, aSRpnt, 0xbae, 5);
2140 if (STp->update_frame_cntr == 0)
2141 osst_write_filler(STp, aSRpnt, 0xbb3, 5);
2142 result &= __osst_write_header(STp, aSRpnt, 5, 5);
2144 if (locate_eod) {
2145 #if DEBUG
2146 printk(OSST_DEB_MSG "%s:D: Locating back to eod frame addr %d\n", name, STp->eod_frame_ppos);
2147 #endif
2148 osst_set_frame_position(STp, aSRpnt, STp->eod_frame_ppos, 0);
2150 if (result)
2151 printk(KERN_ERR "%s:E: Write header failed\n", name);
2152 else {
2153 memcpy(STp->application_sig, "LIN4", 4);
2154 STp->linux_media = 1;
2155 STp->linux_media_version = 4;
2156 STp->header_ok = 1;
2158 return result;
2161 static int osst_reset_header(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt)
2163 if (STp->header_cache != NULL)
2164 memset(STp->header_cache, 0, sizeof(os_header_t));
2166 STp->logical_blk_num = STp->frame_seq_number = 0;
2167 STp->frame_in_buffer = 0;
2168 STp->eod_frame_ppos = STp->first_data_ppos = 0x0000000A;
2169 STp->filemark_cnt = 0;
2170 STp->first_mark_ppos = STp->last_mark_ppos = STp->last_mark_lbn = -1;
2171 return osst_write_header(STp, aSRpnt, 1);
2174 static int __osst_analyze_headers(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int ppos)
2176 char * name = tape_name(STp);
2177 os_header_t * header;
2178 os_aux_t * aux;
2179 char id_string[8];
2180 int linux_media_version,
2181 update_frame_cntr;
2183 if (STp->raw)
2184 return 1;
2186 if (ppos == 5 || ppos == 0xbae || STp->buffer->syscall_result) {
2187 if (osst_set_frame_position(STp, aSRpnt, ppos, 0))
2188 printk(KERN_WARNING "%s:W: Couldn't position tape\n", name);
2189 osst_wait_ready(STp, aSRpnt, 60 * 15, 0);
2190 if (osst_initiate_read (STp, aSRpnt)) {
2191 printk(KERN_WARNING "%s:W: Couldn't initiate read\n", name);
2192 return 0;
2195 if (osst_read_frame(STp, aSRpnt, 180)) {
2196 #if DEBUG
2197 printk(OSST_DEB_MSG "%s:D: Couldn't read header frame\n", name);
2198 #endif
2199 return 0;
2201 header = (os_header_t *) STp->buffer->b_data; /* warning: only first segment addressable */
2202 aux = STp->buffer->aux;
2203 if (aux->frame_type != OS_FRAME_TYPE_HEADER) {
2204 #if DEBUG
2205 printk(OSST_DEB_MSG "%s:D: Skipping non-header frame (%d)\n", name, ppos);
2206 #endif
2207 return 0;
2209 if (ntohl(aux->frame_seq_num) != 0 ||
2210 ntohl(aux->logical_blk_num) != 0 ||
2211 aux->partition.partition_num != OS_CONFIG_PARTITION ||
2212 ntohl(aux->partition.first_frame_ppos) != 0 ||
2213 ntohl(aux->partition.last_frame_ppos) != 0xbb7 ) {
2214 #if DEBUG
2215 printk(OSST_DEB_MSG "%s:D: Invalid header frame (%d,%d,%d,%d,%d)\n", name,
2216 ntohl(aux->frame_seq_num), ntohl(aux->logical_blk_num),
2217 aux->partition.partition_num, ntohl(aux->partition.first_frame_ppos),
2218 ntohl(aux->partition.last_frame_ppos));
2219 #endif
2220 return 0;
2222 if (strncmp(header->ident_str, "ADR_SEQ", 7) != 0 &&
2223 strncmp(header->ident_str, "ADR-SEQ", 7) != 0) {
2224 strlcpy(id_string, header->ident_str, 8);
2225 #if DEBUG
2226 printk(OSST_DEB_MSG "%s:D: Invalid header identification string %s\n", name, id_string);
2227 #endif
2228 return 0;
2230 update_frame_cntr = ntohl(aux->update_frame_cntr);
2231 if (update_frame_cntr < STp->update_frame_cntr) {
2232 #if DEBUG
2233 printk(OSST_DEB_MSG "%s:D: Skipping frame %d with update_frame_counter %d<%d\n",
2234 name, ppos, update_frame_cntr, STp->update_frame_cntr);
2235 #endif
2236 return 0;
2238 if (header->major_rev != 1 || header->minor_rev != 4 ) {
2239 #if DEBUG
2240 printk(OSST_DEB_MSG "%s:D: %s revision %d.%d detected (1.4 supported)\n",
2241 name, (header->major_rev != 1 || header->minor_rev < 2 ||
2242 header->minor_rev > 4 )? "Invalid" : "Warning:",
2243 header->major_rev, header->minor_rev);
2244 #endif
2245 if (header->major_rev != 1 || header->minor_rev < 2 || header->minor_rev > 4)
2246 return 0;
2248 #if DEBUG
2249 if (header->pt_par_num != 1)
2250 printk(KERN_INFO "%s:W: %d partitions defined, only one supported\n",
2251 name, header->pt_par_num);
2252 #endif
2253 memcpy(id_string, aux->application_sig, 4);
2254 id_string[4] = 0;
2255 if (memcmp(id_string, "LIN", 3) == 0) {
2256 STp->linux_media = 1;
2257 linux_media_version = id_string[3] - '0';
2258 if (linux_media_version != 4)
2259 printk(KERN_INFO "%s:I: Linux media version %d detected (current 4)\n",
2260 name, linux_media_version);
2261 } else {
2262 printk(KERN_WARNING "%s:W: Non Linux media detected (%s)\n", name, id_string);
2263 return 0;
2265 if (linux_media_version < STp->linux_media_version) {
2266 #if DEBUG
2267 printk(OSST_DEB_MSG "%s:D: Skipping frame %d with linux_media_version %d\n",
2268 name, ppos, linux_media_version);
2269 #endif
2270 return 0;
2272 if (linux_media_version > STp->linux_media_version) {
2273 #if DEBUG
2274 printk(OSST_DEB_MSG "%s:D: Frame %d sets linux_media_version to %d\n",
2275 name, ppos, linux_media_version);
2276 #endif
2277 memcpy(STp->application_sig, id_string, 5);
2278 STp->linux_media_version = linux_media_version;
2279 STp->update_frame_cntr = -1;
2281 if (update_frame_cntr > STp->update_frame_cntr) {
2282 #if DEBUG
2283 printk(OSST_DEB_MSG "%s:D: Frame %d sets update_frame_counter to %d\n",
2284 name, ppos, update_frame_cntr);
2285 #endif
2286 if (STp->header_cache == NULL) {
2287 if ((STp->header_cache = (os_header_t *)vmalloc(sizeof(os_header_t))) == NULL) {
2288 printk(KERN_ERR "%s:E: Failed to allocate header cache\n", name);
2289 return 0;
2291 #if DEBUG
2292 printk(OSST_DEB_MSG "%s:D: Allocated memory for header cache\n", name);
2293 #endif
2295 osst_copy_from_buffer(STp->buffer, (unsigned char *)STp->header_cache);
2296 header = STp->header_cache; /* further accesses from cached (full) copy */
2298 STp->wrt_pass_cntr = ntohs(header->partition[0].wrt_pass_cntr);
2299 STp->first_data_ppos = ntohl(header->partition[0].first_frame_ppos);
2300 STp->eod_frame_ppos = ntohl(header->partition[0].eod_frame_ppos);
2301 STp->eod_frame_lfa = ntohl(header->ext_track_tb.dat_ext_trk_ey.last_hlb);
2302 STp->filemark_cnt = ntohl(aux->filemark_cnt);
2303 STp->first_mark_ppos = ntohl(aux->next_mark_ppos);
2304 STp->last_mark_ppos = ntohl(aux->last_mark_ppos);
2305 STp->last_mark_lbn = ntohl(aux->last_mark_lbn);
2306 STp->update_frame_cntr = update_frame_cntr;
2307 #if DEBUG
2308 printk(OSST_DEB_MSG "%s:D: Detected write pass %d, update frame counter %d, filemark counter %d\n",
2309 name, STp->wrt_pass_cntr, STp->update_frame_cntr, STp->filemark_cnt);
2310 printk(OSST_DEB_MSG "%s:D: first data frame on tape = %d, last = %d, eod frame = %d\n", name,
2311 STp->first_data_ppos,
2312 ntohl(header->partition[0].last_frame_ppos),
2313 ntohl(header->partition[0].eod_frame_ppos));
2314 printk(OSST_DEB_MSG "%s:D: first mark on tape = %d, last = %d, eod frame = %d\n",
2315 name, STp->first_mark_ppos, STp->last_mark_ppos, STp->eod_frame_ppos);
2316 #endif
2317 if (header->minor_rev < 4 && STp->linux_media_version == 4) {
2318 #if DEBUG
2319 printk(OSST_DEB_MSG "%s:D: Moving filemark list to ADR 1.4 location\n", name);
2320 #endif
2321 memcpy((void *)header->dat_fm_tab.fm_tab_ent,
2322 (void *)header->old_filemark_list, sizeof(header->dat_fm_tab.fm_tab_ent));
2323 memset((void *)header->old_filemark_list, 0, sizeof(header->old_filemark_list));
2325 if (header->minor_rev == 4 &&
2326 (header->ext_trk_tb_off != htons(17192) ||
2327 header->partition[0].partition_num != OS_DATA_PARTITION ||
2328 header->partition[0].par_desc_ver != OS_PARTITION_VERSION ||
2329 header->partition[0].last_frame_ppos != htonl(STp->capacity) ||
2330 header->cfg_col_width != htonl(20) ||
2331 header->dat_col_width != htonl(1500) ||
2332 header->qfa_col_width != htonl(0) ||
2333 header->ext_track_tb.nr_stream_part != 1 ||
2334 header->ext_track_tb.et_ent_sz != 32 ||
2335 header->ext_track_tb.dat_ext_trk_ey.et_part_num != OS_DATA_PARTITION ||
2336 header->ext_track_tb.dat_ext_trk_ey.fmt != 1 ||
2337 header->ext_track_tb.dat_ext_trk_ey.fm_tab_off != htons(17736) ||
2338 header->ext_track_tb.dat_ext_trk_ey.last_hlb_hi != 0 ||
2339 header->ext_track_tb.dat_ext_trk_ey.last_pp != htonl(STp->eod_frame_ppos) ||
2340 header->dat_fm_tab.fm_part_num != OS_DATA_PARTITION ||
2341 header->dat_fm_tab.fm_tab_ent_sz != 4 ||
2342 header->dat_fm_tab.fm_tab_ent_cnt !=
2343 htons(STp->filemark_cnt<OS_FM_TAB_MAX?STp->filemark_cnt:OS_FM_TAB_MAX)))
2344 printk(KERN_WARNING "%s:W: Failed consistency check ADR 1.4 format\n", name);
2348 return 1;
2351 static int osst_analyze_headers(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt)
2353 int position, ppos;
2354 int first, last;
2355 int valid = 0;
2356 char * name = tape_name(STp);
2358 position = osst_get_frame_position(STp, aSRpnt);
2360 if (STp->raw) {
2361 STp->header_ok = STp->linux_media = 1;
2362 STp->linux_media_version = 0;
2363 return 1;
2365 STp->header_ok = STp->linux_media = STp->linux_media_version = 0;
2366 STp->wrt_pass_cntr = STp->update_frame_cntr = -1;
2367 STp->eod_frame_ppos = STp->first_data_ppos = -1;
2368 STp->first_mark_ppos = STp->last_mark_ppos = STp->last_mark_lbn = -1;
2369 #if DEBUG
2370 printk(OSST_DEB_MSG "%s:D: Reading header\n", name);
2371 #endif
2373 /* optimization for speed - if we are positioned at ppos 10, read second group first */
2374 /* TODO try the ADR 1.1 locations for the second group if we have no valid one yet... */
2376 first = position==10?0xbae: 5;
2377 last = position==10?0xbb3:10;
2379 for (ppos = first; ppos < last; ppos++)
2380 if (__osst_analyze_headers(STp, aSRpnt, ppos))
2381 valid = 1;
2383 first = position==10? 5:0xbae;
2384 last = position==10?10:0xbb3;
2386 for (ppos = first; ppos < last; ppos++)
2387 if (__osst_analyze_headers(STp, aSRpnt, ppos))
2388 valid = 1;
2390 if (!valid) {
2391 printk(KERN_ERR "%s:E: Failed to find valid ADRL header, new media?\n", name);
2392 STp->eod_frame_ppos = STp->first_data_ppos = 0;
2393 osst_set_frame_position(STp, aSRpnt, 10, 0);
2394 return 0;
2396 if (position <= STp->first_data_ppos) {
2397 position = STp->first_data_ppos;
2398 STp->ps[0].drv_file = STp->ps[0].drv_block = STp->frame_seq_number = STp->logical_blk_num = 0;
2400 osst_set_frame_position(STp, aSRpnt, position, 0);
2401 STp->header_ok = 1;
2403 return 1;
2406 static int osst_verify_position(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt)
2408 int frame_position = STp->first_frame_position;
2409 int frame_seq_numbr = STp->frame_seq_number;
2410 int logical_blk_num = STp->logical_blk_num;
2411 int halfway_frame = STp->frame_in_buffer;
2412 int read_pointer = STp->buffer->read_pointer;
2413 int prev_mark_ppos = -1;
2414 int actual_mark_ppos, i, n;
2415 #if DEBUG
2416 char * name = tape_name(STp);
2418 printk(OSST_DEB_MSG "%s:D: Verify that the tape is really the one we think before writing\n", name);
2419 #endif
2420 osst_set_frame_position(STp, aSRpnt, frame_position - 1, 0);
2421 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
2422 #if DEBUG
2423 printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in verify_position\n", name);
2424 #endif
2425 return (-EIO);
2427 if (STp->linux_media_version >= 4) {
2428 for (i=0; i<STp->filemark_cnt; i++)
2429 if ((n=ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[i])) < frame_position)
2430 prev_mark_ppos = n;
2431 } else
2432 prev_mark_ppos = frame_position - 1; /* usually - we don't really know */
2433 actual_mark_ppos = STp->buffer->aux->frame_type == OS_FRAME_TYPE_MARKER ?
2434 frame_position - 1 : ntohl(STp->buffer->aux->last_mark_ppos);
2435 if (frame_position != STp->first_frame_position ||
2436 frame_seq_numbr != STp->frame_seq_number + (halfway_frame?0:1) ||
2437 prev_mark_ppos != actual_mark_ppos ) {
2438 #if DEBUG
2439 printk(OSST_DEB_MSG "%s:D: Block mismatch: fppos %d-%d, fseq %d-%d, mark %d-%d\n", name,
2440 STp->first_frame_position, frame_position,
2441 STp->frame_seq_number + (halfway_frame?0:1),
2442 frame_seq_numbr, actual_mark_ppos, prev_mark_ppos);
2443 #endif
2444 return (-EIO);
2446 if (halfway_frame) {
2447 /* prepare buffer for append and rewrite on top of original */
2448 osst_set_frame_position(STp, aSRpnt, frame_position - 1, 0);
2449 STp->buffer->buffer_bytes = read_pointer;
2450 STp->ps[STp->partition].rw = ST_WRITING;
2451 STp->dirty = 1;
2453 STp->frame_in_buffer = halfway_frame;
2454 STp->frame_seq_number = frame_seq_numbr;
2455 STp->logical_blk_num = logical_blk_num;
2456 return 0;
2459 /* Acc. to OnStream, the vers. numbering is the following:
2460 * X.XX for released versions (X=digit),
2461 * XXXY for unreleased versions (Y=letter)
2462 * Ordering 1.05 < 106A < 106B < ... < 106a < ... < 1.06
2463 * This fn makes monoton numbers out of this scheme ...
2465 static unsigned int osst_parse_firmware_rev (const char * str)
2467 if (str[1] == '.') {
2468 return (str[0]-'0')*10000
2469 +(str[2]-'0')*1000
2470 +(str[3]-'0')*100;
2471 } else {
2472 return (str[0]-'0')*10000
2473 +(str[1]-'0')*1000
2474 +(str[2]-'0')*100 - 100
2475 +(str[3]-'@');
2480 * Configure the OnStream SCII tape drive for default operation
2482 static int osst_configure_onstream(OS_Scsi_Tape *STp, Scsi_Request ** aSRpnt)
2484 unsigned char cmd[MAX_COMMAND_SIZE];
2485 char * name = tape_name(STp);
2486 Scsi_Request * SRpnt = * aSRpnt;
2487 osst_mode_parameter_header_t * header;
2488 osst_block_size_page_t * bs;
2489 osst_capabilities_page_t * cp;
2490 osst_tape_paramtr_page_t * prm;
2491 int drive_buffer_size;
2493 if (STp->ready != ST_READY) {
2494 #if DEBUG
2495 printk(OSST_DEB_MSG "%s:D: Not Ready\n", name);
2496 #endif
2497 return (-EIO);
2500 if (STp->os_fw_rev < 10600) {
2501 printk(KERN_INFO "%s:I: Old OnStream firmware revision detected (%s),\n", name, STp->device->rev);
2502 printk(KERN_INFO "%s:I: an upgrade to version 1.06 or above is recommended\n", name);
2506 * Configure 32.5KB (data+aux) frame size.
2507 * Get the current frame size from the block size mode page
2509 memset(cmd, 0, MAX_COMMAND_SIZE);
2510 cmd[0] = MODE_SENSE;
2511 cmd[1] = 8;
2512 cmd[2] = BLOCK_SIZE_PAGE;
2513 cmd[4] = BLOCK_SIZE_PAGE_LENGTH + MODE_HEADER_LENGTH;
2515 SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], SCSI_DATA_READ, STp->timeout, 0, TRUE);
2516 if (SRpnt == NULL) {
2517 #if DEBUG
2518 printk(OSST_DEB_MSG "osst :D: Busy\n");
2519 #endif
2520 return (-EBUSY);
2522 *aSRpnt = SRpnt;
2523 if ((STp->buffer)->syscall_result != 0) {
2524 printk (KERN_ERR "%s:E: Can't get tape block size mode page\n", name);
2525 return (-EIO);
2528 header = (osst_mode_parameter_header_t *) (STp->buffer)->b_data;
2529 bs = (osst_block_size_page_t *) ((STp->buffer)->b_data + sizeof(osst_mode_parameter_header_t) + header->bdl);
2531 #if DEBUG
2532 printk(OSST_DEB_MSG "%s:D: 32KB play back: %s\n", name, bs->play32 ? "Yes" : "No");
2533 printk(OSST_DEB_MSG "%s:D: 32.5KB play back: %s\n", name, bs->play32_5 ? "Yes" : "No");
2534 printk(OSST_DEB_MSG "%s:D: 32KB record: %s\n", name, bs->record32 ? "Yes" : "No");
2535 printk(OSST_DEB_MSG "%s:D: 32.5KB record: %s\n", name, bs->record32_5 ? "Yes" : "No");
2536 #endif
2539 * Configure default auto columns mode, 32.5KB transfer mode
2541 bs->one = 1;
2542 bs->play32 = 0;
2543 bs->play32_5 = 1;
2544 bs->record32 = 0;
2545 bs->record32_5 = 1;
2547 memset(cmd, 0, MAX_COMMAND_SIZE);
2548 cmd[0] = MODE_SELECT;
2549 cmd[1] = 0x10;
2550 cmd[4] = BLOCK_SIZE_PAGE_LENGTH + MODE_HEADER_LENGTH;
2552 SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], SCSI_DATA_WRITE, STp->timeout, 0, TRUE);
2553 *aSRpnt = SRpnt;
2554 if ((STp->buffer)->syscall_result != 0) {
2555 printk (KERN_ERR "%s:E: Couldn't set tape block size mode page\n", name);
2556 return (-EIO);
2559 #if DEBUG
2560 printk(KERN_INFO "%s:D: Drive Block Size changed to 32.5K\n", name);
2562 * In debug mode, we want to see as many errors as possible
2563 * to test the error recovery mechanism.
2565 osst_set_retries(STp, aSRpnt, 0);
2566 SRpnt = * aSRpnt;
2567 #endif
2570 * Set vendor name to 'LIN4' for "Linux support version 4".
2573 memset(cmd, 0, MAX_COMMAND_SIZE);
2574 cmd[0] = MODE_SELECT;
2575 cmd[1] = 0x10;
2576 cmd[4] = VENDOR_IDENT_PAGE_LENGTH + MODE_HEADER_LENGTH;
2578 header->mode_data_length = VENDOR_IDENT_PAGE_LENGTH + MODE_HEADER_LENGTH - 1;
2579 header->medium_type = 0; /* Medium Type - ignoring */
2580 header->dsp = 0; /* Reserved */
2581 header->bdl = 0; /* Block Descriptor Length */
2583 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 0] = VENDOR_IDENT_PAGE | (1 << 7);
2584 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 1] = 6;
2585 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] = 'L';
2586 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] = 'I';
2587 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 4] = 'N';
2588 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 5] = '4';
2589 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 6] = 0;
2590 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 7] = 0;
2592 SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], SCSI_DATA_WRITE, STp->timeout, 0, TRUE);
2593 *aSRpnt = SRpnt;
2595 if ((STp->buffer)->syscall_result != 0) {
2596 printk (KERN_ERR "%s:E: Couldn't set vendor name to %s\n", name,
2597 (char *) ((STp->buffer)->b_data + MODE_HEADER_LENGTH + 2));
2598 return (-EIO);
2601 memset(cmd, 0, MAX_COMMAND_SIZE);
2602 cmd[0] = MODE_SENSE;
2603 cmd[1] = 8;
2604 cmd[2] = CAPABILITIES_PAGE;
2605 cmd[4] = CAPABILITIES_PAGE_LENGTH + MODE_HEADER_LENGTH;
2607 SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], SCSI_DATA_READ, STp->timeout, 0, TRUE);
2608 *aSRpnt = SRpnt;
2610 if ((STp->buffer)->syscall_result != 0) {
2611 printk (KERN_ERR "%s:E: Can't get capabilities page\n", name);
2612 return (-EIO);
2615 header = (osst_mode_parameter_header_t *) (STp->buffer)->b_data;
2616 cp = (osst_capabilities_page_t *) ((STp->buffer)->b_data +
2617 sizeof(osst_mode_parameter_header_t) + header->bdl);
2619 drive_buffer_size = ntohs(cp->buffer_size) / 2;
2621 memset(cmd, 0, MAX_COMMAND_SIZE);
2622 cmd[0] = MODE_SENSE;
2623 cmd[1] = 8;
2624 cmd[2] = TAPE_PARAMTR_PAGE;
2625 cmd[4] = TAPE_PARAMTR_PAGE_LENGTH + MODE_HEADER_LENGTH;
2627 SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], SCSI_DATA_READ, STp->timeout, 0, TRUE);
2628 *aSRpnt = SRpnt;
2630 if ((STp->buffer)->syscall_result != 0) {
2631 printk (KERN_ERR "%s:E: Can't get tape parameter page\n", name);
2632 return (-EIO);
2635 header = (osst_mode_parameter_header_t *) (STp->buffer)->b_data;
2636 prm = (osst_tape_paramtr_page_t *) ((STp->buffer)->b_data +
2637 sizeof(osst_mode_parameter_header_t) + header->bdl);
2639 STp->density = prm->density;
2640 STp->capacity = ntohs(prm->segtrk) * ntohs(prm->trks);
2641 #if DEBUG
2642 printk(OSST_DEB_MSG "%s:D: Density %d, tape length: %dMB, drive buffer size: %dKB\n",
2643 name, STp->density, STp->capacity / 32, drive_buffer_size);
2644 #endif
2646 return 0;
2651 /* Step over EOF if it has been inadvertently crossed (ioctl not used because
2652 it messes up the block number). */
2653 static int cross_eof(OS_Scsi_Tape *STp, Scsi_Request ** aSRpnt, int forward)
2655 int result;
2656 char * name = tape_name(STp);
2658 #if DEBUG
2659 if (debugging)
2660 printk(OSST_DEB_MSG "%s:D: Stepping over filemark %s.\n",
2661 name, forward ? "forward" : "backward");
2662 #endif
2664 if (forward) {
2665 /* assumes that the filemark is already read by the drive, so this is low cost */
2666 result = osst_space_over_filemarks_forward_slow(STp, aSRpnt, MTFSF, 1);
2668 else
2669 /* assumes this is only called if we just read the filemark! */
2670 result = osst_seek_logical_blk(STp, aSRpnt, STp->logical_blk_num - 1);
2672 if (result < 0)
2673 printk(KERN_WARNING "%s:W: Stepping over filemark %s failed.\n",
2674 name, forward ? "forward" : "backward");
2676 return result;
2680 /* Get the tape position. */
2682 static int osst_get_frame_position(OS_Scsi_Tape *STp, Scsi_Request ** aSRpnt)
2684 unsigned char scmd[MAX_COMMAND_SIZE];
2685 Scsi_Request * SRpnt;
2686 int result = 0;
2688 /* KG: We want to be able to use it for checking Write Buffer availability
2689 * and thus don't want to risk to overwrite anything. Exchange buffers ... */
2690 char mybuf[24];
2691 char * olddata = STp->buffer->b_data;
2692 int oldsize = STp->buffer->buffer_size;
2693 char * name = tape_name(STp);
2695 if (STp->ready != ST_READY) return (-EIO);
2697 memset (scmd, 0, MAX_COMMAND_SIZE);
2698 scmd[0] = READ_POSITION;
2700 STp->buffer->b_data = mybuf; STp->buffer->buffer_size = 24;
2701 SRpnt = osst_do_scsi(*aSRpnt, STp, scmd, 20, SCSI_DATA_READ,
2702 STp->timeout, MAX_RETRIES, TRUE);
2703 if (!SRpnt) {
2704 STp->buffer->b_data = olddata; STp->buffer->buffer_size = oldsize;
2705 return (-EBUSY);
2707 *aSRpnt = SRpnt;
2709 if (STp->buffer->syscall_result)
2710 result = ((SRpnt->sr_sense_buffer[2] & 0x0f) == 3) ? -EIO : -EINVAL;
2712 if (result == -EINVAL)
2713 printk(KERN_ERR "%s:E: Can't read tape position.\n", name);
2714 else {
2716 if (result == -EIO) { /* re-read position */
2717 unsigned char mysense[16];
2718 memcpy (mysense, SRpnt->sr_sense_buffer, 16);
2719 memset (scmd, 0, MAX_COMMAND_SIZE);
2720 scmd[0] = READ_POSITION;
2721 STp->buffer->b_data = mybuf; STp->buffer->buffer_size = 24;
2722 SRpnt = osst_do_scsi(SRpnt, STp, scmd, 20, SCSI_DATA_READ,
2723 STp->timeout, MAX_RETRIES, TRUE);
2724 if (!STp->buffer->syscall_result)
2725 memcpy (SRpnt->sr_sense_buffer, mysense, 16);
2727 STp->first_frame_position = ((STp->buffer)->b_data[4] << 24)
2728 + ((STp->buffer)->b_data[5] << 16)
2729 + ((STp->buffer)->b_data[6] << 8)
2730 + (STp->buffer)->b_data[7];
2731 STp->last_frame_position = ((STp->buffer)->b_data[ 8] << 24)
2732 + ((STp->buffer)->b_data[ 9] << 16)
2733 + ((STp->buffer)->b_data[10] << 8)
2734 + (STp->buffer)->b_data[11];
2735 STp->cur_frames = (STp->buffer)->b_data[15];
2736 #if DEBUG
2737 if (debugging) {
2738 printk(OSST_DEB_MSG "%s:D: Drive Positions: host %d, tape %d%s, buffer %d\n", name,
2739 STp->first_frame_position, STp->last_frame_position,
2740 ((STp->buffer)->b_data[0]&0x80)?" (BOP)":
2741 ((STp->buffer)->b_data[0]&0x40)?" (EOP)":"",
2742 STp->cur_frames);
2744 #endif
2745 if (STp->cur_frames == 0 && STp->first_frame_position != STp->last_frame_position) {
2746 #if DEBUG
2747 printk(KERN_WARNING "%s:D: Correcting read position %d, %d, %d\n", name,
2748 STp->first_frame_position, STp->last_frame_position, STp->cur_frames);
2749 #endif
2750 STp->first_frame_position = STp->last_frame_position;
2753 STp->buffer->b_data = olddata; STp->buffer->buffer_size = oldsize;
2755 return (result == 0 ? STp->first_frame_position : result);
2759 /* Set the tape block */
2760 static int osst_set_frame_position(OS_Scsi_Tape *STp, Scsi_Request ** aSRpnt, int ppos, int skip)
2762 unsigned char scmd[MAX_COMMAND_SIZE];
2763 Scsi_Request * SRpnt;
2764 ST_partstat * STps;
2765 int result = 0;
2766 int pp = (ppos == 3000 && !skip)? 0 : ppos;
2767 char * name = tape_name(STp);
2769 if (STp->ready != ST_READY) return (-EIO);
2771 STps = &(STp->ps[STp->partition]);
2773 if (ppos < 0 || ppos > STp->capacity) {
2774 printk(KERN_WARNING "%s:W: Reposition request %d out of range\n", name, ppos);
2775 pp = ppos = ppos < 0 ? 0 : (STp->capacity - 1);
2776 result = (-EINVAL);
2779 do {
2780 #if DEBUG
2781 if (debugging)
2782 printk(OSST_DEB_MSG "%s:D: Setting ppos to %d.\n", name, pp);
2783 #endif
2784 memset (scmd, 0, MAX_COMMAND_SIZE);
2785 scmd[0] = SEEK_10;
2786 scmd[1] = 1;
2787 scmd[3] = (pp >> 24);
2788 scmd[4] = (pp >> 16);
2789 scmd[5] = (pp >> 8);
2790 scmd[6] = pp;
2791 if (skip)
2792 scmd[9] = 0x80;
2794 SRpnt = osst_do_scsi(*aSRpnt, STp, scmd, 0, SCSI_DATA_NONE, STp->long_timeout,
2795 MAX_RETRIES, TRUE);
2796 if (!SRpnt)
2797 return (-EBUSY);
2798 *aSRpnt = SRpnt;
2800 if ((STp->buffer)->syscall_result != 0) {
2801 #if DEBUG
2802 printk(OSST_DEB_MSG "%s:D: SEEK command from %d to %d failed.\n",
2803 name, STp->first_frame_position, pp);
2804 #endif
2805 result = (-EIO);
2807 if (pp != ppos)
2808 osst_wait_ready(STp, aSRpnt, 5 * 60, OSST_WAIT_POSITION_COMPLETE);
2809 } while ((pp != ppos) && (pp = ppos));
2810 STp->first_frame_position = STp->last_frame_position = ppos;
2811 STps->eof = ST_NOEOF;
2812 STps->at_sm = 0;
2813 STps->rw = ST_IDLE;
2814 STp->frame_in_buffer = 0;
2815 return result;
2818 static int osst_write_trailer(OS_Scsi_Tape *STp, Scsi_Request ** aSRpnt, int leave_at_EOT)
2820 ST_partstat * STps = &(STp->ps[STp->partition]);
2821 int result = 0;
2823 if (STp->write_type != OS_WRITE_NEW_MARK) {
2824 /* true unless the user wrote the filemark for us */
2825 result = osst_flush_drive_buffer(STp, aSRpnt);
2826 if (result < 0) goto out;
2827 result = osst_write_filemark(STp, aSRpnt);
2828 if (result < 0) goto out;
2830 if (STps->drv_file >= 0)
2831 STps->drv_file++ ;
2832 STps->drv_block = 0;
2834 result = osst_write_eod(STp, aSRpnt);
2835 osst_write_header(STp, aSRpnt, leave_at_EOT);
2837 STps->eof = ST_FM;
2838 out:
2839 return result;
2842 /* osst versions of st functions - augmented and stripped to suit OnStream only */
2844 /* Flush the write buffer (never need to write if variable blocksize). */
2845 static int osst_flush_write_buffer(OS_Scsi_Tape *STp, Scsi_Request ** aSRpnt)
2847 int offset, transfer, blks = 0;
2848 int result = 0;
2849 unsigned char cmd[MAX_COMMAND_SIZE];
2850 Scsi_Request * SRpnt = *aSRpnt;
2851 ST_partstat * STps;
2852 char * name = tape_name(STp);
2854 if ((STp->buffer)->writing) {
2855 if (SRpnt == (STp->buffer)->last_SRpnt)
2856 #if DEBUG
2857 { printk(OSST_DEB_MSG
2858 "%s:D: aSRpnt points to Scsi_Request that write_behind_check will release -- cleared\n", name);
2859 #endif
2860 *aSRpnt = SRpnt = NULL;
2861 #if DEBUG
2862 } else if (SRpnt)
2863 printk(OSST_DEB_MSG
2864 "%s:D: aSRpnt does not point to Scsi_Request that write_behind_check will release -- strange\n", name);
2865 #endif
2866 osst_write_behind_check(STp);
2867 if ((STp->buffer)->syscall_result) {
2868 #if DEBUG
2869 if (debugging)
2870 printk(OSST_DEB_MSG "%s:D: Async write error (flush) %x.\n",
2871 name, (STp->buffer)->midlevel_result);
2872 #endif
2873 if ((STp->buffer)->midlevel_result == INT_MAX)
2874 return (-ENOSPC);
2875 return (-EIO);
2879 result = 0;
2880 if (STp->dirty == 1) {
2882 STp->write_count++;
2883 STps = &(STp->ps[STp->partition]);
2884 STps->rw = ST_WRITING;
2885 offset = STp->buffer->buffer_bytes;
2886 blks = (offset + STp->block_size - 1) / STp->block_size;
2887 transfer = OS_FRAME_SIZE;
2889 if (offset < OS_DATA_SIZE)
2890 osst_zero_buffer_tail(STp->buffer);
2892 /* TODO: Error handling! */
2893 if (STp->poll)
2894 result = osst_wait_frame (STp, aSRpnt, STp->first_frame_position, -50, 120);
2896 memset(cmd, 0, MAX_COMMAND_SIZE);
2897 cmd[0] = WRITE_6;
2898 cmd[1] = 1;
2899 cmd[4] = 1;
2901 switch (STp->write_type) {
2902 case OS_WRITE_DATA:
2903 #if DEBUG
2904 if (debugging)
2905 printk(OSST_DEB_MSG "%s:D: Writing %d blocks to frame %d, lblks %d-%d\n",
2906 name, blks, STp->frame_seq_number,
2907 STp->logical_blk_num - blks, STp->logical_blk_num - 1);
2908 #endif
2909 osst_init_aux(STp, OS_FRAME_TYPE_DATA, STp->frame_seq_number++,
2910 STp->logical_blk_num - blks, STp->block_size, blks);
2911 break;
2912 case OS_WRITE_EOD:
2913 osst_init_aux(STp, OS_FRAME_TYPE_EOD, STp->frame_seq_number++,
2914 STp->logical_blk_num, 0, 0);
2915 break;
2916 case OS_WRITE_NEW_MARK:
2917 osst_init_aux(STp, OS_FRAME_TYPE_MARKER, STp->frame_seq_number++,
2918 STp->logical_blk_num++, 0, blks=1);
2919 break;
2920 case OS_WRITE_HEADER:
2921 osst_init_aux(STp, OS_FRAME_TYPE_HEADER, 0, 0, 0, blks=0);
2922 break;
2923 default: /* probably FILLER */
2924 osst_init_aux(STp, OS_FRAME_TYPE_FILL, 0, 0, 0, 0);
2926 #if DEBUG
2927 if (debugging)
2928 printk(OSST_DEB_MSG "%s:D: Flushing %d bytes, Transfering %d bytes in %d lblocks.\n",
2929 name, offset, transfer, blks);
2930 #endif
2932 SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, transfer, SCSI_DATA_WRITE,
2933 STp->timeout, MAX_WRITE_RETRIES, TRUE);
2934 *aSRpnt = SRpnt;
2935 if (!SRpnt)
2936 return (-EBUSY);
2938 if ((STp->buffer)->syscall_result != 0) {
2939 #if DEBUG
2940 printk(OSST_DEB_MSG
2941 "%s:D: write sense [0]=0x%02x [2]=%02x [12]=%02x [13]=%02x\n",
2942 name, SRpnt->sr_sense_buffer[0], SRpnt->sr_sense_buffer[2],
2943 SRpnt->sr_sense_buffer[12], SRpnt->sr_sense_buffer[13]);
2944 #endif
2945 if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 &&
2946 (SRpnt->sr_sense_buffer[2] & 0x40) && /* FIXME - SC-30 drive doesn't assert EOM bit */
2947 (SRpnt->sr_sense_buffer[2] & 0x0f) == NO_SENSE) {
2948 STp->dirty = 0;
2949 (STp->buffer)->buffer_bytes = 0;
2950 result = (-ENOSPC);
2952 else {
2953 if (osst_write_error_recovery(STp, aSRpnt, 1)) {
2954 printk(KERN_ERR "%s:E: Error on flush write.\n", name);
2955 result = (-EIO);
2958 STps->drv_block = (-1); /* FIXME - even if write recovery succeeds? */
2960 else {
2961 STp->first_frame_position++;
2962 STp->dirty = 0;
2963 (STp->buffer)->buffer_bytes = 0;
2966 #if DEBUG
2967 printk(OSST_DEB_MSG "%s:D: Exit flush write buffer with code %d\n", name, result);
2968 #endif
2969 return result;
2973 /* Flush the tape buffer. The tape will be positioned correctly unless
2974 seek_next is true. */
2975 static int osst_flush_buffer(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int seek_next)
2977 ST_partstat * STps;
2978 int backspace = 0, result = 0;
2979 #if DEBUG
2980 char * name = tape_name(STp);
2981 #endif
2984 * If there was a bus reset, block further access
2985 * to this device.
2987 if( STp->pos_unknown)
2988 return (-EIO);
2990 if (STp->ready != ST_READY)
2991 return 0;
2993 STps = &(STp->ps[STp->partition]);
2994 if (STps->rw == ST_WRITING || STp->dirty) { /* Writing */
2995 STp->write_type = OS_WRITE_DATA;
2996 return osst_flush_write_buffer(STp, aSRpnt);
2998 if (STp->block_size == 0)
2999 return 0;
3001 #if DEBUG
3002 printk(OSST_DEB_MSG "%s:D: Reached flush (read) buffer\n", name);
3003 #endif
3005 if (!STp->can_bsr) {
3006 backspace = ((STp->buffer)->buffer_bytes + (STp->buffer)->read_pointer) / STp->block_size -
3007 ((STp->buffer)->read_pointer + STp->block_size - 1 ) / STp->block_size ;
3008 (STp->buffer)->buffer_bytes = 0;
3009 (STp->buffer)->read_pointer = 0;
3010 STp->frame_in_buffer = 0; /* FIXME is this relevant w. OSST? */
3013 if (!seek_next) {
3014 if (STps->eof == ST_FM_HIT) {
3015 result = cross_eof(STp, aSRpnt, FALSE); /* Back over the EOF hit */
3016 if (!result)
3017 STps->eof = ST_NOEOF;
3018 else {
3019 if (STps->drv_file >= 0)
3020 STps->drv_file++;
3021 STps->drv_block = 0;
3024 if (!result && backspace > 0) /* TODO -- design and run a test case for this */
3025 result = osst_seek_logical_blk(STp, aSRpnt, STp->logical_blk_num - backspace);
3027 else if (STps->eof == ST_FM_HIT) {
3028 if (STps->drv_file >= 0)
3029 STps->drv_file++;
3030 STps->drv_block = 0;
3031 STps->eof = ST_NOEOF;
3034 return result;
3037 static int osst_write_frame(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int synchronous)
3039 unsigned char cmd[MAX_COMMAND_SIZE];
3040 Scsi_Request * SRpnt;
3041 int blks;
3042 #if DEBUG
3043 char * name = tape_name(STp);
3044 #endif
3046 if ((!STp-> raw) && (STp->first_frame_position == 0xbae)) { /* _must_ preserve buffer! */
3047 #if DEBUG
3048 printk(OSST_DEB_MSG "%s:D: Reaching config partition.\n", name);
3049 #endif
3050 if (osst_flush_drive_buffer(STp, aSRpnt) < 0) {
3051 return (-EIO);
3053 /* error recovery may have bumped us past the header partition */
3054 if (osst_get_frame_position(STp, aSRpnt) < 0xbb8) {
3055 #if DEBUG
3056 printk(OSST_DEB_MSG "%s:D: Skipping over config partition.\n", name);
3057 #endif
3058 osst_position_tape_and_confirm(STp, aSRpnt, 0xbb8);
3062 if (STp->poll)
3063 osst_wait_frame (STp, aSRpnt, STp->first_frame_position, -50, 60);
3064 /* TODO: Check for an error ! */
3066 // osst_build_stats(STp, &SRpnt);
3068 STp->ps[STp->partition].rw = ST_WRITING;
3069 STp->write_type = OS_WRITE_DATA;
3071 memset(cmd, 0, MAX_COMMAND_SIZE);
3072 cmd[0] = WRITE_6;
3073 cmd[1] = 1;
3074 cmd[4] = 1; /* one frame at a time... */
3075 blks = STp->buffer->buffer_bytes / STp->block_size;
3076 #if DEBUG
3077 if (debugging)
3078 printk(OSST_DEB_MSG "%s:D: Writing %d blocks to frame %d, lblks %d-%d\n", name, blks,
3079 STp->frame_seq_number, STp->logical_blk_num - blks, STp->logical_blk_num - 1);
3080 #endif
3081 osst_init_aux(STp, OS_FRAME_TYPE_DATA, STp->frame_seq_number++,
3082 STp->logical_blk_num - blks, STp->block_size, blks);
3084 #if DEBUG
3085 if (!synchronous)
3086 STp->write_pending = 1;
3087 #endif
3088 SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, OS_FRAME_SIZE, SCSI_DATA_WRITE, STp->timeout,
3089 MAX_WRITE_RETRIES, synchronous);
3090 if (!SRpnt)
3091 return (-EBUSY);
3092 *aSRpnt = SRpnt;
3094 if (synchronous) {
3095 if (STp->buffer->syscall_result != 0) {
3096 #if DEBUG
3097 if (debugging)
3098 printk(OSST_DEB_MSG "%s:D: Error on write:\n", name);
3099 #endif
3100 if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 &&
3101 (SRpnt->sr_sense_buffer[2] & 0x40)) {
3102 if ((SRpnt->sr_sense_buffer[2] & 0x0f) == VOLUME_OVERFLOW)
3103 return (-ENOSPC);
3105 else {
3106 if (osst_write_error_recovery(STp, aSRpnt, 1))
3107 return (-EIO);
3110 else
3111 STp->first_frame_position++;
3114 STp->write_count++;
3116 return 0;
3119 /* Lock or unlock the drive door. Don't use when Scsi_Request allocated. */
3120 static int do_door_lock(OS_Scsi_Tape * STp, int do_lock)
3122 int retval, cmd;
3124 cmd = do_lock ? SCSI_IOCTL_DOORLOCK : SCSI_IOCTL_DOORUNLOCK;
3125 #if DEBUG
3126 printk(OSST_DEB_MSG "%s:D: %socking drive door.\n", tape_name(STp), do_lock ? "L" : "Unl");
3127 #endif
3128 retval = scsi_ioctl(STp->device, cmd, NULL);
3129 if (!retval) {
3130 STp->door_locked = do_lock ? ST_LOCKED_EXPLICIT : ST_UNLOCKED;
3132 else {
3133 STp->door_locked = ST_LOCK_FAILS;
3135 return retval;
3138 /* Set the internal state after reset */
3139 static void reset_state(OS_Scsi_Tape *STp)
3141 int i;
3142 ST_partstat *STps;
3144 STp->pos_unknown = 0;
3145 for (i = 0; i < ST_NBR_PARTITIONS; i++) {
3146 STps = &(STp->ps[i]);
3147 STps->rw = ST_IDLE;
3148 STps->eof = ST_NOEOF;
3149 STps->at_sm = 0;
3150 STps->last_block_valid = FALSE;
3151 STps->drv_block = -1;
3152 STps->drv_file = -1;
3157 /* Entry points to osst */
3159 /* Write command */
3160 static ssize_t osst_write(struct file * filp, const char __user * buf, size_t count, loff_t *ppos)
3162 ssize_t total, retval = 0;
3163 ssize_t i, do_count, blks, transfer;
3164 int write_threshold;
3165 int doing_write = 0;
3166 const char __user * b_point;
3167 Scsi_Request * SRpnt = NULL;
3168 ST_mode * STm;
3169 ST_partstat * STps;
3170 OS_Scsi_Tape * STp = filp->private_data;
3171 char * name = tape_name(STp);
3174 if (down_interruptible(&STp->lock))
3175 return (-ERESTARTSYS);
3178 * If we are in the middle of error recovery, don't let anyone
3179 * else try and use this device. Also, if error recovery fails, it
3180 * may try and take the device offline, in which case all further
3181 * access to the device is prohibited.
3183 if( !scsi_block_when_processing_errors(STp->device) ) {
3184 retval = (-ENXIO);
3185 goto out;
3188 if (STp->ready != ST_READY) {
3189 if (STp->ready == ST_NO_TAPE)
3190 retval = (-ENOMEDIUM);
3191 else
3192 retval = (-EIO);
3193 goto out;
3195 STm = &(STp->modes[STp->current_mode]);
3196 if (!STm->defined) {
3197 retval = (-ENXIO);
3198 goto out;
3200 if (count == 0)
3201 goto out;
3204 * If there was a bus reset, block further access
3205 * to this device.
3207 if (STp->pos_unknown) {
3208 retval = (-EIO);
3209 goto out;
3212 #if DEBUG
3213 if (!STp->in_use) {
3214 printk(OSST_DEB_MSG "%s:D: Incorrect device.\n", name);
3215 retval = (-EIO);
3216 goto out;
3218 #endif
3220 if (STp->write_prot) {
3221 retval = (-EACCES);
3222 goto out;
3225 /* Write must be integral number of blocks */
3226 if (STp->block_size != 0 && (count % STp->block_size) != 0) {
3227 printk(KERN_ERR "%s:E: Write (%Zd bytes) not multiple of tape block size (%d%c).\n",
3228 name, count, STp->block_size<1024?
3229 STp->block_size:STp->block_size/1024, STp->block_size<1024?'b':'k');
3230 retval = (-EINVAL);
3231 goto out;
3234 if (STp->first_frame_position >= STp->capacity - OSST_EOM_RESERVE) {
3235 printk(KERN_ERR "%s:E: Write truncated at EOM early warning (frame %d).\n",
3236 name, STp->first_frame_position);
3237 retval = (-ENOSPC);
3238 goto out;
3241 if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED && !do_door_lock(STp, 1))
3242 STp->door_locked = ST_LOCKED_AUTO;
3244 STps = &(STp->ps[STp->partition]);
3246 if (STps->rw == ST_READING) {
3247 #if DEBUG
3248 printk(OSST_DEB_MSG "%s:D: Switching from read to write at file %d, block %d\n", name,
3249 STps->drv_file, STps->drv_block);
3250 #endif
3251 retval = osst_flush_buffer(STp, &SRpnt, 0);
3252 if (retval)
3253 goto out;
3254 STps->rw = ST_IDLE;
3256 if (STps->rw != ST_WRITING) {
3257 /* Are we totally rewriting this tape? */
3258 if (!STp->header_ok ||
3259 (STp->first_frame_position == STp->first_data_ppos && STps->drv_block < 0) ||
3260 (STps->drv_file == 0 && STps->drv_block == 0)) {
3261 STp->wrt_pass_cntr++;
3262 #if DEBUG
3263 printk(OSST_DEB_MSG "%s:D: Allocating next write pass counter: %d\n",
3264 name, STp->wrt_pass_cntr);
3265 #endif
3266 osst_reset_header(STp, &SRpnt);
3267 STps->drv_file = STps->drv_block = 0;
3269 /* Do we know where we'll be writing on the tape? */
3270 else {
3271 if ((STp->fast_open && osst_verify_position(STp, &SRpnt)) ||
3272 STps->drv_file < 0 || STps->drv_block < 0) {
3273 if (STp->first_frame_position == STp->eod_frame_ppos) { /* at EOD */
3274 STps->drv_file = STp->filemark_cnt;
3275 STps->drv_block = 0;
3277 else {
3278 /* We have no idea where the tape is positioned - give up */
3279 #if DEBUG
3280 printk(OSST_DEB_MSG
3281 "%s:D: Cannot write at indeterminate position.\n", name);
3282 #endif
3283 retval = (-EIO);
3284 goto out;
3287 if ((STps->drv_file + STps->drv_block) > 0 && STps->drv_file < STp->filemark_cnt) {
3288 STp->filemark_cnt = STps->drv_file;
3289 STp->last_mark_ppos =
3290 ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[STp->filemark_cnt-1]);
3291 printk(KERN_WARNING
3292 "%s:W: Overwriting file %d with old write pass counter %d\n",
3293 name, STps->drv_file, STp->wrt_pass_cntr);
3294 printk(KERN_WARNING
3295 "%s:W: may lead to stale data being accepted on reading back!\n",
3296 name);
3297 #if DEBUG
3298 printk(OSST_DEB_MSG
3299 "%s:D: resetting filemark count to %d and last mark ppos,lbn to %d,%d\n",
3300 name, STp->filemark_cnt, STp->last_mark_ppos, STp->last_mark_lbn);
3301 #endif
3304 STp->fast_open = FALSE;
3306 if (!STp->header_ok) {
3307 #if DEBUG
3308 printk(OSST_DEB_MSG "%s:D: Write cannot proceed without valid headers\n", name);
3309 #endif
3310 retval = (-EIO);
3311 goto out;
3314 if ((STp->buffer)->writing) {
3315 if (SRpnt) printk(KERN_ERR "%s:A: Not supposed to have SRpnt at line %d\n", name, __LINE__);
3316 osst_write_behind_check(STp);
3317 if ((STp->buffer)->syscall_result) {
3318 #if DEBUG
3319 if (debugging)
3320 printk(OSST_DEB_MSG "%s:D: Async write error (write) %x.\n", name,
3321 (STp->buffer)->midlevel_result);
3322 #endif
3323 if ((STp->buffer)->midlevel_result == INT_MAX)
3324 STps->eof = ST_EOM_OK;
3325 else
3326 STps->eof = ST_EOM_ERROR;
3329 if (STps->eof == ST_EOM_OK) {
3330 retval = (-ENOSPC);
3331 goto out;
3333 else if (STps->eof == ST_EOM_ERROR) {
3334 retval = (-EIO);
3335 goto out;
3338 /* Check the buffer readability in cases where copy_user might catch
3339 the problems after some tape movement. */
3340 if ((copy_from_user(&i, buf, 1) != 0 ||
3341 copy_from_user(&i, buf + count - 1, 1) != 0)) {
3342 retval = (-EFAULT);
3343 goto out;
3346 if (!STm->do_buffer_writes) {
3347 write_threshold = 1;
3349 else
3350 write_threshold = (STp->buffer)->buffer_blocks * STp->block_size;
3351 if (!STm->do_async_writes)
3352 write_threshold--;
3354 total = count;
3355 #if DEBUG
3356 if (debugging)
3357 printk(OSST_DEB_MSG "%s:D: Writing %d bytes to file %d block %d lblk %d fseq %d fppos %d\n",
3358 name, count, STps->drv_file, STps->drv_block,
3359 STp->logical_blk_num, STp->frame_seq_number, STp->first_frame_position);
3360 #endif
3361 b_point = buf;
3362 while ((STp->buffer)->buffer_bytes + count > write_threshold)
3364 doing_write = 1;
3365 do_count = (STp->buffer)->buffer_blocks * STp->block_size -
3366 (STp->buffer)->buffer_bytes;
3367 if (do_count > count)
3368 do_count = count;
3370 i = append_to_buffer(b_point, STp->buffer, do_count);
3371 if (i) {
3372 retval = i;
3373 goto out;
3376 blks = do_count / STp->block_size;
3377 STp->logical_blk_num += blks; /* logical_blk_num is incremented as data is moved from user */
3379 i = osst_write_frame(STp, &SRpnt, TRUE);
3381 if (i == (-ENOSPC)) {
3382 transfer = STp->buffer->writing; /* FIXME -- check this logic */
3383 if (transfer <= do_count) {
3384 filp->f_pos += do_count - transfer;
3385 count -= do_count - transfer;
3386 if (STps->drv_block >= 0) {
3387 STps->drv_block += (do_count - transfer) / STp->block_size;
3389 STps->eof = ST_EOM_OK;
3390 retval = (-ENOSPC); /* EOM within current request */
3391 #if DEBUG
3392 if (debugging)
3393 printk(OSST_DEB_MSG "%s:D: EOM with %d bytes unwritten.\n",
3394 name, transfer);
3395 #endif
3397 else {
3398 STps->eof = ST_EOM_ERROR;
3399 STps->drv_block = (-1); /* Too cautious? */
3400 retval = (-EIO); /* EOM for old data */
3401 #if DEBUG
3402 if (debugging)
3403 printk(OSST_DEB_MSG "%s:D: EOM with lost data.\n", name);
3404 #endif
3407 else
3408 retval = i;
3410 if (retval < 0) {
3411 if (SRpnt != NULL) {
3412 scsi_release_request(SRpnt);
3413 SRpnt = NULL;
3415 STp->buffer->buffer_bytes = 0;
3416 STp->dirty = 0;
3417 if (count < total)
3418 retval = total - count;
3419 goto out;
3422 filp->f_pos += do_count;
3423 b_point += do_count;
3424 count -= do_count;
3425 if (STps->drv_block >= 0) {
3426 STps->drv_block += blks;
3428 STp->buffer->buffer_bytes = 0;
3429 STp->dirty = 0;
3430 } /* end while write threshold exceeded */
3432 if (count != 0) {
3433 STp->dirty = 1;
3434 i = append_to_buffer(b_point, STp->buffer, count);
3435 if (i) {
3436 retval = i;
3437 goto out;
3439 blks = count / STp->block_size;
3440 STp->logical_blk_num += blks;
3441 if (STps->drv_block >= 0) {
3442 STps->drv_block += blks;
3444 filp->f_pos += count;
3445 count = 0;
3448 if (doing_write && (STp->buffer)->syscall_result != 0) {
3449 retval = (STp->buffer)->syscall_result;
3450 goto out;
3453 if (STm->do_async_writes && ((STp->buffer)->buffer_bytes >= STp->write_threshold)) {
3454 /* Schedule an asynchronous write */
3455 (STp->buffer)->writing = ((STp->buffer)->buffer_bytes /
3456 STp->block_size) * STp->block_size;
3457 STp->dirty = !((STp->buffer)->writing ==
3458 (STp->buffer)->buffer_bytes);
3460 i = osst_write_frame(STp, &SRpnt, FALSE);
3461 if (i < 0) {
3462 retval = (-EIO);
3463 goto out;
3465 SRpnt = NULL; /* Prevent releasing this request! */
3467 STps->at_sm &= (total == 0);
3468 if (total > 0)
3469 STps->eof = ST_NOEOF;
3471 retval = total;
3473 out:
3474 if (SRpnt != NULL) scsi_release_request(SRpnt);
3476 up(&STp->lock);
3478 return retval;
3482 /* Read command */
3483 static ssize_t osst_read(struct file * filp, char __user * buf, size_t count, loff_t *ppos)
3485 ssize_t total, retval = 0;
3486 ssize_t i, transfer;
3487 int special;
3488 ST_mode * STm;
3489 ST_partstat * STps;
3490 Scsi_Request * SRpnt = NULL;
3491 OS_Scsi_Tape * STp = filp->private_data;
3492 char * name = tape_name(STp);
3495 if (down_interruptible(&STp->lock))
3496 return (-ERESTARTSYS);
3499 * If we are in the middle of error recovery, don't let anyone
3500 * else try and use this device. Also, if error recovery fails, it
3501 * may try and take the device offline, in which case all further
3502 * access to the device is prohibited.
3504 if( !scsi_block_when_processing_errors(STp->device) ) {
3505 retval = (-ENXIO);
3506 goto out;
3509 if (STp->ready != ST_READY) {
3510 if (STp->ready == ST_NO_TAPE)
3511 retval = (-ENOMEDIUM);
3512 else
3513 retval = (-EIO);
3514 goto out;
3516 STm = &(STp->modes[STp->current_mode]);
3517 if (!STm->defined) {
3518 retval = (-ENXIO);
3519 goto out;
3521 #if DEBUG
3522 if (!STp->in_use) {
3523 printk(OSST_DEB_MSG "%s:D: Incorrect device.\n", name);
3524 retval = (-EIO);
3525 goto out;
3527 #endif
3528 /* Must have initialized medium */
3529 if (!STp->header_ok) {
3530 retval = (-EIO);
3531 goto out;
3534 if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED && !do_door_lock(STp, 1))
3535 STp->door_locked = ST_LOCKED_AUTO;
3537 STps = &(STp->ps[STp->partition]);
3538 if (STps->rw == ST_WRITING) {
3539 retval = osst_flush_buffer(STp, &SRpnt, 0);
3540 if (retval)
3541 goto out;
3542 STps->rw = ST_IDLE;
3543 /* FIXME -- this may leave the tape without EOD and up2date headers */
3546 if ((count % STp->block_size) != 0) {
3547 printk(KERN_WARNING
3548 "%s:W: Read (%Zd bytes) not multiple of tape block size (%d%c).\n", name, count,
3549 STp->block_size<1024?STp->block_size:STp->block_size/1024, STp->block_size<1024?'b':'k');
3552 #if DEBUG
3553 if (debugging && STps->eof != ST_NOEOF)
3554 printk(OSST_DEB_MSG "%s:D: EOF/EOM flag up (%d). Bytes %d\n", name,
3555 STps->eof, (STp->buffer)->buffer_bytes);
3556 #endif
3557 if ((STp->buffer)->buffer_bytes == 0 &&
3558 STps->eof >= ST_EOD_1) {
3559 if (STps->eof < ST_EOD) {
3560 STps->eof += 1;
3561 retval = 0;
3562 goto out;
3564 retval = (-EIO); /* EOM or Blank Check */
3565 goto out;
3568 /* Check the buffer writability before any tape movement. Don't alter
3569 buffer data. */
3570 if (copy_from_user(&i, buf, 1) != 0 ||
3571 copy_to_user (buf, &i, 1) != 0 ||
3572 copy_from_user(&i, buf + count - 1, 1) != 0 ||
3573 copy_to_user (buf + count - 1, &i, 1) != 0) {
3574 retval = (-EFAULT);
3575 goto out;
3578 /* Loop until enough data in buffer or a special condition found */
3579 for (total = 0, special = 0; total < count - STp->block_size + 1 && !special; ) {
3581 /* Get new data if the buffer is empty */
3582 if ((STp->buffer)->buffer_bytes == 0) {
3583 if (STps->eof == ST_FM_HIT)
3584 break;
3585 special = osst_get_logical_frame(STp, &SRpnt, STp->frame_seq_number, 0);
3586 if (special < 0) { /* No need to continue read */
3587 STp->frame_in_buffer = 0;
3588 retval = special;
3589 goto out;
3593 /* Move the data from driver buffer to user buffer */
3594 if ((STp->buffer)->buffer_bytes > 0) {
3595 #if DEBUG
3596 if (debugging && STps->eof != ST_NOEOF)
3597 printk(OSST_DEB_MSG "%s:D: EOF up (%d). Left %d, needed %d.\n", name,
3598 STps->eof, (STp->buffer)->buffer_bytes, count - total);
3599 #endif
3600 /* force multiple of block size, note block_size may have been adjusted */
3601 transfer = (((STp->buffer)->buffer_bytes < count - total ?
3602 (STp->buffer)->buffer_bytes : count - total)/
3603 STp->block_size) * STp->block_size;
3605 if (transfer == 0) {
3606 printk(KERN_WARNING
3607 "%s:W: Nothing can be transfered, requested %Zd, tape block size (%d%c).\n",
3608 name, count, STp->block_size < 1024?
3609 STp->block_size:STp->block_size/1024,
3610 STp->block_size<1024?'b':'k');
3611 break;
3613 i = from_buffer(STp->buffer, buf, transfer);
3614 if (i) {
3615 retval = i;
3616 goto out;
3618 STp->logical_blk_num += transfer / STp->block_size;
3619 STps->drv_block += transfer / STp->block_size;
3620 filp->f_pos += transfer;
3621 buf += transfer;
3622 total += transfer;
3625 if ((STp->buffer)->buffer_bytes == 0) {
3626 #if DEBUG
3627 if (debugging)
3628 printk(OSST_DEB_MSG "%s:D: Finished with frame %d\n",
3629 name, STp->frame_seq_number);
3630 #endif
3631 STp->frame_in_buffer = 0;
3632 STp->frame_seq_number++; /* frame to look for next time */
3634 } /* for (total = 0, special = 0; total < count && !special; ) */
3636 /* Change the eof state if no data from tape or buffer */
3637 if (total == 0) {
3638 if (STps->eof == ST_FM_HIT) {
3639 STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD_2:ST_FM;
3640 STps->drv_block = 0;
3641 if (STps->drv_file >= 0)
3642 STps->drv_file++;
3644 else if (STps->eof == ST_EOD_1) {
3645 STps->eof = ST_EOD_2;
3646 if (STps->drv_block > 0 && STps->drv_file >= 0)
3647 STps->drv_file++;
3648 STps->drv_block = 0;
3650 else if (STps->eof == ST_EOD_2)
3651 STps->eof = ST_EOD;
3653 else if (STps->eof == ST_FM)
3654 STps->eof = ST_NOEOF;
3656 retval = total;
3658 out:
3659 if (SRpnt != NULL) scsi_release_request(SRpnt);
3661 up(&STp->lock);
3663 return retval;
3667 /* Set the driver options */
3668 static void osst_log_options(OS_Scsi_Tape *STp, ST_mode *STm, char *name)
3670 printk(KERN_INFO
3671 "%s:I: Mode %d options: buffer writes: %d, async writes: %d, read ahead: %d\n",
3672 name, STp->current_mode, STm->do_buffer_writes, STm->do_async_writes,
3673 STm->do_read_ahead);
3674 printk(KERN_INFO
3675 "%s:I: can bsr: %d, two FMs: %d, fast mteom: %d, auto lock: %d,\n",
3676 name, STp->can_bsr, STp->two_fm, STp->fast_mteom, STp->do_auto_lock);
3677 printk(KERN_INFO
3678 "%s:I: defs for wr: %d, no block limits: %d, partitions: %d, s2 log: %d\n",
3679 name, STm->defaults_for_writes, STp->omit_blklims, STp->can_partitions,
3680 STp->scsi2_logical);
3681 printk(KERN_INFO
3682 "%s:I: sysv: %d\n", name, STm->sysv);
3683 #if DEBUG
3684 printk(KERN_INFO
3685 "%s:D: debugging: %d\n",
3686 name, debugging);
3687 #endif
3691 static int osst_set_options(OS_Scsi_Tape *STp, long options)
3693 int value;
3694 long code;
3695 ST_mode * STm;
3696 char * name = tape_name(STp);
3698 STm = &(STp->modes[STp->current_mode]);
3699 if (!STm->defined) {
3700 memcpy(STm, &(STp->modes[0]), sizeof(ST_mode));
3701 modes_defined = TRUE;
3702 #if DEBUG
3703 if (debugging)
3704 printk(OSST_DEB_MSG "%s:D: Initialized mode %d definition from mode 0\n",
3705 name, STp->current_mode);
3706 #endif
3709 code = options & MT_ST_OPTIONS;
3710 if (code == MT_ST_BOOLEANS) {
3711 STm->do_buffer_writes = (options & MT_ST_BUFFER_WRITES) != 0;
3712 STm->do_async_writes = (options & MT_ST_ASYNC_WRITES) != 0;
3713 STm->defaults_for_writes = (options & MT_ST_DEF_WRITES) != 0;
3714 STm->do_read_ahead = (options & MT_ST_READ_AHEAD) != 0;
3715 STp->two_fm = (options & MT_ST_TWO_FM) != 0;
3716 STp->fast_mteom = (options & MT_ST_FAST_MTEOM) != 0;
3717 STp->do_auto_lock = (options & MT_ST_AUTO_LOCK) != 0;
3718 STp->can_bsr = (options & MT_ST_CAN_BSR) != 0;
3719 STp->omit_blklims = (options & MT_ST_NO_BLKLIMS) != 0;
3720 if ((STp->device)->scsi_level >= SCSI_2)
3721 STp->can_partitions = (options & MT_ST_CAN_PARTITIONS) != 0;
3722 STp->scsi2_logical = (options & MT_ST_SCSI2LOGICAL) != 0;
3723 STm->sysv = (options & MT_ST_SYSV) != 0;
3724 #if DEBUG
3725 debugging = (options & MT_ST_DEBUGGING) != 0;
3726 #endif
3727 osst_log_options(STp, STm, name);
3729 else if (code == MT_ST_SETBOOLEANS || code == MT_ST_CLEARBOOLEANS) {
3730 value = (code == MT_ST_SETBOOLEANS);
3731 if ((options & MT_ST_BUFFER_WRITES) != 0)
3732 STm->do_buffer_writes = value;
3733 if ((options & MT_ST_ASYNC_WRITES) != 0)
3734 STm->do_async_writes = value;
3735 if ((options & MT_ST_DEF_WRITES) != 0)
3736 STm->defaults_for_writes = value;
3737 if ((options & MT_ST_READ_AHEAD) != 0)
3738 STm->do_read_ahead = value;
3739 if ((options & MT_ST_TWO_FM) != 0)
3740 STp->two_fm = value;
3741 if ((options & MT_ST_FAST_MTEOM) != 0)
3742 STp->fast_mteom = value;
3743 if ((options & MT_ST_AUTO_LOCK) != 0)
3744 STp->do_auto_lock = value;
3745 if ((options & MT_ST_CAN_BSR) != 0)
3746 STp->can_bsr = value;
3747 if ((options & MT_ST_NO_BLKLIMS) != 0)
3748 STp->omit_blklims = value;
3749 if ((STp->device)->scsi_level >= SCSI_2 &&
3750 (options & MT_ST_CAN_PARTITIONS) != 0)
3751 STp->can_partitions = value;
3752 if ((options & MT_ST_SCSI2LOGICAL) != 0)
3753 STp->scsi2_logical = value;
3754 if ((options & MT_ST_SYSV) != 0)
3755 STm->sysv = value;
3756 #if DEBUG
3757 if ((options & MT_ST_DEBUGGING) != 0)
3758 debugging = value;
3759 #endif
3760 osst_log_options(STp, STm, name);
3762 else if (code == MT_ST_WRITE_THRESHOLD) {
3763 value = (options & ~MT_ST_OPTIONS) * ST_KILOBYTE;
3764 if (value < 1 || value > osst_buffer_size) {
3765 printk(KERN_WARNING "%s:W: Write threshold %d too small or too large.\n",
3766 name, value);
3767 return (-EIO);
3769 STp->write_threshold = value;
3770 printk(KERN_INFO "%s:I: Write threshold set to %d bytes.\n",
3771 name, value);
3773 else if (code == MT_ST_DEF_BLKSIZE) {
3774 value = (options & ~MT_ST_OPTIONS);
3775 if (value == ~MT_ST_OPTIONS) {
3776 STm->default_blksize = (-1);
3777 printk(KERN_INFO "%s:I: Default block size disabled.\n", name);
3779 else {
3780 if (value < 512 || value > OS_DATA_SIZE || OS_DATA_SIZE % value) {
3781 printk(KERN_WARNING "%s:W: Default block size cannot be set to %d.\n",
3782 name, value);
3783 return (-EINVAL);
3785 STm->default_blksize = value;
3786 printk(KERN_INFO "%s:I: Default block size set to %d bytes.\n",
3787 name, STm->default_blksize);
3790 else if (code == MT_ST_TIMEOUTS) {
3791 value = (options & ~MT_ST_OPTIONS);
3792 if ((value & MT_ST_SET_LONG_TIMEOUT) != 0) {
3793 STp->long_timeout = (value & ~MT_ST_SET_LONG_TIMEOUT) * HZ;
3794 printk(KERN_INFO "%s:I: Long timeout set to %d seconds.\n", name,
3795 (value & ~MT_ST_SET_LONG_TIMEOUT));
3797 else {
3798 STp->timeout = value * HZ;
3799 printk(KERN_INFO "%s:I: Normal timeout set to %d seconds.\n", name, value);
3802 else if (code == MT_ST_DEF_OPTIONS) {
3803 code = (options & ~MT_ST_CLEAR_DEFAULT);
3804 value = (options & MT_ST_CLEAR_DEFAULT);
3805 if (code == MT_ST_DEF_DENSITY) {
3806 if (value == MT_ST_CLEAR_DEFAULT) {
3807 STm->default_density = (-1);
3808 printk(KERN_INFO "%s:I: Density default disabled.\n", name);
3810 else {
3811 STm->default_density = value & 0xff;
3812 printk(KERN_INFO "%s:I: Density default set to %x\n",
3813 name, STm->default_density);
3816 else if (code == MT_ST_DEF_DRVBUFFER) {
3817 if (value == MT_ST_CLEAR_DEFAULT) {
3818 STp->default_drvbuffer = 0xff;
3819 printk(KERN_INFO "%s:I: Drive buffer default disabled.\n", name);
3821 else {
3822 STp->default_drvbuffer = value & 7;
3823 printk(KERN_INFO "%s:I: Drive buffer default set to %x\n",
3824 name, STp->default_drvbuffer);
3827 else if (code == MT_ST_DEF_COMPRESSION) {
3828 if (value == MT_ST_CLEAR_DEFAULT) {
3829 STm->default_compression = ST_DONT_TOUCH;
3830 printk(KERN_INFO "%s:I: Compression default disabled.\n", name);
3832 else {
3833 STm->default_compression = (value & 1 ? ST_YES : ST_NO);
3834 printk(KERN_INFO "%s:I: Compression default set to %x\n",
3835 name, (value & 1));
3839 else
3840 return (-EIO);
3842 return 0;
3846 /* Internal ioctl function */
3847 static int osst_int_ioctl(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, unsigned int cmd_in, unsigned long arg)
3849 int timeout;
3850 long ltmp;
3851 int i, ioctl_result;
3852 int chg_eof = TRUE;
3853 unsigned char cmd[MAX_COMMAND_SIZE];
3854 Scsi_Request * SRpnt = * aSRpnt;
3855 ST_partstat * STps;
3856 int fileno, blkno, at_sm, frame_seq_numbr, logical_blk_num;
3857 int datalen = 0, direction = SCSI_DATA_NONE;
3858 char * name = tape_name(STp);
3860 if (STp->ready != ST_READY && cmd_in != MTLOAD) {
3861 if (STp->ready == ST_NO_TAPE)
3862 return (-ENOMEDIUM);
3863 else
3864 return (-EIO);
3866 timeout = STp->long_timeout;
3867 STps = &(STp->ps[STp->partition]);
3868 fileno = STps->drv_file;
3869 blkno = STps->drv_block;
3870 at_sm = STps->at_sm;
3871 frame_seq_numbr = STp->frame_seq_number;
3872 logical_blk_num = STp->logical_blk_num;
3874 memset(cmd, 0, MAX_COMMAND_SIZE);
3875 switch (cmd_in) {
3876 case MTFSFM:
3877 chg_eof = FALSE; /* Changed from the FSF after this */
3878 case MTFSF:
3879 if (STp->raw)
3880 return (-EIO);
3881 if (STp->linux_media)
3882 ioctl_result = osst_space_over_filemarks_forward_fast(STp, &SRpnt, cmd_in, arg);
3883 else
3884 ioctl_result = osst_space_over_filemarks_forward_slow(STp, &SRpnt, cmd_in, arg);
3885 if (fileno >= 0)
3886 fileno += arg;
3887 blkno = 0;
3888 at_sm &= (arg == 0);
3889 goto os_bypass;
3891 case MTBSF:
3892 chg_eof = FALSE; /* Changed from the FSF after this */
3893 case MTBSFM:
3894 if (STp->raw)
3895 return (-EIO);
3896 ioctl_result = osst_space_over_filemarks_backward(STp, &SRpnt, cmd_in, arg);
3897 if (fileno >= 0)
3898 fileno -= arg;
3899 blkno = (-1); /* We can't know the block number */
3900 at_sm &= (arg == 0);
3901 goto os_bypass;
3903 case MTFSR:
3904 case MTBSR:
3905 #if DEBUG
3906 if (debugging)
3907 printk(OSST_DEB_MSG "%s:D: Skipping %lu blocks %s from logical block %d\n",
3908 name, arg, cmd_in==MTFSR?"forward":"backward", logical_blk_num);
3909 #endif
3910 if (cmd_in == MTFSR) {
3911 logical_blk_num += arg;
3912 if (blkno >= 0) blkno += arg;
3914 else {
3915 logical_blk_num -= arg;
3916 if (blkno >= 0) blkno -= arg;
3918 ioctl_result = osst_seek_logical_blk(STp, &SRpnt, logical_blk_num);
3919 fileno = STps->drv_file;
3920 blkno = STps->drv_block;
3921 at_sm &= (arg == 0);
3922 goto os_bypass;
3924 case MTFSS:
3925 cmd[0] = SPACE;
3926 cmd[1] = 0x04; /* Space Setmarks */ /* FIXME -- OS can't do this? */
3927 cmd[2] = (arg >> 16);
3928 cmd[3] = (arg >> 8);
3929 cmd[4] = arg;
3930 #if DEBUG
3931 if (debugging)
3932 printk(OSST_DEB_MSG "%s:D: Spacing tape forward %d setmarks.\n", name,
3933 cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
3934 #endif
3935 if (arg != 0) {
3936 blkno = fileno = (-1);
3937 at_sm = 1;
3939 break;
3940 case MTBSS:
3941 cmd[0] = SPACE;
3942 cmd[1] = 0x04; /* Space Setmarks */ /* FIXME -- OS can't do this? */
3943 ltmp = (-arg);
3944 cmd[2] = (ltmp >> 16);
3945 cmd[3] = (ltmp >> 8);
3946 cmd[4] = ltmp;
3947 #if DEBUG
3948 if (debugging) {
3949 if (cmd[2] & 0x80)
3950 ltmp = 0xff000000;
3951 ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4];
3952 printk(OSST_DEB_MSG "%s:D: Spacing tape backward %ld setmarks.\n",
3953 name, (-ltmp));
3955 #endif
3956 if (arg != 0) {
3957 blkno = fileno = (-1);
3958 at_sm = 1;
3960 break;
3961 case MTWEOF:
3962 if ((STps->rw == ST_WRITING || STp->dirty) && !STp->pos_unknown) {
3963 STp->write_type = OS_WRITE_DATA;
3964 ioctl_result = osst_flush_write_buffer(STp, &SRpnt);
3965 } else
3966 ioctl_result = 0;
3967 #if DEBUG
3968 if (debugging)
3969 printk(OSST_DEB_MSG "%s:D: Writing %ld filemark(s).\n", name, arg);
3970 #endif
3971 for (i=0; i<arg; i++)
3972 ioctl_result |= osst_write_filemark(STp, &SRpnt);
3973 if (fileno >= 0) fileno += arg;
3974 if (blkno >= 0) blkno = 0;
3975 goto os_bypass;
3977 case MTWSM:
3978 if (STp->write_prot)
3979 return (-EACCES);
3980 if (!STp->raw)
3981 return 0;
3982 cmd[0] = WRITE_FILEMARKS; /* FIXME -- need OS version */
3983 if (cmd_in == MTWSM)
3984 cmd[1] = 2;
3985 cmd[2] = (arg >> 16);
3986 cmd[3] = (arg >> 8);
3987 cmd[4] = arg;
3988 timeout = STp->timeout;
3989 #if DEBUG
3990 if (debugging)
3991 printk(OSST_DEB_MSG "%s:D: Writing %d setmark(s).\n", name,
3992 cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
3993 #endif
3994 if (fileno >= 0)
3995 fileno += arg;
3996 blkno = 0;
3997 at_sm = (cmd_in == MTWSM);
3998 break;
3999 case MTOFFL:
4000 case MTLOAD:
4001 case MTUNLOAD:
4002 case MTRETEN:
4003 cmd[0] = START_STOP;
4004 cmd[1] = 1; /* Don't wait for completion */
4005 if (cmd_in == MTLOAD) {
4006 if (STp->ready == ST_NO_TAPE)
4007 cmd[4] = 4; /* open tray */
4008 else
4009 cmd[4] = 1; /* load */
4011 if (cmd_in == MTRETEN)
4012 cmd[4] = 3; /* retension then mount */
4013 if (cmd_in == MTOFFL)
4014 cmd[4] = 4; /* rewind then eject */
4015 timeout = STp->timeout;
4016 #if DEBUG
4017 if (debugging) {
4018 switch (cmd_in) {
4019 case MTUNLOAD:
4020 printk(OSST_DEB_MSG "%s:D: Unloading tape.\n", name);
4021 break;
4022 case MTLOAD:
4023 printk(OSST_DEB_MSG "%s:D: Loading tape.\n", name);
4024 break;
4025 case MTRETEN:
4026 printk(OSST_DEB_MSG "%s:D: Retensioning tape.\n", name);
4027 break;
4028 case MTOFFL:
4029 printk(OSST_DEB_MSG "%s:D: Ejecting tape.\n", name);
4030 break;
4033 #endif
4034 fileno = blkno = at_sm = frame_seq_numbr = logical_blk_num = 0 ;
4035 break;
4036 case MTNOP:
4037 #if DEBUG
4038 if (debugging)
4039 printk(OSST_DEB_MSG "%s:D: No-op on tape.\n", name);
4040 #endif
4041 return 0; /* Should do something ? */
4042 break;
4043 case MTEOM:
4044 #if DEBUG
4045 if (debugging)
4046 printk(OSST_DEB_MSG "%s:D: Spacing to end of recorded medium.\n", name);
4047 #endif
4048 if ((osst_position_tape_and_confirm(STp, &SRpnt, STp->eod_frame_ppos) < 0) ||
4049 (osst_get_logical_frame(STp, &SRpnt, -1, 0) < 0)) {
4050 ioctl_result = -EIO;
4051 goto os_bypass;
4053 if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_EOD) {
4054 #if DEBUG
4055 printk(OSST_DEB_MSG "%s:D: No EOD frame found where expected.\n", name);
4056 #endif
4057 ioctl_result = -EIO;
4058 goto os_bypass;
4060 ioctl_result = osst_set_frame_position(STp, &SRpnt, STp->eod_frame_ppos, 0);
4061 fileno = STp->filemark_cnt;
4062 blkno = at_sm = 0;
4063 goto os_bypass;
4065 case MTERASE:
4066 if (STp->write_prot)
4067 return (-EACCES);
4068 ioctl_result = osst_reset_header(STp, &SRpnt);
4069 i = osst_write_eod(STp, &SRpnt);
4070 if (i < ioctl_result) ioctl_result = i;
4071 i = osst_position_tape_and_confirm(STp, &SRpnt, STp->eod_frame_ppos);
4072 if (i < ioctl_result) ioctl_result = i;
4073 fileno = blkno = at_sm = 0 ;
4074 goto os_bypass;
4076 case MTREW:
4077 cmd[0] = REZERO_UNIT; /* rewind */
4078 cmd[1] = 1;
4079 #if DEBUG
4080 if (debugging)
4081 printk(OSST_DEB_MSG "%s:D: Rewinding tape, Immed=%d.\n", name, cmd[1]);
4082 #endif
4083 fileno = blkno = at_sm = frame_seq_numbr = logical_blk_num = 0 ;
4084 break;
4086 case MTSETBLK: /* Set block length */
4087 if ((STps->drv_block == 0 ) &&
4088 !STp->dirty &&
4089 ((STp->buffer)->buffer_bytes == 0) &&
4090 ((arg & MT_ST_BLKSIZE_MASK) >= 512 ) &&
4091 ((arg & MT_ST_BLKSIZE_MASK) <= OS_DATA_SIZE) &&
4092 !(OS_DATA_SIZE % (arg & MT_ST_BLKSIZE_MASK)) ) {
4094 * Only allowed to change the block size if you opened the
4095 * device at the beginning of a file before writing anything.
4096 * Note, that when reading, changing block_size is futile,
4097 * as the size used when writing overrides it.
4099 STp->block_size = (arg & MT_ST_BLKSIZE_MASK);
4100 printk(KERN_INFO "%s:I: Block size set to %d bytes.\n",
4101 name, STp->block_size);
4102 return 0;
4104 case MTSETDENSITY: /* Set tape density */
4105 case MTSETDRVBUFFER: /* Set drive buffering */
4106 case SET_DENS_AND_BLK: /* Set density and block size */
4107 chg_eof = FALSE;
4108 if (STp->dirty || (STp->buffer)->buffer_bytes != 0)
4109 return (-EIO); /* Not allowed if data in buffer */
4110 if ((cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) &&
4111 (arg & MT_ST_BLKSIZE_MASK) != 0 &&
4112 (arg & MT_ST_BLKSIZE_MASK) != STp->block_size ) {
4113 printk(KERN_WARNING "%s:W: Illegal to set block size to %d%s.\n",
4114 name, (int)(arg & MT_ST_BLKSIZE_MASK),
4115 (OS_DATA_SIZE % (arg & MT_ST_BLKSIZE_MASK))?"":" now");
4116 return (-EINVAL);
4118 return 0; /* FIXME silently ignore if block size didn't change */
4120 default:
4121 return (-ENOSYS);
4124 SRpnt = osst_do_scsi(SRpnt, STp, cmd, datalen, direction, timeout, MAX_RETRIES, TRUE);
4126 ioctl_result = (STp->buffer)->syscall_result;
4128 if (!SRpnt) {
4129 #if DEBUG
4130 printk(OSST_DEB_MSG "%s:D: Couldn't exec scsi cmd for IOCTL\n", name);
4131 #endif
4132 return ioctl_result;
4135 if (!ioctl_result) { /* SCSI command successful */
4136 STp->frame_seq_number = frame_seq_numbr;
4137 STp->logical_blk_num = logical_blk_num;
4140 os_bypass:
4141 #if DEBUG
4142 if (debugging)
4143 printk(OSST_DEB_MSG "%s:D: IOCTL (%d) Result=%d\n", name, cmd_in, ioctl_result);
4144 #endif
4146 if (!ioctl_result) { /* success */
4148 if (cmd_in == MTFSFM) {
4149 fileno--;
4150 blkno--;
4152 if (cmd_in == MTBSFM) {
4153 fileno++;
4154 blkno++;
4156 STps->drv_block = blkno;
4157 STps->drv_file = fileno;
4158 STps->at_sm = at_sm;
4160 if (cmd_in == MTEOM)
4161 STps->eof = ST_EOD;
4162 else if ((cmd_in == MTFSFM || cmd_in == MTBSF) && STps->eof == ST_FM_HIT) {
4163 ioctl_result = osst_seek_logical_blk(STp, &SRpnt, STp->logical_blk_num-1);
4164 STps->drv_block++;
4165 STp->logical_blk_num++;
4166 STp->frame_seq_number++;
4167 STp->frame_in_buffer = 0;
4168 STp->buffer->read_pointer = 0;
4170 else if (cmd_in == MTFSF)
4171 STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD:ST_FM;
4172 else if (chg_eof)
4173 STps->eof = ST_NOEOF;
4175 if (cmd_in == MTOFFL || cmd_in == MTUNLOAD)
4176 STp->rew_at_close = 0;
4177 else if (cmd_in == MTLOAD) {
4178 for (i=0; i < ST_NBR_PARTITIONS; i++) {
4179 STp->ps[i].rw = ST_IDLE;
4180 STp->ps[i].last_block_valid = FALSE;/* FIXME - where else is this field maintained? */
4182 STp->partition = 0;
4185 if (cmd_in == MTREW) {
4186 ioctl_result = osst_position_tape_and_confirm(STp, &SRpnt, STp->first_data_ppos);
4187 if (ioctl_result > 0)
4188 ioctl_result = 0;
4191 } else if (cmd_in == MTBSF || cmd_in == MTBSFM ) {
4192 if (osst_position_tape_and_confirm(STp, &SRpnt, STp->first_data_ppos) < 0)
4193 STps->drv_file = STps->drv_block = -1;
4194 else
4195 STps->drv_file = STps->drv_block = 0;
4196 STps->eof = ST_NOEOF;
4197 } else if (cmd_in == MTFSF || cmd_in == MTFSFM) {
4198 if (osst_position_tape_and_confirm(STp, &SRpnt, STp->eod_frame_ppos) < 0)
4199 STps->drv_file = STps->drv_block = -1;
4200 else {
4201 STps->drv_file = STp->filemark_cnt;
4202 STps->drv_block = 0;
4204 STps->eof = ST_EOD;
4205 } else if (cmd_in == MTBSR || cmd_in == MTFSR || cmd_in == MTWEOF || cmd_in == MTEOM) {
4206 STps->drv_file = STps->drv_block = (-1);
4207 STps->eof = ST_NOEOF;
4208 STp->header_ok = 0;
4209 } else if (cmd_in == MTERASE) {
4210 STp->header_ok = 0;
4211 } else if (SRpnt) { /* SCSI command was not completely successful. */
4212 if (SRpnt->sr_sense_buffer[2] & 0x40) {
4213 STps->eof = ST_EOM_OK;
4214 STps->drv_block = 0;
4216 if (chg_eof)
4217 STps->eof = ST_NOEOF;
4219 if ((SRpnt->sr_sense_buffer[2] & 0x0f) == BLANK_CHECK)
4220 STps->eof = ST_EOD;
4222 if (cmd_in == MTLOAD && osst_wait_for_medium(STp, &SRpnt, 60))
4223 ioctl_result = osst_wait_ready(STp, &SRpnt, 5 * 60, OSST_WAIT_POSITION_COMPLETE);
4225 *aSRpnt = SRpnt;
4227 return ioctl_result;
4231 /* Open the device */
4232 static int os_scsi_tape_open(struct inode * inode, struct file * filp)
4234 unsigned short flags;
4235 int i, b_size, new_session = FALSE, retval = 0;
4236 unsigned char cmd[MAX_COMMAND_SIZE];
4237 Scsi_Request * SRpnt = NULL;
4238 OS_Scsi_Tape * STp;
4239 ST_mode * STm;
4240 ST_partstat * STps;
4241 char * name;
4242 int dev = TAPE_NR(inode);
4243 int mode = TAPE_MODE(inode);
4245 nonseekable_open(inode, filp);
4246 write_lock(&os_scsi_tapes_lock);
4247 if (dev >= osst_max_dev || os_scsi_tapes == NULL ||
4248 (STp = os_scsi_tapes[dev]) == NULL || !STp->device) {
4249 write_unlock(&os_scsi_tapes_lock);
4250 return (-ENXIO);
4253 name = tape_name(STp);
4255 if (STp->in_use) {
4256 write_unlock(&os_scsi_tapes_lock);
4257 #if DEBUG
4258 printk(OSST_DEB_MSG "%s:D: Device already in use.\n", name);
4259 #endif
4260 return (-EBUSY);
4262 if (scsi_device_get(STp->device)) {
4263 write_unlock(&os_scsi_tapes_lock);
4264 #if DEBUG
4265 printk(OSST_DEB_MSG "%s:D: Failed scsi_device_get.\n", name);
4266 #endif
4267 return (-ENXIO);
4269 filp->private_data = STp;
4270 STp->in_use = 1;
4271 write_unlock(&os_scsi_tapes_lock);
4272 STp->rew_at_close = TAPE_REWIND(inode);
4274 if( !scsi_block_when_processing_errors(STp->device) ) {
4275 return -ENXIO;
4278 if (mode != STp->current_mode) {
4279 #if DEBUG
4280 if (debugging)
4281 printk(OSST_DEB_MSG "%s:D: Mode change from %d to %d.\n",
4282 name, STp->current_mode, mode);
4283 #endif
4284 new_session = TRUE;
4285 STp->current_mode = mode;
4287 STm = &(STp->modes[STp->current_mode]);
4289 flags = filp->f_flags;
4290 STp->write_prot = ((flags & O_ACCMODE) == O_RDONLY);
4292 STp->raw = TAPE_IS_RAW(inode);
4293 if (STp->raw)
4294 STp->header_ok = 0;
4296 /* Allocate data segments for this device's tape buffer */
4297 if (!enlarge_buffer(STp->buffer, STp->restr_dma)) {
4298 printk(KERN_ERR "%s:E: Unable to allocate memory segments for tape buffer.\n", name);
4299 retval = (-EOVERFLOW);
4300 goto err_out;
4302 if (STp->buffer->buffer_size >= OS_FRAME_SIZE) {
4303 for (i = 0, b_size = 0;
4304 (i < STp->buffer->sg_segs) && ((b_size + STp->buffer->sg[i].length) <= OS_DATA_SIZE);
4305 b_size += STp->buffer->sg[i++].length);
4306 STp->buffer->aux = (os_aux_t *) (page_address(STp->buffer->sg[i].page) + OS_DATA_SIZE - b_size);
4307 #if DEBUG
4308 printk(OSST_DEB_MSG "%s:D: b_data points to %p in segment 0 at %p\n", name,
4309 STp->buffer->b_data, page_address(STp->buffer->sg[0].page));
4310 printk(OSST_DEB_MSG "%s:D: AUX points to %p in segment %d at %p\n", name,
4311 STp->buffer->aux, i, page_address(STp->buffer->sg[i].page));
4312 #endif
4313 } else {
4314 STp->buffer->aux = NULL; /* this had better never happen! */
4315 printk(KERN_NOTICE "%s:A: Framesize %d too large for buffer.\n", name, OS_FRAME_SIZE);
4316 retval = (-EIO);
4317 goto err_out;
4319 STp->buffer->writing = 0;
4320 STp->buffer->syscall_result = 0;
4321 STp->dirty = 0;
4322 for (i=0; i < ST_NBR_PARTITIONS; i++) {
4323 STps = &(STp->ps[i]);
4324 STps->rw = ST_IDLE;
4326 STp->ready = ST_READY;
4327 #if DEBUG
4328 STp->nbr_waits = STp->nbr_finished = 0;
4329 #endif
4331 memset (cmd, 0, MAX_COMMAND_SIZE);
4332 cmd[0] = TEST_UNIT_READY;
4334 SRpnt = osst_do_scsi(NULL, STp, cmd, 0, SCSI_DATA_NONE, STp->timeout, MAX_READY_RETRIES, TRUE);
4335 if (!SRpnt) {
4336 retval = (STp->buffer)->syscall_result;
4337 goto err_out;
4339 if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 &&
4340 (SRpnt->sr_sense_buffer[2] & 0x0f) == NOT_READY &&
4341 SRpnt->sr_sense_buffer[12] == 4 ) {
4342 #if DEBUG
4343 printk(OSST_DEB_MSG "%s:D: Unit not ready, cause %x\n", name, SRpnt->sr_sense_buffer[13]);
4344 #endif
4345 if (filp->f_flags & O_NONBLOCK) {
4346 retval = -EAGAIN;
4347 goto err_out;
4349 if (SRpnt->sr_sense_buffer[13] == 2) { /* initialize command required (LOAD) */
4350 memset (cmd, 0, MAX_COMMAND_SIZE);
4351 cmd[0] = START_STOP;
4352 cmd[1] = 1;
4353 cmd[4] = 1;
4354 SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, SCSI_DATA_NONE,
4355 STp->timeout, MAX_READY_RETRIES, TRUE);
4357 osst_wait_ready(STp, &SRpnt, (SRpnt->sr_sense_buffer[13]==1?15:3) * 60, 0);
4359 if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 &&
4360 (SRpnt->sr_sense_buffer[2] & 0x0f) == UNIT_ATTENTION) { /* New media? */
4361 #if DEBUG
4362 printk(OSST_DEB_MSG "%s:D: Unit wants attention\n", name);
4363 #endif
4364 STp->header_ok = 0;
4366 for (i=0; i < 10; i++) {
4368 memset (cmd, 0, MAX_COMMAND_SIZE);
4369 cmd[0] = TEST_UNIT_READY;
4371 SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, SCSI_DATA_NONE,
4372 STp->timeout, MAX_READY_RETRIES, TRUE);
4373 if ((SRpnt->sr_sense_buffer[0] & 0x70) != 0x70 ||
4374 (SRpnt->sr_sense_buffer[2] & 0x0f) != UNIT_ATTENTION)
4375 break;
4378 STp->pos_unknown = 0;
4379 STp->partition = STp->new_partition = 0;
4380 if (STp->can_partitions)
4381 STp->nbr_partitions = 1; /* This guess will be updated later if necessary */
4382 for (i=0; i < ST_NBR_PARTITIONS; i++) {
4383 STps = &(STp->ps[i]);
4384 STps->rw = ST_IDLE; /* FIXME - seems to be redundant... */
4385 STps->eof = ST_NOEOF;
4386 STps->at_sm = 0;
4387 STps->last_block_valid = FALSE;
4388 STps->drv_block = 0;
4389 STps->drv_file = 0 ;
4391 new_session = TRUE;
4392 STp->recover_count = 0;
4395 * if we have valid headers from before, and the drive/tape seem untouched,
4396 * open without reconfiguring and re-reading the headers
4398 if (!STp->buffer->syscall_result && STp->header_ok &&
4399 !SRpnt->sr_result && SRpnt->sr_sense_buffer[0] == 0) {
4401 memset(cmd, 0, MAX_COMMAND_SIZE);
4402 cmd[0] = MODE_SENSE;
4403 cmd[1] = 8;
4404 cmd[2] = VENDOR_IDENT_PAGE;
4405 cmd[4] = VENDOR_IDENT_PAGE_LENGTH + MODE_HEADER_LENGTH;
4407 SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], SCSI_DATA_READ, STp->timeout, 0, TRUE);
4409 if (STp->buffer->syscall_result ||
4410 STp->buffer->b_data[MODE_HEADER_LENGTH + 2] != 'L' ||
4411 STp->buffer->b_data[MODE_HEADER_LENGTH + 3] != 'I' ||
4412 STp->buffer->b_data[MODE_HEADER_LENGTH + 4] != 'N' ||
4413 STp->buffer->b_data[MODE_HEADER_LENGTH + 5] != '4' ) {
4414 #if DEBUG
4415 printk(OSST_DEB_MSG "%s:D: Signature was changed to %c%c%c%c\n", name,
4416 STp->buffer->b_data[MODE_HEADER_LENGTH + 2],
4417 STp->buffer->b_data[MODE_HEADER_LENGTH + 3],
4418 STp->buffer->b_data[MODE_HEADER_LENGTH + 4],
4419 STp->buffer->b_data[MODE_HEADER_LENGTH + 5]);
4420 #endif
4421 STp->header_ok = 0;
4423 i = STp->first_frame_position;
4424 if (STp->header_ok && i == osst_get_frame_position(STp, &SRpnt)) {
4425 if (STp->door_locked == ST_UNLOCKED) {
4426 if (do_door_lock(STp, 1))
4427 printk(KERN_INFO "%s:I: Can't lock drive door\n", name);
4428 else
4429 STp->door_locked = ST_LOCKED_AUTO;
4431 if (!STp->frame_in_buffer) {
4432 STp->block_size = (STm->default_blksize > 0) ?
4433 STm->default_blksize : OS_DATA_SIZE;
4434 STp->buffer->buffer_bytes = STp->buffer->read_pointer = 0;
4436 STp->buffer->buffer_blocks = OS_DATA_SIZE / STp->block_size;
4437 STp->fast_open = TRUE;
4438 scsi_release_request(SRpnt);
4439 return 0;
4441 #if DEBUG
4442 if (i != STp->first_frame_position)
4443 printk(OSST_DEB_MSG "%s:D: Tape position changed from %d to %d\n",
4444 name, i, STp->first_frame_position);
4445 #endif
4446 STp->header_ok = 0;
4448 STp->fast_open = FALSE;
4450 if ((STp->buffer)->syscall_result != 0 && /* in all error conditions except no medium */
4451 (SRpnt->sr_sense_buffer[2] != 2 || SRpnt->sr_sense_buffer[12] != 0x3A) ) {
4453 memset(cmd, 0, MAX_COMMAND_SIZE);
4454 cmd[0] = MODE_SELECT;
4455 cmd[1] = 0x10;
4456 cmd[4] = 4 + MODE_HEADER_LENGTH;
4458 (STp->buffer)->b_data[0] = cmd[4] - 1;
4459 (STp->buffer)->b_data[1] = 0; /* Medium Type - ignoring */
4460 (STp->buffer)->b_data[2] = 0; /* Reserved */
4461 (STp->buffer)->b_data[3] = 0; /* Block Descriptor Length */
4462 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 0] = 0x3f;
4463 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 1] = 1;
4464 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] = 2;
4465 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] = 3;
4467 #if DEBUG
4468 printk(OSST_DEB_MSG "%s:D: Applying soft reset\n", name);
4469 #endif
4470 SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], SCSI_DATA_WRITE, STp->timeout, 0, TRUE);
4472 STp->header_ok = 0;
4474 for (i=0; i < 10; i++) {
4476 memset (cmd, 0, MAX_COMMAND_SIZE);
4477 cmd[0] = TEST_UNIT_READY;
4479 SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, SCSI_DATA_NONE,
4480 STp->timeout, MAX_READY_RETRIES, TRUE);
4481 if ((SRpnt->sr_sense_buffer[0] & 0x70) != 0x70 ||
4482 (SRpnt->sr_sense_buffer[2] & 0x0f) == NOT_READY)
4483 break;
4485 if ((SRpnt->sr_sense_buffer[2] & 0x0f) == UNIT_ATTENTION) {
4486 STp->pos_unknown = 0;
4487 STp->partition = STp->new_partition = 0;
4488 if (STp->can_partitions)
4489 STp->nbr_partitions = 1; /* This guess will be updated later if necessary */
4490 for (i=0; i < ST_NBR_PARTITIONS; i++) {
4491 STps = &(STp->ps[i]);
4492 STps->rw = ST_IDLE;
4493 STps->eof = ST_NOEOF;
4494 STps->at_sm = 0;
4495 STps->last_block_valid = FALSE;
4496 STps->drv_block = 0;
4497 STps->drv_file = 0 ;
4499 new_session = TRUE;
4504 if (osst_wait_ready(STp, &SRpnt, 15 * 60, 0)) /* FIXME - not allowed with NOBLOCK */
4505 printk(KERN_INFO "%s:I: Device did not become Ready in open\n", name);
4507 if ((STp->buffer)->syscall_result != 0) {
4508 if ((STp->device)->scsi_level >= SCSI_2 &&
4509 (SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 &&
4510 (SRpnt->sr_sense_buffer[2] & 0x0f) == NOT_READY &&
4511 SRpnt->sr_sense_buffer[12] == 0x3a) { /* Check ASC */
4512 STp->ready = ST_NO_TAPE;
4513 } else
4514 STp->ready = ST_NOT_READY;
4515 scsi_release_request(SRpnt);
4516 SRpnt = NULL;
4517 STp->density = 0; /* Clear the erroneous "residue" */
4518 STp->write_prot = 0;
4519 STp->block_size = 0;
4520 STp->ps[0].drv_file = STp->ps[0].drv_block = (-1);
4521 STp->partition = STp->new_partition = 0;
4522 STp->door_locked = ST_UNLOCKED;
4523 return 0;
4526 osst_configure_onstream(STp, &SRpnt);
4528 STp->block_size = STp->raw ? OS_FRAME_SIZE : (
4529 (STm->default_blksize > 0) ? STm->default_blksize : OS_DATA_SIZE);
4530 STp->buffer->buffer_blocks = STp->raw ? 1 : OS_DATA_SIZE / STp->block_size;
4531 STp->buffer->buffer_bytes =
4532 STp->buffer->read_pointer =
4533 STp->frame_in_buffer = 0;
4535 #if DEBUG
4536 if (debugging)
4537 printk(OSST_DEB_MSG "%s:D: Block size: %d, frame size: %d, buffer size: %d (%d blocks).\n",
4538 name, STp->block_size, OS_FRAME_SIZE, (STp->buffer)->buffer_size,
4539 (STp->buffer)->buffer_blocks);
4540 #endif
4542 if (STp->drv_write_prot) {
4543 STp->write_prot = 1;
4544 #if DEBUG
4545 if (debugging)
4546 printk(OSST_DEB_MSG "%s:D: Write protected\n", name);
4547 #endif
4548 if ((flags & O_ACCMODE) == O_WRONLY || (flags & O_ACCMODE) == O_RDWR) {
4549 retval = (-EROFS);
4550 goto err_out;
4554 if (new_session) { /* Change the drive parameters for the new mode */
4555 #if DEBUG
4556 if (debugging)
4557 printk(OSST_DEB_MSG "%s:D: New Session\n", name);
4558 #endif
4559 STp->density_changed = STp->blksize_changed = FALSE;
4560 STp->compression_changed = FALSE;
4564 * properly position the tape and check the ADR headers
4566 if (STp->door_locked == ST_UNLOCKED) {
4567 if (do_door_lock(STp, 1))
4568 printk(KERN_INFO "%s:I: Can't lock drive door\n", name);
4569 else
4570 STp->door_locked = ST_LOCKED_AUTO;
4573 osst_analyze_headers(STp, &SRpnt);
4575 scsi_release_request(SRpnt);
4576 SRpnt = NULL;
4578 return 0;
4580 err_out:
4581 if (SRpnt != NULL)
4582 scsi_release_request(SRpnt);
4583 normalize_buffer(STp->buffer);
4584 STp->header_ok = 0;
4585 STp->in_use = 0;
4586 scsi_device_put(STp->device);
4588 return retval;
4592 /* Flush the tape buffer before close */
4593 static int os_scsi_tape_flush(struct file * filp)
4595 int result = 0, result2;
4596 OS_Scsi_Tape * STp = filp->private_data;
4597 ST_mode * STm = &(STp->modes[STp->current_mode]);
4598 ST_partstat * STps = &(STp->ps[STp->partition]);
4599 Scsi_Request * SRpnt = NULL;
4600 char * name = tape_name(STp);
4602 if (file_count(filp) > 1)
4603 return 0;
4605 if ((STps->rw == ST_WRITING || STp->dirty) && !STp->pos_unknown) {
4606 STp->write_type = OS_WRITE_DATA;
4607 result = osst_flush_write_buffer(STp, &SRpnt);
4608 if (result != 0 && result != (-ENOSPC))
4609 goto out;
4611 if ( STps->rw >= ST_WRITING && !STp->pos_unknown) {
4613 #if DEBUG
4614 if (debugging) {
4615 printk(OSST_DEB_MSG "%s:D: File length %ld bytes.\n",
4616 name, (long)(filp->f_pos));
4617 printk(OSST_DEB_MSG "%s:D: Async write waits %d, finished %d.\n",
4618 name, STp->nbr_waits, STp->nbr_finished);
4620 #endif
4621 result = osst_write_trailer(STp, &SRpnt, !(STp->rew_at_close));
4622 #if DEBUG
4623 if (debugging)
4624 printk(OSST_DEB_MSG "%s:D: Buffer flushed, %d EOF(s) written\n",
4625 name, 1+STp->two_fm);
4626 #endif
4628 else if (!STp->rew_at_close) {
4629 STps = &(STp->ps[STp->partition]);
4630 if (!STm->sysv || STps->rw != ST_READING) {
4631 if (STp->can_bsr)
4632 result = osst_flush_buffer(STp, &SRpnt, 0); /* this is the default path */
4633 else if (STps->eof == ST_FM_HIT) {
4634 result = cross_eof(STp, &SRpnt, FALSE);
4635 if (result) {
4636 if (STps->drv_file >= 0)
4637 STps->drv_file++;
4638 STps->drv_block = 0;
4639 STps->eof = ST_FM;
4641 else
4642 STps->eof = ST_NOEOF;
4645 else if ((STps->eof == ST_NOEOF &&
4646 !(result = cross_eof(STp, &SRpnt, TRUE))) ||
4647 STps->eof == ST_FM_HIT) {
4648 if (STps->drv_file >= 0)
4649 STps->drv_file++;
4650 STps->drv_block = 0;
4651 STps->eof = ST_FM;
4655 out:
4656 if (STp->rew_at_close) {
4657 result2 = osst_position_tape_and_confirm(STp, &SRpnt, STp->first_data_ppos);
4658 STps->drv_file = STps->drv_block = STp->frame_seq_number = STp->logical_blk_num = 0;
4659 if (result == 0 && result2 < 0)
4660 result = result2;
4662 if (SRpnt) scsi_release_request(SRpnt);
4664 if (STp->recover_count) {
4665 printk(KERN_INFO "%s:I: %d recovered errors in", name, STp->recover_count);
4666 if (STp->write_count)
4667 printk(" %d frames written", STp->write_count);
4668 if (STp->read_count)
4669 printk(" %d frames read", STp->read_count);
4670 printk("\n");
4671 STp->recover_count = 0;
4673 STp->write_count = 0;
4674 STp->read_count = 0;
4676 return result;
4680 /* Close the device and release it */
4681 static int os_scsi_tape_close(struct inode * inode, struct file * filp)
4683 int result = 0;
4684 OS_Scsi_Tape * STp = filp->private_data;
4685 Scsi_Request * SRpnt = NULL;
4687 if (SRpnt) scsi_release_request(SRpnt);
4689 if (STp->door_locked == ST_LOCKED_AUTO)
4690 do_door_lock(STp, 0);
4692 if (STp->raw)
4693 STp->header_ok = 0;
4695 normalize_buffer(STp->buffer);
4696 write_lock(&os_scsi_tapes_lock);
4697 STp->in_use = 0;
4698 write_unlock(&os_scsi_tapes_lock);
4700 scsi_device_put(STp->device);
4702 return result;
4706 /* The ioctl command */
4707 static int osst_ioctl(struct inode * inode,struct file * file,
4708 unsigned int cmd_in, unsigned long arg)
4710 int i, cmd_nr, cmd_type, retval = 0;
4711 unsigned int blk;
4712 ST_mode * STm;
4713 ST_partstat * STps;
4714 Scsi_Request * SRpnt = NULL;
4715 OS_Scsi_Tape * STp = file->private_data;
4716 char * name = tape_name(STp);
4717 void __user *p = (void __user *)arg;
4719 if (down_interruptible(&STp->lock))
4720 return -ERESTARTSYS;
4722 #if DEBUG
4723 if (debugging && !STp->in_use) {
4724 printk(OSST_DEB_MSG "%s:D: Incorrect device.\n", name);
4725 retval = (-EIO);
4726 goto out;
4728 #endif
4729 STm = &(STp->modes[STp->current_mode]);
4730 STps = &(STp->ps[STp->partition]);
4733 * If we are in the middle of error recovery, don't let anyone
4734 * else try and use this device. Also, if error recovery fails, it
4735 * may try and take the device offline, in which case all further
4736 * access to the device is prohibited.
4738 if( !scsi_block_when_processing_errors(STp->device) ) {
4739 retval = (-ENXIO);
4740 goto out;
4743 cmd_type = _IOC_TYPE(cmd_in);
4744 cmd_nr = _IOC_NR(cmd_in);
4745 #if DEBUG
4746 printk(OSST_DEB_MSG "%s:D: Ioctl %d,%d in %s mode\n", name,
4747 cmd_type, cmd_nr, STp->raw?"raw":"normal");
4748 #endif
4749 if (cmd_type == _IOC_TYPE(MTIOCTOP) && cmd_nr == _IOC_NR(MTIOCTOP)) {
4750 struct mtop mtc;
4751 int auto_weof = 0;
4753 if (_IOC_SIZE(cmd_in) != sizeof(mtc)) {
4754 retval = (-EINVAL);
4755 goto out;
4758 i = copy_from_user((char *) &mtc, p, sizeof(struct mtop));
4759 if (i) {
4760 retval = (-EFAULT);
4761 goto out;
4764 if (mtc.mt_op == MTSETDRVBUFFER && !capable(CAP_SYS_ADMIN)) {
4765 printk(KERN_WARNING "%s:W: MTSETDRVBUFFER only allowed for root.\n", name);
4766 retval = (-EPERM);
4767 goto out;
4770 if (!STm->defined && (mtc.mt_op != MTSETDRVBUFFER && (mtc.mt_count & MT_ST_OPTIONS) == 0)) {
4771 retval = (-ENXIO);
4772 goto out;
4775 if (!STp->pos_unknown) {
4777 if (STps->eof == ST_FM_HIT) {
4778 if (mtc.mt_op == MTFSF || mtc.mt_op == MTFSFM|| mtc.mt_op == MTEOM) {
4779 mtc.mt_count -= 1;
4780 if (STps->drv_file >= 0)
4781 STps->drv_file += 1;
4783 else if (mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM) {
4784 mtc.mt_count += 1;
4785 if (STps->drv_file >= 0)
4786 STps->drv_file += 1;
4790 if (mtc.mt_op == MTSEEK) {
4791 /* Old position must be restored if partition will be changed */
4792 i = !STp->can_partitions || (STp->new_partition != STp->partition);
4794 else {
4795 i = mtc.mt_op == MTREW || mtc.mt_op == MTOFFL ||
4796 mtc.mt_op == MTRETEN || mtc.mt_op == MTEOM ||
4797 mtc.mt_op == MTLOCK || mtc.mt_op == MTLOAD ||
4798 mtc.mt_op == MTFSF || mtc.mt_op == MTFSFM ||
4799 mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM ||
4800 mtc.mt_op == MTCOMPRESSION;
4802 i = osst_flush_buffer(STp, &SRpnt, i);
4803 if (i < 0) {
4804 retval = i;
4805 goto out;
4808 else {
4810 * If there was a bus reset, block further access
4811 * to this device. If the user wants to rewind the tape,
4812 * then reset the flag and allow access again.
4814 if(mtc.mt_op != MTREW &&
4815 mtc.mt_op != MTOFFL &&
4816 mtc.mt_op != MTRETEN &&
4817 mtc.mt_op != MTERASE &&
4818 mtc.mt_op != MTSEEK &&
4819 mtc.mt_op != MTEOM) {
4820 retval = (-EIO);
4821 goto out;
4823 reset_state(STp);
4824 /* remove this when the midlevel properly clears was_reset */
4825 STp->device->was_reset = 0;
4828 if (mtc.mt_op != MTCOMPRESSION && mtc.mt_op != MTLOCK &&
4829 mtc.mt_op != MTNOP && mtc.mt_op != MTSETBLK &&
4830 mtc.mt_op != MTSETDENSITY && mtc.mt_op != MTSETDRVBUFFER &&
4831 mtc.mt_op != MTMKPART && mtc.mt_op != MTSETPART &&
4832 mtc.mt_op != MTWEOF && mtc.mt_op != MTWSM ) {
4835 * The user tells us to move to another position on the tape.
4836 * If we were appending to the tape content, that would leave
4837 * the tape without proper end, in that case write EOD and
4838 * update the header to reflect its position.
4840 #if DEBUG
4841 printk(KERN_WARNING "%s:D: auto_weod %s at ffp=%d,efp=%d,fsn=%d,lbn=%d,fn=%d,bn=%d\n", name,
4842 STps->rw >= ST_WRITING ? "write" : STps->rw == ST_READING ? "read" : "idle",
4843 STp->first_frame_position, STp->eod_frame_ppos, STp->frame_seq_number,
4844 STp->logical_blk_num, STps->drv_file, STps->drv_block );
4845 #endif
4846 if (STps->rw >= ST_WRITING && STp->first_frame_position >= STp->eod_frame_ppos) {
4847 auto_weof = ((STp->write_type != OS_WRITE_NEW_MARK) &&
4848 !(mtc.mt_op == MTREW || mtc.mt_op == MTOFFL));
4849 i = osst_write_trailer(STp, &SRpnt,
4850 !(mtc.mt_op == MTREW || mtc.mt_op == MTOFFL));
4851 #if DEBUG
4852 printk(KERN_WARNING "%s:D: post trailer xeof=%d,ffp=%d,efp=%d,fsn=%d,lbn=%d,fn=%d,bn=%d\n",
4853 name, auto_weof, STp->first_frame_position, STp->eod_frame_ppos,
4854 STp->frame_seq_number, STp->logical_blk_num, STps->drv_file, STps->drv_block );
4855 #endif
4856 if (i < 0) {
4857 retval = i;
4858 goto out;
4861 STps->rw = ST_IDLE;
4864 if (mtc.mt_op == MTOFFL && STp->door_locked != ST_UNLOCKED)
4865 do_door_lock(STp, 0); /* Ignore result! */
4867 if (mtc.mt_op == MTSETDRVBUFFER &&
4868 (mtc.mt_count & MT_ST_OPTIONS) != 0) {
4869 retval = osst_set_options(STp, mtc.mt_count);
4870 goto out;
4873 if (mtc.mt_op == MTSETPART) {
4874 if (mtc.mt_count >= STp->nbr_partitions)
4875 retval = -EINVAL;
4876 else {
4877 STp->new_partition = mtc.mt_count;
4878 retval = 0;
4880 goto out;
4883 if (mtc.mt_op == MTMKPART) {
4884 if (!STp->can_partitions) {
4885 retval = (-EINVAL);
4886 goto out;
4888 if ((i = osst_int_ioctl(STp, &SRpnt, MTREW, 0)) < 0 /*||
4889 (i = partition_tape(inode, mtc.mt_count)) < 0*/) {
4890 retval = i;
4891 goto out;
4893 for (i=0; i < ST_NBR_PARTITIONS; i++) {
4894 STp->ps[i].rw = ST_IDLE;
4895 STp->ps[i].at_sm = 0;
4896 STp->ps[i].last_block_valid = FALSE;
4898 STp->partition = STp->new_partition = 0;
4899 STp->nbr_partitions = 1; /* Bad guess ?-) */
4900 STps->drv_block = STps->drv_file = 0;
4901 retval = 0;
4902 goto out;
4905 if (mtc.mt_op == MTSEEK) {
4906 if (STp->raw)
4907 i = osst_set_frame_position(STp, &SRpnt, mtc.mt_count, 0);
4908 else
4909 i = osst_seek_sector(STp, &SRpnt, mtc.mt_count);
4910 if (!STp->can_partitions)
4911 STp->ps[0].rw = ST_IDLE;
4912 retval = i;
4913 goto out;
4916 if (mtc.mt_op == MTLOCK || mtc.mt_op == MTUNLOCK) {
4917 retval = do_door_lock(STp, (mtc.mt_op == MTLOCK));
4918 goto out;
4921 if (auto_weof)
4922 cross_eof(STp, &SRpnt, FALSE);
4924 if (mtc.mt_op == MTCOMPRESSION)
4925 retval = -EINVAL; /* OnStream drives don't have compression hardware */
4926 else
4927 /* MTBSF MTBSFM MTBSR MTBSS MTEOM MTERASE MTFSF MTFSFB MTFSR MTFSS
4928 * MTLOAD MTOFFL MTRESET MTRETEN MTREW MTUNLOAD MTWEOF MTWSM */
4929 retval = osst_int_ioctl(STp, &SRpnt, mtc.mt_op, mtc.mt_count);
4930 goto out;
4933 if (!STm->defined) {
4934 retval = (-ENXIO);
4935 goto out;
4938 if ((i = osst_flush_buffer(STp, &SRpnt, FALSE)) < 0) {
4939 retval = i;
4940 goto out;
4943 if (cmd_type == _IOC_TYPE(MTIOCGET) && cmd_nr == _IOC_NR(MTIOCGET)) {
4944 struct mtget mt_status;
4946 if (_IOC_SIZE(cmd_in) != sizeof(struct mtget)) {
4947 retval = (-EINVAL);
4948 goto out;
4951 mt_status.mt_type = MT_ISONSTREAM_SC;
4952 mt_status.mt_erreg = STp->recover_erreg << MT_ST_SOFTERR_SHIFT;
4953 mt_status.mt_dsreg =
4954 ((STp->block_size << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK) |
4955 ((STp->density << MT_ST_DENSITY_SHIFT) & MT_ST_DENSITY_MASK);
4956 mt_status.mt_blkno = STps->drv_block;
4957 mt_status.mt_fileno = STps->drv_file;
4958 if (STp->block_size != 0) {
4959 if (STps->rw == ST_WRITING)
4960 mt_status.mt_blkno += (STp->buffer)->buffer_bytes / STp->block_size;
4961 else if (STps->rw == ST_READING)
4962 mt_status.mt_blkno -= ((STp->buffer)->buffer_bytes +
4963 STp->block_size - 1) / STp->block_size;
4966 mt_status.mt_gstat = 0;
4967 if (STp->drv_write_prot)
4968 mt_status.mt_gstat |= GMT_WR_PROT(0xffffffff);
4969 if (mt_status.mt_blkno == 0) {
4970 if (mt_status.mt_fileno == 0)
4971 mt_status.mt_gstat |= GMT_BOT(0xffffffff);
4972 else
4973 mt_status.mt_gstat |= GMT_EOF(0xffffffff);
4975 mt_status.mt_resid = STp->partition;
4976 if (STps->eof == ST_EOM_OK || STps->eof == ST_EOM_ERROR)
4977 mt_status.mt_gstat |= GMT_EOT(0xffffffff);
4978 else if (STps->eof >= ST_EOM_OK)
4979 mt_status.mt_gstat |= GMT_EOD(0xffffffff);
4980 if (STp->density == 1)
4981 mt_status.mt_gstat |= GMT_D_800(0xffffffff);
4982 else if (STp->density == 2)
4983 mt_status.mt_gstat |= GMT_D_1600(0xffffffff);
4984 else if (STp->density == 3)
4985 mt_status.mt_gstat |= GMT_D_6250(0xffffffff);
4986 if (STp->ready == ST_READY)
4987 mt_status.mt_gstat |= GMT_ONLINE(0xffffffff);
4988 if (STp->ready == ST_NO_TAPE)
4989 mt_status.mt_gstat |= GMT_DR_OPEN(0xffffffff);
4990 if (STps->at_sm)
4991 mt_status.mt_gstat |= GMT_SM(0xffffffff);
4992 if (STm->do_async_writes || (STm->do_buffer_writes && STp->block_size != 0) ||
4993 STp->drv_buffer != 0)
4994 mt_status.mt_gstat |= GMT_IM_REP_EN(0xffffffff);
4996 i = copy_to_user(p, &mt_status, sizeof(struct mtget));
4997 if (i) {
4998 retval = (-EFAULT);
4999 goto out;
5002 STp->recover_erreg = 0; /* Clear after read */
5003 retval = 0;
5004 goto out;
5005 } /* End of MTIOCGET */
5007 if (cmd_type == _IOC_TYPE(MTIOCPOS) && cmd_nr == _IOC_NR(MTIOCPOS)) {
5008 struct mtpos mt_pos;
5010 if (_IOC_SIZE(cmd_in) != sizeof(struct mtpos)) {
5011 retval = (-EINVAL);
5012 goto out;
5014 if (STp->raw)
5015 blk = osst_get_frame_position(STp, &SRpnt);
5016 else
5017 blk = osst_get_sector(STp, &SRpnt);
5018 if (blk < 0) {
5019 retval = blk;
5020 goto out;
5022 mt_pos.mt_blkno = blk;
5023 i = copy_to_user(p, &mt_pos, sizeof(struct mtpos));
5024 if (i)
5025 retval = -EFAULT;
5026 goto out;
5028 if (SRpnt) scsi_release_request(SRpnt);
5030 up(&STp->lock);
5032 return scsi_ioctl(STp->device, cmd_in, p);
5034 out:
5035 if (SRpnt) scsi_release_request(SRpnt);
5037 up(&STp->lock);
5039 return retval;
5043 /* Memory handling routines */
5045 /* Try to allocate a new tape buffer skeleton. Caller must not hold os_scsi_tapes_lock */
5046 static OSST_buffer * new_tape_buffer( int from_initialization, int need_dma, int max_sg )
5048 int i, priority;
5049 OSST_buffer *tb;
5051 if (from_initialization)
5052 priority = GFP_ATOMIC;
5053 else
5054 priority = GFP_KERNEL;
5056 i = sizeof(OSST_buffer) + (osst_max_sg_segs - 1) * sizeof(struct scatterlist);
5057 tb = (OSST_buffer *)kmalloc(i, priority);
5058 if (!tb) {
5059 printk(KERN_NOTICE "osst :I: Can't allocate new tape buffer.\n");
5060 return NULL;
5062 memset(tb, 0, i);
5063 tb->sg_segs = tb->orig_sg_segs = 0;
5064 tb->use_sg = max_sg;
5065 tb->in_use = TRUE;
5066 tb->dma = need_dma;
5067 tb->buffer_size = 0;
5068 #if DEBUG
5069 if (debugging)
5070 printk(OSST_DEB_MSG
5071 "osst :D: Allocated tape buffer skeleton (%d bytes, %d segments, dma: %d).\n",
5072 i, max_sg, need_dma);
5073 #endif
5074 return tb;
5077 /* Try to allocate a temporary (while a user has the device open) enlarged tape buffer */
5078 static int enlarge_buffer(OSST_buffer *STbuffer, int need_dma)
5080 int segs, nbr, max_segs, b_size, priority, order, got;
5082 if (STbuffer->buffer_size >= OS_FRAME_SIZE)
5083 return TRUE;
5085 if (STbuffer->sg_segs) {
5086 printk(KERN_WARNING "osst :A: Buffer not previously normalized.\n");
5087 normalize_buffer(STbuffer);
5089 /* See how many segments we can use -- need at least two */
5090 nbr = max_segs = STbuffer->use_sg;
5091 if (nbr <= 2)
5092 return FALSE;
5094 priority = GFP_KERNEL;
5095 if (need_dma)
5096 priority |= GFP_DMA;
5098 priority |= __GFP_NOWARN;
5100 /* Try to allocate the first segment up to OS_DATA_SIZE and the others
5101 big enough to reach the goal (code assumes no segments in place) */
5102 for (b_size = OS_DATA_SIZE, order = OSST_FIRST_ORDER; b_size >= PAGE_SIZE; order--, b_size /= 2) {
5103 STbuffer->sg[0].page = alloc_pages(priority, order);
5104 STbuffer->sg[0].offset = 0;
5105 if (STbuffer->sg[0].page != NULL) {
5106 STbuffer->sg[0].length = b_size;
5107 STbuffer->b_data = page_address(STbuffer->sg[0].page);
5108 break;
5111 if (STbuffer->sg[0].page == NULL) {
5112 printk(KERN_NOTICE "osst :I: Can't allocate tape buffer main segment.\n");
5113 return FALSE;
5115 /* Got initial segment of 'bsize,order', continue with same size if possible, except for AUX */
5116 for (segs=STbuffer->sg_segs=1, got=b_size;
5117 segs < max_segs && got < OS_FRAME_SIZE; ) {
5118 STbuffer->sg[segs].page =
5119 alloc_pages(priority, (OS_FRAME_SIZE - got <= PAGE_SIZE) ? 0 : order);
5120 STbuffer->sg[segs].offset = 0;
5121 if (STbuffer->sg[segs].page == NULL) {
5122 if (OS_FRAME_SIZE - got <= (max_segs - segs) * b_size / 2 && order) {
5123 b_size /= 2; /* Large enough for the rest of the buffers */
5124 order--;
5125 continue;
5127 printk(KERN_WARNING "osst :W: Failed to enlarge buffer to %d bytes.\n",
5128 OS_FRAME_SIZE);
5129 #if DEBUG
5130 STbuffer->buffer_size = got;
5131 #endif
5132 normalize_buffer(STbuffer);
5133 return FALSE;
5135 STbuffer->sg[segs].length = (OS_FRAME_SIZE - got <= PAGE_SIZE / 2) ? (OS_FRAME_SIZE - got) : b_size;
5136 got += STbuffer->sg[segs].length;
5137 STbuffer->buffer_size = got;
5138 STbuffer->sg_segs = ++segs;
5140 #if DEBUG
5141 if (debugging) {
5142 printk(OSST_DEB_MSG
5143 "osst :D: Expanded tape buffer (%d bytes, %d->%d segments, dma: %d, at: %p).\n",
5144 got, STbuffer->orig_sg_segs, STbuffer->sg_segs, need_dma, STbuffer->b_data);
5145 printk(OSST_DEB_MSG
5146 "osst :D: segment sizes: first %d at %p, last %d bytes at %p.\n",
5147 STbuffer->sg[0].length, page_address(STbuffer->sg[0].page),
5148 STbuffer->sg[segs-1].length, page_address(STbuffer->sg[segs-1].page));
5150 #endif
5152 return TRUE;
5156 /* Release the segments */
5157 static void normalize_buffer(OSST_buffer *STbuffer)
5159 int i, order, b_size;
5161 for (i=0; i < STbuffer->sg_segs; i++) {
5163 for (b_size = PAGE_SIZE, order = 0;
5164 b_size < STbuffer->sg[i].length;
5165 b_size *= 2, order++);
5167 __free_pages(STbuffer->sg[i].page, order);
5168 STbuffer->buffer_size -= STbuffer->sg[i].length;
5170 #if DEBUG
5171 if (debugging && STbuffer->orig_sg_segs < STbuffer->sg_segs)
5172 printk(OSST_DEB_MSG "osst :D: Buffer at %p normalized to %d bytes (segs %d).\n",
5173 STbuffer->b_data, STbuffer->buffer_size, STbuffer->sg_segs);
5174 #endif
5175 STbuffer->sg_segs = STbuffer->orig_sg_segs = 0;
5179 /* Move data from the user buffer to the tape buffer. Returns zero (success) or
5180 negative error code. */
5181 static int append_to_buffer(const char __user *ubp, OSST_buffer *st_bp, int do_count)
5183 int i, cnt, res, offset;
5185 for (i=0, offset=st_bp->buffer_bytes;
5186 i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++)
5187 offset -= st_bp->sg[i].length;
5188 if (i == st_bp->sg_segs) { /* Should never happen */
5189 printk(KERN_WARNING "osst :A: Append_to_buffer offset overflow.\n");
5190 return (-EIO);
5192 for ( ; i < st_bp->sg_segs && do_count > 0; i++) {
5193 cnt = st_bp->sg[i].length - offset < do_count ?
5194 st_bp->sg[i].length - offset : do_count;
5195 res = copy_from_user(page_address(st_bp->sg[i].page) + offset, ubp, cnt);
5196 if (res)
5197 return (-EFAULT);
5198 do_count -= cnt;
5199 st_bp->buffer_bytes += cnt;
5200 ubp += cnt;
5201 offset = 0;
5203 if (do_count) { /* Should never happen */
5204 printk(KERN_WARNING "osst :A: Append_to_buffer overflow (left %d).\n",
5205 do_count);
5206 return (-EIO);
5208 return 0;
5212 /* Move data from the tape buffer to the user buffer. Returns zero (success) or
5213 negative error code. */
5214 static int from_buffer(OSST_buffer *st_bp, char __user *ubp, int do_count)
5216 int i, cnt, res, offset;
5218 for (i=0, offset=st_bp->read_pointer;
5219 i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++)
5220 offset -= st_bp->sg[i].length;
5221 if (i == st_bp->sg_segs) { /* Should never happen */
5222 printk(KERN_WARNING "osst :A: From_buffer offset overflow.\n");
5223 return (-EIO);
5225 for ( ; i < st_bp->sg_segs && do_count > 0; i++) {
5226 cnt = st_bp->sg[i].length - offset < do_count ?
5227 st_bp->sg[i].length - offset : do_count;
5228 res = copy_to_user(ubp, page_address(st_bp->sg[i].page) + offset, cnt);
5229 if (res)
5230 return (-EFAULT);
5231 do_count -= cnt;
5232 st_bp->buffer_bytes -= cnt;
5233 st_bp->read_pointer += cnt;
5234 ubp += cnt;
5235 offset = 0;
5237 if (do_count) { /* Should never happen */
5238 printk(KERN_WARNING "osst :A: From_buffer overflow (left %d).\n", do_count);
5239 return (-EIO);
5241 return 0;
5244 /* Sets the tail of the buffer after fill point to zero.
5245 Returns zero (success) or negative error code. */
5246 static int osst_zero_buffer_tail(OSST_buffer *st_bp)
5248 int i, offset, do_count, cnt;
5250 for (i = 0, offset = st_bp->buffer_bytes;
5251 i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++)
5252 offset -= st_bp->sg[i].length;
5253 if (i == st_bp->sg_segs) { /* Should never happen */
5254 printk(KERN_WARNING "osst :A: Zero_buffer offset overflow.\n");
5255 return (-EIO);
5257 for (do_count = OS_DATA_SIZE - st_bp->buffer_bytes;
5258 i < st_bp->sg_segs && do_count > 0; i++) {
5259 cnt = st_bp->sg[i].length - offset < do_count ?
5260 st_bp->sg[i].length - offset : do_count ;
5261 memset(page_address(st_bp->sg[i].page) + offset, 0, cnt);
5262 do_count -= cnt;
5263 offset = 0;
5265 if (do_count) { /* Should never happen */
5266 printk(KERN_WARNING "osst :A: Zero_buffer overflow (left %d).\n", do_count);
5267 return (-EIO);
5269 return 0;
5272 /* Copy a osst 32K chunk of memory into the buffer.
5273 Returns zero (success) or negative error code. */
5274 static int osst_copy_to_buffer(OSST_buffer *st_bp, unsigned char *ptr)
5276 int i, cnt, do_count = OS_DATA_SIZE;
5278 for (i = 0; i < st_bp->sg_segs && do_count > 0; i++) {
5279 cnt = st_bp->sg[i].length < do_count ?
5280 st_bp->sg[i].length : do_count ;
5281 memcpy(page_address(st_bp->sg[i].page), ptr, cnt);
5282 do_count -= cnt;
5283 ptr += cnt;
5285 if (do_count || i != st_bp->sg_segs-1) { /* Should never happen */
5286 printk(KERN_WARNING "osst :A: Copy_to_buffer overflow (left %d at sg %d).\n",
5287 do_count, i);
5288 return (-EIO);
5290 return 0;
5293 /* Copy a osst 32K chunk of memory from the buffer.
5294 Returns zero (success) or negative error code. */
5295 static int osst_copy_from_buffer(OSST_buffer *st_bp, unsigned char *ptr)
5297 int i, cnt, do_count = OS_DATA_SIZE;
5299 for (i = 0; i < st_bp->sg_segs && do_count > 0; i++) {
5300 cnt = st_bp->sg[i].length < do_count ?
5301 st_bp->sg[i].length : do_count ;
5302 memcpy(ptr, page_address(st_bp->sg[i].page), cnt);
5303 do_count -= cnt;
5304 ptr += cnt;
5306 if (do_count || i != st_bp->sg_segs-1) { /* Should never happen */
5307 printk(KERN_WARNING "osst :A: Copy_from_buffer overflow (left %d at sg %d).\n",
5308 do_count, i);
5309 return (-EIO);
5311 return 0;
5315 /* Module housekeeping */
5317 static void validate_options (void)
5319 if (max_dev > 0)
5320 osst_max_dev = max_dev;
5321 if (write_threshold_kbs > 0)
5322 osst_write_threshold = write_threshold_kbs * ST_KILOBYTE;
5323 if (osst_write_threshold > osst_buffer_size)
5324 osst_write_threshold = osst_buffer_size;
5325 if (max_sg_segs >= OSST_FIRST_SG)
5326 osst_max_sg_segs = max_sg_segs;
5327 #if DEBUG
5328 printk(OSST_DEB_MSG "osst :D: max tapes %d, write threshold %d, max s/g segs %d.\n",
5329 osst_max_dev, osst_write_threshold, osst_max_sg_segs);
5330 #endif
5333 #ifndef MODULE
5334 /* Set the boot options. Syntax: osst=xxx,yyy,...
5335 where xxx is write threshold in 1024 byte blocks,
5336 and yyy is number of s/g segments to use. */
5337 static int __init osst_setup (char *str)
5339 int i, ints[5];
5340 char *stp;
5342 stp = get_options(str, ARRAY_SIZE(ints), ints);
5344 if (ints[0] > 0) {
5345 for (i = 0; i < ints[0] && i < ARRAY_SIZE(parms); i++)
5346 *parms[i].val = ints[i + 1];
5347 } else {
5348 while (stp != NULL) {
5349 for (i = 0; i < ARRAY_SIZE(parms); i++) {
5350 int len = strlen(parms[i].name);
5351 if (!strncmp(stp, parms[i].name, len) &&
5352 (*(stp + len) == ':' || *(stp + len) == '=')) {
5353 *parms[i].val =
5354 simple_strtoul(stp + len + 1, NULL, 0);
5355 break;
5358 if (i >= sizeof(parms) / sizeof(struct osst_dev_parm))
5359 printk(KERN_INFO "osst :I: Illegal parameter in '%s'\n",
5360 stp);
5361 stp = strchr(stp, ',');
5362 if (stp)
5363 stp++;
5367 return 1;
5370 __setup("osst=", osst_setup);
5372 #endif
5374 static struct file_operations osst_fops = {
5375 .owner = THIS_MODULE,
5376 .read = osst_read,
5377 .write = osst_write,
5378 .ioctl = osst_ioctl,
5379 .open = os_scsi_tape_open,
5380 .flush = os_scsi_tape_flush,
5381 .release = os_scsi_tape_close,
5384 static int osst_supports(Scsi_Device * SDp)
5386 struct osst_support_data {
5387 char *vendor;
5388 char *model;
5389 char *rev;
5390 char *driver_hint; /* Name of the correct driver, NULL if unknown */
5393 static struct osst_support_data support_list[] = {
5394 /* {"XXX", "Yy-", "", NULL}, example */
5395 SIGS_FROM_OSST,
5396 {NULL, }};
5398 struct osst_support_data *rp;
5400 /* We are willing to drive OnStream SC-x0 as well as the
5401 * * IDE, ParPort, FireWire, USB variants, if accessible by
5402 * * emulation layer (ide-scsi, usb-storage, ...) */
5404 for (rp=&(support_list[0]); rp->vendor != NULL; rp++)
5405 if (!strncmp(rp->vendor, SDp->vendor, strlen(rp->vendor)) &&
5406 !strncmp(rp->model, SDp->model, strlen(rp->model)) &&
5407 !strncmp(rp->rev, SDp->rev, strlen(rp->rev)))
5408 return 1;
5409 return 0;
5413 * osst startup / cleanup code
5416 static int osst_probe(struct device *dev)
5418 Scsi_Device * SDp = to_scsi_device(dev);
5419 OS_Scsi_Tape * tpnt;
5420 ST_mode * STm;
5421 ST_partstat * STps;
5422 OSST_buffer * buffer;
5423 struct gendisk * drive;
5424 int i, mode, dev_num;
5426 if (SDp->type != TYPE_TAPE || !osst_supports(SDp))
5427 return -ENODEV;
5429 drive = alloc_disk(1);
5430 if (!drive) {
5431 printk(KERN_ERR "osst :E: Out of memory. Device not attached.\n");
5432 return -ENODEV;
5435 /* if this is the first attach, build the infrastructure */
5436 write_lock(&os_scsi_tapes_lock);
5437 if (os_scsi_tapes == NULL) {
5438 os_scsi_tapes =
5439 (OS_Scsi_Tape **)kmalloc(osst_max_dev * sizeof(OS_Scsi_Tape *),
5440 GFP_ATOMIC);
5441 if (os_scsi_tapes == NULL) {
5442 write_unlock(&os_scsi_tapes_lock);
5443 printk(KERN_ERR "osst :E: Unable to allocate array for OnStream SCSI tapes.\n");
5444 goto out_put_disk;
5446 for (i=0; i < osst_max_dev; ++i) os_scsi_tapes[i] = NULL;
5449 if (osst_nr_dev >= osst_max_dev) {
5450 write_unlock(&os_scsi_tapes_lock);
5451 printk(KERN_ERR "osst :E: Too many tape devices (max. %d).\n", osst_max_dev);
5452 goto out_put_disk;
5455 /* find a free minor number */
5456 for (i=0; os_scsi_tapes[i] && i<osst_max_dev; i++);
5457 if(i >= osst_max_dev) panic ("Scsi_devices corrupt (osst)");
5458 dev_num = i;
5460 /* allocate a OS_Scsi_Tape for this device */
5461 tpnt = (OS_Scsi_Tape *)kmalloc(sizeof(OS_Scsi_Tape), GFP_ATOMIC);
5462 if (tpnt == NULL) {
5463 write_unlock(&os_scsi_tapes_lock);
5464 printk(KERN_ERR "osst :E: Can't allocate device descriptor, device not attached.\n");
5465 goto out_put_disk;
5467 memset(tpnt, 0, sizeof(OS_Scsi_Tape));
5469 /* allocate a buffer for this device */
5470 i = SDp->host->sg_tablesize;
5471 if (osst_max_sg_segs < i)
5472 i = osst_max_sg_segs;
5473 buffer = new_tape_buffer(TRUE, SDp->host->unchecked_isa_dma, i);
5474 if (buffer == NULL) {
5475 write_unlock(&os_scsi_tapes_lock);
5476 printk(KERN_ERR "osst :E: Unable to allocate a tape buffer, device not attached.\n");
5477 kfree(tpnt);
5478 goto out_put_disk;
5480 os_scsi_tapes[dev_num] = tpnt;
5481 tpnt->buffer = buffer;
5482 tpnt->device = SDp;
5483 drive->private_data = &tpnt->driver;
5484 sprintf(drive->disk_name, "osst%d", dev_num);
5485 tpnt->driver = &osst_template;
5486 tpnt->drive = drive;
5487 tpnt->in_use = 0;
5488 tpnt->capacity = 0xfffff;
5489 tpnt->dirty = 0;
5490 tpnt->drv_buffer = 1; /* Try buffering if no mode sense */
5491 tpnt->restr_dma = (SDp->host)->unchecked_isa_dma;
5492 tpnt->density = 0;
5493 tpnt->do_auto_lock = OSST_AUTO_LOCK;
5494 tpnt->can_bsr = OSST_IN_FILE_POS;
5495 tpnt->can_partitions = 0;
5496 tpnt->two_fm = OSST_TWO_FM;
5497 tpnt->fast_mteom = OSST_FAST_MTEOM;
5498 tpnt->scsi2_logical = OSST_SCSI2LOGICAL; /* FIXME */
5499 tpnt->write_threshold = osst_write_threshold;
5500 tpnt->default_drvbuffer = 0xff; /* No forced buffering */
5501 tpnt->partition = 0;
5502 tpnt->new_partition = 0;
5503 tpnt->nbr_partitions = 0;
5504 tpnt->min_block = 512;
5505 tpnt->max_block = OS_DATA_SIZE;
5506 tpnt->timeout = OSST_TIMEOUT;
5507 tpnt->long_timeout = OSST_LONG_TIMEOUT;
5509 /* Recognize OnStream tapes */
5510 /* We don't need to test for OnStream, as this has been done in detect () */
5511 tpnt->os_fw_rev = osst_parse_firmware_rev (SDp->rev);
5512 tpnt->omit_blklims = 1;
5514 tpnt->poll = (strncmp(SDp->model, "DI-", 3) == 0) ||
5515 (strncmp(SDp->model, "FW-", 3) == 0) || OSST_FW_NEED_POLL(tpnt->os_fw_rev,SDp);
5516 tpnt->frame_in_buffer = 0;
5517 tpnt->header_ok = 0;
5518 tpnt->linux_media = 0;
5519 tpnt->header_cache = NULL;
5521 for (i=0; i < ST_NBR_MODES; i++) {
5522 STm = &(tpnt->modes[i]);
5523 STm->defined = FALSE;
5524 STm->sysv = OSST_SYSV;
5525 STm->defaults_for_writes = 0;
5526 STm->do_async_writes = OSST_ASYNC_WRITES;
5527 STm->do_buffer_writes = OSST_BUFFER_WRITES;
5528 STm->do_read_ahead = OSST_READ_AHEAD;
5529 STm->default_compression = ST_DONT_TOUCH;
5530 STm->default_blksize = 512;
5531 STm->default_density = (-1); /* No forced density */
5534 for (i=0; i < ST_NBR_PARTITIONS; i++) {
5535 STps = &(tpnt->ps[i]);
5536 STps->rw = ST_IDLE;
5537 STps->eof = ST_NOEOF;
5538 STps->at_sm = 0;
5539 STps->last_block_valid = FALSE;
5540 STps->drv_block = (-1);
5541 STps->drv_file = (-1);
5544 tpnt->current_mode = 0;
5545 tpnt->modes[0].defined = TRUE;
5546 tpnt->modes[2].defined = TRUE;
5547 tpnt->density_changed = tpnt->compression_changed = tpnt->blksize_changed = FALSE;
5549 init_MUTEX(&tpnt->lock);
5550 osst_nr_dev++;
5551 write_unlock(&os_scsi_tapes_lock);
5553 for (mode = 0; mode < ST_NBR_MODES; ++mode) {
5554 /* Rewind entry */
5555 devfs_mk_cdev(MKDEV(OSST_MAJOR, dev_num + (mode << 5)),
5556 S_IFCHR | S_IRUGO | S_IWUGO,
5557 "%s/ot%s", SDp->devfs_name, osst_formats[mode]);
5559 /* No-rewind entry */
5560 devfs_mk_cdev(MKDEV(OSST_MAJOR, dev_num + (mode << 5) + 128),
5561 S_IFCHR | S_IRUGO | S_IWUGO,
5562 "%s/ot%sn", SDp->devfs_name, osst_formats[mode]);
5564 drive->number = devfs_register_tape(SDp->devfs_name);
5566 printk(KERN_INFO
5567 "osst :I: Attached OnStream %.5s tape at scsi%d, channel %d, id %d, lun %d as %s\n",
5568 SDp->model, SDp->host->host_no, SDp->channel, SDp->id, SDp->lun, tape_name(tpnt));
5570 return 0;
5572 out_put_disk:
5573 put_disk(drive);
5574 return -ENODEV;
5577 static int osst_remove(struct device *dev)
5579 Scsi_Device * SDp = to_scsi_device(dev);
5580 OS_Scsi_Tape * tpnt;
5581 int i, mode;
5583 if ((SDp->type != TYPE_TAPE) || (osst_nr_dev <= 0))
5584 return 0;
5586 write_lock(&os_scsi_tapes_lock);
5587 for(i=0; i < osst_max_dev; i++) {
5588 if((tpnt = os_scsi_tapes[i]) && (tpnt->device == SDp)) {
5589 tpnt->device = NULL;
5590 for (mode = 0; mode < ST_NBR_MODES; ++mode) {
5591 devfs_remove("%s/ot%s", SDp->devfs_name, osst_formats[mode]);
5592 devfs_remove("%s/ot%sn", SDp->devfs_name, osst_formats[mode]);
5594 devfs_unregister_tape(tpnt->drive->number);
5595 put_disk(tpnt->drive);
5596 os_scsi_tapes[i] = NULL;
5597 osst_nr_dev--;
5598 write_unlock(&os_scsi_tapes_lock);
5599 if (tpnt->header_cache != NULL) vfree(tpnt->header_cache);
5600 if (tpnt->buffer) {
5601 normalize_buffer(tpnt->buffer);
5602 kfree(tpnt->buffer);
5604 kfree(tpnt);
5605 return 0;
5608 write_unlock(&os_scsi_tapes_lock);
5609 return 0;
5612 static int __init init_osst(void)
5614 printk(KERN_INFO "osst :I: Tape driver with OnStream support version %s\nosst :I: %s\n", osst_version, cvsid);
5616 validate_options();
5618 if ((register_chrdev(OSST_MAJOR,"osst", &osst_fops) < 0) || scsi_register_driver(&osst_template.gendrv)) {
5619 printk(KERN_ERR "osst :E: Unable to register major %d for OnStream tapes\n", OSST_MAJOR);
5620 return 1;
5623 return 0;
5626 static void __exit exit_osst (void)
5628 int i;
5629 OS_Scsi_Tape * STp;
5631 scsi_unregister_driver(&osst_template.gendrv);
5632 unregister_chrdev(OSST_MAJOR, "osst");
5634 if (os_scsi_tapes) {
5635 for (i=0; i < osst_max_dev; ++i) {
5636 if (!(STp = os_scsi_tapes[i])) continue;
5637 /* This is defensive, supposed to happen during detach */
5638 if (STp->header_cache)
5639 vfree(STp->header_cache);
5640 if (STp->buffer) {
5641 normalize_buffer(STp->buffer);
5642 kfree(STp->buffer);
5644 put_disk(STp->drive);
5645 kfree(STp);
5647 kfree(os_scsi_tapes);
5649 printk(KERN_INFO "osst :I: Unloaded.\n");
5652 module_init(init_osst);
5653 module_exit(exit_osst);