Merge with Linux 2.5.74.
[linux-2.6/linux-mips.git] / drivers / scsi / osst.c
blob445d38fc98c9ea07d9debed68146a6a1ab73160f
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: /home/cvsroot/Driver/osst.c,v 1.68 2002/12/23 16:33:36 riede 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.68 2002/12/23 16:33:36 riede Exp $";
27 const char * osst_version = "0.99.0";
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/version.h>
49 #include <linux/blk.h>
50 #include <linux/devfs_fs_kernel.h>
51 #include <asm/uaccess.h>
52 #include <asm/dma.h>
53 #include <asm/system.h>
55 /* The driver prints some debugging information on the console if DEBUG
56 is defined and non-zero. */
57 #define DEBUG 0
59 /* The message level for the debug messages is currently set to KERN_NOTICE
60 so that people can easily see the messages. Later when the debugging messages
61 in the drivers are more widely classified, this may be changed to KERN_DEBUG. */
62 #define OSST_DEB_MSG KERN_NOTICE
64 #include "scsi.h"
65 #include "hosts.h"
66 #include <scsi/scsi_driver.h>
67 #include <scsi/scsi_ioctl.h>
69 #define ST_KILOBYTE 1024
71 #include "st.h"
72 #include "osst.h"
73 #include "osst_options.h"
74 #include "osst_detect.h"
76 static int max_dev = 0;
77 static int write_threshold_kbs = 0;
78 static int max_sg_segs = 0;
80 #ifdef MODULE
81 MODULE_AUTHOR("Willem Riede");
82 MODULE_DESCRIPTION("OnStream {DI-|FW-|SC-|USB}{30|50} Tape Driver");
83 MODULE_LICENSE("GPL");
85 MODULE_PARM(max_dev, "i");
86 MODULE_PARM_DESC(max_dev, "Maximum number of OnStream Tape Drives to attach (4)");
88 MODULE_PARM(write_threshold_kbs, "i");
89 MODULE_PARM_DESC(write_threshold_kbs, "Asynchronous write threshold (KB; 32)");
91 MODULE_PARM(max_sg_segs, "i");
92 MODULE_PARM_DESC(max_sg_segs, "Maximum number of scatter/gather segments to use (9)");
93 #else
94 static struct osst_dev_parm {
95 char *name;
96 int *val;
97 } parms[] __initdata = {
98 { "max_dev", &max_dev },
99 { "write_threshold_kbs", &write_threshold_kbs },
100 { "max_sg_segs", &max_sg_segs }
102 #endif
104 static char *osst_formats[ST_NBR_MODES] ={"", "l", "m", "a"};
106 /* Some default definitions have been moved to osst_options.h */
107 #define OSST_BUFFER_SIZE (OSST_BUFFER_BLOCKS * ST_KILOBYTE)
108 #define OSST_WRITE_THRESHOLD (OSST_WRITE_THRESHOLD_BLOCKS * ST_KILOBYTE)
110 /* The buffer size should fit into the 24 bits for length in the
111 6-byte SCSI read and write commands. */
112 #if OSST_BUFFER_SIZE >= (2 << 24 - 1)
113 #error "Buffer size should not exceed (2 << 24 - 1) bytes!"
114 #endif
116 #if DEBUG
117 static int debugging = 1;
118 /* uncomment define below to test error recovery */
119 // #define OSST_INJECT_ERRORS 1
120 #endif
122 #define MAX_RETRIES 2
123 #define MAX_READ_RETRIES 0
124 #define MAX_WRITE_RETRIES 0
125 #define MAX_READY_RETRIES 0
126 #define NO_TAPE NOT_READY
128 #define OSST_WAIT_POSITION_COMPLETE (HZ > 200 ? HZ / 200 : 1)
129 #define OSST_WAIT_WRITE_COMPLETE (HZ / 12)
130 #define OSST_WAIT_LONG_WRITE_COMPLETE (HZ / 2)
132 #define OSST_TIMEOUT (200 * HZ)
133 #define OSST_LONG_TIMEOUT (1800 * HZ)
135 #define TAPE_NR(x) (minor(x) & ~(-1 << ST_MODE_SHIFT))
136 #define TAPE_MODE(x) ((minor(x) & ST_MODE_MASK) >> ST_MODE_SHIFT)
137 #define TAPE_REWIND(x) ((minor(x) & 0x80) == 0)
138 #define TAPE_IS_RAW(x) (TAPE_MODE(x) & (ST_NBR_MODES >> 1))
140 /* Internal ioctl to set both density (uppermost 8 bits) and blocksize (lower
141 24 bits) */
142 #define SET_DENS_AND_BLK 0x10001
144 static int osst_buffer_size = OSST_BUFFER_SIZE;
145 static int osst_write_threshold = OSST_WRITE_THRESHOLD;
146 static int osst_max_sg_segs = OSST_MAX_SG;
147 static int osst_max_dev = OSST_MAX_TAPES;
148 static int osst_nr_dev;
150 static OS_Scsi_Tape **os_scsi_tapes = NULL;
151 static rwlock_t os_scsi_tapes_lock = RW_LOCK_UNLOCKED;
153 static int modes_defined = FALSE;
155 static OSST_buffer *new_tape_buffer(int, int, int);
156 static int enlarge_buffer(OSST_buffer *, int);
157 static void normalize_buffer(OSST_buffer *);
158 static int append_to_buffer(const char *, OSST_buffer *, int);
159 static int from_buffer(OSST_buffer *, char *, int);
160 static int osst_zero_buffer_tail(OSST_buffer *);
161 static int osst_copy_to_buffer(OSST_buffer *, unsigned char *);
162 static int osst_copy_from_buffer(OSST_buffer *, unsigned char *);
164 static int osst_probe(struct device *);
165 static int osst_remove(struct device *);
167 struct scsi_driver osst_template = {
168 .owner = THIS_MODULE,
169 .gendrv = {
170 .name = "osst",
171 .probe = osst_probe,
172 .remove = osst_remove,
176 static int osst_int_ioctl(OS_Scsi_Tape *STp, Scsi_Request ** aSRpnt, unsigned int cmd_in,unsigned long arg);
178 static int osst_set_frame_position(OS_Scsi_Tape *STp, Scsi_Request ** aSRpnt, int frame, int skip);
180 static int osst_get_frame_position(OS_Scsi_Tape *STp, Scsi_Request ** aSRpnt);
182 static int osst_flush_write_buffer(OS_Scsi_Tape *STp, Scsi_Request ** aSRpnt);
184 static int osst_write_error_recovery(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int pending);
186 static inline char *tape_name(OS_Scsi_Tape *tape)
188 return tape->drive->disk_name;
191 /* Routines that handle the interaction with mid-layer SCSI routines */
193 /* Convert the result to success code */
194 static int osst_chk_result(OS_Scsi_Tape * STp, Scsi_Request * SRpnt)
196 char *name = tape_name(STp);
197 int result = SRpnt->sr_result;
198 unsigned char * sense = SRpnt->sr_sense_buffer, scode;
199 #if DEBUG
200 const char *stp;
201 #endif
203 if (!result) {
204 sense[0] = 0; /* We don't have sense data if this byte is zero */
205 return 0;
207 if ((driver_byte(result) & DRIVER_MASK) == DRIVER_SENSE)
208 scode = sense[2] & 0x0f;
209 else {
210 sense[0] = 0; /* We don't have sense data if this byte is zero */
211 scode = 0;
213 #if DEBUG
214 if (debugging) {
215 printk(OSST_DEB_MSG "%s:D: Error: %x, cmd: %x %x %x %x %x %x Len: %d\n",
216 name, result,
217 SRpnt->sr_cmnd[0], SRpnt->sr_cmnd[1], SRpnt->sr_cmnd[2],
218 SRpnt->sr_cmnd[3], SRpnt->sr_cmnd[4], SRpnt->sr_cmnd[5],
219 SRpnt->sr_bufflen);
220 if (scode) printk(OSST_DEB_MSG "%s:D: Sense: %02x, ASC: %02x, ASCQ: %02x\n",
221 name, scode, sense[12], sense[13]);
222 if (driver_byte(result) & DRIVER_SENSE)
223 print_req_sense("osst ", SRpnt);
225 // else
226 #endif
227 if (!(driver_byte(result) & DRIVER_SENSE) ||
228 ((sense[0] & 0x70) == 0x70 &&
229 scode != NO_SENSE &&
230 scode != RECOVERED_ERROR &&
231 /* scode != UNIT_ATTENTION && */
232 scode != BLANK_CHECK &&
233 scode != VOLUME_OVERFLOW &&
234 SRpnt->sr_cmnd[0] != MODE_SENSE &&
235 SRpnt->sr_cmnd[0] != TEST_UNIT_READY)) { /* Abnormal conditions for tape */
236 if (driver_byte(result) & DRIVER_SENSE) {
237 printk(KERN_WARNING "%s:W: Command with sense data: ", name);
238 print_req_sense("osst:", SRpnt);
240 else {
241 static int notyetprinted = 1;
243 printk(KERN_WARNING
244 "%s:W: Warning %x (sugg. bt 0x%x, driver bt 0x%x, host bt 0x%x).\n",
245 name, result, suggestion(result), driver_byte(result) & DRIVER_MASK,
246 host_byte(result));
247 if (notyetprinted) {
248 notyetprinted = 0;
249 printk(KERN_INFO
250 "%s:I: This warning may be caused by your scsi controller,\n", name);
251 printk(KERN_INFO
252 "%s:I: it has been reported with some Buslogic cards.\n", name);
256 STp->pos_unknown |= STp->device->was_reset;
258 if ((sense[0] & 0x70) == 0x70 &&
259 scode == RECOVERED_ERROR) {
260 STp->recover_count++;
261 STp->recover_erreg++;
262 #if DEBUG
263 if (debugging) {
264 if (SRpnt->sr_cmnd[0] == READ_6)
265 stp = "read";
266 else if (SRpnt->sr_cmnd[0] == WRITE_6)
267 stp = "write";
268 else
269 stp = "ioctl";
270 printk(OSST_DEB_MSG "%s:D: Recovered %s error (%d).\n", name, stp,
271 STp->recover_count);
273 #endif
274 if ((sense[2] & 0xe0) == 0)
275 return 0;
277 return (-EIO);
281 /* Wakeup from interrupt */
282 static void osst_sleep_done (Scsi_Cmnd * SCpnt)
284 OS_Scsi_Tape * STp = container_of(SCpnt->request->rq_disk->private_data, OS_Scsi_Tape, driver);
286 if ((STp->buffer)->writing &&
287 (SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
288 (SCpnt->sense_buffer[2] & 0x40)) {
289 /* EOM at write-behind, has all been written? */
290 if ((SCpnt->sense_buffer[2] & 0x0f) == VOLUME_OVERFLOW)
291 STp->buffer->midlevel_result = SCpnt->result; /* Error */
292 else
293 STp->buffer->midlevel_result = INT_MAX; /* OK */
295 else
296 STp->buffer->midlevel_result = SCpnt->result;
297 SCpnt->request->rq_status = RQ_SCSI_DONE;
298 STp->buffer->last_SRpnt = SCpnt->sc_request;
300 #if DEBUG
301 STp->write_pending = 0;
302 #endif
303 complete(SCpnt->request->waiting);
307 /* Do the scsi command. Waits until command performed if do_wait is true.
308 Otherwise osst_write_behind_check() is used to check that the command
309 has finished. */
310 static Scsi_Request * osst_do_scsi(Scsi_Request *SRpnt, OS_Scsi_Tape *STp,
311 unsigned char *cmd, int bytes, int direction, int timeout, int retries, int do_wait)
313 unsigned char *bp;
314 #ifdef OSST_INJECT_ERRORS
315 static int inject = 0;
316 static int repeat = 0;
317 #endif
318 if (SRpnt == NULL) {
319 if ((SRpnt = scsi_allocate_request(STp->device)) == NULL) {
320 printk(KERN_ERR "%s:E: Can't get SCSI request.\n", tape_name(STp));
321 if (signal_pending(current))
322 (STp->buffer)->syscall_result = (-EINTR);
323 else
324 (STp->buffer)->syscall_result = (-EBUSY);
325 return NULL;
329 init_completion(&STp->wait);
330 SRpnt->sr_use_sg = (bytes > (STp->buffer)->sg[0].length) ?
331 (STp->buffer)->use_sg : 0;
332 if (SRpnt->sr_use_sg) {
333 bp = (char *)&(STp->buffer->sg[0]);
334 if (STp->buffer->sg_segs < SRpnt->sr_use_sg)
335 SRpnt->sr_use_sg = STp->buffer->sg_segs;
337 else
338 bp = (STp->buffer)->b_data;
339 SRpnt->sr_data_direction = direction;
340 SRpnt->sr_cmd_len = 0;
341 SRpnt->sr_request->waiting = &(STp->wait);
342 SRpnt->sr_request->rq_status = RQ_SCSI_BUSY;
343 SRpnt->sr_request->rq_disk = STp->drive;
345 scsi_do_req(SRpnt, (void *)cmd, bp, bytes, osst_sleep_done, timeout, retries);
347 if (do_wait) {
348 wait_for_completion(SRpnt->sr_request->waiting);
349 SRpnt->sr_request->waiting = NULL;
350 STp->buffer->syscall_result = osst_chk_result(STp, SRpnt);
351 #ifdef OSST_INJECT_ERRORS
352 if (STp->buffer->syscall_result == 0 &&
353 cmd[0] == READ_6 &&
354 cmd[4] &&
355 ( (++ inject % 83) == 29 ||
356 (STp->first_frame_position == 240
357 /* or STp->read_error_frame to fail again on the block calculated above */ &&
358 ++repeat < 3))) {
359 printk(OSST_DEB_MSG "%s:D: Injecting read error\n", tape_name(STp));
360 STp->buffer->last_result_fatal = 1;
362 #endif
364 return SRpnt;
368 /* Handle the write-behind checking (downs the semaphore) */
369 static void osst_write_behind_check(OS_Scsi_Tape *STp)
371 OSST_buffer * STbuffer;
373 STbuffer = STp->buffer;
375 #if DEBUG
376 if (STp->write_pending)
377 STp->nbr_waits++;
378 else
379 STp->nbr_finished++;
380 #endif
381 wait_for_completion(&(STp->wait));
382 (STp->buffer)->last_SRpnt->sr_request->waiting = NULL;
384 STp->buffer->syscall_result = osst_chk_result(STp, STp->buffer->last_SRpnt);
386 if ((STp->buffer)->syscall_result)
387 (STp->buffer)->syscall_result =
388 osst_write_error_recovery(STp, &((STp->buffer)->last_SRpnt), 1);
389 else
390 STp->first_frame_position++;
392 scsi_release_request((STp->buffer)->last_SRpnt);
394 if (STbuffer->writing < STbuffer->buffer_bytes)
395 printk(KERN_WARNING "osst :A: write_behind_check: something left in buffer!\n");
397 STbuffer->buffer_bytes -= STbuffer->writing;
398 STbuffer->writing = 0;
400 return;
405 /* Onstream specific Routines */
407 * Initialize the OnStream AUX
409 static void osst_init_aux(OS_Scsi_Tape * STp, int frame_type, int frame_seq_number,
410 int logical_blk_num, int blk_sz, int blk_cnt)
412 os_aux_t *aux = STp->buffer->aux;
413 os_partition_t *par = &aux->partition;
414 os_dat_t *dat = &aux->dat;
416 if (STp->raw) return;
418 memset(aux, 0, sizeof(*aux));
419 aux->format_id = htonl(0);
420 memcpy(aux->application_sig, "LIN4", 4);
421 aux->hdwr = htonl(0);
422 aux->frame_type = frame_type;
424 switch (frame_type) {
425 case OS_FRAME_TYPE_HEADER:
426 aux->update_frame_cntr = htonl(STp->update_frame_cntr);
427 par->partition_num = OS_CONFIG_PARTITION;
428 par->par_desc_ver = OS_PARTITION_VERSION;
429 par->wrt_pass_cntr = htons(0xffff);
430 /* 0-4 = reserved, 5-9 = header, 2990-2994 = header, 2995-2999 = reserved */
431 par->first_frame_ppos = htonl(0);
432 par->last_frame_ppos = htonl(0xbb7);
433 aux->frame_seq_num = htonl(0);
434 aux->logical_blk_num_high = htonl(0);
435 aux->logical_blk_num = htonl(0);
436 aux->next_mark_ppos = htonl(STp->first_mark_ppos);
437 break;
438 case OS_FRAME_TYPE_DATA:
439 case OS_FRAME_TYPE_MARKER:
440 dat->dat_sz = 8;
441 dat->reserved1 = 0;
442 dat->entry_cnt = 1;
443 dat->reserved3 = 0;
444 dat->dat_list[0].blk_sz = htonl(blk_sz);
445 dat->dat_list[0].blk_cnt = htons(blk_cnt);
446 dat->dat_list[0].flags = frame_type==OS_FRAME_TYPE_MARKER?
447 OS_DAT_FLAGS_MARK:OS_DAT_FLAGS_DATA;
448 dat->dat_list[0].reserved = 0;
449 case OS_FRAME_TYPE_EOD:
450 aux->update_frame_cntr = htonl(0);
451 par->partition_num = OS_DATA_PARTITION;
452 par->par_desc_ver = OS_PARTITION_VERSION;
453 par->wrt_pass_cntr = htons(STp->wrt_pass_cntr);
454 par->first_frame_ppos = htonl(STp->first_data_ppos);
455 par->last_frame_ppos = htonl(STp->capacity);
456 aux->frame_seq_num = htonl(frame_seq_number);
457 aux->logical_blk_num_high = htonl(0);
458 aux->logical_blk_num = htonl(logical_blk_num);
459 break;
460 default: ; /* probably FILL */
462 aux->filemark_cnt = ntohl(STp->filemark_cnt);
463 aux->phys_fm = ntohl(0xffffffff);
464 aux->last_mark_ppos = ntohl(STp->last_mark_ppos);
465 aux->last_mark_lbn = ntohl(STp->last_mark_lbn);
469 * Verify that we have the correct tape frame
471 static int osst_verify_frame(OS_Scsi_Tape * STp, int frame_seq_number, int quiet)
473 char * name = tape_name(STp);
474 os_aux_t * aux = STp->buffer->aux;
475 os_partition_t * par = &(aux->partition);
476 ST_partstat * STps = &(STp->ps[STp->partition]);
477 int blk_cnt, blk_sz, i;
479 if (STp->raw) {
480 if (STp->buffer->syscall_result) {
481 for (i=0; i < STp->buffer->sg_segs; i++)
482 memset(page_address(STp->buffer->sg[i].page),
483 0, STp->buffer->sg[i].length);
484 strcpy(STp->buffer->b_data, "READ ERROR ON FRAME");
485 } else
486 STp->buffer->buffer_bytes = OS_FRAME_SIZE;
487 return 1;
489 if (STp->buffer->syscall_result) {
490 #if DEBUG
491 printk(OSST_DEB_MSG "%s:D: Skipping frame, read error\n", name);
492 #endif
493 return 0;
495 if (ntohl(aux->format_id) != 0) {
496 #if DEBUG
497 printk(OSST_DEB_MSG "%s:D: Skipping frame, format_id %u\n", name, ntohl(aux->format_id));
498 #endif
499 goto err_out;
501 if (memcmp(aux->application_sig, STp->application_sig, 4) != 0 &&
502 (memcmp(aux->application_sig, "LIN3", 4) != 0 || STp->linux_media_version != 4)) {
503 #if DEBUG
504 printk(OSST_DEB_MSG "%s:D: Skipping frame, incorrect application signature\n", name);
505 #endif
506 goto err_out;
508 if (par->partition_num != OS_DATA_PARTITION) {
509 if (!STp->linux_media || STp->linux_media_version != 2) {
510 #if DEBUG
511 printk(OSST_DEB_MSG "%s:D: Skipping frame, partition num %d\n",
512 name, par->partition_num);
513 #endif
514 goto err_out;
517 if (par->par_desc_ver != OS_PARTITION_VERSION) {
518 #if DEBUG
519 printk(OSST_DEB_MSG "%s:D: Skipping frame, partition version %d\n", name, par->par_desc_ver);
520 #endif
521 goto err_out;
523 if (ntohs(par->wrt_pass_cntr) != STp->wrt_pass_cntr) {
524 #if DEBUG
525 printk(OSST_DEB_MSG "%s:D: Skipping frame, wrt_pass_cntr %d (expected %d)\n",
526 name, ntohs(par->wrt_pass_cntr), STp->wrt_pass_cntr);
527 #endif
528 goto err_out;
530 if (aux->frame_type != OS_FRAME_TYPE_DATA &&
531 aux->frame_type != OS_FRAME_TYPE_EOD &&
532 aux->frame_type != OS_FRAME_TYPE_MARKER) {
533 if (!quiet)
534 #if DEBUG
535 printk(OSST_DEB_MSG "%s:D: Skipping frame, frame type %x\n", name, aux->frame_type);
536 #endif
537 goto err_out;
539 if (aux->frame_type == OS_FRAME_TYPE_EOD &&
540 STp->first_frame_position < STp->eod_frame_ppos) {
541 printk(KERN_INFO "%s:I: Skipping premature EOD frame %d\n", name,
542 STp->first_frame_position);
543 goto err_out;
545 if (frame_seq_number != -1 && ntohl(aux->frame_seq_num) != frame_seq_number) {
546 if (!quiet)
547 #if DEBUG
548 printk(OSST_DEB_MSG "%s:D: Skipping frame, sequence number %u (expected %d)\n",
549 name, ntohl(aux->frame_seq_num), frame_seq_number);
550 #endif
551 goto err_out;
553 if (aux->frame_type == OS_FRAME_TYPE_MARKER) {
554 STps->eof = ST_FM_HIT;
556 i = ntohl(aux->filemark_cnt);
557 if (STp->header_cache != NULL && i < OS_FM_TAB_MAX && (i > STp->filemark_cnt ||
558 STp->first_frame_position - 1 != ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[i]))) {
559 #if DEBUG
560 printk(OSST_DEB_MSG "%s:D: %s filemark %d at frame pos %d\n", name,
561 STp->header_cache->dat_fm_tab.fm_tab_ent[i] == 0?"Learned":"Corrected",
562 i, STp->first_frame_position - 1);
563 #endif
564 STp->header_cache->dat_fm_tab.fm_tab_ent[i] = htonl(STp->first_frame_position - 1);
565 if (i >= STp->filemark_cnt)
566 STp->filemark_cnt = i+1;
569 if (aux->frame_type == OS_FRAME_TYPE_EOD) {
570 STps->eof = ST_EOD_1;
571 STp->frame_in_buffer = 1;
573 if (aux->frame_type == OS_FRAME_TYPE_DATA) {
574 blk_cnt = ntohs(aux->dat.dat_list[0].blk_cnt);
575 blk_sz = ntohl(aux->dat.dat_list[0].blk_sz);
576 STp->buffer->buffer_bytes = blk_cnt * blk_sz;
577 STp->buffer->read_pointer = 0;
578 STp->frame_in_buffer = 1;
580 /* See what block size was used to write file */
581 if (STp->block_size != blk_sz && blk_sz > 0) {
582 printk(KERN_INFO
583 "%s:I: File was written with block size %d%c, currently %d%c, adjusted to match.\n",
584 name, blk_sz<1024?blk_sz:blk_sz/1024,blk_sz<1024?'b':'k',
585 STp->block_size<1024?STp->block_size:STp->block_size/1024,
586 STp->block_size<1024?'b':'k');
587 STp->block_size = blk_sz;
588 STp->buffer->buffer_blocks = OS_DATA_SIZE / blk_sz;
590 STps->eof = ST_NOEOF;
592 STp->frame_seq_number = ntohl(aux->frame_seq_num);
593 STp->logical_blk_num = ntohl(aux->logical_blk_num);
594 return 1;
596 err_out:
597 if (STp->read_error_frame == 0)
598 STp->read_error_frame = STp->first_frame_position - 1;
599 return 0;
603 * Wait for the unit to become Ready
605 static int osst_wait_ready(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, unsigned timeout, int initial_delay)
607 unsigned char cmd[MAX_COMMAND_SIZE];
608 Scsi_Request * SRpnt;
609 unsigned long startwait = jiffies;
610 #if DEBUG
611 int dbg = debugging;
612 char * name = tape_name(STp);
614 printk(OSST_DEB_MSG "%s:D: Reached onstream wait ready\n", name);
615 #endif
617 if (initial_delay > 0) {
618 set_current_state(TASK_INTERRUPTIBLE);
619 schedule_timeout(initial_delay);
622 memset(cmd, 0, MAX_COMMAND_SIZE);
623 cmd[0] = TEST_UNIT_READY;
625 SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, SCSI_DATA_NONE, STp->timeout, MAX_READY_RETRIES, TRUE);
626 *aSRpnt = SRpnt;
627 if (!SRpnt) return (-EBUSY);
629 while ( STp->buffer->syscall_result && time_before(jiffies, startwait + timeout*HZ) &&
630 (( SRpnt->sr_sense_buffer[2] == 2 && SRpnt->sr_sense_buffer[12] == 4 &&
631 (SRpnt->sr_sense_buffer[13] == 1 || SRpnt->sr_sense_buffer[13] == 8) ) ||
632 ( SRpnt->sr_sense_buffer[2] == 6 && SRpnt->sr_sense_buffer[12] == 0x28 &&
633 SRpnt->sr_sense_buffer[13] == 0 ) )) {
634 #if DEBUG
635 if (debugging) {
636 printk(OSST_DEB_MSG "%s:D: Sleeping in onstream wait ready\n", name);
637 printk(OSST_DEB_MSG "%s:D: Turning off debugging for a while\n", name);
638 debugging = 0;
640 #endif
641 set_current_state(TASK_INTERRUPTIBLE);
642 schedule_timeout(HZ / 10);
644 memset(cmd, 0, MAX_COMMAND_SIZE);
645 cmd[0] = TEST_UNIT_READY;
647 SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, SCSI_DATA_NONE, STp->timeout, MAX_READY_RETRIES, TRUE);
649 *aSRpnt = SRpnt;
650 #if DEBUG
651 debugging = dbg;
652 #endif
653 if ( STp->buffer->syscall_result &&
654 osst_write_error_recovery(STp, aSRpnt, 0) ) {
655 #if DEBUG
656 printk(OSST_DEB_MSG "%s:D: Abnormal exit from onstream wait ready\n", name);
657 printk(OSST_DEB_MSG "%s:D: Result = %d, Sense: 0=%02x, 2=%02x, 12=%02x, 13=%02x\n", name,
658 STp->buffer->syscall_result, SRpnt->sr_sense_buffer[0], SRpnt->sr_sense_buffer[2],
659 SRpnt->sr_sense_buffer[12], SRpnt->sr_sense_buffer[13]);
660 #endif
661 return (-EIO);
663 #if DEBUG
664 printk(OSST_DEB_MSG "%s:D: Normal exit from onstream wait ready\n", name);
665 #endif
666 return 0;
670 * Wait for a tape to be inserted in the unit
672 static int osst_wait_for_medium(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, unsigned timeout)
674 unsigned char cmd[MAX_COMMAND_SIZE];
675 Scsi_Request * SRpnt;
676 unsigned long startwait = jiffies;
677 #if DEBUG
678 int dbg = debugging;
679 char * name = tape_name(STp);
681 printk(OSST_DEB_MSG "%s:D: Reached onstream wait for medium\n", name);
682 #endif
684 memset(cmd, 0, MAX_COMMAND_SIZE);
685 cmd[0] = TEST_UNIT_READY;
687 SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, SCSI_DATA_NONE, STp->timeout, MAX_READY_RETRIES, TRUE);
688 *aSRpnt = SRpnt;
689 if (!SRpnt) return (-EBUSY);
691 while ( STp->buffer->syscall_result && time_before(jiffies, startwait + timeout*HZ) &&
692 SRpnt->sr_sense_buffer[2] == 2 && SRpnt->sr_sense_buffer[12] == 0x3a &&
693 SRpnt->sr_sense_buffer[13] == 0 ) {
694 #if DEBUG
695 if (debugging) {
696 printk(OSST_DEB_MSG "%s:D: Sleeping in onstream wait medium\n", name);
697 printk(OSST_DEB_MSG "%s:D: Turning off debugging for a while\n", name);
698 debugging = 0;
700 #endif
701 set_current_state(TASK_INTERRUPTIBLE);
702 schedule_timeout(HZ / 10);
704 memset(cmd, 0, MAX_COMMAND_SIZE);
705 cmd[0] = TEST_UNIT_READY;
707 SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, SCSI_DATA_NONE, STp->timeout, MAX_READY_RETRIES, TRUE);
709 *aSRpnt = SRpnt;
710 #if DEBUG
711 debugging = dbg;
712 #endif
713 if ( STp->buffer->syscall_result && SRpnt->sr_sense_buffer[2] != 2 &&
714 SRpnt->sr_sense_buffer[12] != 4 && SRpnt->sr_sense_buffer[13] == 1) {
715 #if DEBUG
716 printk(OSST_DEB_MSG "%s:D: Abnormal exit from onstream wait medium\n", name);
717 printk(OSST_DEB_MSG "%s:D: Result = %d, Sense: 0=%02x, 2=%02x, 12=%02x, 13=%02x\n", name,
718 STp->buffer->syscall_result, SRpnt->sr_sense_buffer[0], SRpnt->sr_sense_buffer[2],
719 SRpnt->sr_sense_buffer[12], SRpnt->sr_sense_buffer[13]);
720 #endif
721 return 0;
723 #if DEBUG
724 printk(OSST_DEB_MSG "%s:D: Normal exit from onstream wait medium\n", name);
725 #endif
726 return 1;
729 static int osst_position_tape_and_confirm(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int frame)
731 int retval;
733 osst_wait_ready(STp, aSRpnt, 15 * 60, 0); /* TODO - can this catch a write error? */
734 retval = osst_set_frame_position(STp, aSRpnt, frame, 0);
735 if (retval) return (retval);
736 osst_wait_ready(STp, aSRpnt, 15 * 60, OSST_WAIT_POSITION_COMPLETE);
737 return (osst_get_frame_position(STp, aSRpnt));
741 * Wait for write(s) to complete
743 static int osst_flush_drive_buffer(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt)
745 unsigned char cmd[MAX_COMMAND_SIZE];
746 Scsi_Request * SRpnt;
748 int result = 0;
749 int delay = OSST_WAIT_WRITE_COMPLETE;
750 #if DEBUG
751 char * name = tape_name(STp);
753 printk(OSST_DEB_MSG "%s:D: Reached onstream flush drive buffer (write filemark)\n", name);
754 #endif
756 memset(cmd, 0, MAX_COMMAND_SIZE);
757 cmd[0] = WRITE_FILEMARKS;
758 cmd[1] = 1;
760 SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, SCSI_DATA_NONE, STp->timeout, MAX_WRITE_RETRIES, TRUE);
761 *aSRpnt = SRpnt;
762 if (!SRpnt) return (-EBUSY);
763 if (STp->buffer->syscall_result) {
764 if ((SRpnt->sr_sense_buffer[2] & 0x0f) == 2 && SRpnt->sr_sense_buffer[12] == 4) {
765 if (SRpnt->sr_sense_buffer[13] == 8) {
766 delay = OSST_WAIT_LONG_WRITE_COMPLETE;
768 } else
769 result = osst_write_error_recovery(STp, aSRpnt, 0);
771 result |= osst_wait_ready(STp, aSRpnt, 5 * 60, delay);
772 STp->ps[STp->partition].rw = OS_WRITING_COMPLETE;
774 return (result);
777 #define OSST_POLL_PER_SEC 10
778 static int osst_wait_frame(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int curr, int minlast, int to)
780 unsigned long startwait = jiffies;
781 char * name = tape_name(STp);
782 #if DEBUG
783 char notyetprinted = 1;
784 #endif
785 if (minlast >= 0 && STp->ps[STp->partition].rw != ST_READING)
786 printk(KERN_ERR "%s:A: Waiting for frame without having initialized read!\n", name);
788 while (time_before (jiffies, startwait + to*HZ))
790 int result;
791 result = osst_get_frame_position (STp, aSRpnt);
792 if (result == -EIO)
793 if ((result = osst_write_error_recovery(STp, aSRpnt, 0)) == 0)
794 return 0; /* successful recovery leaves drive ready for frame */
795 if (result < 0) break;
796 if (STp->first_frame_position == curr &&
797 ((minlast < 0 &&
798 (signed)STp->last_frame_position > (signed)curr + minlast) ||
799 (minlast >= 0 && STp->cur_frames > minlast)
800 ) && result >= 0)
802 #if DEBUG
803 if (debugging || jiffies - startwait >= 2*HZ/OSST_POLL_PER_SEC)
804 printk (OSST_DEB_MSG
805 "%s:D: Succ wait f fr %i (>%i): %i-%i %i (%i): %3li.%li s\n",
806 name, curr, curr+minlast, STp->first_frame_position,
807 STp->last_frame_position, STp->cur_frames,
808 result, (jiffies-startwait)/HZ,
809 (((jiffies-startwait)%HZ)*10)/HZ);
810 #endif
811 return 0;
813 #if DEBUG
814 if (jiffies - startwait >= 2*HZ/OSST_POLL_PER_SEC && notyetprinted)
816 printk (OSST_DEB_MSG "%s:D: Wait for frame %i (>%i): %i-%i %i (%i)\n",
817 name, curr, curr+minlast, STp->first_frame_position,
818 STp->last_frame_position, STp->cur_frames, result);
819 notyetprinted--;
821 #endif
822 set_current_state(TASK_INTERRUPTIBLE);
823 schedule_timeout (HZ / OSST_POLL_PER_SEC);
825 #if DEBUG
826 printk (OSST_DEB_MSG "%s:D: Fail wait f fr %i (>%i): %i-%i %i: %3li.%li s\n",
827 name, curr, curr+minlast, STp->first_frame_position,
828 STp->last_frame_position, STp->cur_frames,
829 (jiffies-startwait)/HZ, (((jiffies-startwait)%HZ)*10)/HZ);
830 #endif
831 return -EBUSY;
835 * Read the next OnStream tape frame at the current location
837 static int osst_read_frame(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int timeout)
839 unsigned char cmd[MAX_COMMAND_SIZE];
840 Scsi_Request * SRpnt;
841 int retval = 0;
842 #if DEBUG
843 os_aux_t * aux = STp->buffer->aux;
844 char * name = tape_name(STp);
845 #endif
847 /* TODO: Error handling */
848 if (STp->poll)
849 retval = osst_wait_frame (STp, aSRpnt, STp->first_frame_position, 0, timeout);
850 #if 0// DEBUG
851 printk ("osst_read: wait for frame returned %i\n", retval);
852 #endif
854 memset(cmd, 0, MAX_COMMAND_SIZE);
855 cmd[0] = READ_6;
856 cmd[1] = 1;
857 cmd[4] = 1;
859 #if DEBUG
860 if (debugging)
861 printk(OSST_DEB_MSG "%s:D: Reading frame from OnStream tape\n", name);
862 #endif
863 SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, OS_FRAME_SIZE, SCSI_DATA_READ,
864 STp->timeout, MAX_READ_RETRIES, TRUE);
865 *aSRpnt = SRpnt;
866 if (!SRpnt)
867 return (-EBUSY);
869 if ((STp->buffer)->syscall_result) {
870 retval = 1;
871 if (STp->read_error_frame == 0) {
872 STp->read_error_frame = STp->first_frame_position;
873 #if DEBUG
874 printk(OSST_DEB_MSG "%s:D: Recording read error at %d\n", name, STp->read_error_frame);
875 #endif
877 #if DEBUG
878 if (debugging)
879 printk(OSST_DEB_MSG "%s:D: Sense: %2x %2x %2x %2x %2x %2x %2x %2x\n",
880 name,
881 SRpnt->sr_sense_buffer[0], SRpnt->sr_sense_buffer[1],
882 SRpnt->sr_sense_buffer[2], SRpnt->sr_sense_buffer[3],
883 SRpnt->sr_sense_buffer[4], SRpnt->sr_sense_buffer[5],
884 SRpnt->sr_sense_buffer[6], SRpnt->sr_sense_buffer[7]);
885 #endif
887 else
888 STp->first_frame_position++;
889 #if DEBUG
890 if (debugging) {
891 char sig[8]; int i;
892 for (i=0;i<4;i++)
893 sig[i] = aux->application_sig[i]<32?'^':aux->application_sig[i];
894 sig[4] = '\0';
895 printk(OSST_DEB_MSG
896 "%s:D: AUX: %s UpdFrCt#%d Wpass#%d %s FrSeq#%d LogBlk#%d Qty=%d Sz=%d\n", name, sig,
897 ntohl(aux->update_frame_cntr), ntohs(aux->partition.wrt_pass_cntr),
898 aux->frame_type==1?"EOD":aux->frame_type==2?"MARK":
899 aux->frame_type==8?"HEADR":aux->frame_type==0x80?"DATA":"FILL",
900 ntohl(aux->frame_seq_num), ntohl(aux->logical_blk_num),
901 ntohs(aux->dat.dat_list[0].blk_cnt), ntohl(aux->dat.dat_list[0].blk_sz) );
902 if (aux->frame_type==2)
903 printk(OSST_DEB_MSG "%s:D: mark_cnt=%d, last_mark_ppos=%d, last_mark_lbn=%d\n", name,
904 ntohl(aux->filemark_cnt), ntohl(aux->last_mark_ppos), ntohl(aux->last_mark_lbn));
905 printk(OSST_DEB_MSG "%s:D: Exit read frame from OnStream tape with code %d\n", name, retval);
907 #endif
908 return (retval);
911 static int osst_initiate_read(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt)
913 ST_partstat * STps = &(STp->ps[STp->partition]);
914 Scsi_Request * SRpnt ;
915 unsigned char cmd[MAX_COMMAND_SIZE];
916 int retval = 0;
917 #if DEBUG
918 char * name = tape_name(STp);
919 #endif
921 if (STps->rw != ST_READING) { /* Initialize read operation */
922 if (STps->rw == ST_WRITING || STp->dirty) {
923 STp->write_type = OS_WRITE_DATA;
924 osst_flush_write_buffer(STp, aSRpnt);
925 osst_flush_drive_buffer(STp, aSRpnt);
927 STps->rw = ST_READING;
928 STp->frame_in_buffer = 0;
931 * Issue a read 0 command to get the OnStream drive
932 * read frames into its buffer.
934 memset(cmd, 0, MAX_COMMAND_SIZE);
935 cmd[0] = READ_6;
936 cmd[1] = 1;
938 #if DEBUG
939 printk(OSST_DEB_MSG "%s:D: Start Read Ahead on OnStream tape\n", name);
940 #endif
941 SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, SCSI_DATA_NONE, STp->timeout, MAX_READ_RETRIES, TRUE);
942 *aSRpnt = SRpnt;
943 retval = STp->buffer->syscall_result;
946 return retval;
949 static int osst_get_logical_frame(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int frame_seq_number, int quiet)
951 ST_partstat * STps = &(STp->ps[STp->partition]);
952 char * name = tape_name(STp);
953 int cnt = 0,
954 bad = 0,
955 past = 0,
957 position;
960 * If we want just any frame (-1) and there is a frame in the buffer, return it
962 if (frame_seq_number == -1 && STp->frame_in_buffer) {
963 #if DEBUG
964 printk(OSST_DEB_MSG "%s:D: Frame %d still in buffer\n", name, STp->frame_seq_number);
965 #endif
966 return (STps->eof);
969 * Search and wait for the next logical tape frame
971 while (1) {
972 if (cnt++ > 400) {
973 printk(KERN_ERR "%s:E: Couldn't find logical frame %d, aborting\n",
974 name, frame_seq_number);
975 if (STp->read_error_frame) {
976 osst_set_frame_position(STp, aSRpnt, STp->read_error_frame, 0);
977 #if DEBUG
978 printk(OSST_DEB_MSG "%s:D: Repositioning tape to bad frame %d\n",
979 name, STp->read_error_frame);
980 #endif
981 STp->read_error_frame = 0;
983 return (-EIO);
985 #if DEBUG
986 if (debugging)
987 printk(OSST_DEB_MSG "%s:D: Looking for frame %d, attempt %d\n",
988 name, frame_seq_number, cnt);
989 #endif
990 if ( osst_initiate_read(STp, aSRpnt)
991 || ( (!STp->frame_in_buffer) && osst_read_frame(STp, aSRpnt, 30) ) ) {
992 if (STp->raw)
993 return (-EIO);
994 position = osst_get_frame_position(STp, aSRpnt);
995 if (position >= 0xbae && position < 0xbb8)
996 position = 0xbb8;
997 else if (position > STp->eod_frame_ppos || ++bad == 10) {
998 position = STp->read_error_frame - 1;
1000 else {
1001 position += 39;
1002 cnt += 20;
1004 #if DEBUG
1005 printk(OSST_DEB_MSG "%s:D: Bad frame detected, positioning tape to block %d\n",
1006 name, position);
1007 #endif
1008 osst_set_frame_position(STp, aSRpnt, position, 0);
1009 continue;
1011 if (osst_verify_frame(STp, frame_seq_number, quiet))
1012 break;
1013 if (osst_verify_frame(STp, -1, quiet)) {
1014 x = ntohl(STp->buffer->aux->frame_seq_num);
1015 if (STp->fast_open) {
1016 printk(KERN_WARNING
1017 "%s:W: Found logical frame %d instead of %d after fast open\n",
1018 name, x, frame_seq_number);
1019 STp->header_ok = 0;
1020 STp->read_error_frame = 0;
1021 return (-EIO);
1023 if (x > frame_seq_number) {
1024 if (++past > 3) {
1025 /* positioning backwards did not bring us to the desired frame */
1026 position = STp->read_error_frame - 1;
1028 else {
1029 position = osst_get_frame_position(STp, aSRpnt)
1030 + frame_seq_number - x - 1;
1032 if (STp->first_frame_position >= 3000 && position < 3000)
1033 position -= 10;
1035 #if DEBUG
1036 printk(OSST_DEB_MSG
1037 "%s:D: Found logical frame %d while looking for %d: back up %d\n",
1038 name, x, frame_seq_number,
1039 STp->first_frame_position - position);
1040 #endif
1041 osst_set_frame_position(STp, aSRpnt, position, 0);
1042 cnt += 10;
1044 else
1045 past = 0;
1047 if (osst_get_frame_position(STp, aSRpnt) == 0xbaf) {
1048 #if DEBUG
1049 printk(OSST_DEB_MSG "%s:D: Skipping config partition\n", name);
1050 #endif
1051 osst_set_frame_position(STp, aSRpnt, 0xbb8, 0);
1052 cnt--;
1054 STp->frame_in_buffer = 0;
1056 if (cnt > 1) {
1057 STp->recover_count++;
1058 STp->recover_erreg++;
1059 printk(KERN_WARNING "%s:I: Don't worry, Read error at position %d recovered\n",
1060 name, STp->read_error_frame);
1062 STp->read_count++;
1064 #if DEBUG
1065 if (debugging || STps->eof)
1066 printk(OSST_DEB_MSG
1067 "%s:D: Exit get logical frame (%d=>%d) from OnStream tape with code %d\n",
1068 name, frame_seq_number, STp->frame_seq_number, STps->eof);
1069 #endif
1070 STp->fast_open = FALSE;
1071 STp->read_error_frame = 0;
1072 return (STps->eof);
1075 static int osst_seek_logical_blk(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int logical_blk_num)
1077 ST_partstat * STps = &(STp->ps[STp->partition]);
1078 char * name = tape_name(STp);
1079 int retries = 0;
1080 int frame_seq_estimate, ppos_estimate, move;
1082 if (logical_blk_num < 0) logical_blk_num = 0;
1083 #if DEBUG
1084 printk(OSST_DEB_MSG "%s:D: Seeking logical block %d (now at %d, size %d%c)\n",
1085 name, logical_blk_num, STp->logical_blk_num,
1086 STp->block_size<1024?STp->block_size:STp->block_size/1024,
1087 STp->block_size<1024?'b':'k');
1088 #endif
1089 /* Do we know where we are? */
1090 if (STps->drv_block >= 0) {
1091 move = logical_blk_num - STp->logical_blk_num;
1092 if (move < 0) move -= (OS_DATA_SIZE / STp->block_size) - 1;
1093 move /= (OS_DATA_SIZE / STp->block_size);
1094 frame_seq_estimate = STp->frame_seq_number + move;
1095 } else
1096 frame_seq_estimate = logical_blk_num * STp->block_size / OS_DATA_SIZE;
1098 if (frame_seq_estimate < 2980) ppos_estimate = frame_seq_estimate + 10;
1099 else ppos_estimate = frame_seq_estimate + 20;
1100 while (++retries < 10) {
1101 if (ppos_estimate > STp->eod_frame_ppos-2) {
1102 frame_seq_estimate += STp->eod_frame_ppos - 2 - ppos_estimate;
1103 ppos_estimate = STp->eod_frame_ppos - 2;
1105 if (frame_seq_estimate < 0) {
1106 frame_seq_estimate = 0;
1107 ppos_estimate = 10;
1109 osst_set_frame_position(STp, aSRpnt, ppos_estimate, 0);
1110 if (osst_get_logical_frame(STp, aSRpnt, frame_seq_estimate, 1) >= 0) {
1111 /* we've located the estimated frame, now does it have our block? */
1112 if (logical_blk_num < STp->logical_blk_num ||
1113 logical_blk_num >= STp->logical_blk_num + ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt)) {
1114 if (STps->eof == ST_FM_HIT)
1115 move = logical_blk_num < STp->logical_blk_num? -2 : 1;
1116 else {
1117 move = logical_blk_num - STp->logical_blk_num;
1118 if (move < 0) move -= (OS_DATA_SIZE / STp->block_size) - 1;
1119 move /= (OS_DATA_SIZE / STp->block_size);
1121 if (!move) move = logical_blk_num > STp->logical_blk_num ? 1 : -1;
1122 #if DEBUG
1123 printk(OSST_DEB_MSG
1124 "%s:D: Seek retry %d at ppos %d fsq %d (est %d) lbn %d (need %d) move %d\n",
1125 name, retries, ppos_estimate, STp->frame_seq_number, frame_seq_estimate,
1126 STp->logical_blk_num, logical_blk_num, move);
1127 #endif
1128 frame_seq_estimate += move;
1129 ppos_estimate += move;
1130 continue;
1131 } else {
1132 STp->buffer->read_pointer = (logical_blk_num - STp->logical_blk_num) * STp->block_size;
1133 STp->buffer->buffer_bytes -= STp->buffer->read_pointer;
1134 STp->logical_blk_num = logical_blk_num;
1135 #if DEBUG
1136 printk(OSST_DEB_MSG
1137 "%s:D: Seek success at ppos %d fsq %d in_buf %d, bytes %d, ptr %d*%d\n",
1138 name, ppos_estimate, STp->frame_seq_number, STp->frame_in_buffer,
1139 STp->buffer->buffer_bytes, STp->buffer->read_pointer / STp->block_size,
1140 STp->block_size);
1141 #endif
1142 STps->drv_file = ntohl(STp->buffer->aux->filemark_cnt);
1143 if (STps->eof == ST_FM_HIT) {
1144 STps->drv_file++;
1145 STps->drv_block = 0;
1146 } else {
1147 STps->drv_block = ntohl(STp->buffer->aux->last_mark_lbn)?
1148 STp->logical_blk_num -
1149 (STps->drv_file ? ntohl(STp->buffer->aux->last_mark_lbn) + 1 : 0):
1152 STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD:ST_NOEOF;
1153 return 0;
1156 if (osst_get_logical_frame(STp, aSRpnt, -1, 1) < 0)
1157 goto error;
1158 /* we are not yet at the estimated frame, adjust our estimate of its physical position */
1159 #if DEBUG
1160 printk(OSST_DEB_MSG "%s:D: Seek retry %d at ppos %d fsq %d (est %d) lbn %d (need %d)\n",
1161 name, retries, ppos_estimate, STp->frame_seq_number, frame_seq_estimate,
1162 STp->logical_blk_num, logical_blk_num);
1163 #endif
1164 if (frame_seq_estimate != STp->frame_seq_number)
1165 ppos_estimate += frame_seq_estimate - STp->frame_seq_number;
1166 else
1167 break;
1169 error:
1170 printk(KERN_ERR "%s:E: Couldn't seek to logical block %d (at %d), %d retries\n",
1171 name, logical_blk_num, STp->logical_blk_num, retries);
1172 return (-EIO);
1175 /* The values below are based on the OnStream frame payload size of 32K == 2**15,
1176 * that is, OSST_FRAME_SHIFT + OSST_SECTOR_SHIFT must be 15. With a minimum block
1177 * size of 512 bytes, we need to be able to resolve 32K/512 == 64 == 2**6 positions
1178 * inside each frame. Finaly, OSST_SECTOR_MASK == 2**OSST_FRAME_SHIFT - 1.
1180 #define OSST_FRAME_SHIFT 6
1181 #define OSST_SECTOR_SHIFT 9
1182 #define OSST_SECTOR_MASK 0x03F
1184 static int osst_get_sector(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt)
1186 int sector;
1187 #if DEBUG
1188 char * name = tape_name(STp);
1190 printk(OSST_DEB_MSG
1191 "%s:D: Positioned at ppos %d, frame %d, lbn %d, file %d, blk %d, %cptr %d, eof %d\n",
1192 name, STp->first_frame_position, STp->frame_seq_number, STp->logical_blk_num,
1193 STp->ps[STp->partition].drv_file, STp->ps[STp->partition].drv_block,
1194 STp->ps[STp->partition].rw == ST_WRITING?'w':'r',
1195 STp->ps[STp->partition].rw == ST_WRITING?STp->buffer->buffer_bytes:
1196 STp->buffer->read_pointer, STp->ps[STp->partition].eof);
1197 #endif
1198 /* do we know where we are inside a file? */
1199 if (STp->ps[STp->partition].drv_block >= 0) {
1200 sector = (STp->frame_in_buffer ? STp->first_frame_position-1 :
1201 STp->first_frame_position) << OSST_FRAME_SHIFT;
1202 if (STp->ps[STp->partition].rw == ST_WRITING)
1203 sector |= (STp->buffer->buffer_bytes >> OSST_SECTOR_SHIFT) & OSST_SECTOR_MASK;
1204 else
1205 sector |= (STp->buffer->read_pointer >> OSST_SECTOR_SHIFT) & OSST_SECTOR_MASK;
1206 } else {
1207 sector = osst_get_frame_position(STp, aSRpnt);
1208 if (sector > 0)
1209 sector <<= OSST_FRAME_SHIFT;
1211 return sector;
1214 static int osst_seek_sector(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int sector)
1216 ST_partstat * STps = &(STp->ps[STp->partition]);
1217 int frame = sector >> OSST_FRAME_SHIFT,
1218 offset = (sector & OSST_SECTOR_MASK) << OSST_SECTOR_SHIFT,
1220 #if DEBUG
1221 char * name = tape_name(STp);
1223 printk(OSST_DEB_MSG "%s:D: Seeking sector %d in frame %d at offset %d\n",
1224 name, sector, frame, offset);
1225 #endif
1226 if (frame < 0 || frame >= STp->capacity) return (-ENXIO);
1228 if (frame <= STp->first_data_ppos) {
1229 STp->frame_seq_number = STp->logical_blk_num = STps->drv_file = STps->drv_block = 0;
1230 return (osst_set_frame_position(STp, aSRpnt, frame, 0));
1232 r = osst_set_frame_position(STp, aSRpnt, offset?frame:frame-1, 0);
1233 if (r < 0) return r;
1235 r = osst_get_logical_frame(STp, aSRpnt, -1, 1);
1236 if (r < 0) return r;
1238 if (osst_get_frame_position(STp, aSRpnt) != (offset?frame+1:frame)) return (-EIO);
1240 if (offset) {
1241 STp->logical_blk_num += offset / STp->block_size;
1242 STp->buffer->read_pointer = offset;
1243 STp->buffer->buffer_bytes -= offset;
1244 } else {
1245 STp->frame_seq_number++;
1246 STp->frame_in_buffer = 0;
1247 STp->logical_blk_num += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
1248 STp->buffer->buffer_bytes = STp->buffer->read_pointer = 0;
1250 STps->drv_file = ntohl(STp->buffer->aux->filemark_cnt);
1251 if (STps->eof == ST_FM_HIT) {
1252 STps->drv_file++;
1253 STps->drv_block = 0;
1254 } else {
1255 STps->drv_block = ntohl(STp->buffer->aux->last_mark_lbn)?
1256 STp->logical_blk_num -
1257 (STps->drv_file ? ntohl(STp->buffer->aux->last_mark_lbn) + 1 : 0):
1260 STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD:ST_NOEOF;
1261 #if DEBUG
1262 printk(OSST_DEB_MSG
1263 "%s:D: Now positioned at ppos %d, frame %d, lbn %d, file %d, blk %d, rptr %d, eof %d\n",
1264 name, STp->first_frame_position, STp->frame_seq_number, STp->logical_blk_num,
1265 STps->drv_file, STps->drv_block, STp->buffer->read_pointer, STps->eof);
1266 #endif
1267 return 0;
1271 * Read back the drive's internal buffer contents, as a part
1272 * of the write error recovery mechanism for old OnStream
1273 * firmware revisions.
1274 * Precondition for this function to work: all frames in the
1275 * drive's buffer must be of one type (DATA, MARK or EOD)!
1277 static int osst_read_back_buffer_and_rewrite(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt,
1278 unsigned int frame, unsigned int skip, int pending)
1280 Scsi_Request * SRpnt = * aSRpnt;
1281 unsigned char * buffer, * p;
1282 unsigned char cmd[MAX_COMMAND_SIZE];
1283 int flag, new_frame, i;
1284 int nframes = STp->cur_frames;
1285 int blks_per_frame = ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
1286 int frame_seq_number = ntohl(STp->buffer->aux->frame_seq_num)
1287 - (nframes + pending - 1);
1288 int logical_blk_num = ntohl(STp->buffer->aux->logical_blk_num)
1289 - (nframes + pending - 1) * blks_per_frame;
1290 char * name = tape_name(STp);
1291 unsigned long startwait = jiffies;
1292 #if DEBUG
1293 int dbg = debugging;
1294 #endif
1296 if ((buffer = (unsigned char *)vmalloc((nframes + 1) * OS_DATA_SIZE)) == NULL)
1297 return (-EIO);
1299 printk(KERN_INFO "%s:I: Reading back %d frames from drive buffer%s\n",
1300 name, nframes, pending?" and one that was pending":"");
1302 osst_copy_from_buffer(STp->buffer, (p = &buffer[nframes * OS_DATA_SIZE]));
1303 #if DEBUG
1304 if (pending && debugging)
1305 printk(OSST_DEB_MSG "%s:D: Pending frame %d (lblk %d), data %02x %02x %02x %02x\n",
1306 name, frame_seq_number + nframes,
1307 logical_blk_num + nframes * blks_per_frame,
1308 p[0], p[1], p[2], p[3]);
1309 #endif
1310 for (i = 0, p = buffer; i < nframes; i++, p += OS_DATA_SIZE) {
1312 memset(cmd, 0, MAX_COMMAND_SIZE);
1313 cmd[0] = 0x3C; /* Buffer Read */
1314 cmd[1] = 6; /* Retrieve Faulty Block */
1315 cmd[7] = 32768 >> 8;
1316 cmd[8] = 32768 & 0xff;
1318 SRpnt = osst_do_scsi(SRpnt, STp, cmd, OS_FRAME_SIZE, SCSI_DATA_READ,
1319 STp->timeout, MAX_READ_RETRIES, TRUE);
1321 if ((STp->buffer)->syscall_result || !SRpnt) {
1322 printk(KERN_ERR "%s:E: Failed to read frame back from OnStream buffer\n", name);
1323 vfree((void *)buffer);
1324 *aSRpnt = SRpnt;
1325 return (-EIO);
1327 osst_copy_from_buffer(STp->buffer, p);
1328 #if DEBUG
1329 if (debugging)
1330 printk(OSST_DEB_MSG "%s:D: Read back logical frame %d, data %02x %02x %02x %02x\n",
1331 name, frame_seq_number + i, p[0], p[1], p[2], p[3]);
1332 #endif
1334 *aSRpnt = SRpnt;
1335 osst_get_frame_position(STp, aSRpnt);
1337 #if DEBUG
1338 printk(OSST_DEB_MSG "%s:D: Frames left in buffer: %d\n", name, STp->cur_frames);
1339 #endif
1340 /* Write synchronously so we can be sure we're OK again and don't have to recover recursively */
1341 /* In the header we don't actually re-write the frames that fail, just the ones after them */
1343 for (flag=1, new_frame=frame, p=buffer, i=0; i < nframes + pending; ) {
1345 if (flag) {
1346 if (STp->write_type == OS_WRITE_HEADER) {
1347 i += skip;
1348 p += skip * OS_DATA_SIZE;
1350 else if (new_frame < 2990 && new_frame+skip+nframes+pending >= 2990)
1351 new_frame = 3000-i;
1352 else
1353 new_frame += skip;
1354 #if DEBUG
1355 printk(OSST_DEB_MSG "%s:D: Position to frame %d, write fseq %d\n",
1356 name, new_frame+i, frame_seq_number+i);
1357 #endif
1358 osst_set_frame_position(STp, aSRpnt, new_frame + i, 0);
1359 osst_wait_ready(STp, aSRpnt, 60, OSST_WAIT_POSITION_COMPLETE);
1360 osst_get_frame_position(STp, aSRpnt);
1361 SRpnt = * aSRpnt;
1363 if (new_frame > frame + 1000) {
1364 printk(KERN_ERR "%s:E: Failed to find writable tape media\n", name);
1365 vfree((void *)buffer);
1366 return (-EIO);
1368 flag = 0;
1369 if ( i >= nframes + pending ) break;
1371 osst_copy_to_buffer(STp->buffer, p);
1373 * IMPORTANT: for error recovery to work, _never_ queue frames with mixed frame type!
1375 osst_init_aux(STp, STp->buffer->aux->frame_type, frame_seq_number+i,
1376 logical_blk_num + i*blks_per_frame,
1377 ntohl(STp->buffer->aux->dat.dat_list[0].blk_sz), blks_per_frame);
1378 memset(cmd, 0, MAX_COMMAND_SIZE);
1379 cmd[0] = WRITE_6;
1380 cmd[1] = 1;
1381 cmd[4] = 1;
1383 #if DEBUG
1384 if (debugging)
1385 printk(OSST_DEB_MSG
1386 "%s:D: About to write frame %d, seq %d, lbn %d, data %02x %02x %02x %02x\n",
1387 name, new_frame+i, frame_seq_number+i, logical_blk_num + i*blks_per_frame,
1388 p[0], p[1], p[2], p[3]);
1389 #endif
1390 SRpnt = osst_do_scsi(SRpnt, STp, cmd, OS_FRAME_SIZE, SCSI_DATA_WRITE,
1391 STp->timeout, MAX_WRITE_RETRIES, TRUE);
1393 if (STp->buffer->syscall_result)
1394 flag = 1;
1395 else {
1396 p += OS_DATA_SIZE; i++;
1398 /* if we just sent the last frame, wait till all successfully written */
1399 if ( i == nframes + pending ) {
1400 #if DEBUG
1401 printk(OSST_DEB_MSG "%s:D: Check re-write successful\n", name);
1402 #endif
1403 memset(cmd, 0, MAX_COMMAND_SIZE);
1404 cmd[0] = WRITE_FILEMARKS;
1405 cmd[1] = 1;
1406 SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, SCSI_DATA_NONE,
1407 STp->timeout, MAX_WRITE_RETRIES, TRUE);
1408 #if DEBUG
1409 if (debugging) {
1410 printk(OSST_DEB_MSG "%s:D: Sleeping in re-write wait ready\n", name);
1411 printk(OSST_DEB_MSG "%s:D: Turning off debugging for a while\n", name);
1412 debugging = 0;
1414 #endif
1415 flag = STp->buffer->syscall_result;
1416 while ( !flag && time_before(jiffies, startwait + 60*HZ) ) {
1418 memset(cmd, 0, MAX_COMMAND_SIZE);
1419 cmd[0] = TEST_UNIT_READY;
1421 SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, SCSI_DATA_NONE, STp->timeout,
1422 MAX_READY_RETRIES, TRUE);
1424 if (SRpnt->sr_sense_buffer[2] == 2 && SRpnt->sr_sense_buffer[12] == 4 &&
1425 (SRpnt->sr_sense_buffer[13] == 1 || SRpnt->sr_sense_buffer[13] == 8)) {
1426 /* in the process of becoming ready */
1427 set_current_state(TASK_INTERRUPTIBLE);
1428 schedule_timeout(HZ / 10);
1429 continue;
1431 if (STp->buffer->syscall_result)
1432 flag = 1;
1433 break;
1435 #if DEBUG
1436 debugging = dbg;
1437 printk(OSST_DEB_MSG "%s:D: Wait re-write finished\n", name);
1438 #endif
1441 *aSRpnt = SRpnt;
1442 if (flag) {
1443 if ((SRpnt->sr_sense_buffer[ 2] & 0x0f) == 13 &&
1444 SRpnt->sr_sense_buffer[12] == 0 &&
1445 SRpnt->sr_sense_buffer[13] == 2) {
1446 printk(KERN_ERR "%s:E: Volume overflow in write error recovery\n", name);
1447 vfree((void *)buffer);
1448 return (-EIO); /* hit end of tape = fail */
1450 i = ((SRpnt->sr_sense_buffer[3] << 24) |
1451 (SRpnt->sr_sense_buffer[4] << 16) |
1452 (SRpnt->sr_sense_buffer[5] << 8) |
1453 SRpnt->sr_sense_buffer[6] ) - new_frame;
1454 p = &buffer[i * OS_DATA_SIZE];
1455 #if DEBUG
1456 printk(OSST_DEB_MSG "%s:D: Additional write error at %d\n", name, new_frame+i);
1457 #endif
1458 osst_get_frame_position(STp, aSRpnt);
1459 #if DEBUG
1460 printk(OSST_DEB_MSG "%s:D: reported frame positions: host = %d, tape = %d\n",
1461 name, STp->first_frame_position, STp->last_frame_position);
1462 #endif
1465 if (!pending)
1466 osst_copy_to_buffer(STp->buffer, p); /* so buffer content == at entry in all cases */
1467 vfree((void *)buffer);
1468 return 0;
1471 static int osst_reposition_and_retry(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt,
1472 unsigned int frame, unsigned int skip, int pending)
1474 unsigned char cmd[MAX_COMMAND_SIZE];
1475 Scsi_Request * SRpnt;
1476 char * name = tape_name(STp);
1477 int expected = 0;
1478 int attempts = 1000 / skip;
1479 int flag = 1;
1480 unsigned long startwait = jiffies;
1481 #if DEBUG
1482 int dbg = debugging;
1483 #endif
1485 while (attempts && time_before(jiffies, startwait + 60*HZ)) {
1486 if (flag) {
1487 #if DEBUG
1488 debugging = dbg;
1489 #endif
1490 if (frame < 2990 && frame+skip+STp->cur_frames+pending >= 2990)
1491 frame = 3000-skip;
1492 expected = frame+skip+STp->cur_frames+pending;
1493 #if DEBUG
1494 printk(OSST_DEB_MSG "%s:D: Position to fppos %d, re-write from fseq %d\n",
1495 name, frame+skip, STp->frame_seq_number-STp->cur_frames-pending);
1496 #endif
1497 osst_set_frame_position(STp, aSRpnt, frame + skip, 1);
1498 flag = 0;
1499 attempts--;
1500 set_current_state(TASK_INTERRUPTIBLE);
1501 schedule_timeout(HZ / 10);
1503 if (osst_get_frame_position(STp, aSRpnt) < 0) { /* additional write error */
1504 #if DEBUG
1505 printk(OSST_DEB_MSG "%s:D: Addl error, host %d, tape %d, buffer %d\n",
1506 name, STp->first_frame_position,
1507 STp->last_frame_position, STp->cur_frames);
1508 #endif
1509 frame = STp->last_frame_position;
1510 flag = 1;
1511 continue;
1513 if (pending && STp->cur_frames < 50) {
1515 memset(cmd, 0, MAX_COMMAND_SIZE);
1516 cmd[0] = WRITE_6;
1517 cmd[1] = 1;
1518 cmd[4] = 1;
1519 #if DEBUG
1520 printk(OSST_DEB_MSG "%s:D: About to write pending fseq %d at fppos %d\n",
1521 name, STp->frame_seq_number-1, STp->first_frame_position);
1522 #endif
1523 SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, OS_FRAME_SIZE, SCSI_DATA_WRITE,
1524 STp->timeout, MAX_WRITE_RETRIES, TRUE);
1525 *aSRpnt = SRpnt;
1527 if (STp->buffer->syscall_result) { /* additional write error */
1528 if ((SRpnt->sr_sense_buffer[ 2] & 0x0f) == 13 &&
1529 SRpnt->sr_sense_buffer[12] == 0 &&
1530 SRpnt->sr_sense_buffer[13] == 2) {
1531 printk(KERN_ERR
1532 "%s:E: Volume overflow in write error recovery\n",
1533 name);
1534 break; /* hit end of tape = fail */
1536 flag = 1;
1538 else
1539 pending = 0;
1541 continue;
1543 if (STp->cur_frames == 0) {
1544 #if DEBUG
1545 debugging = dbg;
1546 printk(OSST_DEB_MSG "%s:D: Wait re-write finished\n", name);
1547 #endif
1548 if (STp->first_frame_position != expected) {
1549 printk(KERN_ERR "%s:A: Actual position %d - expected %d\n",
1550 name, STp->first_frame_position, expected);
1551 return (-EIO);
1553 return 0;
1555 #if DEBUG
1556 if (debugging) {
1557 printk(OSST_DEB_MSG "%s:D: Sleeping in re-write wait ready\n", name);
1558 printk(OSST_DEB_MSG "%s:D: Turning off debugging for a while\n", name);
1559 debugging = 0;
1561 #endif
1562 schedule_timeout(HZ / 10);
1564 printk(KERN_ERR "%s:E: Failed to find valid tape media\n", name);
1565 #if DEBUG
1566 debugging = dbg;
1567 #endif
1568 return (-EIO);
1572 * Error recovery algorithm for the OnStream tape.
1575 static int osst_write_error_recovery(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int pending)
1577 Scsi_Request * SRpnt = * aSRpnt;
1578 ST_partstat * STps = & STp->ps[STp->partition];
1579 char * name = tape_name(STp);
1580 int retval = 0;
1581 int rw_state;
1582 unsigned int frame, skip;
1584 rw_state = STps->rw;
1586 if ((SRpnt->sr_sense_buffer[ 2] & 0x0f) != 3
1587 || SRpnt->sr_sense_buffer[12] != 12
1588 || SRpnt->sr_sense_buffer[13] != 0) {
1589 #if DEBUG
1590 printk(OSST_DEB_MSG "%s:D: Write error recovery cannot handle %02x:%02x:%02x\n", name,
1591 SRpnt->sr_sense_buffer[2], SRpnt->sr_sense_buffer[12], SRpnt->sr_sense_buffer[13]);
1592 #endif
1593 return (-EIO);
1595 frame = (SRpnt->sr_sense_buffer[3] << 24) |
1596 (SRpnt->sr_sense_buffer[4] << 16) |
1597 (SRpnt->sr_sense_buffer[5] << 8) |
1598 SRpnt->sr_sense_buffer[6];
1599 skip = SRpnt->sr_sense_buffer[9];
1601 #if DEBUG
1602 printk(OSST_DEB_MSG "%s:D: Detected physical bad frame at %u, advised to skip %d\n", name, frame, skip);
1603 #endif
1604 osst_get_frame_position(STp, aSRpnt);
1605 #if DEBUG
1606 printk(OSST_DEB_MSG "%s:D: reported frame positions: host = %d, tape = %d\n",
1607 name, STp->first_frame_position, STp->last_frame_position);
1608 #endif
1609 switch (STp->write_type) {
1610 case OS_WRITE_DATA:
1611 case OS_WRITE_EOD:
1612 case OS_WRITE_NEW_MARK:
1613 printk(KERN_WARNING
1614 "%s:I: Relocating %d buffered logical frames from position %u to %u\n",
1615 name, STp->cur_frames, frame, (frame + skip > 3000 && frame < 3000)?3000:frame + skip);
1616 if (STp->os_fw_rev >= 10600)
1617 retval = osst_reposition_and_retry(STp, aSRpnt, frame, skip, pending);
1618 else
1619 retval = osst_read_back_buffer_and_rewrite(STp, aSRpnt, frame, skip, pending);
1620 printk(KERN_WARNING "%s:%s: %sWrite error%srecovered\n", name,
1621 retval?"E" :"I",
1622 retval?"" :"Don't worry, ",
1623 retval?" not ":" ");
1624 break;
1625 case OS_WRITE_LAST_MARK:
1626 printk(KERN_ERR "%s:E: Bad frame in update last marker, fatal\n", name);
1627 osst_set_frame_position(STp, aSRpnt, frame + STp->cur_frames + pending, 0);
1628 retval = -EIO;
1629 break;
1630 case OS_WRITE_HEADER:
1631 printk(KERN_WARNING "%s:I: Bad frame in header partition, skipped\n", name);
1632 retval = osst_read_back_buffer_and_rewrite(STp, aSRpnt, frame, 1, pending);
1633 break;
1634 default:
1635 printk(KERN_INFO "%s:I: Bad frame in filler, ignored\n", name);
1636 osst_set_frame_position(STp, aSRpnt, frame + STp->cur_frames + pending, 0);
1638 osst_get_frame_position(STp, aSRpnt);
1639 #if DEBUG
1640 printk(OSST_DEB_MSG "%s:D: Positioning complete, cur_frames %d, pos %d, tape pos %d\n",
1641 name, STp->cur_frames, STp->first_frame_position, STp->last_frame_position);
1642 printk(OSST_DEB_MSG "%s:D: next logical frame to write: %d\n", name, STp->logical_blk_num);
1643 #endif
1644 if (retval == 0) {
1645 STp->recover_count++;
1646 STp->recover_erreg++;
1648 STps->rw = rw_state;
1649 return retval;
1652 static int osst_space_over_filemarks_backward(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt,
1653 int mt_op, int mt_count)
1655 char * name = tape_name(STp);
1656 int cnt;
1657 int last_mark_ppos = -1;
1659 #if DEBUG
1660 printk(OSST_DEB_MSG "%s:D: Reached space_over_filemarks_backwards %d %d\n", name, mt_op, mt_count);
1661 #endif
1662 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
1663 #if DEBUG
1664 printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks_bwd\n", name);
1665 #endif
1666 return -EIO;
1668 if (STp->linux_media_version >= 4) {
1670 * direct lookup in header filemark list
1672 cnt = ntohl(STp->buffer->aux->filemark_cnt);
1673 if (STp->header_ok &&
1674 STp->header_cache != NULL &&
1675 (cnt - mt_count) >= 0 &&
1676 (cnt - mt_count) < OS_FM_TAB_MAX &&
1677 (cnt - mt_count) < STp->filemark_cnt &&
1678 STp->header_cache->dat_fm_tab.fm_tab_ent[cnt-1] == STp->buffer->aux->last_mark_ppos)
1680 last_mark_ppos = ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[cnt - mt_count]);
1681 #if DEBUG
1682 if (STp->header_cache == NULL || (cnt - mt_count) < 0 || (cnt - mt_count) >= OS_FM_TAB_MAX)
1683 printk(OSST_DEB_MSG "%s:D: Filemark lookup fail due to %s\n", name,
1684 STp->header_cache == NULL?"lack of header cache":"count out of range");
1685 else
1686 printk(OSST_DEB_MSG "%s:D: Filemark lookup: prev mark %d (%s), skip %d to %d\n",
1687 name, cnt,
1688 ((cnt == -1 && ntohl(STp->buffer->aux->last_mark_ppos) == -1) ||
1689 (STp->header_cache->dat_fm_tab.fm_tab_ent[cnt-1] ==
1690 STp->buffer->aux->last_mark_ppos))?"match":"error",
1691 mt_count, last_mark_ppos);
1692 #endif
1693 if (last_mark_ppos > 10 && last_mark_ppos < STp->eod_frame_ppos) {
1694 osst_position_tape_and_confirm(STp, aSRpnt, last_mark_ppos);
1695 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
1696 #if DEBUG
1697 printk(OSST_DEB_MSG
1698 "%s:D: Couldn't get logical blk num in space_filemarks\n", name);
1699 #endif
1700 return (-EIO);
1702 if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
1703 printk(KERN_WARNING "%s:W: Expected to find marker at ppos %d, not found\n",
1704 name, last_mark_ppos);
1705 return (-EIO);
1707 goto found;
1709 #if DEBUG
1710 printk(OSST_DEB_MSG "%s:D: Reverting to scan filemark backwards\n", name);
1711 #endif
1713 cnt = 0;
1714 while (cnt != mt_count) {
1715 last_mark_ppos = ntohl(STp->buffer->aux->last_mark_ppos);
1716 if (last_mark_ppos == -1)
1717 return (-EIO);
1718 #if DEBUG
1719 printk(OSST_DEB_MSG "%s:D: Positioning to last mark at %d\n", name, last_mark_ppos);
1720 #endif
1721 osst_position_tape_and_confirm(STp, aSRpnt, last_mark_ppos);
1722 cnt++;
1723 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
1724 #if DEBUG
1725 printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks\n", name);
1726 #endif
1727 return (-EIO);
1729 if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
1730 printk(KERN_WARNING "%s:W: Expected to find marker at ppos %d, not found\n",
1731 name, last_mark_ppos);
1732 return (-EIO);
1735 found:
1736 if (mt_op == MTBSFM) {
1737 STp->frame_seq_number++;
1738 STp->frame_in_buffer = 0;
1739 STp->buffer->buffer_bytes = 0;
1740 STp->buffer->read_pointer = 0;
1741 STp->logical_blk_num += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
1743 return 0;
1747 * ADRL 1.1 compatible "slow" space filemarks fwd version
1749 * Just scans for the filemark sequentially.
1751 static int osst_space_over_filemarks_forward_slow(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt,
1752 int mt_op, int mt_count)
1754 int cnt = 0;
1755 #if DEBUG
1756 char * name = tape_name(STp);
1758 printk(OSST_DEB_MSG "%s:D: Reached space_over_filemarks_forward_slow %d %d\n", name, mt_op, mt_count);
1759 #endif
1760 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
1761 #if DEBUG
1762 printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks_fwd\n", name);
1763 #endif
1764 return (-EIO);
1766 while (1) {
1767 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
1768 #if DEBUG
1769 printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks\n", name);
1770 #endif
1771 return (-EIO);
1773 if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_MARKER)
1774 cnt++;
1775 if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_EOD) {
1776 #if DEBUG
1777 printk(OSST_DEB_MSG "%s:D: space_fwd: EOD reached\n", name);
1778 #endif
1779 if (STp->first_frame_position > STp->eod_frame_ppos+1) {
1780 #if DEBUG
1781 printk(OSST_DEB_MSG "%s:D: EOD position corrected (%d=>%d)\n",
1782 name, STp->eod_frame_ppos, STp->first_frame_position-1);
1783 #endif
1784 STp->eod_frame_ppos = STp->first_frame_position-1;
1786 return (-EIO);
1788 if (cnt == mt_count)
1789 break;
1790 STp->frame_in_buffer = 0;
1792 if (mt_op == MTFSF) {
1793 STp->frame_seq_number++;
1794 STp->frame_in_buffer = 0;
1795 STp->buffer->buffer_bytes = 0;
1796 STp->buffer->read_pointer = 0;
1797 STp->logical_blk_num += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
1799 return 0;
1803 * Fast linux specific version of OnStream FSF
1805 static int osst_space_over_filemarks_forward_fast(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt,
1806 int mt_op, int mt_count)
1808 char * name = tape_name(STp);
1809 int cnt = 0,
1810 next_mark_ppos = -1;
1812 #if DEBUG
1813 printk(OSST_DEB_MSG "%s:D: Reached space_over_filemarks_forward_fast %d %d\n", name, mt_op, mt_count);
1814 #endif
1815 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
1816 #if DEBUG
1817 printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks_fwd\n", name);
1818 #endif
1819 return (-EIO);
1822 if (STp->linux_media_version >= 4) {
1824 * direct lookup in header filemark list
1826 cnt = ntohl(STp->buffer->aux->filemark_cnt) - 1;
1827 if (STp->header_ok &&
1828 STp->header_cache != NULL &&
1829 (cnt + mt_count) < OS_FM_TAB_MAX &&
1830 (cnt + mt_count) < STp->filemark_cnt &&
1831 ((cnt == -1 && ntohl(STp->buffer->aux->last_mark_ppos) == -1) ||
1832 (STp->header_cache->dat_fm_tab.fm_tab_ent[cnt] == STp->buffer->aux->last_mark_ppos)))
1834 next_mark_ppos = ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[cnt + mt_count]);
1835 #if DEBUG
1836 if (STp->header_cache == NULL || (cnt + mt_count) >= OS_FM_TAB_MAX)
1837 printk(OSST_DEB_MSG "%s:D: Filemark lookup fail due to %s\n", name,
1838 STp->header_cache == NULL?"lack of header cache":"count out of range");
1839 else
1840 printk(OSST_DEB_MSG "%s:D: Filemark lookup: prev mark %d (%s), skip %d to %d\n",
1841 name, cnt,
1842 ((cnt == -1 && ntohl(STp->buffer->aux->last_mark_ppos) == -1) ||
1843 (STp->header_cache->dat_fm_tab.fm_tab_ent[cnt] ==
1844 STp->buffer->aux->last_mark_ppos))?"match":"error",
1845 mt_count, next_mark_ppos);
1846 #endif
1847 if (next_mark_ppos <= 10 || next_mark_ppos > STp->eod_frame_ppos) {
1848 #if DEBUG
1849 printk(OSST_DEB_MSG "%s:D: Reverting to slow filemark space\n", name);
1850 #endif
1851 return osst_space_over_filemarks_forward_slow(STp, aSRpnt, mt_op, mt_count);
1852 } else {
1853 osst_position_tape_and_confirm(STp, aSRpnt, next_mark_ppos);
1854 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
1855 #if DEBUG
1856 printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks\n",
1857 name);
1858 #endif
1859 return (-EIO);
1861 if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
1862 printk(KERN_WARNING "%s:W: Expected to find marker at ppos %d, not found\n",
1863 name, next_mark_ppos);
1864 return (-EIO);
1866 if (ntohl(STp->buffer->aux->filemark_cnt) != cnt + mt_count) {
1867 printk(KERN_WARNING "%s:W: Expected to find marker %d at ppos %d, not %d\n",
1868 name, cnt+mt_count, next_mark_ppos,
1869 ntohl(STp->buffer->aux->filemark_cnt));
1870 return (-EIO);
1873 } else {
1875 * Find nearest (usually previous) marker, then jump from marker to marker
1877 while (1) {
1878 if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_MARKER)
1879 break;
1880 if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_EOD) {
1881 #if DEBUG
1882 printk(OSST_DEB_MSG "%s:D: space_fwd: EOD reached\n", name);
1883 #endif
1884 return (-EIO);
1886 if (ntohl(STp->buffer->aux->filemark_cnt) == 0) {
1887 if (STp->first_mark_ppos == -1) {
1888 #if DEBUG
1889 printk(OSST_DEB_MSG "%s:D: Reverting to slow filemark space\n", name);
1890 #endif
1891 return osst_space_over_filemarks_forward_slow(STp, aSRpnt, mt_op, mt_count);
1893 osst_position_tape_and_confirm(STp, aSRpnt, STp->first_mark_ppos);
1894 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
1895 #if DEBUG
1896 printk(OSST_DEB_MSG
1897 "%s:D: Couldn't get logical blk num in space_filemarks_fwd_fast\n",
1898 name);
1899 #endif
1900 return (-EIO);
1902 if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
1903 printk(KERN_WARNING "%s:W: Expected to find filemark at %d\n",
1904 name, STp->first_mark_ppos);
1905 return (-EIO);
1907 } else {
1908 if (osst_space_over_filemarks_backward(STp, aSRpnt, MTBSF, 1) < 0)
1909 return (-EIO);
1910 mt_count++;
1913 cnt++;
1914 while (cnt != mt_count) {
1915 next_mark_ppos = ntohl(STp->buffer->aux->next_mark_ppos);
1916 if (!next_mark_ppos || next_mark_ppos > STp->eod_frame_ppos) {
1917 #if DEBUG
1918 printk(OSST_DEB_MSG "%s:D: Reverting to slow filemark space\n", name);
1919 #endif
1920 return osst_space_over_filemarks_forward_slow(STp, aSRpnt, mt_op, mt_count - cnt);
1922 #if DEBUG
1923 else printk(OSST_DEB_MSG "%s:D: Positioning to next mark at %d\n", name, next_mark_ppos);
1924 #endif
1925 osst_position_tape_and_confirm(STp, aSRpnt, next_mark_ppos);
1926 cnt++;
1927 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
1928 #if DEBUG
1929 printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks\n",
1930 name);
1931 #endif
1932 return (-EIO);
1934 if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
1935 printk(KERN_WARNING "%s:W: Expected to find marker at ppos %d, not found\n",
1936 name, next_mark_ppos);
1937 return (-EIO);
1941 if (mt_op == MTFSF) {
1942 STp->frame_seq_number++;
1943 STp->frame_in_buffer = 0;
1944 STp->buffer->buffer_bytes = 0;
1945 STp->buffer->read_pointer = 0;
1946 STp->logical_blk_num += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
1948 return 0;
1952 * In debug mode, we want to see as many errors as possible
1953 * to test the error recovery mechanism.
1955 #if DEBUG
1956 static void osst_set_retries(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int retries)
1958 unsigned char cmd[MAX_COMMAND_SIZE];
1959 Scsi_Request * SRpnt = * aSRpnt;
1960 char * name = tape_name(STp);
1962 memset(cmd, 0, MAX_COMMAND_SIZE);
1963 cmd[0] = MODE_SELECT;
1964 cmd[1] = 0x10;
1965 cmd[4] = NUMBER_RETRIES_PAGE_LENGTH + MODE_HEADER_LENGTH;
1967 (STp->buffer)->b_data[0] = cmd[4] - 1;
1968 (STp->buffer)->b_data[1] = 0; /* Medium Type - ignoring */
1969 (STp->buffer)->b_data[2] = 0; /* Reserved */
1970 (STp->buffer)->b_data[3] = 0; /* Block Descriptor Length */
1971 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 0] = NUMBER_RETRIES_PAGE | (1 << 7);
1972 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 1] = 2;
1973 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] = 4;
1974 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] = retries;
1976 if (debugging)
1977 printk(OSST_DEB_MSG "%s:D: Setting number of retries on OnStream tape to %d\n", name, retries);
1979 SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], SCSI_DATA_WRITE, STp->timeout, 0, TRUE);
1980 *aSRpnt = SRpnt;
1982 if ((STp->buffer)->syscall_result)
1983 printk (KERN_ERR "%s:D: Couldn't set retries to %d\n", name, retries);
1985 #endif
1988 static int osst_write_filemark(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt)
1990 int result;
1991 int this_mark_ppos = STp->first_frame_position;
1992 int this_mark_lbn = STp->logical_blk_num;
1993 #if DEBUG
1994 char * name = tape_name(STp);
1995 #endif
1997 if (STp->raw) return 0;
1999 STp->write_type = OS_WRITE_NEW_MARK;
2000 #if DEBUG
2001 printk(OSST_DEB_MSG "%s:D: Writing Filemark %i at fppos %d (fseq %d, lblk %d)\n",
2002 name, STp->filemark_cnt, this_mark_ppos, STp->frame_seq_number, this_mark_lbn);
2003 #endif
2004 STp->dirty = 1;
2005 result = osst_flush_write_buffer(STp, aSRpnt);
2006 result |= osst_flush_drive_buffer(STp, aSRpnt);
2007 STp->last_mark_ppos = this_mark_ppos;
2008 STp->last_mark_lbn = this_mark_lbn;
2009 if (STp->header_cache != NULL && STp->filemark_cnt < OS_FM_TAB_MAX)
2010 STp->header_cache->dat_fm_tab.fm_tab_ent[STp->filemark_cnt] = htonl(this_mark_ppos);
2011 if (STp->filemark_cnt++ == 0)
2012 STp->first_mark_ppos = this_mark_ppos;
2013 return result;
2016 static int osst_write_eod(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt)
2018 int result;
2019 #if DEBUG
2020 char * name = tape_name(STp);
2021 #endif
2023 if (STp->raw) return 0;
2025 STp->write_type = OS_WRITE_EOD;
2026 STp->eod_frame_ppos = STp->first_frame_position;
2027 #if DEBUG
2028 printk(OSST_DEB_MSG "%s:D: Writing EOD at fppos %d (fseq %d, lblk %d)\n", name,
2029 STp->eod_frame_ppos, STp->frame_seq_number, STp->logical_blk_num);
2030 #endif
2031 STp->dirty = 1;
2033 result = osst_flush_write_buffer(STp, aSRpnt);
2034 result |= osst_flush_drive_buffer(STp, aSRpnt);
2035 STp->eod_frame_lfa = --(STp->frame_seq_number);
2036 return result;
2039 static int osst_write_filler(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int where, int count)
2041 char * name = tape_name(STp);
2043 #if DEBUG
2044 printk(OSST_DEB_MSG "%s:D: Reached onstream write filler group %d\n", name, where);
2045 #endif
2046 osst_wait_ready(STp, aSRpnt, 60 * 5, 0);
2047 osst_set_frame_position(STp, aSRpnt, where, 0);
2048 STp->write_type = OS_WRITE_FILLER;
2049 while (count--) {
2050 memcpy(STp->buffer->b_data, "Filler", 6);
2051 STp->buffer->buffer_bytes = 6;
2052 STp->dirty = 1;
2053 if (osst_flush_write_buffer(STp, aSRpnt)) {
2054 printk(KERN_INFO "%s:I: Couldn't write filler frame\n", name);
2055 return (-EIO);
2058 #if DEBUG
2059 printk(OSST_DEB_MSG "%s:D: Exiting onstream write filler group\n", name);
2060 #endif
2061 return osst_flush_drive_buffer(STp, aSRpnt);
2064 static int __osst_write_header(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int where, int count)
2066 char * name = tape_name(STp);
2067 int result;
2069 #if DEBUG
2070 printk(OSST_DEB_MSG "%s:D: Reached onstream write header group %d\n", name, where);
2071 #endif
2072 osst_wait_ready(STp, aSRpnt, 60 * 5, 0);
2073 osst_set_frame_position(STp, aSRpnt, where, 0);
2074 STp->write_type = OS_WRITE_HEADER;
2075 while (count--) {
2076 osst_copy_to_buffer(STp->buffer, (unsigned char *)STp->header_cache);
2077 STp->buffer->buffer_bytes = sizeof(os_header_t);
2078 STp->dirty = 1;
2079 if (osst_flush_write_buffer(STp, aSRpnt)) {
2080 printk(KERN_INFO "%s:I: Couldn't write header frame\n", name);
2081 return (-EIO);
2084 result = osst_flush_drive_buffer(STp, aSRpnt);
2085 #if DEBUG
2086 printk(OSST_DEB_MSG "%s:D: Write onstream header group %s\n", name, result?"failed":"done");
2087 #endif
2088 return result;
2091 static int osst_write_header(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int locate_eod)
2093 os_header_t * header;
2094 int result;
2095 char * name = tape_name(STp);
2097 #if DEBUG
2098 printk(OSST_DEB_MSG "%s:D: Writing tape header\n", name);
2099 #endif
2100 if (STp->raw) return 0;
2102 if (STp->header_cache == NULL) {
2103 if ((STp->header_cache = (os_header_t *)vmalloc(sizeof(os_header_t))) == NULL) {
2104 printk(KERN_ERR "%s:E: Failed to allocate header cache\n", name);
2105 return (-ENOMEM);
2107 memset(STp->header_cache, 0, sizeof(os_header_t));
2108 #if DEBUG
2109 printk(OSST_DEB_MSG "%s:D: Allocated and cleared memory for header cache\n", name);
2110 #endif
2112 if (STp->header_ok) STp->update_frame_cntr++;
2113 else STp->update_frame_cntr = 0;
2115 header = STp->header_cache;
2116 strcpy(header->ident_str, "ADR_SEQ");
2117 header->major_rev = 1;
2118 header->minor_rev = 4;
2119 header->ext_trk_tb_off = htons(17192);
2120 header->pt_par_num = 1;
2121 header->partition[0].partition_num = OS_DATA_PARTITION;
2122 header->partition[0].par_desc_ver = OS_PARTITION_VERSION;
2123 header->partition[0].wrt_pass_cntr = htons(STp->wrt_pass_cntr);
2124 header->partition[0].first_frame_ppos = htonl(STp->first_data_ppos);
2125 header->partition[0].last_frame_ppos = htonl(STp->capacity);
2126 header->partition[0].eod_frame_ppos = htonl(STp->eod_frame_ppos);
2127 header->cfg_col_width = htonl(20);
2128 header->dat_col_width = htonl(1500);
2129 header->qfa_col_width = htonl(0);
2130 header->ext_track_tb.nr_stream_part = 1;
2131 header->ext_track_tb.et_ent_sz = 32;
2132 header->ext_track_tb.dat_ext_trk_ey.et_part_num = 0;
2133 header->ext_track_tb.dat_ext_trk_ey.fmt = 1;
2134 header->ext_track_tb.dat_ext_trk_ey.fm_tab_off = htons(17736);
2135 header->ext_track_tb.dat_ext_trk_ey.last_hlb_hi = 0;
2136 header->ext_track_tb.dat_ext_trk_ey.last_hlb = htonl(STp->eod_frame_lfa);
2137 header->ext_track_tb.dat_ext_trk_ey.last_pp = htonl(STp->eod_frame_ppos);
2138 header->dat_fm_tab.fm_part_num = 0;
2139 header->dat_fm_tab.fm_tab_ent_sz = 4;
2140 header->dat_fm_tab.fm_tab_ent_cnt = htons(STp->filemark_cnt<OS_FM_TAB_MAX?
2141 STp->filemark_cnt:OS_FM_TAB_MAX);
2143 result = __osst_write_header(STp, aSRpnt, 0xbae, 5);
2144 if (STp->update_frame_cntr == 0)
2145 osst_write_filler(STp, aSRpnt, 0xbb3, 5);
2146 result &= __osst_write_header(STp, aSRpnt, 5, 5);
2148 if (locate_eod) {
2149 #if DEBUG
2150 printk(OSST_DEB_MSG "%s:D: Locating back to eod frame addr %d\n", name, STp->eod_frame_ppos);
2151 #endif
2152 osst_set_frame_position(STp, aSRpnt, STp->eod_frame_ppos, 0);
2154 if (result)
2155 printk(KERN_ERR "%s:E: Write header failed\n", name);
2156 else {
2157 memcpy(STp->application_sig, "LIN4", 4);
2158 STp->linux_media = 1;
2159 STp->linux_media_version = 4;
2160 STp->header_ok = 1;
2162 return result;
2165 static int osst_reset_header(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt)
2167 if (STp->header_cache != NULL)
2168 memset(STp->header_cache, 0, sizeof(os_header_t));
2170 STp->logical_blk_num = STp->frame_seq_number = 0;
2171 STp->frame_in_buffer = 0;
2172 STp->eod_frame_ppos = STp->first_data_ppos = 0x0000000A;
2173 STp->filemark_cnt = 0;
2174 STp->first_mark_ppos = STp->last_mark_ppos = STp->last_mark_lbn = -1;
2175 return osst_write_header(STp, aSRpnt, 1);
2178 static int __osst_analyze_headers(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int ppos)
2180 char * name = tape_name(STp);
2181 os_header_t * header;
2182 os_aux_t * aux;
2183 char id_string[8];
2184 int linux_media_version,
2185 update_frame_cntr;
2187 if (STp->raw)
2188 return 1;
2190 if (ppos == 5 || ppos == 0xbae || STp->buffer->syscall_result) {
2191 if (osst_set_frame_position(STp, aSRpnt, ppos, 0))
2192 printk(KERN_WARNING "%s:W: Couldn't position tape\n", name);
2193 if (osst_initiate_read (STp, aSRpnt)) {
2194 printk(KERN_WARNING "%s:W: Couldn't initiate read\n", name);
2195 return 0;
2198 if (osst_read_frame(STp, aSRpnt, 180)) {
2199 #if DEBUG
2200 printk(OSST_DEB_MSG "%s:D: Couldn't read header frame\n", name);
2201 #endif
2202 return 0;
2204 header = (os_header_t *) STp->buffer->b_data; /* warning: only first segment addressable */
2205 aux = STp->buffer->aux;
2206 if (aux->frame_type != OS_FRAME_TYPE_HEADER) {
2207 #if DEBUG
2208 printk(OSST_DEB_MSG "%s:D: Skipping non-header frame (%d)\n", name, ppos);
2209 #endif
2210 return 0;
2212 if (ntohl(aux->frame_seq_num) != 0 ||
2213 ntohl(aux->logical_blk_num) != 0 ||
2214 aux->partition.partition_num != OS_CONFIG_PARTITION ||
2215 ntohl(aux->partition.first_frame_ppos) != 0 ||
2216 ntohl(aux->partition.last_frame_ppos) != 0xbb7 ) {
2217 #if DEBUG
2218 printk(OSST_DEB_MSG "%s:D: Invalid header frame (%d,%d,%d,%d,%d)\n", name,
2219 ntohl(aux->frame_seq_num), ntohl(aux->logical_blk_num),
2220 aux->partition.partition_num, ntohl(aux->partition.first_frame_ppos),
2221 ntohl(aux->partition.last_frame_ppos));
2222 #endif
2223 return 0;
2225 if (strncmp(header->ident_str, "ADR_SEQ", 7) != 0 &&
2226 strncmp(header->ident_str, "ADR-SEQ", 7) != 0) {
2227 strlcpy(id_string, header->ident_str, 8);
2228 #if DEBUG
2229 printk(OSST_DEB_MSG "%s:D: Invalid header identification string %s\n", name, id_string);
2230 #endif
2231 return 0;
2233 update_frame_cntr = ntohl(aux->update_frame_cntr);
2234 if (update_frame_cntr < STp->update_frame_cntr) {
2235 #if DEBUG
2236 printk(OSST_DEB_MSG "%s:D: Skipping frame %d with update_frame_counter %d<%d\n",
2237 name, ppos, update_frame_cntr, STp->update_frame_cntr);
2238 #endif
2239 return 0;
2241 if (header->major_rev != 1 || header->minor_rev != 4 ) {
2242 #if DEBUG
2243 printk(OSST_DEB_MSG "%s:D: %s revision %d.%d detected (1.4 supported)\n",
2244 name, (header->major_rev != 1 || header->minor_rev < 2 ||
2245 header->minor_rev > 4 )? "Invalid" : "Warning:",
2246 header->major_rev, header->minor_rev);
2247 #endif
2248 if (header->major_rev != 1 || header->minor_rev < 2 || header->minor_rev > 4)
2249 return 0;
2251 #if DEBUG
2252 if (header->pt_par_num != 1)
2253 printk(KERN_INFO "%s:W: %d partitions defined, only one supported\n",
2254 name, header->pt_par_num);
2255 #endif
2256 memcpy(id_string, aux->application_sig, 4);
2257 id_string[4] = 0;
2258 if (memcmp(id_string, "LIN", 3) == 0) {
2259 STp->linux_media = 1;
2260 linux_media_version = id_string[3] - '0';
2261 if (linux_media_version != 4)
2262 printk(KERN_INFO "%s:I: Linux media version %d detected (current 4)\n",
2263 name, linux_media_version);
2264 } else {
2265 printk(KERN_WARNING "%s:W: Non Linux media detected (%s)\n", name, id_string);
2266 return 0;
2268 if (linux_media_version < STp->linux_media_version) {
2269 #if DEBUG
2270 printk(OSST_DEB_MSG "%s:D: Skipping frame %d with linux_media_version %d\n",
2271 name, ppos, linux_media_version);
2272 #endif
2273 return 0;
2275 if (linux_media_version > STp->linux_media_version) {
2276 #if DEBUG
2277 printk(OSST_DEB_MSG "%s:D: Frame %d sets linux_media_version to %d\n",
2278 name, ppos, linux_media_version);
2279 #endif
2280 memcpy(STp->application_sig, id_string, 5);
2281 STp->linux_media_version = linux_media_version;
2282 STp->update_frame_cntr = -1;
2284 if (update_frame_cntr > STp->update_frame_cntr) {
2285 #if DEBUG
2286 printk(OSST_DEB_MSG "%s:D: Frame %d sets update_frame_counter to %d\n",
2287 name, ppos, update_frame_cntr);
2288 #endif
2289 if (STp->header_cache == NULL) {
2290 if ((STp->header_cache = (os_header_t *)vmalloc(sizeof(os_header_t))) == NULL) {
2291 printk(KERN_ERR "%s:E: Failed to allocate header cache\n", name);
2292 return 0;
2294 #if DEBUG
2295 printk(OSST_DEB_MSG "%s:D: Allocated memory for header cache\n", name);
2296 #endif
2298 osst_copy_from_buffer(STp->buffer, (unsigned char *)STp->header_cache);
2299 header = STp->header_cache; /* further accesses from cached (full) copy */
2301 STp->wrt_pass_cntr = ntohs(header->partition[0].wrt_pass_cntr);
2302 STp->first_data_ppos = ntohl(header->partition[0].first_frame_ppos);
2303 STp->eod_frame_ppos = ntohl(header->partition[0].eod_frame_ppos);
2304 STp->eod_frame_lfa = ntohl(header->ext_track_tb.dat_ext_trk_ey.last_hlb);
2305 STp->filemark_cnt = ntohl(aux->filemark_cnt);
2306 STp->first_mark_ppos = ntohl(aux->next_mark_ppos);
2307 STp->last_mark_ppos = ntohl(aux->last_mark_ppos);
2308 STp->last_mark_lbn = ntohl(aux->last_mark_lbn);
2309 STp->update_frame_cntr = update_frame_cntr;
2310 #if DEBUG
2311 printk(OSST_DEB_MSG "%s:D: Detected write pass %d, update frame counter %d, filemark counter %d\n",
2312 name, STp->wrt_pass_cntr, STp->update_frame_cntr, STp->filemark_cnt);
2313 printk(OSST_DEB_MSG "%s:D: first data frame on tape = %d, last = %d, eod frame = %d\n", name,
2314 STp->first_data_ppos,
2315 ntohl(header->partition[0].last_frame_ppos),
2316 ntohl(header->partition[0].eod_frame_ppos));
2317 printk(OSST_DEB_MSG "%s:D: first mark on tape = %d, last = %d, eod frame = %d\n",
2318 name, STp->first_mark_ppos, STp->last_mark_ppos, STp->eod_frame_ppos);
2319 #endif
2320 if (header->minor_rev < 4 && STp->linux_media_version == 4) {
2321 #if DEBUG
2322 printk(OSST_DEB_MSG "%s:D: Moving filemark list to ADR 1.4 location\n", name);
2323 #endif
2324 memcpy((void *)header->dat_fm_tab.fm_tab_ent,
2325 (void *)header->old_filemark_list, sizeof(header->dat_fm_tab.fm_tab_ent));
2326 memset((void *)header->old_filemark_list, 0, sizeof(header->old_filemark_list));
2328 if (header->minor_rev == 4 &&
2329 (header->ext_trk_tb_off != htons(17192) ||
2330 header->partition[0].partition_num != OS_DATA_PARTITION ||
2331 header->partition[0].par_desc_ver != OS_PARTITION_VERSION ||
2332 header->partition[0].last_frame_ppos != htonl(STp->capacity) ||
2333 header->cfg_col_width != htonl(20) ||
2334 header->dat_col_width != htonl(1500) ||
2335 header->qfa_col_width != htonl(0) ||
2336 header->ext_track_tb.nr_stream_part != 1 ||
2337 header->ext_track_tb.et_ent_sz != 32 ||
2338 header->ext_track_tb.dat_ext_trk_ey.et_part_num != OS_DATA_PARTITION ||
2339 header->ext_track_tb.dat_ext_trk_ey.fmt != 1 ||
2340 header->ext_track_tb.dat_ext_trk_ey.fm_tab_off != htons(17736) ||
2341 header->ext_track_tb.dat_ext_trk_ey.last_hlb_hi != 0 ||
2342 header->ext_track_tb.dat_ext_trk_ey.last_pp != htonl(STp->eod_frame_ppos) ||
2343 header->dat_fm_tab.fm_part_num != OS_DATA_PARTITION ||
2344 header->dat_fm_tab.fm_tab_ent_sz != 4 ||
2345 header->dat_fm_tab.fm_tab_ent_cnt !=
2346 htons(STp->filemark_cnt<OS_FM_TAB_MAX?STp->filemark_cnt:OS_FM_TAB_MAX)))
2347 printk(KERN_WARNING "%s:W: Failed consistency check ADR 1.4 format\n", name);
2351 return 1;
2354 static int osst_analyze_headers(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt)
2356 int position, ppos;
2357 int first, last;
2358 int valid = 0;
2359 char * name = tape_name(STp);
2361 position = osst_get_frame_position(STp, aSRpnt);
2363 if (STp->raw) {
2364 STp->header_ok = STp->linux_media = 1;
2365 STp->linux_media_version = 0;
2366 return 1;
2368 STp->header_ok = STp->linux_media = STp->linux_media_version = 0;
2369 STp->wrt_pass_cntr = STp->update_frame_cntr = -1;
2370 STp->eod_frame_ppos = STp->first_data_ppos = -1;
2371 STp->first_mark_ppos = STp->last_mark_ppos = STp->last_mark_lbn = -1;
2372 #if DEBUG
2373 printk(OSST_DEB_MSG "%s:D: Reading header\n", name);
2374 #endif
2376 /* optimization for speed - if we are positioned at ppos 10, read second group first */
2377 /* TODO try the ADR 1.1 locations for the second group if we have no valid one yet... */
2379 first = position==10?0xbae: 5;
2380 last = position==10?0xbb3:10;
2382 for (ppos = first; ppos < last; ppos++)
2383 if (__osst_analyze_headers(STp, aSRpnt, ppos))
2384 valid = 1;
2386 first = position==10? 5:0xbae;
2387 last = position==10?10:0xbb3;
2389 for (ppos = first; ppos < last; ppos++)
2390 if (__osst_analyze_headers(STp, aSRpnt, ppos))
2391 valid = 1;
2393 if (!valid) {
2394 printk(KERN_ERR "%s:E: Failed to find valid ADRL header, new media?\n", name);
2395 STp->eod_frame_ppos = STp->first_data_ppos = 0;
2396 osst_set_frame_position(STp, aSRpnt, 10, 0);
2397 return 0;
2399 if (position <= STp->first_data_ppos) {
2400 position = STp->first_data_ppos;
2401 STp->ps[0].drv_file = STp->ps[0].drv_block = STp->frame_seq_number = STp->logical_blk_num = 0;
2403 osst_set_frame_position(STp, aSRpnt, position, 0);
2404 STp->header_ok = 1;
2406 return 1;
2409 static int osst_verify_position(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt)
2411 int frame_position = STp->first_frame_position;
2412 int frame_seq_numbr = STp->frame_seq_number;
2413 int logical_blk_num = STp->logical_blk_num;
2414 int halfway_frame = STp->frame_in_buffer;
2415 int read_pointer = STp->buffer->read_pointer;
2416 int prev_mark_ppos = -1;
2417 int actual_mark_ppos, i, n;
2418 #if DEBUG
2419 char * name = tape_name(STp);
2421 printk(OSST_DEB_MSG "%s:D: Verify that the tape is really the one we think before writing\n", name);
2422 #endif
2423 osst_set_frame_position(STp, aSRpnt, frame_position - 1, 0);
2424 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
2425 #if DEBUG
2426 printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in verify_position\n", name);
2427 #endif
2428 return (-EIO);
2430 if (STp->linux_media_version >= 4) {
2431 for (i=0; i<STp->filemark_cnt; i++)
2432 if ((n=ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[i])) < frame_position)
2433 prev_mark_ppos = n;
2434 } else
2435 prev_mark_ppos = frame_position - 1; /* usually - we don't really know */
2436 actual_mark_ppos = STp->buffer->aux->frame_type == OS_FRAME_TYPE_MARKER ?
2437 frame_position - 1 : ntohl(STp->buffer->aux->last_mark_ppos);
2438 if (frame_position != STp->first_frame_position ||
2439 frame_seq_numbr != STp->frame_seq_number + (halfway_frame?0:1) ||
2440 prev_mark_ppos != actual_mark_ppos ) {
2441 #if DEBUG
2442 printk(OSST_DEB_MSG "%s:D: Block mismatch: fppos %d-%d, fseq %d-%d, mark %d-%d\n", name,
2443 STp->first_frame_position, frame_position,
2444 STp->frame_seq_number + (halfway_frame?0:1),
2445 frame_seq_numbr, actual_mark_ppos, prev_mark_ppos);
2446 #endif
2447 return (-EIO);
2449 if (halfway_frame) {
2450 /* prepare buffer for append and rewrite on top of original */
2451 osst_set_frame_position(STp, aSRpnt, frame_position - 1, 0);
2452 STp->buffer->buffer_bytes = read_pointer;
2453 STp->ps[STp->partition].rw = ST_WRITING;
2454 STp->dirty = 1;
2456 STp->frame_in_buffer = halfway_frame;
2457 STp->frame_seq_number = frame_seq_numbr;
2458 STp->logical_blk_num = logical_blk_num;
2459 return 0;
2462 /* Acc. to OnStream, the vers. numbering is the following:
2463 * X.XX for released versions (X=digit),
2464 * XXXY for unreleased versions (Y=letter)
2465 * Ordering 1.05 < 106A < 106B < ... < 106a < ... < 1.06
2466 * This fn makes monoton numbers out of this scheme ...
2468 static unsigned int osst_parse_firmware_rev (const char * str)
2470 if (str[1] == '.') {
2471 return (str[0]-'0')*10000
2472 +(str[2]-'0')*1000
2473 +(str[3]-'0')*100;
2474 } else {
2475 return (str[0]-'0')*10000
2476 +(str[1]-'0')*1000
2477 +(str[2]-'0')*100 - 100
2478 +(str[3]-'@');
2483 * Configure the OnStream SCII tape drive for default operation
2485 static int osst_configure_onstream(OS_Scsi_Tape *STp, Scsi_Request ** aSRpnt)
2487 unsigned char cmd[MAX_COMMAND_SIZE];
2488 char * name = tape_name(STp);
2489 Scsi_Request * SRpnt = * aSRpnt;
2490 osst_mode_parameter_header_t * header;
2491 osst_block_size_page_t * bs;
2492 osst_capabilities_page_t * cp;
2493 osst_tape_paramtr_page_t * prm;
2494 int drive_buffer_size;
2496 if (STp->ready != ST_READY) {
2497 #if DEBUG
2498 printk(OSST_DEB_MSG "%s:D: Not Ready\n", name);
2499 #endif
2500 return (-EIO);
2503 if (STp->os_fw_rev < 10600) {
2504 printk(KERN_INFO "%s:I: Old OnStream firmware revision detected (%s),\n", name, STp->device->rev);
2505 printk(KERN_INFO "%s:I: an upgrade to version 1.06 or above is recommended\n", name);
2509 * Configure 32.5KB (data+aux) frame size.
2510 * Get the current frame size from the block size mode page
2512 memset(cmd, 0, MAX_COMMAND_SIZE);
2513 cmd[0] = MODE_SENSE;
2514 cmd[1] = 8;
2515 cmd[2] = BLOCK_SIZE_PAGE;
2516 cmd[4] = BLOCK_SIZE_PAGE_LENGTH + MODE_HEADER_LENGTH;
2518 SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], SCSI_DATA_READ, STp->timeout, 0, TRUE);
2519 if (SRpnt == NULL) {
2520 #if DEBUG
2521 printk(OSST_DEB_MSG "osst :D: Busy\n");
2522 #endif
2523 return (-EBUSY);
2525 *aSRpnt = SRpnt;
2526 if ((STp->buffer)->syscall_result != 0) {
2527 printk (KERN_ERR "%s:E: Can't get tape block size mode page\n", name);
2528 return (-EIO);
2531 header = (osst_mode_parameter_header_t *) (STp->buffer)->b_data;
2532 bs = (osst_block_size_page_t *) ((STp->buffer)->b_data + sizeof(osst_mode_parameter_header_t) + header->bdl);
2534 #if DEBUG
2535 printk(OSST_DEB_MSG "%s:D: 32KB play back: %s\n", name, bs->play32 ? "Yes" : "No");
2536 printk(OSST_DEB_MSG "%s:D: 32.5KB play back: %s\n", name, bs->play32_5 ? "Yes" : "No");
2537 printk(OSST_DEB_MSG "%s:D: 32KB record: %s\n", name, bs->record32 ? "Yes" : "No");
2538 printk(OSST_DEB_MSG "%s:D: 32.5KB record: %s\n", name, bs->record32_5 ? "Yes" : "No");
2539 #endif
2542 * Configure default auto columns mode, 32.5KB transfer mode
2544 bs->one = 1;
2545 bs->play32 = 0;
2546 bs->play32_5 = 1;
2547 bs->record32 = 0;
2548 bs->record32_5 = 1;
2550 memset(cmd, 0, MAX_COMMAND_SIZE);
2551 cmd[0] = MODE_SELECT;
2552 cmd[1] = 0x10;
2553 cmd[4] = BLOCK_SIZE_PAGE_LENGTH + MODE_HEADER_LENGTH;
2555 SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], SCSI_DATA_WRITE, STp->timeout, 0, TRUE);
2556 *aSRpnt = SRpnt;
2557 if ((STp->buffer)->syscall_result != 0) {
2558 printk (KERN_ERR "%s:E: Couldn't set tape block size mode page\n", name);
2559 return (-EIO);
2562 #if DEBUG
2563 printk(KERN_INFO "%s:D: Drive Block Size changed to 32.5K\n", name);
2565 * In debug mode, we want to see as many errors as possible
2566 * to test the error recovery mechanism.
2568 osst_set_retries(STp, aSRpnt, 0);
2569 SRpnt = * aSRpnt;
2570 #endif
2573 * Set vendor name to 'LIN4' for "Linux support version 4".
2576 memset(cmd, 0, MAX_COMMAND_SIZE);
2577 cmd[0] = MODE_SELECT;
2578 cmd[1] = 0x10;
2579 cmd[4] = VENDOR_IDENT_PAGE_LENGTH + MODE_HEADER_LENGTH;
2581 header->mode_data_length = VENDOR_IDENT_PAGE_LENGTH + MODE_HEADER_LENGTH - 1;
2582 header->medium_type = 0; /* Medium Type - ignoring */
2583 header->dsp = 0; /* Reserved */
2584 header->bdl = 0; /* Block Descriptor Length */
2586 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 0] = VENDOR_IDENT_PAGE | (1 << 7);
2587 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 1] = 6;
2588 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] = 'L';
2589 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] = 'I';
2590 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 4] = 'N';
2591 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 5] = '4';
2592 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 6] = 0;
2593 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 7] = 0;
2595 SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], SCSI_DATA_WRITE, STp->timeout, 0, TRUE);
2596 *aSRpnt = SRpnt;
2598 if ((STp->buffer)->syscall_result != 0) {
2599 printk (KERN_ERR "%s:E: Couldn't set vendor name to %s\n", name,
2600 (char *) ((STp->buffer)->b_data + MODE_HEADER_LENGTH + 2));
2601 return (-EIO);
2604 memset(cmd, 0, MAX_COMMAND_SIZE);
2605 cmd[0] = MODE_SENSE;
2606 cmd[1] = 8;
2607 cmd[2] = CAPABILITIES_PAGE;
2608 cmd[4] = CAPABILITIES_PAGE_LENGTH + MODE_HEADER_LENGTH;
2610 SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], SCSI_DATA_READ, STp->timeout, 0, TRUE);
2611 *aSRpnt = SRpnt;
2613 if ((STp->buffer)->syscall_result != 0) {
2614 printk (KERN_ERR "%s:E: Can't get capabilities page\n", name);
2615 return (-EIO);
2618 header = (osst_mode_parameter_header_t *) (STp->buffer)->b_data;
2619 cp = (osst_capabilities_page_t *) ((STp->buffer)->b_data +
2620 sizeof(osst_mode_parameter_header_t) + header->bdl);
2622 drive_buffer_size = ntohs(cp->buffer_size) / 2;
2624 memset(cmd, 0, MAX_COMMAND_SIZE);
2625 cmd[0] = MODE_SENSE;
2626 cmd[1] = 8;
2627 cmd[2] = TAPE_PARAMTR_PAGE;
2628 cmd[4] = TAPE_PARAMTR_PAGE_LENGTH + MODE_HEADER_LENGTH;
2630 SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], SCSI_DATA_READ, STp->timeout, 0, TRUE);
2631 *aSRpnt = SRpnt;
2633 if ((STp->buffer)->syscall_result != 0) {
2634 printk (KERN_ERR "%s:E: Can't get tape parameter page\n", name);
2635 return (-EIO);
2638 header = (osst_mode_parameter_header_t *) (STp->buffer)->b_data;
2639 prm = (osst_tape_paramtr_page_t *) ((STp->buffer)->b_data +
2640 sizeof(osst_mode_parameter_header_t) + header->bdl);
2642 STp->density = prm->density;
2643 STp->capacity = ntohs(prm->segtrk) * ntohs(prm->trks);
2644 #if DEBUG
2645 printk(OSST_DEB_MSG "%s:D: Density %d, tape length: %dMB, drive buffer size: %dKB\n",
2646 name, STp->density, STp->capacity / 32, drive_buffer_size);
2647 #endif
2649 return 0;
2654 /* Step over EOF if it has been inadvertently crossed (ioctl not used because
2655 it messes up the block number). */
2656 static int cross_eof(OS_Scsi_Tape *STp, Scsi_Request ** aSRpnt, int forward)
2658 int result;
2659 char * name = tape_name(STp);
2661 #if DEBUG
2662 if (debugging)
2663 printk(OSST_DEB_MSG "%s:D: Stepping over filemark %s.\n",
2664 name, forward ? "forward" : "backward");
2665 #endif
2667 if (forward) {
2668 /* assumes that the filemark is already read by the drive, so this is low cost */
2669 result = osst_space_over_filemarks_forward_slow(STp, aSRpnt, MTFSF, 1);
2671 else
2672 /* assumes this is only called if we just read the filemark! */
2673 result = osst_seek_logical_blk(STp, aSRpnt, STp->logical_blk_num - 1);
2675 if (result < 0)
2676 printk(KERN_WARNING "%s:W: Stepping over filemark %s failed.\n",
2677 name, forward ? "forward" : "backward");
2679 return result;
2683 /* Get the tape position. */
2685 static int osst_get_frame_position(OS_Scsi_Tape *STp, Scsi_Request ** aSRpnt)
2687 unsigned char scmd[MAX_COMMAND_SIZE];
2688 Scsi_Request * SRpnt;
2689 int result = 0;
2691 /* KG: We want to be able to use it for checking Write Buffer availability
2692 * and thus don't want to risk to overwrite anything. Exchange buffers ... */
2693 char mybuf[24];
2694 char * olddata = STp->buffer->b_data;
2695 int oldsize = STp->buffer->buffer_size;
2696 char * name = tape_name(STp);
2698 if (STp->ready != ST_READY) return (-EIO);
2700 memset (scmd, 0, MAX_COMMAND_SIZE);
2701 scmd[0] = READ_POSITION;
2703 STp->buffer->b_data = mybuf; STp->buffer->buffer_size = 24;
2704 SRpnt = osst_do_scsi(*aSRpnt, STp, scmd, 20, SCSI_DATA_READ,
2705 STp->timeout, MAX_RETRIES, TRUE);
2706 if (!SRpnt) {
2707 STp->buffer->b_data = olddata; STp->buffer->buffer_size = oldsize;
2708 return (-EBUSY);
2710 *aSRpnt = SRpnt;
2712 if (STp->buffer->syscall_result)
2713 result = ((SRpnt->sr_sense_buffer[2] & 0x0f) == 3) ? -EIO : -EINVAL;
2715 if (result == -EINVAL)
2716 printk(KERN_ERR "%s:E: Can't read tape position.\n", name);
2717 else {
2719 if (result == -EIO) { /* re-read position */
2720 unsigned char mysense[16];
2721 memcpy (mysense, SRpnt->sr_sense_buffer, 16);
2722 memset (scmd, 0, MAX_COMMAND_SIZE);
2723 scmd[0] = READ_POSITION;
2724 STp->buffer->b_data = mybuf; STp->buffer->buffer_size = 24;
2725 SRpnt = osst_do_scsi(SRpnt, STp, scmd, 20, SCSI_DATA_READ,
2726 STp->timeout, MAX_RETRIES, TRUE);
2727 if (!STp->buffer->syscall_result)
2728 memcpy (SRpnt->sr_sense_buffer, mysense, 16);
2730 STp->first_frame_position = ((STp->buffer)->b_data[4] << 24)
2731 + ((STp->buffer)->b_data[5] << 16)
2732 + ((STp->buffer)->b_data[6] << 8)
2733 + (STp->buffer)->b_data[7];
2734 STp->last_frame_position = ((STp->buffer)->b_data[ 8] << 24)
2735 + ((STp->buffer)->b_data[ 9] << 16)
2736 + ((STp->buffer)->b_data[10] << 8)
2737 + (STp->buffer)->b_data[11];
2738 STp->cur_frames = (STp->buffer)->b_data[15];
2739 #if DEBUG
2740 if (debugging) {
2741 printk(OSST_DEB_MSG "%s:D: Drive Positions: host %d, tape %d%s, buffer %d\n", name,
2742 STp->first_frame_position, STp->last_frame_position,
2743 ((STp->buffer)->b_data[0]&0x80)?" (BOP)":
2744 ((STp->buffer)->b_data[0]&0x40)?" (EOP)":"",
2745 STp->cur_frames);
2747 #endif
2748 if (STp->cur_frames == 0 && STp->first_frame_position != STp->last_frame_position) {
2749 #if DEBUG
2750 printk(KERN_WARNING "%s:D: Correcting read position %d, %d, %d\n", name,
2751 STp->first_frame_position, STp->last_frame_position, STp->cur_frames);
2752 #endif
2753 STp->first_frame_position = STp->last_frame_position;
2756 STp->buffer->b_data = olddata; STp->buffer->buffer_size = oldsize;
2758 return (result == 0 ? STp->first_frame_position : result);
2762 /* Set the tape block */
2763 static int osst_set_frame_position(OS_Scsi_Tape *STp, Scsi_Request ** aSRpnt, int ppos, int skip)
2765 unsigned char scmd[MAX_COMMAND_SIZE];
2766 Scsi_Request * SRpnt;
2767 ST_partstat * STps;
2768 int result = 0;
2769 int pp = (ppos == 3000 && !skip)? 0 : ppos;
2770 char * name = tape_name(STp);
2772 if (STp->ready != ST_READY) return (-EIO);
2774 STps = &(STp->ps[STp->partition]);
2776 if (ppos < 0 || ppos > STp->capacity) {
2777 printk(KERN_WARNING "%s:W: Reposition request %d out of range\n", name, ppos);
2778 pp = ppos = ppos < 0 ? 0 : (STp->capacity - 1);
2779 result = (-EINVAL);
2782 do {
2783 #if DEBUG
2784 if (debugging)
2785 printk(OSST_DEB_MSG "%s:D: Setting ppos to %d.\n", name, pp);
2786 #endif
2787 memset (scmd, 0, MAX_COMMAND_SIZE);
2788 scmd[0] = SEEK_10;
2789 scmd[1] = 1;
2790 scmd[3] = (pp >> 24);
2791 scmd[4] = (pp >> 16);
2792 scmd[5] = (pp >> 8);
2793 scmd[6] = pp;
2794 if (skip)
2795 scmd[9] = 0x80;
2797 SRpnt = osst_do_scsi(*aSRpnt, STp, scmd, 0, SCSI_DATA_NONE, STp->long_timeout,
2798 MAX_RETRIES, TRUE);
2799 if (!SRpnt)
2800 return (-EBUSY);
2801 *aSRpnt = SRpnt;
2803 if ((STp->buffer)->syscall_result != 0) {
2804 #if DEBUG
2805 printk(OSST_DEB_MSG "%s:D: SEEK command from %d to %d failed.\n",
2806 name, STp->first_frame_position, pp);
2807 #endif
2808 result = (-EIO);
2810 if (pp != ppos)
2811 osst_wait_ready(STp, aSRpnt, 5 * 60, OSST_WAIT_POSITION_COMPLETE);
2812 } while ((pp != ppos) && (pp = ppos));
2813 STp->first_frame_position = STp->last_frame_position = ppos;
2814 STps->eof = ST_NOEOF;
2815 STps->at_sm = 0;
2816 STps->rw = ST_IDLE;
2817 STp->frame_in_buffer = 0;
2818 return result;
2823 /* osst versions of st functions - augmented and stripped to suit OnStream only */
2825 /* Flush the write buffer (never need to write if variable blocksize). */
2826 static int osst_flush_write_buffer(OS_Scsi_Tape *STp, Scsi_Request ** aSRpnt)
2828 int offset, transfer, blks = 0;
2829 int result = 0;
2830 unsigned char cmd[MAX_COMMAND_SIZE];
2831 Scsi_Request * SRpnt = *aSRpnt;
2832 ST_partstat * STps;
2833 char * name = tape_name(STp);
2835 if ((STp->buffer)->writing) {
2836 if (SRpnt == (STp->buffer)->last_SRpnt)
2837 #if DEBUG
2838 { printk(OSST_DEB_MSG
2839 "%s:D: aSRpnt points to Scsi_Request that write_behind_check will release -- cleared\n", name);
2840 #endif
2841 *aSRpnt = SRpnt = NULL;
2842 #if DEBUG
2843 } else if (SRpnt)
2844 printk(OSST_DEB_MSG
2845 "%s:D: aSRpnt does not point to Scsi_Request that write_behind_check will release -- strange\n", name);
2846 #endif
2847 osst_write_behind_check(STp);
2848 if ((STp->buffer)->syscall_result) {
2849 #if DEBUG
2850 if (debugging)
2851 printk(OSST_DEB_MSG "%s:D: Async write error (flush) %x.\n",
2852 name, (STp->buffer)->midlevel_result);
2853 #endif
2854 if ((STp->buffer)->midlevel_result == INT_MAX)
2855 return (-ENOSPC);
2856 return (-EIO);
2860 result = 0;
2861 if (STp->dirty == 1) {
2863 STp->write_count++;
2864 STps = &(STp->ps[STp->partition]);
2865 STps->rw = ST_WRITING;
2866 offset = STp->buffer->buffer_bytes;
2867 blks = (offset + STp->block_size - 1) / STp->block_size;
2868 transfer = OS_FRAME_SIZE;
2870 if (offset < OS_DATA_SIZE)
2871 osst_zero_buffer_tail(STp->buffer);
2873 /* TODO: Error handling! */
2874 if (STp->poll)
2875 result = osst_wait_frame (STp, aSRpnt, STp->first_frame_position, -50, 120);
2877 memset(cmd, 0, MAX_COMMAND_SIZE);
2878 cmd[0] = WRITE_6;
2879 cmd[1] = 1;
2880 cmd[4] = 1;
2882 switch (STp->write_type) {
2883 case OS_WRITE_DATA:
2884 #if DEBUG
2885 if (debugging)
2886 printk(OSST_DEB_MSG "%s:D: Writing %d blocks to frame %d, lblks %d-%d\n",
2887 name, blks, STp->frame_seq_number,
2888 STp->logical_blk_num - blks, STp->logical_blk_num - 1);
2889 #endif
2890 osst_init_aux(STp, OS_FRAME_TYPE_DATA, STp->frame_seq_number++,
2891 STp->logical_blk_num - blks, STp->block_size, blks);
2892 break;
2893 case OS_WRITE_EOD:
2894 osst_init_aux(STp, OS_FRAME_TYPE_EOD, STp->frame_seq_number++,
2895 STp->logical_blk_num, 0, 0);
2896 break;
2897 case OS_WRITE_NEW_MARK:
2898 osst_init_aux(STp, OS_FRAME_TYPE_MARKER, STp->frame_seq_number++,
2899 STp->logical_blk_num++, 0, blks=1);
2900 break;
2901 case OS_WRITE_HEADER:
2902 osst_init_aux(STp, OS_FRAME_TYPE_HEADER, 0, 0, 0, blks=0);
2903 break;
2904 default: /* probably FILLER */
2905 osst_init_aux(STp, OS_FRAME_TYPE_FILL, 0, 0, 0, 0);
2907 #if DEBUG
2908 if (debugging)
2909 printk(OSST_DEB_MSG "%s:D: Flushing %d bytes, Transfering %d bytes in %d lblocks.\n",
2910 name, offset, transfer, blks);
2911 #endif
2913 SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, transfer, SCSI_DATA_WRITE,
2914 STp->timeout, MAX_WRITE_RETRIES, TRUE);
2915 *aSRpnt = SRpnt;
2916 if (!SRpnt)
2917 return (-EBUSY);
2919 if ((STp->buffer)->syscall_result != 0) {
2920 #if DEBUG
2921 printk(OSST_DEB_MSG
2922 "%s:D: write sense [0]=0x%02x [2]=%02x [12]=%02x [13]=%02x\n",
2923 name, SRpnt->sr_sense_buffer[0], SRpnt->sr_sense_buffer[2],
2924 SRpnt->sr_sense_buffer[12], SRpnt->sr_sense_buffer[13]);
2925 #endif
2926 if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 &&
2927 (SRpnt->sr_sense_buffer[2] & 0x40) && /* FIXME - SC-30 drive doesn't assert EOM bit */
2928 (SRpnt->sr_sense_buffer[2] & 0x0f) == NO_SENSE) {
2929 STp->dirty = 0;
2930 (STp->buffer)->buffer_bytes = 0;
2931 result = (-ENOSPC);
2933 else {
2934 if (osst_write_error_recovery(STp, aSRpnt, 1)) {
2935 printk(KERN_ERR "%s:E: Error on flush write.\n", name);
2936 result = (-EIO);
2939 STps->drv_block = (-1);
2941 else {
2942 STp->first_frame_position++;
2943 STp->dirty = 0;
2944 (STp->buffer)->buffer_bytes = 0;
2947 #if DEBUG
2948 printk(OSST_DEB_MSG "%s:D: Exit flush write buffer with code %d\n", name, result);
2949 #endif
2950 return result;
2954 /* Flush the tape buffer. The tape will be positioned correctly unless
2955 seek_next is true. */
2956 static int osst_flush_buffer(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int seek_next)
2958 ST_partstat * STps;
2959 int backspace = 0, result = 0;
2960 #if DEBUG
2961 char * name = tape_name(STp);
2962 #endif
2965 * If there was a bus reset, block further access
2966 * to this device.
2968 if( STp->pos_unknown)
2969 return (-EIO);
2971 if (STp->ready != ST_READY)
2972 return 0;
2974 STps = &(STp->ps[STp->partition]);
2975 if (STps->rw == ST_WRITING || STp->dirty) { /* Writing */
2976 STp->write_type = OS_WRITE_DATA;
2977 return osst_flush_write_buffer(STp, aSRpnt);
2979 if (STp->block_size == 0)
2980 return 0;
2982 #if DEBUG
2983 printk(OSST_DEB_MSG "%s:D: Reached flush (read) buffer\n", name);
2984 #endif
2986 if (!STp->can_bsr) {
2987 backspace = ((STp->buffer)->buffer_bytes + (STp->buffer)->read_pointer) / STp->block_size -
2988 ((STp->buffer)->read_pointer + STp->block_size - 1 ) / STp->block_size ;
2989 (STp->buffer)->buffer_bytes = 0;
2990 (STp->buffer)->read_pointer = 0;
2991 STp->frame_in_buffer = 0; /* FIXME is this relevant w. OSST? */
2994 if (!seek_next) {
2995 if (STps->eof == ST_FM_HIT) {
2996 result = cross_eof(STp, aSRpnt, FALSE); /* Back over the EOF hit */
2997 if (!result)
2998 STps->eof = ST_NOEOF;
2999 else {
3000 if (STps->drv_file >= 0)
3001 STps->drv_file++;
3002 STps->drv_block = 0;
3005 if (!result && backspace > 0) /* TODO -- design and run a test case for this */
3006 result = osst_seek_logical_blk(STp, aSRpnt, STp->logical_blk_num - backspace);
3008 else if (STps->eof == ST_FM_HIT) {
3009 if (STps->drv_file >= 0)
3010 STps->drv_file++;
3011 STps->drv_block = 0;
3012 STps->eof = ST_NOEOF;
3015 return result;
3018 static int osst_write_frame(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int synchronous)
3020 unsigned char cmd[MAX_COMMAND_SIZE];
3021 Scsi_Request * SRpnt;
3022 int blks;
3023 #if DEBUG
3024 char * name = tape_name(STp);
3025 #endif
3027 if ((!STp-> raw) && (STp->first_frame_position == 0xbae)) { /* _must_ preserve buffer! */
3028 #if DEBUG
3029 printk(OSST_DEB_MSG "%s:D: Reaching config partition.\n", name);
3030 #endif
3031 if (osst_flush_drive_buffer(STp, aSRpnt) < 0) {
3032 return (-EIO);
3034 /* error recovery may have bumped us past the header partition */
3035 if (osst_get_frame_position(STp, aSRpnt) < 0xbb8) {
3036 #if DEBUG
3037 printk(OSST_DEB_MSG "%s:D: Skipping over config partition.\n", name);
3038 #endif
3039 osst_position_tape_and_confirm(STp, aSRpnt, 0xbb8);
3043 if (STp->poll)
3044 osst_wait_frame (STp, aSRpnt, STp->first_frame_position, -50, 60);
3045 /* TODO: Check for an error ! */
3047 // osst_build_stats(STp, &SRpnt);
3049 STp->ps[STp->partition].rw = ST_WRITING;
3050 STp->write_type = OS_WRITE_DATA;
3052 memset(cmd, 0, MAX_COMMAND_SIZE);
3053 cmd[0] = WRITE_6;
3054 cmd[1] = 1;
3055 cmd[4] = 1; /* one frame at a time... */
3056 blks = STp->buffer->buffer_bytes / STp->block_size;
3057 #if DEBUG
3058 if (debugging)
3059 printk(OSST_DEB_MSG "%s:D: Writing %d blocks to frame %d, lblks %d-%d\n", name, blks,
3060 STp->frame_seq_number, STp->logical_blk_num - blks, STp->logical_blk_num - 1);
3061 #endif
3062 osst_init_aux(STp, OS_FRAME_TYPE_DATA, STp->frame_seq_number++,
3063 STp->logical_blk_num - blks, STp->block_size, blks);
3065 #if DEBUG
3066 if (!synchronous)
3067 STp->write_pending = 1;
3068 #endif
3069 SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, OS_FRAME_SIZE, SCSI_DATA_WRITE, STp->timeout,
3070 MAX_WRITE_RETRIES, synchronous);
3071 if (!SRpnt)
3072 return (-EBUSY);
3073 *aSRpnt = SRpnt;
3075 if (synchronous) {
3076 if (STp->buffer->syscall_result != 0) {
3077 #if DEBUG
3078 if (debugging)
3079 printk(OSST_DEB_MSG "%s:D: Error on write:\n", name);
3080 #endif
3081 if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 &&
3082 (SRpnt->sr_sense_buffer[2] & 0x40)) {
3083 if ((SRpnt->sr_sense_buffer[2] & 0x0f) == VOLUME_OVERFLOW)
3084 return (-ENOSPC);
3086 else {
3087 if (osst_write_error_recovery(STp, aSRpnt, 1))
3088 return (-EIO);
3091 else
3092 STp->first_frame_position++;
3095 STp->write_count++;
3097 return 0;
3100 /* Lock or unlock the drive door. Don't use when Scsi_Request allocated. */
3101 static int do_door_lock(OS_Scsi_Tape * STp, int do_lock)
3103 int retval, cmd;
3105 cmd = do_lock ? SCSI_IOCTL_DOORLOCK : SCSI_IOCTL_DOORUNLOCK;
3106 #if DEBUG
3107 printk(OSST_DEB_MSG "%s:D: %socking drive door.\n", tape_name(STp), do_lock ? "L" : "Unl");
3108 #endif
3109 retval = scsi_ioctl(STp->device, cmd, NULL);
3110 if (!retval) {
3111 STp->door_locked = do_lock ? ST_LOCKED_EXPLICIT : ST_UNLOCKED;
3113 else {
3114 STp->door_locked = ST_LOCK_FAILS;
3116 return retval;
3119 /* Set the internal state after reset */
3120 static void reset_state(OS_Scsi_Tape *STp)
3122 int i;
3123 ST_partstat *STps;
3125 STp->pos_unknown = 0;
3126 for (i = 0; i < ST_NBR_PARTITIONS; i++) {
3127 STps = &(STp->ps[i]);
3128 STps->rw = ST_IDLE;
3129 STps->eof = ST_NOEOF;
3130 STps->at_sm = 0;
3131 STps->last_block_valid = FALSE;
3132 STps->drv_block = -1;
3133 STps->drv_file = -1;
3138 /* Entry points to osst */
3140 /* Write command */
3141 static ssize_t osst_write(struct file * filp, const char * buf, size_t count, loff_t *ppos)
3143 ssize_t total, retval = 0;
3144 ssize_t i, do_count, blks, transfer;
3145 int write_threshold;
3146 int doing_write = 0;
3147 const char * b_point;
3148 Scsi_Request * SRpnt = NULL;
3149 ST_mode * STm;
3150 ST_partstat * STps;
3151 OS_Scsi_Tape * STp = filp->private_data;
3152 char * name = tape_name(STp);
3155 if (down_interruptible(&STp->lock))
3156 return (-ERESTARTSYS);
3159 * If we are in the middle of error recovery, don't let anyone
3160 * else try and use this device. Also, if error recovery fails, it
3161 * may try and take the device offline, in which case all further
3162 * access to the device is prohibited.
3164 if( !scsi_block_when_processing_errors(STp->device) ) {
3165 retval = (-ENXIO);
3166 goto out;
3169 if (ppos != &filp->f_pos) {
3170 /* "A request was outside the capabilities of the device." */
3171 retval = (-ENXIO);
3172 goto out;
3175 if (STp->ready != ST_READY) {
3176 if (STp->ready == ST_NO_TAPE)
3177 retval = (-ENOMEDIUM);
3178 else
3179 retval = (-EIO);
3180 goto out;
3182 STm = &(STp->modes[STp->current_mode]);
3183 if (!STm->defined) {
3184 retval = (-ENXIO);
3185 goto out;
3187 if (count == 0)
3188 goto out;
3191 * If there was a bus reset, block further access
3192 * to this device.
3194 if (STp->pos_unknown) {
3195 retval = (-EIO);
3196 goto out;
3199 #if DEBUG
3200 if (!STp->in_use) {
3201 printk(OSST_DEB_MSG "%s:D: Incorrect device.\n", name);
3202 retval = (-EIO);
3203 goto out;
3205 #endif
3207 if (STp->write_prot) {
3208 retval = (-EACCES);
3209 goto out;
3212 /* Write must be integral number of blocks */
3213 if (STp->block_size != 0 && (count % STp->block_size) != 0) {
3214 printk(KERN_ERR "%s:E: Write (%Zd bytes) not multiple of tape block size (%d%c).\n",
3215 name, count, STp->block_size<1024?
3216 STp->block_size:STp->block_size/1024, STp->block_size<1024?'b':'k');
3217 retval = (-EINVAL);
3218 goto out;
3221 if (STp->first_frame_position >= STp->capacity - OSST_EOM_RESERVE) {
3222 printk(KERN_ERR "%s:E: Write truncated at EOM early warning (frame %d).\n",
3223 name, STp->first_frame_position);
3224 retval = (-ENOSPC);
3225 goto out;
3228 if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED && !do_door_lock(STp, 1))
3229 STp->door_locked = ST_LOCKED_AUTO;
3231 STps = &(STp->ps[STp->partition]);
3233 if (STps->rw == ST_READING) {
3234 #if DEBUG
3235 printk(OSST_DEB_MSG "%s:D: Switching from read to write at file %d, block %d\n", name,
3236 STps->drv_file, STps->drv_block);
3237 #endif
3238 retval = osst_flush_buffer(STp, &SRpnt, 0);
3239 if (retval)
3240 goto out;
3241 STps->rw = ST_IDLE;
3243 if (STps->rw != ST_WRITING) {
3244 /* Are we totally rewriting this tape? */
3245 if (!STp->header_ok ||
3246 (STp->first_frame_position == STp->first_data_ppos && STps->drv_block < 0) ||
3247 (STps->drv_file == 0 && STps->drv_block == 0)) {
3248 STp->wrt_pass_cntr++;
3249 #if DEBUG
3250 printk(OSST_DEB_MSG "%s:D: Allocating next write pass counter: %d\n",
3251 name, STp->wrt_pass_cntr);
3252 #endif
3253 osst_reset_header(STp, &SRpnt);
3254 STps->drv_file = STps->drv_block = 0;
3256 /* Do we know where we'll be writing on the tape? */
3257 else {
3258 if ((STp->fast_open && osst_verify_position(STp, &SRpnt)) ||
3259 STps->drv_file < 0 || STps->drv_block < 0) {
3260 if (STp->first_frame_position == STp->eod_frame_ppos) { /* at EOD */
3261 STps->drv_file = STp->filemark_cnt;
3262 STps->drv_block = 0;
3264 else {
3265 /* We have no idea where the tape is positioned - give up */
3266 #if DEBUG
3267 printk(OSST_DEB_MSG
3268 "%s:D: Cannot write at indeterminate position.\n", name);
3269 #endif
3270 retval = (-EIO);
3271 goto out;
3274 if ((STps->drv_file + STps->drv_block) > 0 && STps->drv_file < STp->filemark_cnt) {
3275 STp->filemark_cnt = STps->drv_file;
3276 STp->last_mark_ppos =
3277 ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[STp->filemark_cnt-1]);
3278 printk(KERN_WARNING
3279 "%s:W: Overwriting file %d with old write pass counter %d\n",
3280 name, STps->drv_file, STp->wrt_pass_cntr);
3281 printk(KERN_WARNING
3282 "%s:W: may lead to stale data being accepted on reading back!\n",
3283 name);
3284 #if DEBUG
3285 printk(OSST_DEB_MSG
3286 "%s:D: resetting filemark count to %d and last mark ppos,lbn to %d,%d\n",
3287 name, STp->filemark_cnt, STp->last_mark_ppos, STp->last_mark_lbn);
3288 #endif
3291 STp->fast_open = FALSE;
3293 if (!STp->header_ok) {
3294 #if DEBUG
3295 printk(OSST_DEB_MSG "%s:D: Write cannot proceed without valid headers\n", name);
3296 #endif
3297 retval = (-EIO);
3298 goto out;
3301 if ((STp->buffer)->writing) {
3302 if (SRpnt) printk(KERN_ERR "%s:A: Not supposed to have SRpnt at line %d\n", name, __LINE__);
3303 osst_write_behind_check(STp);
3304 if ((STp->buffer)->syscall_result) {
3305 #if DEBUG
3306 if (debugging)
3307 printk(OSST_DEB_MSG "%s:D: Async write error (write) %x.\n", name,
3308 (STp->buffer)->midlevel_result);
3309 #endif
3310 if ((STp->buffer)->midlevel_result == INT_MAX)
3311 STps->eof = ST_EOM_OK;
3312 else
3313 STps->eof = ST_EOM_ERROR;
3316 if (STps->eof == ST_EOM_OK) {
3317 retval = (-ENOSPC);
3318 goto out;
3320 else if (STps->eof == ST_EOM_ERROR) {
3321 retval = (-EIO);
3322 goto out;
3325 /* Check the buffer readability in cases where copy_user might catch
3326 the problems after some tape movement. */
3327 if ((copy_from_user(&i, buf, 1) != 0 ||
3328 copy_from_user(&i, buf + count - 1, 1) != 0)) {
3329 retval = (-EFAULT);
3330 goto out;
3333 if (!STm->do_buffer_writes) {
3334 write_threshold = 1;
3336 else
3337 write_threshold = (STp->buffer)->buffer_blocks * STp->block_size;
3338 if (!STm->do_async_writes)
3339 write_threshold--;
3341 total = count;
3342 #if DEBUG
3343 if (debugging)
3344 printk(OSST_DEB_MSG "%s:D: Writing %d bytes to file %d block %d lblk %d fseq %d fppos %d\n",
3345 name, count, STps->drv_file, STps->drv_block,
3346 STp->logical_blk_num, STp->frame_seq_number, STp->first_frame_position);
3347 #endif
3348 b_point = buf;
3349 while ((STp->buffer)->buffer_bytes + count > write_threshold)
3351 doing_write = 1;
3352 do_count = (STp->buffer)->buffer_blocks * STp->block_size -
3353 (STp->buffer)->buffer_bytes;
3354 if (do_count > count)
3355 do_count = count;
3357 i = append_to_buffer(b_point, STp->buffer, do_count);
3358 if (i) {
3359 retval = i;
3360 goto out;
3363 blks = do_count / STp->block_size;
3364 STp->logical_blk_num += blks; /* logical_blk_num is incremented as data is moved from user */
3366 i = osst_write_frame(STp, &SRpnt, TRUE);
3368 if (i == (-ENOSPC)) {
3369 transfer = STp->buffer->writing; /* FIXME -- check this logic */
3370 if (transfer <= do_count) {
3371 filp->f_pos += do_count - transfer;
3372 count -= do_count - transfer;
3373 if (STps->drv_block >= 0) {
3374 STps->drv_block += (do_count - transfer) / STp->block_size;
3376 STps->eof = ST_EOM_OK;
3377 retval = (-ENOSPC); /* EOM within current request */
3378 #if DEBUG
3379 if (debugging)
3380 printk(OSST_DEB_MSG "%s:D: EOM with %d bytes unwritten.\n",
3381 name, transfer);
3382 #endif
3384 else {
3385 STps->eof = ST_EOM_ERROR;
3386 STps->drv_block = (-1); /* Too cautious? */
3387 retval = (-EIO); /* EOM for old data */
3388 #if DEBUG
3389 if (debugging)
3390 printk(OSST_DEB_MSG "%s:D: EOM with lost data.\n", name);
3391 #endif
3394 else
3395 retval = i;
3397 if (retval < 0) {
3398 if (SRpnt != NULL) {
3399 scsi_release_request(SRpnt);
3400 SRpnt = NULL;
3402 STp->buffer->buffer_bytes = 0;
3403 STp->dirty = 0;
3404 if (count < total)
3405 retval = total - count;
3406 goto out;
3409 filp->f_pos += do_count;
3410 b_point += do_count;
3411 count -= do_count;
3412 if (STps->drv_block >= 0) {
3413 STps->drv_block += blks;
3415 STp->buffer->buffer_bytes = 0;
3416 STp->dirty = 0;
3417 } /* end while write threshold exceeded */
3419 if (count != 0) {
3420 STp->dirty = 1;
3421 i = append_to_buffer(b_point, STp->buffer, count);
3422 if (i) {
3423 retval = i;
3424 goto out;
3426 blks = count / STp->block_size;
3427 STp->logical_blk_num += blks;
3428 if (STps->drv_block >= 0) {
3429 STps->drv_block += blks;
3431 filp->f_pos += count;
3432 count = 0;
3435 if (doing_write && (STp->buffer)->syscall_result != 0) {
3436 retval = (STp->buffer)->syscall_result;
3437 goto out;
3440 if (STm->do_async_writes && ((STp->buffer)->buffer_bytes >= STp->write_threshold)) {
3441 /* Schedule an asynchronous write */
3442 (STp->buffer)->writing = ((STp->buffer)->buffer_bytes /
3443 STp->block_size) * STp->block_size;
3444 STp->dirty = !((STp->buffer)->writing ==
3445 (STp->buffer)->buffer_bytes);
3447 i = osst_write_frame(STp, &SRpnt, FALSE);
3448 if (i < 0) {
3449 retval = (-EIO);
3450 goto out;
3452 SRpnt = NULL; /* Prevent releasing this request! */
3454 STps->at_sm &= (total == 0);
3455 if (total > 0)
3456 STps->eof = ST_NOEOF;
3458 retval = total;
3460 out:
3461 if (SRpnt != NULL) scsi_release_request(SRpnt);
3463 up(&STp->lock);
3465 return retval;
3469 /* Read command */
3470 static ssize_t osst_read(struct file * filp, char * buf, size_t count, loff_t *ppos)
3472 ssize_t total, retval = 0;
3473 ssize_t i, transfer;
3474 int special;
3475 ST_mode * STm;
3476 ST_partstat * STps;
3477 Scsi_Request * SRpnt = NULL;
3478 OS_Scsi_Tape * STp = filp->private_data;
3479 char * name = tape_name(STp);
3482 if (down_interruptible(&STp->lock))
3483 return (-ERESTARTSYS);
3486 * If we are in the middle of error recovery, don't let anyone
3487 * else try and use this device. Also, if error recovery fails, it
3488 * may try and take the device offline, in which case all further
3489 * access to the device is prohibited.
3491 if( !scsi_block_when_processing_errors(STp->device) ) {
3492 retval = (-ENXIO);
3493 goto out;
3496 if (ppos != &filp->f_pos) {
3497 /* "A request was outside the capabilities of the device." */
3498 retval = (-ENXIO);
3499 goto out;
3502 if (STp->ready != ST_READY) {
3503 if (STp->ready == ST_NO_TAPE)
3504 retval = (-ENOMEDIUM);
3505 else
3506 retval = (-EIO);
3507 goto out;
3509 STm = &(STp->modes[STp->current_mode]);
3510 if (!STm->defined) {
3511 retval = (-ENXIO);
3512 goto out;
3514 #if DEBUG
3515 if (!STp->in_use) {
3516 printk(OSST_DEB_MSG "%s:D: Incorrect device.\n", name);
3517 retval = (-EIO);
3518 goto out;
3520 #endif
3521 /* Must have initialized medium */
3522 if (!STp->header_ok) {
3523 retval = (-EIO);
3524 goto out;
3527 if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED && !do_door_lock(STp, 1))
3528 STp->door_locked = ST_LOCKED_AUTO;
3530 STps = &(STp->ps[STp->partition]);
3531 if (STps->rw == ST_WRITING) {
3532 retval = osst_flush_buffer(STp, &SRpnt, 0);
3533 if (retval)
3534 goto out;
3535 STps->rw = ST_IDLE;
3536 /* FIXME -- this may leave the tape without EOD and up2date headers */
3539 if ((count % STp->block_size) != 0) {
3540 printk(KERN_WARNING
3541 "%s:W: Read (%Zd bytes) not multiple of tape block size (%d%c).\n", name, count,
3542 STp->block_size<1024?STp->block_size:STp->block_size/1024, STp->block_size<1024?'b':'k');
3545 #if DEBUG
3546 if (debugging && STps->eof != ST_NOEOF)
3547 printk(OSST_DEB_MSG "%s:D: EOF/EOM flag up (%d). Bytes %d\n", name,
3548 STps->eof, (STp->buffer)->buffer_bytes);
3549 #endif
3550 if ((STp->buffer)->buffer_bytes == 0 &&
3551 STps->eof >= ST_EOD_1) {
3552 if (STps->eof < ST_EOD) {
3553 STps->eof += 1;
3554 retval = 0;
3555 goto out;
3557 retval = (-EIO); /* EOM or Blank Check */
3558 goto out;
3561 /* Check the buffer writability before any tape movement. Don't alter
3562 buffer data. */
3563 if (copy_from_user(&i, buf, 1) != 0 ||
3564 copy_to_user (buf, &i, 1) != 0 ||
3565 copy_from_user(&i, buf + count - 1, 1) != 0 ||
3566 copy_to_user (buf + count - 1, &i, 1) != 0) {
3567 retval = (-EFAULT);
3568 goto out;
3571 /* Loop until enough data in buffer or a special condition found */
3572 for (total = 0, special = 0; total < count - STp->block_size + 1 && !special; ) {
3574 /* Get new data if the buffer is empty */
3575 if ((STp->buffer)->buffer_bytes == 0) {
3576 if (STps->eof == ST_FM_HIT)
3577 break;
3578 special = osst_get_logical_frame(STp, &SRpnt, STp->frame_seq_number, 0);
3579 if (special < 0) { /* No need to continue read */
3580 STp->frame_in_buffer = 0;
3581 retval = special;
3582 goto out;
3586 /* Move the data from driver buffer to user buffer */
3587 if ((STp->buffer)->buffer_bytes > 0) {
3588 #if DEBUG
3589 if (debugging && STps->eof != ST_NOEOF)
3590 printk(OSST_DEB_MSG "%s:D: EOF up (%d). Left %d, needed %d.\n", name,
3591 STps->eof, (STp->buffer)->buffer_bytes, count - total);
3592 #endif
3593 /* force multiple of block size, note block_size may have been adjusted */
3594 transfer = (((STp->buffer)->buffer_bytes < count - total ?
3595 (STp->buffer)->buffer_bytes : count - total)/
3596 STp->block_size) * STp->block_size;
3598 if (transfer == 0) {
3599 printk(KERN_WARNING
3600 "%s:W: Nothing can be transfered, requested %Zd, tape block size (%d%c).\n",
3601 name, count, STp->block_size < 1024?
3602 STp->block_size:STp->block_size/1024,
3603 STp->block_size<1024?'b':'k');
3604 break;
3606 i = from_buffer(STp->buffer, buf, transfer);
3607 if (i) {
3608 retval = i;
3609 goto out;
3611 STp->logical_blk_num += transfer / STp->block_size;
3612 STps->drv_block += transfer / STp->block_size;
3613 filp->f_pos += transfer;
3614 buf += transfer;
3615 total += transfer;
3618 if ((STp->buffer)->buffer_bytes == 0) {
3619 #if DEBUG
3620 if (debugging)
3621 printk(OSST_DEB_MSG "%s:D: Finished with frame %d\n",
3622 name, STp->frame_seq_number);
3623 #endif
3624 STp->frame_in_buffer = 0;
3625 STp->frame_seq_number++; /* frame to look for next time */
3627 } /* for (total = 0, special = 0; total < count && !special; ) */
3629 /* Change the eof state if no data from tape or buffer */
3630 if (total == 0) {
3631 if (STps->eof == ST_FM_HIT) {
3632 STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD:ST_FM;
3633 STps->drv_block = 0;
3634 if (STps->drv_file >= 0)
3635 STps->drv_file++;
3637 else if (STps->eof == ST_EOD_1) {
3638 STps->eof = ST_EOD_2;
3639 if (STps->drv_block > 0 && STps->drv_file >= 0)
3640 STps->drv_file++;
3641 STps->drv_block = 0;
3643 else if (STps->eof == ST_EOD_2)
3644 STps->eof = ST_EOD;
3646 else if (STps->eof == ST_FM)
3647 STps->eof = ST_NOEOF;
3649 retval = total;
3651 out:
3652 if (SRpnt != NULL) scsi_release_request(SRpnt);
3654 up(&STp->lock);
3656 return retval;
3660 /* Set the driver options */
3661 static void osst_log_options(OS_Scsi_Tape *STp, ST_mode *STm, char *name)
3663 printk(KERN_INFO
3664 "%s:I: Mode %d options: buffer writes: %d, async writes: %d, read ahead: %d\n",
3665 name, STp->current_mode, STm->do_buffer_writes, STm->do_async_writes,
3666 STm->do_read_ahead);
3667 printk(KERN_INFO
3668 "%s:I: can bsr: %d, two FMs: %d, fast mteom: %d, auto lock: %d,\n",
3669 name, STp->can_bsr, STp->two_fm, STp->fast_mteom, STp->do_auto_lock);
3670 printk(KERN_INFO
3671 "%s:I: defs for wr: %d, no block limits: %d, partitions: %d, s2 log: %d\n",
3672 name, STm->defaults_for_writes, STp->omit_blklims, STp->can_partitions,
3673 STp->scsi2_logical);
3674 printk(KERN_INFO
3675 "%s:I: sysv: %d\n", name, STm->sysv);
3676 #if DEBUG
3677 printk(KERN_INFO
3678 "%s:D: debugging: %d\n",
3679 name, debugging);
3680 #endif
3684 static int osst_set_options(OS_Scsi_Tape *STp, long options)
3686 int value;
3687 long code;
3688 ST_mode * STm;
3689 char * name = tape_name(STp);
3691 STm = &(STp->modes[STp->current_mode]);
3692 if (!STm->defined) {
3693 memcpy(STm, &(STp->modes[0]), sizeof(ST_mode));
3694 modes_defined = TRUE;
3695 #if DEBUG
3696 if (debugging)
3697 printk(OSST_DEB_MSG "%s:D: Initialized mode %d definition from mode 0\n",
3698 name, STp->current_mode);
3699 #endif
3702 code = options & MT_ST_OPTIONS;
3703 if (code == MT_ST_BOOLEANS) {
3704 STm->do_buffer_writes = (options & MT_ST_BUFFER_WRITES) != 0;
3705 STm->do_async_writes = (options & MT_ST_ASYNC_WRITES) != 0;
3706 STm->defaults_for_writes = (options & MT_ST_DEF_WRITES) != 0;
3707 STm->do_read_ahead = (options & MT_ST_READ_AHEAD) != 0;
3708 STp->two_fm = (options & MT_ST_TWO_FM) != 0;
3709 STp->fast_mteom = (options & MT_ST_FAST_MTEOM) != 0;
3710 STp->do_auto_lock = (options & MT_ST_AUTO_LOCK) != 0;
3711 STp->can_bsr = (options & MT_ST_CAN_BSR) != 0;
3712 STp->omit_blklims = (options & MT_ST_NO_BLKLIMS) != 0;
3713 if ((STp->device)->scsi_level >= SCSI_2)
3714 STp->can_partitions = (options & MT_ST_CAN_PARTITIONS) != 0;
3715 STp->scsi2_logical = (options & MT_ST_SCSI2LOGICAL) != 0;
3716 STm->sysv = (options & MT_ST_SYSV) != 0;
3717 #if DEBUG
3718 debugging = (options & MT_ST_DEBUGGING) != 0;
3719 #endif
3720 osst_log_options(STp, STm, name);
3722 else if (code == MT_ST_SETBOOLEANS || code == MT_ST_CLEARBOOLEANS) {
3723 value = (code == MT_ST_SETBOOLEANS);
3724 if ((options & MT_ST_BUFFER_WRITES) != 0)
3725 STm->do_buffer_writes = value;
3726 if ((options & MT_ST_ASYNC_WRITES) != 0)
3727 STm->do_async_writes = value;
3728 if ((options & MT_ST_DEF_WRITES) != 0)
3729 STm->defaults_for_writes = value;
3730 if ((options & MT_ST_READ_AHEAD) != 0)
3731 STm->do_read_ahead = value;
3732 if ((options & MT_ST_TWO_FM) != 0)
3733 STp->two_fm = value;
3734 if ((options & MT_ST_FAST_MTEOM) != 0)
3735 STp->fast_mteom = value;
3736 if ((options & MT_ST_AUTO_LOCK) != 0)
3737 STp->do_auto_lock = value;
3738 if ((options & MT_ST_CAN_BSR) != 0)
3739 STp->can_bsr = value;
3740 if ((options & MT_ST_NO_BLKLIMS) != 0)
3741 STp->omit_blklims = value;
3742 if ((STp->device)->scsi_level >= SCSI_2 &&
3743 (options & MT_ST_CAN_PARTITIONS) != 0)
3744 STp->can_partitions = value;
3745 if ((options & MT_ST_SCSI2LOGICAL) != 0)
3746 STp->scsi2_logical = value;
3747 if ((options & MT_ST_SYSV) != 0)
3748 STm->sysv = value;
3749 #if DEBUG
3750 if ((options & MT_ST_DEBUGGING) != 0)
3751 debugging = value;
3752 #endif
3753 osst_log_options(STp, STm, name);
3755 else if (code == MT_ST_WRITE_THRESHOLD) {
3756 value = (options & ~MT_ST_OPTIONS) * ST_KILOBYTE;
3757 if (value < 1 || value > osst_buffer_size) {
3758 printk(KERN_WARNING "%s:W: Write threshold %d too small or too large.\n",
3759 name, value);
3760 return (-EIO);
3762 STp->write_threshold = value;
3763 printk(KERN_INFO "%s:I: Write threshold set to %d bytes.\n",
3764 name, value);
3766 else if (code == MT_ST_DEF_BLKSIZE) {
3767 value = (options & ~MT_ST_OPTIONS);
3768 if (value == ~MT_ST_OPTIONS) {
3769 STm->default_blksize = (-1);
3770 printk(KERN_INFO "%s:I: Default block size disabled.\n", name);
3772 else {
3773 if (value < 512 || value > OS_DATA_SIZE || OS_DATA_SIZE % value) {
3774 printk(KERN_WARNING "%s:W: Default block size cannot be set to %d.\n",
3775 name, value);
3776 return (-EINVAL);
3778 STm->default_blksize = value;
3779 printk(KERN_INFO "%s:I: Default block size set to %d bytes.\n",
3780 name, STm->default_blksize);
3783 else if (code == MT_ST_TIMEOUTS) {
3784 value = (options & ~MT_ST_OPTIONS);
3785 if ((value & MT_ST_SET_LONG_TIMEOUT) != 0) {
3786 STp->long_timeout = (value & ~MT_ST_SET_LONG_TIMEOUT) * HZ;
3787 printk(KERN_INFO "%s:I: Long timeout set to %d seconds.\n", name,
3788 (value & ~MT_ST_SET_LONG_TIMEOUT));
3790 else {
3791 STp->timeout = value * HZ;
3792 printk(KERN_INFO "%s:I: Normal timeout set to %d seconds.\n", name, value);
3795 else if (code == MT_ST_DEF_OPTIONS) {
3796 code = (options & ~MT_ST_CLEAR_DEFAULT);
3797 value = (options & MT_ST_CLEAR_DEFAULT);
3798 if (code == MT_ST_DEF_DENSITY) {
3799 if (value == MT_ST_CLEAR_DEFAULT) {
3800 STm->default_density = (-1);
3801 printk(KERN_INFO "%s:I: Density default disabled.\n", name);
3803 else {
3804 STm->default_density = value & 0xff;
3805 printk(KERN_INFO "%s:I: Density default set to %x\n",
3806 name, STm->default_density);
3809 else if (code == MT_ST_DEF_DRVBUFFER) {
3810 if (value == MT_ST_CLEAR_DEFAULT) {
3811 STp->default_drvbuffer = 0xff;
3812 printk(KERN_INFO "%s:I: Drive buffer default disabled.\n", name);
3814 else {
3815 STp->default_drvbuffer = value & 7;
3816 printk(KERN_INFO "%s:I: Drive buffer default set to %x\n",
3817 name, STp->default_drvbuffer);
3820 else if (code == MT_ST_DEF_COMPRESSION) {
3821 if (value == MT_ST_CLEAR_DEFAULT) {
3822 STm->default_compression = ST_DONT_TOUCH;
3823 printk(KERN_INFO "%s:I: Compression default disabled.\n", name);
3825 else {
3826 STm->default_compression = (value & 1 ? ST_YES : ST_NO);
3827 printk(KERN_INFO "%s:I: Compression default set to %x\n",
3828 name, (value & 1));
3832 else
3833 return (-EIO);
3835 return 0;
3839 /* Internal ioctl function */
3840 static int osst_int_ioctl(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, unsigned int cmd_in, unsigned long arg)
3842 int timeout;
3843 long ltmp;
3844 int i, ioctl_result;
3845 int chg_eof = TRUE;
3846 unsigned char cmd[MAX_COMMAND_SIZE];
3847 Scsi_Request * SRpnt = * aSRpnt;
3848 ST_partstat * STps;
3849 int fileno, blkno, at_sm, frame_seq_numbr, logical_blk_num;
3850 int datalen = 0, direction = SCSI_DATA_NONE;
3851 char * name = tape_name(STp);
3853 if (STp->ready != ST_READY && cmd_in != MTLOAD) {
3854 if (STp->ready == ST_NO_TAPE)
3855 return (-ENOMEDIUM);
3856 else
3857 return (-EIO);
3859 timeout = STp->long_timeout;
3860 STps = &(STp->ps[STp->partition]);
3861 fileno = STps->drv_file;
3862 blkno = STps->drv_block;
3863 at_sm = STps->at_sm;
3864 frame_seq_numbr = STp->frame_seq_number;
3865 logical_blk_num = STp->logical_blk_num;
3867 memset(cmd, 0, MAX_COMMAND_SIZE);
3868 switch (cmd_in) {
3869 case MTFSFM:
3870 chg_eof = FALSE; /* Changed from the FSF after this */
3871 case MTFSF:
3872 if (STp->raw)
3873 return (-EIO);
3874 if (STp->linux_media)
3875 ioctl_result = osst_space_over_filemarks_forward_fast(STp, &SRpnt, cmd_in, arg);
3876 else
3877 ioctl_result = osst_space_over_filemarks_forward_slow(STp, &SRpnt, cmd_in, arg);
3878 if (fileno >= 0)
3879 fileno += arg;
3880 blkno = 0;
3881 at_sm &= (arg == 0);
3882 goto os_bypass;
3884 case MTBSF:
3885 chg_eof = FALSE; /* Changed from the FSF after this */
3886 case MTBSFM:
3887 if (STp->raw)
3888 return (-EIO);
3889 ioctl_result = osst_space_over_filemarks_backward(STp, &SRpnt, cmd_in, arg);
3890 if (fileno >= 0)
3891 fileno -= arg;
3892 blkno = (-1); /* We can't know the block number */
3893 at_sm &= (arg == 0);
3894 goto os_bypass;
3896 case MTFSR:
3897 case MTBSR:
3898 #if DEBUG
3899 if (debugging)
3900 printk(OSST_DEB_MSG "%s:D: Skipping %lu blocks %s from logical block %d\n",
3901 name, arg, cmd_in==MTFSR?"forward":"backward", logical_blk_num);
3902 #endif
3903 if (cmd_in == MTFSR) {
3904 logical_blk_num += arg;
3905 if (blkno >= 0) blkno += arg;
3907 else {
3908 logical_blk_num -= arg;
3909 if (blkno >= 0) blkno -= arg;
3911 ioctl_result = osst_seek_logical_blk(STp, &SRpnt, logical_blk_num);
3912 fileno = STps->drv_file;
3913 blkno = STps->drv_block;
3914 at_sm &= (arg == 0);
3915 goto os_bypass;
3917 case MTFSS:
3918 cmd[0] = SPACE;
3919 cmd[1] = 0x04; /* Space Setmarks */ /* FIXME -- OS can't do this? */
3920 cmd[2] = (arg >> 16);
3921 cmd[3] = (arg >> 8);
3922 cmd[4] = arg;
3923 #if DEBUG
3924 if (debugging)
3925 printk(OSST_DEB_MSG "%s:D: Spacing tape forward %d setmarks.\n", name,
3926 cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
3927 #endif
3928 if (arg != 0) {
3929 blkno = fileno = (-1);
3930 at_sm = 1;
3932 break;
3933 case MTBSS:
3934 cmd[0] = SPACE;
3935 cmd[1] = 0x04; /* Space Setmarks */ /* FIXME -- OS can't do this? */
3936 ltmp = (-arg);
3937 cmd[2] = (ltmp >> 16);
3938 cmd[3] = (ltmp >> 8);
3939 cmd[4] = ltmp;
3940 #if DEBUG
3941 if (debugging) {
3942 if (cmd[2] & 0x80)
3943 ltmp = 0xff000000;
3944 ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4];
3945 printk(OSST_DEB_MSG "%s:D: Spacing tape backward %ld setmarks.\n",
3946 name, (-ltmp));
3948 #endif
3949 if (arg != 0) {
3950 blkno = fileno = (-1);
3951 at_sm = 1;
3953 break;
3954 case MTWEOF:
3955 if ((STps->rw == ST_WRITING || STp->dirty) && !STp->pos_unknown) {
3956 STp->write_type = OS_WRITE_DATA;
3957 ioctl_result = osst_flush_write_buffer(STp, &SRpnt);
3958 } else
3959 ioctl_result = 0;
3960 #if DEBUG
3961 if (debugging)
3962 printk(OSST_DEB_MSG "%s:D: Writing %ld filemark(s).\n", name, arg);
3963 #endif
3964 for (i=0; i<arg; i++)
3965 ioctl_result |= osst_write_filemark(STp, &SRpnt);
3966 if (fileno >= 0) fileno += arg;
3967 if (blkno >= 0) blkno = 0;
3968 goto os_bypass;
3970 case MTWSM:
3971 if (STp->write_prot)
3972 return (-EACCES);
3973 if (!STp->raw)
3974 return 0;
3975 cmd[0] = WRITE_FILEMARKS; /* FIXME -- need OS version */
3976 if (cmd_in == MTWSM)
3977 cmd[1] = 2;
3978 cmd[2] = (arg >> 16);
3979 cmd[3] = (arg >> 8);
3980 cmd[4] = arg;
3981 timeout = STp->timeout;
3982 #if DEBUG
3983 if (debugging)
3984 printk(OSST_DEB_MSG "%s:D: Writing %d setmark(s).\n", name,
3985 cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
3986 #endif
3987 if (fileno >= 0)
3988 fileno += arg;
3989 blkno = 0;
3990 at_sm = (cmd_in == MTWSM);
3991 break;
3992 case MTOFFL:
3993 case MTLOAD:
3994 case MTUNLOAD:
3995 case MTRETEN:
3996 cmd[0] = START_STOP;
3997 cmd[1] = 1; /* Don't wait for completion */
3998 if (cmd_in == MTLOAD) {
3999 if (STp->ready == ST_NO_TAPE)
4000 cmd[4] = 4; /* open tray */
4001 else
4002 cmd[4] = 1; /* load */
4004 if (cmd_in == MTRETEN)
4005 cmd[4] = 3; /* retension then mount */
4006 if (cmd_in == MTOFFL)
4007 cmd[4] = 4; /* rewind then eject */
4008 timeout = STp->timeout;
4009 #if DEBUG
4010 if (debugging) {
4011 switch (cmd_in) {
4012 case MTUNLOAD:
4013 printk(OSST_DEB_MSG "%s:D: Unloading tape.\n", name);
4014 break;
4015 case MTLOAD:
4016 printk(OSST_DEB_MSG "%s:D: Loading tape.\n", name);
4017 break;
4018 case MTRETEN:
4019 printk(OSST_DEB_MSG "%s:D: Retensioning tape.\n", name);
4020 break;
4021 case MTOFFL:
4022 printk(OSST_DEB_MSG "%s:D: Ejecting tape.\n", name);
4023 break;
4026 #endif
4027 fileno = blkno = at_sm = frame_seq_numbr = logical_blk_num = 0 ;
4028 break;
4029 case MTNOP:
4030 #if DEBUG
4031 if (debugging)
4032 printk(OSST_DEB_MSG "%s:D: No-op on tape.\n", name);
4033 #endif
4034 return 0; /* Should do something ? */
4035 break;
4036 case MTEOM:
4037 #if DEBUG
4038 if (debugging)
4039 printk(OSST_DEB_MSG "%s:D: Spacing to end of recorded medium.\n", name);
4040 #endif
4041 osst_set_frame_position(STp, &SRpnt, STp->eod_frame_ppos, 0);
4042 if (osst_get_logical_frame(STp, &SRpnt, -1, 0) < 0) {
4043 ioctl_result = -EIO;
4044 goto os_bypass;
4046 if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_EOD) {
4047 #if DEBUG
4048 printk(OSST_DEB_MSG "%s:D: No EOD frame found where expected.\n", name);
4049 #endif
4050 ioctl_result = -EIO;
4051 goto os_bypass;
4053 ioctl_result = osst_set_frame_position(STp, &SRpnt, STp->eod_frame_ppos, 0);
4054 fileno = STp->filemark_cnt;
4055 blkno = at_sm = 0;
4056 goto os_bypass;
4058 case MTERASE:
4059 if (STp->write_prot)
4060 return (-EACCES);
4061 ioctl_result = osst_reset_header(STp, &SRpnt);
4062 i = osst_write_eod(STp, &SRpnt);
4063 if (i < ioctl_result) ioctl_result = i;
4064 i = osst_position_tape_and_confirm(STp, &SRpnt, STp->eod_frame_ppos);
4065 if (i < ioctl_result) ioctl_result = i;
4066 fileno = blkno = at_sm = 0 ;
4067 goto os_bypass;
4069 case MTREW:
4070 cmd[0] = REZERO_UNIT; /* rewind */
4071 cmd[1] = 1;
4072 #if DEBUG
4073 if (debugging)
4074 printk(OSST_DEB_MSG "%s:D: Rewinding tape, Immed=%d.\n", name, cmd[1]);
4075 #endif
4076 fileno = blkno = at_sm = frame_seq_numbr = logical_blk_num = 0 ;
4077 break;
4079 case MTSETBLK: /* Set block length */
4080 case MTSETDENSITY: /* Set tape density */
4081 case MTSETDRVBUFFER: /* Set drive buffering */
4082 case SET_DENS_AND_BLK: /* Set density and block size */
4083 chg_eof = FALSE;
4084 if (STp->dirty || (STp->buffer)->buffer_bytes != 0)
4085 return (-EIO); /* Not allowed if data in buffer */
4086 if ((cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) &&
4087 (arg & MT_ST_BLKSIZE_MASK) != 0 &&
4088 ((arg & MT_ST_BLKSIZE_MASK) < STp->min_block ||
4089 (arg & MT_ST_BLKSIZE_MASK) > STp->max_block ||
4090 (arg & MT_ST_BLKSIZE_MASK) > osst_buffer_size)) {
4091 printk(KERN_WARNING "%s:W: Illegal block size.\n", name);
4092 return (-EINVAL);
4094 return 0; /* FIXME silently ignore if block size didn't change */
4096 default:
4097 return (-ENOSYS);
4100 SRpnt = osst_do_scsi(SRpnt, STp, cmd, datalen, direction, timeout, MAX_RETRIES, TRUE);
4102 ioctl_result = (STp->buffer)->syscall_result;
4104 if (!SRpnt) {
4105 #if DEBUG
4106 printk(OSST_DEB_MSG "%s:D: Couldn't exec scsi cmd for IOCTL\n", name);
4107 #endif
4108 return ioctl_result;
4111 if (!ioctl_result) { /* SCSI command successful */
4112 STp->frame_seq_number = frame_seq_numbr;
4113 STp->logical_blk_num = logical_blk_num;
4116 os_bypass:
4117 #if DEBUG
4118 if (debugging)
4119 printk(OSST_DEB_MSG "%s:D: IOCTL (%d) Result=%d\n", name, cmd_in, ioctl_result);
4120 #endif
4122 if (!ioctl_result) { /* success */
4124 if (cmd_in == MTFSFM) {
4125 fileno--;
4126 blkno--;
4128 if (cmd_in == MTBSFM) {
4129 fileno++;
4130 blkno++;
4132 STps->drv_block = blkno;
4133 STps->drv_file = fileno;
4134 STps->at_sm = at_sm;
4136 if (cmd_in == MTEOM)
4137 STps->eof = ST_EOD;
4138 else if ((cmd_in == MTFSFM || cmd_in == MTBSF) && STps->eof == ST_FM_HIT) {
4139 ioctl_result = osst_seek_logical_blk(STp, &SRpnt, STp->logical_blk_num-1);
4140 STps->drv_block++;
4141 STp->logical_blk_num++;
4142 STp->frame_seq_number++;
4143 STp->frame_in_buffer = 0;
4144 STp->buffer->read_pointer = 0;
4146 else if (cmd_in == MTFSF)
4147 STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD:ST_FM;
4148 else if (chg_eof)
4149 STps->eof = ST_NOEOF;
4151 if (cmd_in == MTOFFL || cmd_in == MTUNLOAD)
4152 STp->rew_at_close = 0;
4153 else if (cmd_in == MTLOAD) {
4154 for (i=0; i < ST_NBR_PARTITIONS; i++) {
4155 STp->ps[i].rw = ST_IDLE;
4156 STp->ps[i].last_block_valid = FALSE;/* FIXME - where else is this field maintained? */
4158 STp->partition = 0;
4161 if (cmd_in == MTREW) {
4162 ioctl_result = osst_position_tape_and_confirm(STp, &SRpnt, STp->first_data_ppos);
4163 if (ioctl_result > 0)
4164 ioctl_result = 0;
4167 } else if (cmd_in == MTBSF || cmd_in == MTBSFM ) {
4168 if (osst_position_tape_and_confirm(STp, &SRpnt, STp->first_data_ppos) < 0)
4169 STps->drv_file = STps->drv_block = -1;
4170 else
4171 STps->drv_file = STps->drv_block = 0;
4172 STps->eof = ST_NOEOF;
4173 } else if (cmd_in == MTFSF || cmd_in == MTFSFM) {
4174 if (osst_position_tape_and_confirm(STp, &SRpnt, STp->eod_frame_ppos) < 0)
4175 STps->drv_file = STps->drv_block = -1;
4176 else {
4177 STps->drv_file = STp->filemark_cnt;
4178 STps->drv_block = 0;
4180 STps->eof = ST_EOD;
4181 } else if (cmd_in == MTBSR || cmd_in == MTFSR || cmd_in == MTWEOF || cmd_in == MTEOM) {
4182 STps->drv_file = STps->drv_block = (-1);
4183 STps->eof = ST_NOEOF;
4184 STp->header_ok = 0;
4185 } else if (cmd_in == MTERASE) {
4186 STp->header_ok = 0;
4187 } else if (SRpnt) { /* SCSI command was not completely successful. */
4188 if (SRpnt->sr_sense_buffer[2] & 0x40) {
4189 STps->eof = ST_EOM_OK;
4190 STps->drv_block = 0;
4192 if (chg_eof)
4193 STps->eof = ST_NOEOF;
4195 if ((SRpnt->sr_sense_buffer[2] & 0x0f) == BLANK_CHECK)
4196 STps->eof = ST_EOD;
4198 if (cmd_in == MTLOAD && osst_wait_for_medium(STp, &SRpnt, 60))
4199 ioctl_result = osst_wait_ready(STp, &SRpnt, 5 * 60, OSST_WAIT_POSITION_COMPLETE);
4201 *aSRpnt = SRpnt;
4203 return ioctl_result;
4207 /* Open the device */
4208 static int os_scsi_tape_open(struct inode * inode, struct file * filp)
4210 unsigned short flags;
4211 int i, b_size, new_session = FALSE, retval = 0;
4212 unsigned char cmd[MAX_COMMAND_SIZE];
4213 Scsi_Request * SRpnt = NULL;
4214 OS_Scsi_Tape * STp;
4215 ST_mode * STm;
4216 ST_partstat * STps;
4217 char * name;
4218 int dev = TAPE_NR(inode->i_rdev);
4219 int mode = TAPE_MODE(inode->i_rdev);
4221 write_lock(&os_scsi_tapes_lock);
4222 if (dev >= osst_max_dev || os_scsi_tapes == NULL ||
4223 (STp = os_scsi_tapes[dev]) == NULL || !STp->device) {
4224 write_unlock(&os_scsi_tapes_lock);
4225 return (-ENXIO);
4228 name = tape_name(STp);
4230 if (STp->in_use) {
4231 write_unlock(&os_scsi_tapes_lock);
4232 #if DEBUG
4233 printk(OSST_DEB_MSG "%s:D: Device already in use.\n", name);
4234 #endif
4235 return (-EBUSY);
4237 if (scsi_device_get(STp->device)) {
4238 write_unlock(&os_scsi_tapes_lock);
4239 #if DEBUG
4240 printk(OSST_DEB_MSG "%s:D: Failed scsi_device_get.\n", name);
4241 #endif
4242 return (-ENXIO);
4244 filp->private_data = STp;
4245 STp->in_use = 1;
4246 write_unlock(&os_scsi_tapes_lock);
4247 STp->rew_at_close = TAPE_REWIND(inode->i_rdev);
4249 if( !scsi_block_when_processing_errors(STp->device) ) {
4250 return -ENXIO;
4253 if (mode != STp->current_mode) {
4254 #if DEBUG
4255 if (debugging)
4256 printk(OSST_DEB_MSG "%s:D: Mode change from %d to %d.\n",
4257 name, STp->current_mode, mode);
4258 #endif
4259 new_session = TRUE;
4260 STp->current_mode = mode;
4262 STm = &(STp->modes[STp->current_mode]);
4264 flags = filp->f_flags;
4265 STp->write_prot = ((flags & O_ACCMODE) == O_RDONLY);
4267 STp->raw = TAPE_IS_RAW(inode->i_rdev);
4268 if (STp->raw)
4269 STp->header_ok = 0;
4271 /* Allocate data segments for this device's tape buffer */
4272 if (!enlarge_buffer(STp->buffer, STp->restr_dma)) {
4273 printk(KERN_ERR "%s:E: Unable to allocate memory segments for tape buffer.\n", name);
4274 retval = (-EOVERFLOW);
4275 goto err_out;
4277 if (STp->buffer->buffer_size >= OS_FRAME_SIZE) {
4278 for (i = 0, b_size = 0;
4279 (i < STp->buffer->sg_segs) && ((b_size + STp->buffer->sg[i].length) <= OS_DATA_SIZE);
4280 b_size += STp->buffer->sg[i++].length);
4281 STp->buffer->aux = (os_aux_t *) (page_address(STp->buffer->sg[i].page) + OS_DATA_SIZE - b_size);
4282 #if DEBUG
4283 printk(OSST_DEB_MSG "%s:D: b_data points to %p in segment 0 at %p\n", name,
4284 STp->buffer->b_data, page_address(STp->buffer->sg[0].page));
4285 printk(OSST_DEB_MSG "%s:D: AUX points to %p in segment %d at %p\n", name,
4286 STp->buffer->aux, i, page_address(STp->buffer->sg[i].page));
4287 #endif
4288 } else {
4289 STp->buffer->aux = NULL; /* this had better never happen! */
4290 printk(KERN_NOTICE "%s:A: Framesize %d too large for buffer.\n", name, OS_FRAME_SIZE);
4291 retval = (-EIO);
4292 goto err_out;
4294 STp->buffer->writing = 0;
4295 STp->buffer->syscall_result = 0;
4296 STp->dirty = 0;
4297 for (i=0; i < ST_NBR_PARTITIONS; i++) {
4298 STps = &(STp->ps[i]);
4299 STps->rw = ST_IDLE;
4301 STp->ready = ST_READY;
4302 #if DEBUG
4303 STp->nbr_waits = STp->nbr_finished = 0;
4304 #endif
4306 memset (cmd, 0, MAX_COMMAND_SIZE);
4307 cmd[0] = TEST_UNIT_READY;
4309 SRpnt = osst_do_scsi(NULL, STp, cmd, 0, SCSI_DATA_NONE, STp->timeout, MAX_READY_RETRIES, TRUE);
4310 if (!SRpnt) {
4311 retval = (STp->buffer)->syscall_result;
4312 goto err_out;
4314 if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 &&
4315 (SRpnt->sr_sense_buffer[2] & 0x0f) == NOT_READY &&
4316 SRpnt->sr_sense_buffer[12] == 4 ) {
4317 #if DEBUG
4318 printk(OSST_DEB_MSG "%s:D: Unit not ready, cause %x\n", name, SRpnt->sr_sense_buffer[13]);
4319 #endif
4320 if (filp->f_flags & O_NONBLOCK) {
4321 retval = -EAGAIN;
4322 goto err_out;
4324 if (SRpnt->sr_sense_buffer[13] == 2) { /* initialize command required (LOAD) */
4325 memset (cmd, 0, MAX_COMMAND_SIZE);
4326 cmd[0] = START_STOP;
4327 cmd[1] = 1;
4328 cmd[4] = 1;
4329 SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, SCSI_DATA_NONE,
4330 STp->timeout, MAX_READY_RETRIES, TRUE);
4332 osst_wait_ready(STp, &SRpnt, (SRpnt->sr_sense_buffer[13]==1?15:3) * 60, 0);
4334 if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 &&
4335 (SRpnt->sr_sense_buffer[2] & 0x0f) == UNIT_ATTENTION) { /* New media? */
4336 #if DEBUG
4337 printk(OSST_DEB_MSG "%s:D: Unit wants attention\n", name);
4338 #endif
4339 STp->header_ok = 0;
4341 for (i=0; i < 10; i++) {
4343 memset (cmd, 0, MAX_COMMAND_SIZE);
4344 cmd[0] = TEST_UNIT_READY;
4346 SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, SCSI_DATA_NONE,
4347 STp->timeout, MAX_READY_RETRIES, TRUE);
4348 if ((SRpnt->sr_sense_buffer[0] & 0x70) != 0x70 ||
4349 (SRpnt->sr_sense_buffer[2] & 0x0f) != UNIT_ATTENTION)
4350 break;
4353 STp->pos_unknown = 0;
4354 STp->partition = STp->new_partition = 0;
4355 if (STp->can_partitions)
4356 STp->nbr_partitions = 1; /* This guess will be updated later if necessary */
4357 for (i=0; i < ST_NBR_PARTITIONS; i++) {
4358 STps = &(STp->ps[i]);
4359 STps->rw = ST_IDLE; /* FIXME - seems to be redundant... */
4360 STps->eof = ST_NOEOF;
4361 STps->at_sm = 0;
4362 STps->last_block_valid = FALSE;
4363 STps->drv_block = 0;
4364 STps->drv_file = 0 ;
4366 new_session = TRUE;
4367 STp->recover_count = 0;
4370 * if we have valid headers from before, and the drive/tape seem untouched,
4371 * open without reconfiguring and re-reading the headers
4373 if (!STp->buffer->syscall_result && STp->header_ok &&
4374 !SRpnt->sr_result && SRpnt->sr_sense_buffer[0] == 0) {
4376 memset(cmd, 0, MAX_COMMAND_SIZE);
4377 cmd[0] = MODE_SENSE;
4378 cmd[1] = 8;
4379 cmd[2] = VENDOR_IDENT_PAGE;
4380 cmd[4] = VENDOR_IDENT_PAGE_LENGTH + MODE_HEADER_LENGTH;
4382 SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], SCSI_DATA_READ, STp->timeout, 0, TRUE);
4384 if (STp->buffer->syscall_result ||
4385 STp->buffer->b_data[MODE_HEADER_LENGTH + 2] != 'L' ||
4386 STp->buffer->b_data[MODE_HEADER_LENGTH + 3] != 'I' ||
4387 STp->buffer->b_data[MODE_HEADER_LENGTH + 4] != 'N' ||
4388 STp->buffer->b_data[MODE_HEADER_LENGTH + 5] != '4' ) {
4389 #if DEBUG
4390 printk(OSST_DEB_MSG "%s:D: Signature was changed to %c%c%c%c\n", name,
4391 STp->buffer->b_data[MODE_HEADER_LENGTH + 2],
4392 STp->buffer->b_data[MODE_HEADER_LENGTH + 3],
4393 STp->buffer->b_data[MODE_HEADER_LENGTH + 4],
4394 STp->buffer->b_data[MODE_HEADER_LENGTH + 5]);
4395 #endif
4396 STp->header_ok = 0;
4398 i = STp->first_frame_position;
4399 if (STp->header_ok && i == osst_get_frame_position(STp, &SRpnt)) {
4400 if (STp->door_locked == ST_UNLOCKED) {
4401 if (do_door_lock(STp, 1))
4402 printk(KERN_INFO "%s:I: Can't lock drive door\n", name);
4403 else
4404 STp->door_locked = ST_LOCKED_AUTO;
4406 if (!STp->frame_in_buffer) {
4407 STp->block_size = (STm->default_blksize > 0) ?
4408 STm->default_blksize : OS_DATA_SIZE;
4409 STp->buffer->buffer_bytes = STp->buffer->read_pointer = 0;
4411 STp->buffer->buffer_blocks = OS_DATA_SIZE / STp->block_size;
4412 STp->fast_open = TRUE;
4413 scsi_release_request(SRpnt);
4414 return 0;
4416 #if DEBUG
4417 if (i != STp->first_frame_position)
4418 printk(OSST_DEB_MSG "%s:D: Tape position changed from %d to %d\n",
4419 name, i, STp->first_frame_position);
4420 #endif
4421 STp->header_ok = 0;
4423 STp->fast_open = FALSE;
4425 if ((STp->buffer)->syscall_result != 0 && /* in all error conditions except no medium */
4426 (SRpnt->sr_sense_buffer[2] != 2 || SRpnt->sr_sense_buffer[12] != 0x3A) ) {
4428 memset(cmd, 0, MAX_COMMAND_SIZE);
4429 cmd[0] = MODE_SELECT;
4430 cmd[1] = 0x10;
4431 cmd[4] = 4 + MODE_HEADER_LENGTH;
4433 (STp->buffer)->b_data[0] = cmd[4] - 1;
4434 (STp->buffer)->b_data[1] = 0; /* Medium Type - ignoring */
4435 (STp->buffer)->b_data[2] = 0; /* Reserved */
4436 (STp->buffer)->b_data[3] = 0; /* Block Descriptor Length */
4437 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 0] = 0x3f;
4438 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 1] = 1;
4439 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] = 2;
4440 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] = 3;
4442 #if DEBUG
4443 printk(OSST_DEB_MSG "%s:D: Applying soft reset\n", name);
4444 #endif
4445 SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], SCSI_DATA_WRITE, STp->timeout, 0, TRUE);
4447 STp->header_ok = 0;
4449 for (i=0; i < 10; i++) {
4451 memset (cmd, 0, MAX_COMMAND_SIZE);
4452 cmd[0] = TEST_UNIT_READY;
4454 SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, SCSI_DATA_NONE,
4455 STp->timeout, MAX_READY_RETRIES, TRUE);
4456 if ((SRpnt->sr_sense_buffer[0] & 0x70) != 0x70 ||
4457 (SRpnt->sr_sense_buffer[2] & 0x0f) == NOT_READY)
4458 break;
4460 if ((SRpnt->sr_sense_buffer[2] & 0x0f) == UNIT_ATTENTION) {
4461 STp->pos_unknown = 0;
4462 STp->partition = STp->new_partition = 0;
4463 if (STp->can_partitions)
4464 STp->nbr_partitions = 1; /* This guess will be updated later if necessary */
4465 for (i=0; i < ST_NBR_PARTITIONS; i++) {
4466 STps = &(STp->ps[i]);
4467 STps->rw = ST_IDLE;
4468 STps->eof = ST_NOEOF;
4469 STps->at_sm = 0;
4470 STps->last_block_valid = FALSE;
4471 STps->drv_block = 0;
4472 STps->drv_file = 0 ;
4474 new_session = TRUE;
4479 if (osst_wait_ready(STp, &SRpnt, 15 * 60, 0)) /* FIXME - not allowed with NOBLOCK */
4480 printk(KERN_INFO "%s:I: Device did not become Ready in open\n", name);
4482 if ((STp->buffer)->syscall_result != 0) {
4483 if ((STp->device)->scsi_level >= SCSI_2 &&
4484 (SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 &&
4485 (SRpnt->sr_sense_buffer[2] & 0x0f) == NOT_READY &&
4486 SRpnt->sr_sense_buffer[12] == 0x3a) { /* Check ASC */
4487 STp->ready = ST_NO_TAPE;
4488 } else
4489 STp->ready = ST_NOT_READY;
4490 scsi_release_request(SRpnt);
4491 SRpnt = NULL;
4492 STp->density = 0; /* Clear the erroneous "residue" */
4493 STp->write_prot = 0;
4494 STp->block_size = 0;
4495 STp->ps[0].drv_file = STp->ps[0].drv_block = (-1);
4496 STp->partition = STp->new_partition = 0;
4497 STp->door_locked = ST_UNLOCKED;
4498 return 0;
4501 osst_configure_onstream(STp, &SRpnt);
4503 STp->block_size = STp->raw ? OS_FRAME_SIZE : (
4504 (STm->default_blksize > 0) ? STm->default_blksize : OS_DATA_SIZE);
4505 STp->buffer->buffer_blocks = STp->raw ? 1 : OS_DATA_SIZE / STp->block_size;
4506 STp->buffer->buffer_bytes =
4507 STp->buffer->read_pointer =
4508 STp->frame_in_buffer = 0;
4510 #if DEBUG
4511 if (debugging)
4512 printk(OSST_DEB_MSG "%s:D: Block size: %d, frame size: %d, buffer size: %d (%d blocks).\n",
4513 name, STp->block_size, OS_FRAME_SIZE, (STp->buffer)->buffer_size,
4514 (STp->buffer)->buffer_blocks);
4515 #endif
4517 if (STp->drv_write_prot) {
4518 STp->write_prot = 1;
4519 #if DEBUG
4520 if (debugging)
4521 printk(OSST_DEB_MSG "%s:D: Write protected\n", name);
4522 #endif
4523 if ((flags & O_ACCMODE) == O_WRONLY || (flags & O_ACCMODE) == O_RDWR) {
4524 retval = (-EROFS);
4525 goto err_out;
4529 if (new_session) { /* Change the drive parameters for the new mode */
4530 #if DEBUG
4531 if (debugging)
4532 printk(OSST_DEB_MSG "%s:D: New Session\n", name);
4533 #endif
4534 STp->density_changed = STp->blksize_changed = FALSE;
4535 STp->compression_changed = FALSE;
4539 * properly position the tape and check the ADR headers
4541 if (STp->door_locked == ST_UNLOCKED) {
4542 if (do_door_lock(STp, 1))
4543 printk(KERN_INFO "%s:I: Can't lock drive door\n", name);
4544 else
4545 STp->door_locked = ST_LOCKED_AUTO;
4548 osst_analyze_headers(STp, &SRpnt);
4550 scsi_release_request(SRpnt);
4551 SRpnt = NULL;
4553 return 0;
4555 err_out:
4556 if (SRpnt != NULL)
4557 scsi_release_request(SRpnt);
4558 normalize_buffer(STp->buffer);
4559 STp->header_ok = 0;
4560 STp->in_use = 0;
4561 scsi_device_put(STp->device);
4563 return retval;
4567 /* Flush the tape buffer before close */
4568 static int os_scsi_tape_flush(struct file * filp)
4570 int result = 0, result2;
4571 OS_Scsi_Tape * STp = filp->private_data;
4572 ST_mode * STm = &(STp->modes[STp->current_mode]);
4573 ST_partstat * STps = &(STp->ps[STp->partition]);
4574 Scsi_Request * SRpnt = NULL;
4575 char * name = tape_name(STp);
4577 if (file_count(filp) > 1)
4578 return 0;
4580 if ((STps->rw == ST_WRITING || STp->dirty) && !STp->pos_unknown) {
4581 STp->write_type = OS_WRITE_DATA;
4582 result = osst_flush_write_buffer(STp, &SRpnt);
4583 if (result != 0 && result != (-ENOSPC))
4584 goto out;
4586 if ( STps->rw >= ST_WRITING && !STp->pos_unknown) {
4588 #if DEBUG
4589 if (debugging) {
4590 printk(OSST_DEB_MSG "%s:D: File length %ld bytes.\n",
4591 name, (long)(filp->f_pos));
4592 printk(OSST_DEB_MSG "%s:D: Async write waits %d, finished %d.\n",
4593 name, STp->nbr_waits, STp->nbr_finished);
4595 #endif
4596 if (STp->write_type != OS_WRITE_NEW_MARK) {
4597 /* true unless the user wrote the filemark for us */
4598 result = osst_flush_drive_buffer(STp, &SRpnt);
4599 if (result < 0) goto out;
4600 result = osst_write_filemark(STp, &SRpnt);
4601 if (result < 0) goto out;
4603 if (STps->drv_file >= 0)
4604 STps->drv_file++ ;
4605 STps->drv_block = 0;
4607 result = osst_write_eod(STp, &SRpnt);
4608 osst_write_header(STp, &SRpnt, !(STp->rew_at_close));
4610 STps->eof = ST_FM;
4612 #if DEBUG
4613 if (debugging)
4614 printk(OSST_DEB_MSG "%s:D: Buffer flushed, %d EOF(s) written\n",
4615 name, 1+STp->two_fm);
4616 #endif
4618 else if (!STp->rew_at_close) {
4619 STps = &(STp->ps[STp->partition]);
4620 if (!STm->sysv || STps->rw != ST_READING) {
4621 if (STp->can_bsr)
4622 result = osst_flush_buffer(STp, &SRpnt, 0); /* this is the default path */
4623 else if (STps->eof == ST_FM_HIT) {
4624 result = cross_eof(STp, &SRpnt, FALSE);
4625 if (result) {
4626 if (STps->drv_file >= 0)
4627 STps->drv_file++;
4628 STps->drv_block = 0;
4629 STps->eof = ST_FM;
4631 else
4632 STps->eof = ST_NOEOF;
4635 else if ((STps->eof == ST_NOEOF &&
4636 !(result = cross_eof(STp, &SRpnt, TRUE))) ||
4637 STps->eof == ST_FM_HIT) {
4638 if (STps->drv_file >= 0)
4639 STps->drv_file++;
4640 STps->drv_block = 0;
4641 STps->eof = ST_FM;
4645 out:
4646 if (STp->rew_at_close) {
4647 result2 = osst_position_tape_and_confirm(STp, &SRpnt, STp->first_data_ppos);
4648 STps->drv_file = STps->drv_block = STp->frame_seq_number = STp->logical_blk_num = 0;
4649 if (result == 0 && result2 < 0)
4650 result = result2;
4652 if (SRpnt) scsi_release_request(SRpnt);
4654 if (STp->recover_count) {
4655 printk(KERN_INFO "%s:I: %d recovered errors in", name, STp->recover_count);
4656 if (STp->write_count)
4657 printk(" %d frames written", STp->write_count);
4658 if (STp->read_count)
4659 printk(" %d frames read", STp->read_count);
4660 printk("\n");
4661 STp->recover_count = 0;
4663 STp->write_count = 0;
4664 STp->read_count = 0;
4666 return result;
4670 /* Close the device and release it */
4671 static int os_scsi_tape_close(struct inode * inode, struct file * filp)
4673 int result = 0;
4674 OS_Scsi_Tape * STp = filp->private_data;
4675 Scsi_Request * SRpnt = NULL;
4677 if (SRpnt) scsi_release_request(SRpnt);
4679 if (STp->door_locked == ST_LOCKED_AUTO)
4680 do_door_lock(STp, 0);
4682 if (STp->raw)
4683 STp->header_ok = 0;
4685 normalize_buffer(STp->buffer);
4686 write_lock(&os_scsi_tapes_lock);
4687 STp->in_use = 0;
4688 write_unlock(&os_scsi_tapes_lock);
4690 scsi_device_put(STp->device);
4692 return result;
4696 /* The ioctl command */
4697 static int osst_ioctl(struct inode * inode,struct file * file,
4698 unsigned int cmd_in, unsigned long arg)
4700 int i, cmd_nr, cmd_type, retval = 0;
4701 unsigned int blk;
4702 ST_mode * STm;
4703 ST_partstat * STps;
4704 Scsi_Request * SRpnt = NULL;
4705 OS_Scsi_Tape * STp = file->private_data;
4706 char * name = tape_name(STp);
4708 if (down_interruptible(&STp->lock))
4709 return -ERESTARTSYS;
4711 #if DEBUG
4712 if (debugging && !STp->in_use) {
4713 printk(OSST_DEB_MSG "%s:D: Incorrect device.\n", name);
4714 retval = (-EIO);
4715 goto out;
4717 #endif
4718 STm = &(STp->modes[STp->current_mode]);
4719 STps = &(STp->ps[STp->partition]);
4722 * If we are in the middle of error recovery, don't let anyone
4723 * else try and use this device. Also, if error recovery fails, it
4724 * may try and take the device offline, in which case all further
4725 * access to the device is prohibited.
4727 if( !scsi_block_when_processing_errors(STp->device) ) {
4728 retval = (-ENXIO);
4729 goto out;
4732 cmd_type = _IOC_TYPE(cmd_in);
4733 cmd_nr = _IOC_NR(cmd_in);
4734 #if DEBUG
4735 printk(OSST_DEB_MSG "%s:D: Ioctl %d,%d in %s mode\n", name,
4736 cmd_type, cmd_nr, STp->raw?"raw":"normal");
4737 #endif
4738 if (cmd_type == _IOC_TYPE(MTIOCTOP) && cmd_nr == _IOC_NR(MTIOCTOP)) {
4739 struct mtop mtc;
4741 if (_IOC_SIZE(cmd_in) != sizeof(mtc)) {
4742 retval = (-EINVAL);
4743 goto out;
4746 i = copy_from_user((char *) &mtc, (char *)arg, sizeof(struct mtop));
4747 if (i) {
4748 retval = (-EFAULT);
4749 goto out;
4752 if (mtc.mt_op == MTSETDRVBUFFER && !capable(CAP_SYS_ADMIN)) {
4753 printk(KERN_WARNING "%s:W: MTSETDRVBUFFER only allowed for root.\n", name);
4754 retval = (-EPERM);
4755 goto out;
4758 if (!STm->defined && (mtc.mt_op != MTSETDRVBUFFER && (mtc.mt_count & MT_ST_OPTIONS) == 0)) {
4759 retval = (-ENXIO);
4760 goto out;
4763 if (!STp->pos_unknown) {
4765 if (STps->eof == ST_FM_HIT) {
4766 if (mtc.mt_op == MTFSF || mtc.mt_op == MTFSFM|| mtc.mt_op == MTEOM) {
4767 mtc.mt_count -= 1;
4768 if (STps->drv_file >= 0)
4769 STps->drv_file += 1;
4771 else if (mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM) {
4772 mtc.mt_count += 1;
4773 if (STps->drv_file >= 0)
4774 STps->drv_file += 1;
4778 if (mtc.mt_op == MTSEEK) {
4779 /* Old position must be restored if partition will be changed */
4780 i = !STp->can_partitions || (STp->new_partition != STp->partition);
4782 else {
4783 i = mtc.mt_op == MTREW || mtc.mt_op == MTOFFL ||
4784 mtc.mt_op == MTRETEN || mtc.mt_op == MTEOM ||
4785 mtc.mt_op == MTLOCK || mtc.mt_op == MTLOAD ||
4786 mtc.mt_op == MTFSF || mtc.mt_op == MTFSFM ||
4787 mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM ||
4788 mtc.mt_op == MTCOMPRESSION;
4790 i = osst_flush_buffer(STp, &SRpnt, i);
4791 if (i < 0) {
4792 retval = i;
4793 goto out;
4796 else {
4798 * If there was a bus reset, block further access
4799 * to this device. If the user wants to rewind the tape,
4800 * then reset the flag and allow access again.
4802 if(mtc.mt_op != MTREW &&
4803 mtc.mt_op != MTOFFL &&
4804 mtc.mt_op != MTRETEN &&
4805 mtc.mt_op != MTERASE &&
4806 mtc.mt_op != MTSEEK &&
4807 mtc.mt_op != MTEOM) {
4808 retval = (-EIO);
4809 goto out;
4811 reset_state(STp);
4812 /* remove this when the midlevel properly clears was_reset */
4813 STp->device->was_reset = 0;
4816 if (mtc.mt_op != MTNOP && mtc.mt_op != MTWEOF && mtc.mt_op != MTWSM &&
4817 mtc.mt_op != MTSETDENSITY && mtc.mt_op != MTSETBLK &&
4818 mtc.mt_op != MTSETDRVBUFFER && mtc.mt_op != MTSETPART)
4819 STps->rw = ST_IDLE; /* Prevent automatic WEOF and fsf */
4821 if (mtc.mt_op == MTOFFL && STp->door_locked != ST_UNLOCKED)
4822 do_door_lock(STp, 0); /* Ignore result! */
4824 if (mtc.mt_op == MTSETDRVBUFFER &&
4825 (mtc.mt_count & MT_ST_OPTIONS) != 0) {
4826 retval = osst_set_options(STp, mtc.mt_count);
4827 goto out;
4830 if (mtc.mt_op == MTSETPART) {
4831 if (mtc.mt_count >= STp->nbr_partitions)
4832 retval = -EINVAL;
4833 else {
4834 STp->new_partition = mtc.mt_count;
4835 retval = 0;
4837 goto out;
4840 if (mtc.mt_op == MTMKPART) {
4841 if (!STp->can_partitions) {
4842 retval = (-EINVAL);
4843 goto out;
4845 if ((i = osst_int_ioctl(STp, &SRpnt, MTREW, 0)) < 0 /*||
4846 (i = partition_tape(inode, mtc.mt_count)) < 0*/) {
4847 retval = i;
4848 goto out;
4850 for (i=0; i < ST_NBR_PARTITIONS; i++) {
4851 STp->ps[i].rw = ST_IDLE;
4852 STp->ps[i].at_sm = 0;
4853 STp->ps[i].last_block_valid = FALSE;
4855 STp->partition = STp->new_partition = 0;
4856 STp->nbr_partitions = 1; /* Bad guess ?-) */
4857 STps->drv_block = STps->drv_file = 0;
4858 retval = 0;
4859 goto out;
4862 if (mtc.mt_op == MTSEEK) {
4863 if (STp->raw)
4864 i = osst_set_frame_position(STp, &SRpnt, mtc.mt_count, 0);
4865 else
4866 i = osst_seek_sector(STp, &SRpnt, mtc.mt_count);
4867 if (!STp->can_partitions)
4868 STp->ps[0].rw = ST_IDLE;
4869 retval = i;
4870 goto out;
4873 if (mtc.mt_op == MTLOCK || mtc.mt_op == MTUNLOCK) {
4874 retval = do_door_lock(STp, (mtc.mt_op == MTLOCK));
4875 goto out;
4878 if (mtc.mt_op == MTCOMPRESSION)
4879 retval = -EINVAL /*osst_compression(STp, (mtc.mt_count & 1))*/;
4880 else
4882 retval = osst_int_ioctl(STp, &SRpnt, mtc.mt_op, mtc.mt_count);
4883 goto out;
4886 if (!STm->defined) {
4887 retval = (-ENXIO);
4888 goto out;
4891 if ((i = osst_flush_buffer(STp, &SRpnt, FALSE)) < 0) {
4892 retval = i;
4893 goto out;
4896 if (cmd_type == _IOC_TYPE(MTIOCGET) && cmd_nr == _IOC_NR(MTIOCGET)) {
4897 struct mtget mt_status;
4899 if (_IOC_SIZE(cmd_in) != sizeof(struct mtget)) {
4900 retval = (-EINVAL);
4901 goto out;
4904 mt_status.mt_type = MT_ISONSTREAM_SC;
4905 mt_status.mt_erreg = STp->recover_erreg << MT_ST_SOFTERR_SHIFT;
4906 mt_status.mt_dsreg =
4907 ((STp->block_size << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK) |
4908 ((STp->density << MT_ST_DENSITY_SHIFT) & MT_ST_DENSITY_MASK);
4909 mt_status.mt_blkno = STps->drv_block;
4910 mt_status.mt_fileno = STps->drv_file;
4911 if (STp->block_size != 0) {
4912 if (STps->rw == ST_WRITING)
4913 mt_status.mt_blkno += (STp->buffer)->buffer_bytes / STp->block_size;
4914 else if (STps->rw == ST_READING)
4915 mt_status.mt_blkno -= ((STp->buffer)->buffer_bytes +
4916 STp->block_size - 1) / STp->block_size;
4919 mt_status.mt_gstat = 0;
4920 if (STp->drv_write_prot)
4921 mt_status.mt_gstat |= GMT_WR_PROT(0xffffffff);
4922 if (mt_status.mt_blkno == 0) {
4923 if (mt_status.mt_fileno == 0)
4924 mt_status.mt_gstat |= GMT_BOT(0xffffffff);
4925 else
4926 mt_status.mt_gstat |= GMT_EOF(0xffffffff);
4928 mt_status.mt_resid = STp->partition;
4929 if (STps->eof == ST_EOM_OK || STps->eof == ST_EOM_ERROR)
4930 mt_status.mt_gstat |= GMT_EOT(0xffffffff);
4931 else if (STps->eof >= ST_EOM_OK)
4932 mt_status.mt_gstat |= GMT_EOD(0xffffffff);
4933 if (STp->density == 1)
4934 mt_status.mt_gstat |= GMT_D_800(0xffffffff);
4935 else if (STp->density == 2)
4936 mt_status.mt_gstat |= GMT_D_1600(0xffffffff);
4937 else if (STp->density == 3)
4938 mt_status.mt_gstat |= GMT_D_6250(0xffffffff);
4939 if (STp->ready == ST_READY)
4940 mt_status.mt_gstat |= GMT_ONLINE(0xffffffff);
4941 if (STp->ready == ST_NO_TAPE)
4942 mt_status.mt_gstat |= GMT_DR_OPEN(0xffffffff);
4943 if (STps->at_sm)
4944 mt_status.mt_gstat |= GMT_SM(0xffffffff);
4945 if (STm->do_async_writes || (STm->do_buffer_writes && STp->block_size != 0) ||
4946 STp->drv_buffer != 0)
4947 mt_status.mt_gstat |= GMT_IM_REP_EN(0xffffffff);
4949 i = copy_to_user((char *)arg, (char *)&mt_status,
4950 sizeof(struct mtget));
4951 if (i) {
4952 retval = (-EFAULT);
4953 goto out;
4956 STp->recover_erreg = 0; /* Clear after read */
4957 retval = 0;
4958 goto out;
4959 } /* End of MTIOCGET */
4961 if (cmd_type == _IOC_TYPE(MTIOCPOS) && cmd_nr == _IOC_NR(MTIOCPOS)) {
4962 struct mtpos mt_pos;
4964 if (_IOC_SIZE(cmd_in) != sizeof(struct mtpos)) {
4965 retval = (-EINVAL);
4966 goto out;
4968 if (STp->raw)
4969 blk = osst_get_frame_position(STp, &SRpnt);
4970 else
4971 blk = osst_get_sector(STp, &SRpnt);
4972 if (blk < 0) {
4973 retval = blk;
4974 goto out;
4976 mt_pos.mt_blkno = blk;
4977 i = copy_to_user((char *)arg, (char *) (&mt_pos), sizeof(struct mtpos));
4978 if (i)
4979 retval = -EFAULT;
4980 goto out;
4982 if (SRpnt) scsi_release_request(SRpnt);
4984 up(&STp->lock);
4986 return scsi_ioctl(STp->device, cmd_in, (void *) arg);
4988 out:
4989 if (SRpnt) scsi_release_request(SRpnt);
4991 up(&STp->lock);
4993 return retval;
4997 /* Memory handling routines */
4999 /* Try to allocate a new tape buffer skeleton. Caller must not hold os_scsi_tapes_lock */
5000 static OSST_buffer * new_tape_buffer( int from_initialization, int need_dma, int max_sg )
5002 int i, priority;
5003 OSST_buffer *tb;
5005 if (from_initialization)
5006 priority = GFP_ATOMIC;
5007 else
5008 priority = GFP_KERNEL;
5010 i = sizeof(OSST_buffer) + (osst_max_sg_segs - 1) * sizeof(struct scatterlist);
5011 tb = (OSST_buffer *)kmalloc(i, priority);
5012 if (!tb) {
5013 printk(KERN_NOTICE "osst :I: Can't allocate new tape buffer.\n");
5014 return NULL;
5016 memset(tb, 0, i);
5017 tb->sg_segs = tb->orig_sg_segs = 0;
5018 tb->use_sg = max_sg;
5019 tb->in_use = TRUE;
5020 tb->dma = need_dma;
5021 tb->buffer_size = 0;
5022 #if DEBUG
5023 if (debugging)
5024 printk(OSST_DEB_MSG
5025 "osst :D: Allocated tape buffer skeleton (%d bytes, %d segments, dma: %d).\n",
5026 i, max_sg, need_dma);
5027 #endif
5028 return tb;
5031 /* Try to allocate a temporary (while a user has the device open) enlarged tape buffer */
5032 static int enlarge_buffer(OSST_buffer *STbuffer, int need_dma)
5034 int segs, nbr, max_segs, b_size, priority, order, got;
5036 if (STbuffer->buffer_size >= OS_FRAME_SIZE)
5037 return TRUE;
5039 if (STbuffer->sg_segs) {
5040 printk(KERN_WARNING "osst :A: Buffer not previously normalized.\n");
5041 normalize_buffer(STbuffer);
5043 /* See how many segments we can use -- need at least two */
5044 nbr = max_segs = STbuffer->use_sg;
5045 if (nbr <= 2)
5046 return FALSE;
5048 priority = GFP_KERNEL;
5049 if (need_dma)
5050 priority |= GFP_DMA;
5052 /* Try to allocate the first segment up to OS_DATA_SIZE and the others
5053 big enough to reach the goal (code assumes no segments in place) */
5054 for (b_size = OS_DATA_SIZE, order = OSST_FIRST_ORDER; b_size >= PAGE_SIZE; order--, b_size /= 2) {
5055 STbuffer->sg[0].page = alloc_pages(priority, order);
5056 STbuffer->sg[0].offset = 0;
5057 if (STbuffer->sg[0].page != NULL) {
5058 STbuffer->sg[0].length = b_size;
5059 STbuffer->b_data = page_address(STbuffer->sg[0].page);
5060 break;
5063 if (STbuffer->sg[0].page == NULL) {
5064 printk(KERN_NOTICE "osst :I: Can't allocate tape buffer main segment.\n");
5065 return FALSE;
5067 /* Got initial segment of 'bsize,order', continue with same size if possible, except for AUX */
5068 for (segs=STbuffer->sg_segs=1, got=b_size;
5069 segs < max_segs && got < OS_FRAME_SIZE; ) {
5070 STbuffer->sg[segs].page =
5071 alloc_pages(priority, (OS_FRAME_SIZE - got <= PAGE_SIZE) ? 0 : order);
5072 STbuffer->sg[segs].offset = 0;
5073 if (STbuffer->sg[segs].page == NULL) {
5074 if (OS_FRAME_SIZE - got <= (max_segs - segs) * b_size / 2 && order) {
5075 b_size /= 2; /* Large enough for the rest of the buffers */
5076 order--;
5077 continue;
5079 printk(KERN_WARNING "osst :W: Failed to enlarge buffer to %d bytes.\n",
5080 OS_FRAME_SIZE);
5081 #if DEBUG
5082 STbuffer->buffer_size = got;
5083 #endif
5084 normalize_buffer(STbuffer);
5085 return FALSE;
5087 STbuffer->sg[segs].length = (OS_FRAME_SIZE - got <= PAGE_SIZE / 2) ? (OS_FRAME_SIZE - got) : b_size;
5088 got += STbuffer->sg[segs].length;
5089 STbuffer->buffer_size = got;
5090 STbuffer->sg_segs = ++segs;
5092 #if DEBUG
5093 if (debugging) {
5094 printk(OSST_DEB_MSG
5095 "osst :D: Expanded tape buffer (%d bytes, %d->%d segments, dma: %d, at: %p).\n",
5096 got, STbuffer->orig_sg_segs, STbuffer->sg_segs, need_dma, STbuffer->b_data);
5097 printk(OSST_DEB_MSG
5098 "osst :D: segment sizes: first %d at %p, last %d bytes at %p.\n",
5099 STbuffer->sg[0].length, page_address(STbuffer->sg[0].page),
5100 STbuffer->sg[segs-1].length, page_address(STbuffer->sg[segs-1].page));
5102 #endif
5104 return TRUE;
5108 /* Release the segments */
5109 static void normalize_buffer(OSST_buffer *STbuffer)
5111 int i, order, b_size;
5113 for (i=0; i < STbuffer->sg_segs; i++) {
5115 for (b_size = PAGE_SIZE, order = 0;
5116 b_size < STbuffer->sg[i].length;
5117 b_size *= 2, order++);
5119 __free_pages(STbuffer->sg[i].page, order);
5120 STbuffer->buffer_size -= STbuffer->sg[i].length;
5122 #if DEBUG
5123 if (debugging && STbuffer->orig_sg_segs < STbuffer->sg_segs)
5124 printk(OSST_DEB_MSG "osst :D: Buffer at %p normalized to %d bytes (segs %d).\n",
5125 STbuffer->b_data, STbuffer->buffer_size, STbuffer->sg_segs);
5126 #endif
5127 STbuffer->sg_segs = STbuffer->orig_sg_segs = 0;
5131 /* Move data from the user buffer to the tape buffer. Returns zero (success) or
5132 negative error code. */
5133 static int append_to_buffer(const char *ubp, OSST_buffer *st_bp, int do_count)
5135 int i, cnt, res, offset;
5137 for (i=0, offset=st_bp->buffer_bytes;
5138 i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++)
5139 offset -= st_bp->sg[i].length;
5140 if (i == st_bp->sg_segs) { /* Should never happen */
5141 printk(KERN_WARNING "osst :A: Append_to_buffer offset overflow.\n");
5142 return (-EIO);
5144 for ( ; i < st_bp->sg_segs && do_count > 0; i++) {
5145 cnt = st_bp->sg[i].length - offset < do_count ?
5146 st_bp->sg[i].length - offset : do_count;
5147 res = copy_from_user(page_address(st_bp->sg[i].page) + offset, ubp, cnt);
5148 if (res)
5149 return (-EFAULT);
5150 do_count -= cnt;
5151 st_bp->buffer_bytes += cnt;
5152 ubp += cnt;
5153 offset = 0;
5155 if (do_count) { /* Should never happen */
5156 printk(KERN_WARNING "osst :A: Append_to_buffer overflow (left %d).\n",
5157 do_count);
5158 return (-EIO);
5160 return 0;
5164 /* Move data from the tape buffer to the user buffer. Returns zero (success) or
5165 negative error code. */
5166 static int from_buffer(OSST_buffer *st_bp, char *ubp, int do_count)
5168 int i, cnt, res, offset;
5170 for (i=0, offset=st_bp->read_pointer;
5171 i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++)
5172 offset -= st_bp->sg[i].length;
5173 if (i == st_bp->sg_segs) { /* Should never happen */
5174 printk(KERN_WARNING "osst :A: From_buffer offset overflow.\n");
5175 return (-EIO);
5177 for ( ; i < st_bp->sg_segs && do_count > 0; i++) {
5178 cnt = st_bp->sg[i].length - offset < do_count ?
5179 st_bp->sg[i].length - offset : do_count;
5180 res = copy_to_user(ubp, page_address(st_bp->sg[i].page) + offset, cnt);
5181 if (res)
5182 return (-EFAULT);
5183 do_count -= cnt;
5184 st_bp->buffer_bytes -= cnt;
5185 st_bp->read_pointer += cnt;
5186 ubp += cnt;
5187 offset = 0;
5189 if (do_count) { /* Should never happen */
5190 printk(KERN_WARNING "osst :A: From_buffer overflow (left %d).\n", do_count);
5191 return (-EIO);
5193 return 0;
5196 /* Sets the tail of the buffer after fill point to zero.
5197 Returns zero (success) or negative error code. */
5198 static int osst_zero_buffer_tail(OSST_buffer *st_bp)
5200 int i, offset, do_count, cnt;
5202 for (i = 0, offset = st_bp->buffer_bytes;
5203 i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++)
5204 offset -= st_bp->sg[i].length;
5205 if (i == st_bp->sg_segs) { /* Should never happen */
5206 printk(KERN_WARNING "osst :A: Zero_buffer offset overflow.\n");
5207 return (-EIO);
5209 for (do_count = OS_DATA_SIZE - st_bp->buffer_bytes;
5210 i < st_bp->sg_segs && do_count > 0; i++) {
5211 cnt = st_bp->sg[i].length - offset < do_count ?
5212 st_bp->sg[i].length - offset : do_count ;
5213 memset(page_address(st_bp->sg[i].page) + offset, 0, cnt);
5214 do_count -= cnt;
5215 offset = 0;
5217 if (do_count) { /* Should never happen */
5218 printk(KERN_WARNING "osst :A: Zero_buffer overflow (left %d).\n", do_count);
5219 return (-EIO);
5221 return 0;
5224 /* Copy a osst 32K chunk of memory into the buffer.
5225 Returns zero (success) or negative error code. */
5226 static int osst_copy_to_buffer(OSST_buffer *st_bp, unsigned char *ptr)
5228 int i, cnt, do_count = OS_DATA_SIZE;
5230 for (i = 0; i < st_bp->sg_segs && do_count > 0; i++) {
5231 cnt = st_bp->sg[i].length < do_count ?
5232 st_bp->sg[i].length : do_count ;
5233 memcpy(page_address(st_bp->sg[i].page), ptr, cnt);
5234 do_count -= cnt;
5235 ptr += cnt;
5237 if (do_count || i != st_bp->sg_segs-1) { /* Should never happen */
5238 printk(KERN_WARNING "osst :A: Copy_to_buffer overflow (left %d at sg %d).\n",
5239 do_count, i);
5240 return (-EIO);
5242 return 0;
5245 /* Copy a osst 32K chunk of memory from the buffer.
5246 Returns zero (success) or negative error code. */
5247 static int osst_copy_from_buffer(OSST_buffer *st_bp, unsigned char *ptr)
5249 int i, cnt, do_count = OS_DATA_SIZE;
5251 for (i = 0; i < st_bp->sg_segs && do_count > 0; i++) {
5252 cnt = st_bp->sg[i].length < do_count ?
5253 st_bp->sg[i].length : do_count ;
5254 memcpy(ptr, page_address(st_bp->sg[i].page), cnt);
5255 do_count -= cnt;
5256 ptr += cnt;
5258 if (do_count || i != st_bp->sg_segs-1) { /* Should never happen */
5259 printk(KERN_WARNING "osst :A: Copy_from_buffer overflow (left %d at sg %d).\n",
5260 do_count, i);
5261 return (-EIO);
5263 return 0;
5267 /* Module housekeeping */
5269 static void validate_options (void)
5271 if (max_dev > 0)
5272 osst_max_dev = max_dev;
5273 if (write_threshold_kbs > 0)
5274 osst_write_threshold = write_threshold_kbs * ST_KILOBYTE;
5275 if (osst_write_threshold > osst_buffer_size)
5276 osst_write_threshold = osst_buffer_size;
5277 if (max_sg_segs >= OSST_FIRST_SG)
5278 osst_max_sg_segs = max_sg_segs;
5279 #if DEBUG
5280 printk(OSST_DEB_MSG "osst :D: max tapes %d, write threshold %d, max s/g segs %d.\n",
5281 osst_max_dev, osst_write_threshold, osst_max_sg_segs);
5282 #endif
5285 #ifndef MODULE
5286 /* Set the boot options. Syntax: osst=xxx,yyy,...
5287 where xxx is write threshold in 1024 byte blocks,
5288 and yyy is number of s/g segments to use. */
5289 static int __init osst_setup (char *str)
5291 int i, ints[5];
5292 char *stp;
5294 stp = get_options(str, ARRAY_SIZE(ints), ints);
5296 if (ints[0] > 0) {
5297 for (i = 0; i < ints[0] && i < ARRAY_SIZE(parms); i++)
5298 *parms[i].val = ints[i + 1];
5299 } else {
5300 while (stp != NULL) {
5301 for (i = 0; i < ARRAY_SIZE(parms); i++) {
5302 int len = strlen(parms[i].name);
5303 if (!strncmp(stp, parms[i].name, len) &&
5304 (*(stp + len) == ':' || *(stp + len) == '=')) {
5305 *parms[i].val =
5306 simple_strtoul(stp + len + 1, NULL, 0);
5307 break;
5310 if (i >= sizeof(parms) / sizeof(struct osst_dev_parm))
5311 printk(KERN_INFO "osst :I: Illegal parameter in '%s'\n",
5312 stp);
5313 stp = strchr(stp, ',');
5314 if (stp)
5315 stp++;
5319 return 1;
5322 __setup("osst=", osst_setup);
5324 #endif
5326 static struct file_operations osst_fops = {
5327 .owner = THIS_MODULE,
5328 .read = osst_read,
5329 .write = osst_write,
5330 .ioctl = osst_ioctl,
5331 .open = os_scsi_tape_open,
5332 .flush = os_scsi_tape_flush,
5333 .release = os_scsi_tape_close,
5336 static int osst_supports(Scsi_Device * SDp)
5338 struct osst_support_data {
5339 char *vendor;
5340 char *model;
5341 char *rev;
5342 char *driver_hint; /* Name of the correct driver, NULL if unknown */
5345 static struct osst_support_data support_list[] = {
5346 /* {"XXX", "Yy-", "", NULL}, example */
5347 SIGS_FROM_OSST,
5348 {NULL, }};
5350 struct osst_support_data *rp;
5352 /* We are willing to drive OnStream SC-x0 as well as the
5353 * * IDE, ParPort, FireWire, USB variants, if accessible by
5354 * * emulation layer (ide-scsi, usb-storage, ...) */
5356 for (rp=&(support_list[0]); rp->vendor != NULL; rp++)
5357 if (!strncmp(rp->vendor, SDp->vendor, strlen(rp->vendor)) &&
5358 !strncmp(rp->model, SDp->model, strlen(rp->model)) &&
5359 !strncmp(rp->rev, SDp->rev, strlen(rp->rev)))
5360 return 1;
5361 return 0;
5365 * osst startup / cleanup code
5368 static int osst_probe(struct device *dev)
5370 Scsi_Device * SDp = to_scsi_device(dev);
5371 OS_Scsi_Tape * tpnt;
5372 ST_mode * STm;
5373 ST_partstat * STps;
5374 OSST_buffer * buffer;
5375 struct gendisk * drive;
5376 int i, mode, dev_num;
5378 if (SDp->type != TYPE_TAPE || !osst_supports(SDp))
5379 return -ENODEV;
5381 drive = alloc_disk(1);
5382 if (!drive) {
5383 printk(KERN_ERR "osst :E: Out of memory. Device not attached.\n");
5384 return -ENODEV;
5387 /* if this is the first attach, build the infrastructure */
5388 write_lock(&os_scsi_tapes_lock);
5389 if (os_scsi_tapes == NULL) {
5390 os_scsi_tapes =
5391 (OS_Scsi_Tape **)kmalloc(osst_max_dev * sizeof(OS_Scsi_Tape *),
5392 GFP_ATOMIC);
5393 if (os_scsi_tapes == NULL) {
5394 write_unlock(&os_scsi_tapes_lock);
5395 printk(KERN_ERR "osst :E: Unable to allocate array for OnStream SCSI tapes.\n");
5396 goto out_put_disk;
5398 for (i=0; i < osst_max_dev; ++i) os_scsi_tapes[i] = NULL;
5401 if (osst_nr_dev >= osst_max_dev) {
5402 write_unlock(&os_scsi_tapes_lock);
5403 printk(KERN_ERR "osst :E: Too many tape devices (max. %d).\n", osst_max_dev);
5404 goto out_put_disk;
5407 /* find a free minor number */
5408 for (i=0; os_scsi_tapes[i] && i<osst_max_dev; i++);
5409 if(i >= osst_max_dev) panic ("Scsi_devices corrupt (osst)");
5410 dev_num = i;
5412 /* allocate a OS_Scsi_Tape for this device */
5413 tpnt = (OS_Scsi_Tape *)kmalloc(sizeof(OS_Scsi_Tape), GFP_ATOMIC);
5414 if (tpnt == NULL) {
5415 write_unlock(&os_scsi_tapes_lock);
5416 printk(KERN_ERR "osst :E: Can't allocate device descriptor, device not attached.\n");
5417 goto out_put_disk;
5419 memset(tpnt, 0, sizeof(OS_Scsi_Tape));
5421 /* allocate a buffer for this device */
5422 i = SDp->host->sg_tablesize;
5423 if (osst_max_sg_segs < i)
5424 i = osst_max_sg_segs;
5425 buffer = new_tape_buffer(TRUE, SDp->host->unchecked_isa_dma, i);
5426 if (buffer == NULL) {
5427 write_unlock(&os_scsi_tapes_lock);
5428 printk(KERN_ERR "osst :E: Unable to allocate a tape buffer, device not attached.\n");
5429 kfree(tpnt);
5430 goto out_put_disk;
5432 os_scsi_tapes[dev_num] = tpnt;
5433 tpnt->buffer = buffer;
5434 tpnt->device = SDp;
5435 drive->private_data = &tpnt->driver;
5436 sprintf(drive->disk_name, "osst%d", dev_num);
5437 tpnt->driver = &osst_template;
5438 tpnt->drive = drive;
5439 tpnt->in_use = 0;
5440 tpnt->capacity = 0xfffff;
5441 tpnt->dirty = 0;
5442 tpnt->drv_buffer = 1; /* Try buffering if no mode sense */
5443 tpnt->restr_dma = (SDp->host)->unchecked_isa_dma;
5444 tpnt->density = 0;
5445 tpnt->do_auto_lock = OSST_AUTO_LOCK;
5446 tpnt->can_bsr = OSST_IN_FILE_POS;
5447 tpnt->can_partitions = 0;
5448 tpnt->two_fm = OSST_TWO_FM;
5449 tpnt->fast_mteom = OSST_FAST_MTEOM;
5450 tpnt->scsi2_logical = OSST_SCSI2LOGICAL; /* FIXME */
5451 tpnt->write_threshold = osst_write_threshold;
5452 tpnt->default_drvbuffer = 0xff; /* No forced buffering */
5453 tpnt->partition = 0;
5454 tpnt->new_partition = 0;
5455 tpnt->nbr_partitions = 0;
5456 tpnt->min_block = 512;
5457 tpnt->max_block = OS_DATA_SIZE;
5458 tpnt->timeout = OSST_TIMEOUT;
5459 tpnt->long_timeout = OSST_LONG_TIMEOUT;
5461 /* Recognize OnStream tapes */
5462 /* We don't need to test for OnStream, as this has been done in detect () */
5463 tpnt->os_fw_rev = osst_parse_firmware_rev (SDp->rev);
5464 tpnt->omit_blklims = 1;
5466 tpnt->poll = (strncmp(SDp->model, "DI-", 3) == 0) ||
5467 (strncmp(SDp->model, "FW-", 3) == 0) || OSST_FW_NEED_POLL(tpnt->os_fw_rev,SDp);
5468 tpnt->frame_in_buffer = 0;
5469 tpnt->header_ok = 0;
5470 tpnt->linux_media = 0;
5471 tpnt->header_cache = NULL;
5473 for (i=0; i < ST_NBR_MODES; i++) {
5474 STm = &(tpnt->modes[i]);
5475 STm->defined = FALSE;
5476 STm->sysv = OSST_SYSV;
5477 STm->defaults_for_writes = 0;
5478 STm->do_async_writes = OSST_ASYNC_WRITES;
5479 STm->do_buffer_writes = OSST_BUFFER_WRITES;
5480 STm->do_read_ahead = OSST_READ_AHEAD;
5481 STm->default_compression = ST_DONT_TOUCH;
5482 STm->default_blksize = 512;
5483 STm->default_density = (-1); /* No forced density */
5486 for (i=0; i < ST_NBR_PARTITIONS; i++) {
5487 STps = &(tpnt->ps[i]);
5488 STps->rw = ST_IDLE;
5489 STps->eof = ST_NOEOF;
5490 STps->at_sm = 0;
5491 STps->last_block_valid = FALSE;
5492 STps->drv_block = (-1);
5493 STps->drv_file = (-1);
5496 tpnt->current_mode = 0;
5497 tpnt->modes[0].defined = TRUE;
5498 tpnt->modes[2].defined = TRUE;
5499 tpnt->density_changed = tpnt->compression_changed = tpnt->blksize_changed = FALSE;
5501 init_MUTEX(&tpnt->lock);
5502 osst_nr_dev++;
5503 write_unlock(&os_scsi_tapes_lock);
5505 for (mode = 0; mode < ST_NBR_MODES; ++mode) {
5506 /* Rewind entry */
5507 devfs_mk_cdev(MKDEV(OSST_MAJOR, dev_num + (mode << 5)),
5508 S_IFCHR | S_IRUGO | S_IWUGO,
5509 "%s/ot%s", SDp->devfs_name, osst_formats[mode]);
5511 /* No-rewind entry */
5512 devfs_mk_cdev(MKDEV(OSST_MAJOR, dev_num + (mode << 5) + 128),
5513 S_IFCHR | S_IRUGO | S_IWUGO,
5514 "%s/ot%sn", SDp->devfs_name, osst_formats[mode]);
5516 drive->number = devfs_register_tape(SDp->devfs_name);
5518 printk(KERN_INFO
5519 "osst :I: Attached OnStream %.5s tape at scsi%d, channel %d, id %d, lun %d as %s\n",
5520 SDp->model, SDp->host->host_no, SDp->channel, SDp->id, SDp->lun, tape_name(tpnt));
5522 return 0;
5524 out_put_disk:
5525 put_disk(drive);
5526 return -ENODEV;
5529 static int osst_remove(struct device *dev)
5531 Scsi_Device * SDp = to_scsi_device(dev);
5532 OS_Scsi_Tape * tpnt;
5533 int i, mode;
5535 if ((SDp->type != TYPE_TAPE) || (osst_nr_dev <= 0))
5536 return 0;
5538 write_lock(&os_scsi_tapes_lock);
5539 for(i=0; i < osst_max_dev; i++) {
5540 if((tpnt = os_scsi_tapes[i]) && (tpnt->device == SDp)) {
5541 tpnt->device = NULL;
5542 for (mode = 0; mode < ST_NBR_MODES; ++mode) {
5543 devfs_remove("%s/ot%s", SDp->devfs_name, osst_formats[mode]);
5544 devfs_remove("%s/ot%sn", SDp->devfs_name, osst_formats[mode]);
5546 devfs_unregister_tape(tpnt->drive->number);
5547 put_disk(tpnt->drive);
5548 os_scsi_tapes[i] = NULL;
5549 osst_nr_dev--;
5550 write_unlock(&os_scsi_tapes_lock);
5551 if (tpnt->header_cache != NULL) vfree(tpnt->header_cache);
5552 if (tpnt->buffer) {
5553 normalize_buffer(tpnt->buffer);
5554 kfree(tpnt->buffer);
5556 kfree(tpnt);
5557 return 0;
5560 write_unlock(&os_scsi_tapes_lock);
5561 return 0;
5564 static int __init init_osst(void)
5566 printk(KERN_INFO "osst :I: Tape driver with OnStream support version %s\nosst :I: %s\n", osst_version, cvsid);
5568 validate_options();
5570 if ((register_chrdev(OSST_MAJOR,"osst", &osst_fops) < 0) || scsi_register_driver(&osst_template.gendrv)) {
5571 printk(KERN_ERR "osst :E: Unable to register major %d for OnStream tapes\n", OSST_MAJOR);
5572 return 1;
5575 return 0;
5578 static void __exit exit_osst (void)
5580 int i;
5581 OS_Scsi_Tape * STp;
5583 scsi_unregister_driver(&osst_template.gendrv);
5584 unregister_chrdev(OSST_MAJOR, "osst");
5586 if (os_scsi_tapes) {
5587 for (i=0; i < osst_max_dev; ++i) {
5588 if (!(STp = os_scsi_tapes[i])) continue;
5589 /* This is defensive, supposed to happen during detach */
5590 if (STp->header_cache)
5591 vfree(STp->header_cache);
5592 if (STp->buffer) {
5593 normalize_buffer(STp->buffer);
5594 kfree(STp->buffer);
5596 put_disk(STp->drive);
5597 kfree(STp);
5599 kfree(os_scsi_tapes);
5601 printk(KERN_INFO "osst :I: Unloaded.\n");
5604 module_init(init_osst);
5605 module_exit(exit_osst);