OMAP3: PM: Added resource refresh to OPP unlock requests
[linux-ginger.git] / drivers / scsi / osst.c
blobacb835837eec6213cae3f70679406570a5eba557
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 / 2000 - 2006 Willem Riede
17 email osst@riede.org
19 $Header: /cvsroot/osst/Driver/osst.c,v 1.73 2005/01/01 21:13:34 wriede Exp $
21 Microscopic alterations - Rik Ling, 2000/12/21
22 Last st.c sync: Tue Oct 15 22:01:04 2002 by makisara
23 Some small formal changes - aeb, 950809
26 static const char * cvsid = "$Id: osst.c,v 1.73 2005/01/01 21:13:34 wriede Exp $";
27 static const char * osst_version = "0.99.4";
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/proc_fs.h>
40 #include <linux/mm.h>
41 #include <linux/init.h>
42 #include <linux/string.h>
43 #include <linux/errno.h>
44 #include <linux/mtio.h>
45 #include <linux/ioctl.h>
46 #include <linux/fcntl.h>
47 #include <linux/spinlock.h>
48 #include <linux/vmalloc.h>
49 #include <linux/blkdev.h>
50 #include <linux/moduleparam.h>
51 #include <linux/delay.h>
52 #include <linux/jiffies.h>
53 #include <linux/smp_lock.h>
54 #include <asm/uaccess.h>
55 #include <asm/dma.h>
56 #include <asm/system.h>
58 /* The driver prints some debugging information on the console if DEBUG
59 is defined and non-zero. */
60 #define DEBUG 0
62 /* The message level for the debug messages is currently set to KERN_NOTICE
63 so that people can easily see the messages. Later when the debugging messages
64 in the drivers are more widely classified, this may be changed to KERN_DEBUG. */
65 #define OSST_DEB_MSG KERN_NOTICE
67 #include <scsi/scsi.h>
68 #include <scsi/scsi_dbg.h>
69 #include <scsi/scsi_device.h>
70 #include <scsi/scsi_driver.h>
71 #include <scsi/scsi_eh.h>
72 #include <scsi/scsi_host.h>
73 #include <scsi/scsi_ioctl.h>
75 #define ST_KILOBYTE 1024
77 #include "st.h"
78 #include "osst.h"
79 #include "osst_options.h"
80 #include "osst_detect.h"
82 static int max_dev = 0;
83 static int write_threshold_kbs = 0;
84 static int max_sg_segs = 0;
86 #ifdef MODULE
87 MODULE_AUTHOR("Willem Riede");
88 MODULE_DESCRIPTION("OnStream {DI-|FW-|SC-|USB}{30|50} Tape Driver");
89 MODULE_LICENSE("GPL");
90 MODULE_ALIAS_CHARDEV_MAJOR(OSST_MAJOR);
91 MODULE_ALIAS_SCSI_DEVICE(TYPE_TAPE);
93 module_param(max_dev, int, 0444);
94 MODULE_PARM_DESC(max_dev, "Maximum number of OnStream Tape Drives to attach (4)");
96 module_param(write_threshold_kbs, int, 0644);
97 MODULE_PARM_DESC(write_threshold_kbs, "Asynchronous write threshold (KB; 32)");
99 module_param(max_sg_segs, int, 0644);
100 MODULE_PARM_DESC(max_sg_segs, "Maximum number of scatter/gather segments to use (9)");
101 #else
102 static struct osst_dev_parm {
103 char *name;
104 int *val;
105 } parms[] __initdata = {
106 { "max_dev", &max_dev },
107 { "write_threshold_kbs", &write_threshold_kbs },
108 { "max_sg_segs", &max_sg_segs }
110 #endif
112 /* Some default definitions have been moved to osst_options.h */
113 #define OSST_BUFFER_SIZE (OSST_BUFFER_BLOCKS * ST_KILOBYTE)
114 #define OSST_WRITE_THRESHOLD (OSST_WRITE_THRESHOLD_BLOCKS * ST_KILOBYTE)
116 /* The buffer size should fit into the 24 bits for length in the
117 6-byte SCSI read and write commands. */
118 #if OSST_BUFFER_SIZE >= (2 << 24 - 1)
119 #error "Buffer size should not exceed (2 << 24 - 1) bytes!"
120 #endif
122 #if DEBUG
123 static int debugging = 1;
124 /* uncomment define below to test error recovery */
125 // #define OSST_INJECT_ERRORS 1
126 #endif
128 /* Do not retry! The drive firmware already retries when appropriate,
129 and when it tries to tell us something, we had better listen... */
130 #define MAX_RETRIES 0
132 #define NO_TAPE NOT_READY
134 #define OSST_WAIT_POSITION_COMPLETE (HZ > 200 ? HZ / 200 : 1)
135 #define OSST_WAIT_WRITE_COMPLETE (HZ / 12)
136 #define OSST_WAIT_LONG_WRITE_COMPLETE (HZ / 2)
138 #define OSST_TIMEOUT (200 * HZ)
139 #define OSST_LONG_TIMEOUT (1800 * HZ)
141 #define TAPE_NR(x) (iminor(x) & ~(-1 << ST_MODE_SHIFT))
142 #define TAPE_MODE(x) ((iminor(x) & ST_MODE_MASK) >> ST_MODE_SHIFT)
143 #define TAPE_REWIND(x) ((iminor(x) & 0x80) == 0)
144 #define TAPE_IS_RAW(x) (TAPE_MODE(x) & (ST_NBR_MODES >> 1))
146 /* Internal ioctl to set both density (uppermost 8 bits) and blocksize (lower
147 24 bits) */
148 #define SET_DENS_AND_BLK 0x10001
150 static int osst_buffer_size = OSST_BUFFER_SIZE;
151 static int osst_write_threshold = OSST_WRITE_THRESHOLD;
152 static int osst_max_sg_segs = OSST_MAX_SG;
153 static int osst_max_dev = OSST_MAX_TAPES;
154 static int osst_nr_dev;
156 static struct osst_tape **os_scsi_tapes = NULL;
157 static DEFINE_RWLOCK(os_scsi_tapes_lock);
159 static int modes_defined = 0;
161 static struct osst_buffer *new_tape_buffer(int, int, int);
162 static int enlarge_buffer(struct osst_buffer *, int);
163 static void normalize_buffer(struct osst_buffer *);
164 static int append_to_buffer(const char __user *, struct osst_buffer *, int);
165 static int from_buffer(struct osst_buffer *, char __user *, int);
166 static int osst_zero_buffer_tail(struct osst_buffer *);
167 static int osst_copy_to_buffer(struct osst_buffer *, unsigned char *);
168 static int osst_copy_from_buffer(struct osst_buffer *, unsigned char *);
170 static int osst_probe(struct device *);
171 static int osst_remove(struct device *);
173 static struct scsi_driver osst_template = {
174 .owner = THIS_MODULE,
175 .gendrv = {
176 .name = "osst",
177 .probe = osst_probe,
178 .remove = osst_remove,
182 static int osst_int_ioctl(struct osst_tape *STp, struct osst_request ** aSRpnt,
183 unsigned int cmd_in, unsigned long arg);
185 static int osst_set_frame_position(struct osst_tape *STp, struct osst_request ** aSRpnt, int frame, int skip);
187 static int osst_get_frame_position(struct osst_tape *STp, struct osst_request ** aSRpnt);
189 static int osst_flush_write_buffer(struct osst_tape *STp, struct osst_request ** aSRpnt);
191 static int osst_write_error_recovery(struct osst_tape * STp, struct osst_request ** aSRpnt, int pending);
193 static inline char *tape_name(struct osst_tape *tape)
195 return tape->drive->disk_name;
198 /* Routines that handle the interaction with mid-layer SCSI routines */
201 /* Normalize Sense */
202 static void osst_analyze_sense(struct osst_request *SRpnt, struct st_cmdstatus *s)
204 const u8 *ucp;
205 const u8 *sense = SRpnt->sense;
207 s->have_sense = scsi_normalize_sense(SRpnt->sense,
208 SCSI_SENSE_BUFFERSIZE, &s->sense_hdr);
209 s->flags = 0;
211 if (s->have_sense) {
212 s->deferred = 0;
213 s->remainder_valid =
214 scsi_get_sense_info_fld(sense, SCSI_SENSE_BUFFERSIZE, &s->uremainder64);
215 switch (sense[0] & 0x7f) {
216 case 0x71:
217 s->deferred = 1;
218 case 0x70:
219 s->fixed_format = 1;
220 s->flags = sense[2] & 0xe0;
221 break;
222 case 0x73:
223 s->deferred = 1;
224 case 0x72:
225 s->fixed_format = 0;
226 ucp = scsi_sense_desc_find(sense, SCSI_SENSE_BUFFERSIZE, 4);
227 s->flags = ucp ? (ucp[3] & 0xe0) : 0;
228 break;
233 /* Convert the result to success code */
234 static int osst_chk_result(struct osst_tape * STp, struct osst_request * SRpnt)
236 char *name = tape_name(STp);
237 int result = SRpnt->result;
238 u8 * sense = SRpnt->sense, scode;
239 #if DEBUG
240 const char *stp;
241 #endif
242 struct st_cmdstatus *cmdstatp;
244 if (!result)
245 return 0;
247 cmdstatp = &STp->buffer->cmdstat;
248 osst_analyze_sense(SRpnt, cmdstatp);
250 if (cmdstatp->have_sense)
251 scode = STp->buffer->cmdstat.sense_hdr.sense_key;
252 else
253 scode = 0;
254 #if DEBUG
255 if (debugging) {
256 printk(OSST_DEB_MSG "%s:D: Error: %x, cmd: %x %x %x %x %x %x\n",
257 name, result,
258 SRpnt->cmd[0], SRpnt->cmd[1], SRpnt->cmd[2],
259 SRpnt->cmd[3], SRpnt->cmd[4], SRpnt->cmd[5]);
260 if (scode) printk(OSST_DEB_MSG "%s:D: Sense: %02x, ASC: %02x, ASCQ: %02x\n",
261 name, scode, sense[12], sense[13]);
262 if (cmdstatp->have_sense)
263 __scsi_print_sense("osst ", SRpnt->sense, SCSI_SENSE_BUFFERSIZE);
265 else
266 #endif
267 if (cmdstatp->have_sense && (
268 scode != NO_SENSE &&
269 scode != RECOVERED_ERROR &&
270 /* scode != UNIT_ATTENTION && */
271 scode != BLANK_CHECK &&
272 scode != VOLUME_OVERFLOW &&
273 SRpnt->cmd[0] != MODE_SENSE &&
274 SRpnt->cmd[0] != TEST_UNIT_READY)) { /* Abnormal conditions for tape */
275 if (cmdstatp->have_sense) {
276 printk(KERN_WARNING "%s:W: Command with sense data:\n", name);
277 __scsi_print_sense("osst ", SRpnt->sense, SCSI_SENSE_BUFFERSIZE);
279 else {
280 static int notyetprinted = 1;
282 printk(KERN_WARNING
283 "%s:W: Warning %x (driver bt 0x%x, host bt 0x%x).\n",
284 name, result, driver_byte(result),
285 host_byte(result));
286 if (notyetprinted) {
287 notyetprinted = 0;
288 printk(KERN_INFO
289 "%s:I: This warning may be caused by your scsi controller,\n", name);
290 printk(KERN_INFO
291 "%s:I: it has been reported with some Buslogic cards.\n", name);
295 STp->pos_unknown |= STp->device->was_reset;
297 if (cmdstatp->have_sense && scode == RECOVERED_ERROR) {
298 STp->recover_count++;
299 STp->recover_erreg++;
300 #if DEBUG
301 if (debugging) {
302 if (SRpnt->cmd[0] == READ_6)
303 stp = "read";
304 else if (SRpnt->cmd[0] == WRITE_6)
305 stp = "write";
306 else
307 stp = "ioctl";
308 printk(OSST_DEB_MSG "%s:D: Recovered %s error (%d).\n", name, stp,
309 STp->recover_count);
311 #endif
312 if ((sense[2] & 0xe0) == 0)
313 return 0;
315 return (-EIO);
319 /* Wakeup from interrupt */
320 static void osst_end_async(struct request *req, int update)
322 struct osst_request *SRpnt = req->end_io_data;
323 struct osst_tape *STp = SRpnt->stp;
324 struct rq_map_data *mdata = &SRpnt->stp->buffer->map_data;
326 STp->buffer->cmdstat.midlevel_result = SRpnt->result = req->errors;
327 #if DEBUG
328 STp->write_pending = 0;
329 #endif
330 if (SRpnt->waiting)
331 complete(SRpnt->waiting);
333 if (SRpnt->bio) {
334 kfree(mdata->pages);
335 blk_rq_unmap_user(SRpnt->bio);
338 __blk_put_request(req->q, req);
341 /* osst_request memory management */
342 static struct osst_request *osst_allocate_request(void)
344 return kzalloc(sizeof(struct osst_request), GFP_KERNEL);
347 static void osst_release_request(struct osst_request *streq)
349 kfree(streq);
352 static int osst_execute(struct osst_request *SRpnt, const unsigned char *cmd,
353 int cmd_len, int data_direction, void *buffer, unsigned bufflen,
354 int use_sg, int timeout, int retries)
356 struct request *req;
357 struct page **pages = NULL;
358 struct rq_map_data *mdata = &SRpnt->stp->buffer->map_data;
360 int err = 0;
361 int write = (data_direction == DMA_TO_DEVICE);
363 req = blk_get_request(SRpnt->stp->device->request_queue, write, GFP_KERNEL);
364 if (!req)
365 return DRIVER_ERROR << 24;
367 req->cmd_type = REQ_TYPE_BLOCK_PC;
368 req->cmd_flags |= REQ_QUIET;
370 SRpnt->bio = NULL;
372 if (use_sg) {
373 struct scatterlist *sg, *sgl = (struct scatterlist *)buffer;
374 int i;
376 pages = kzalloc(use_sg * sizeof(struct page *), GFP_KERNEL);
377 if (!pages)
378 goto free_req;
380 for_each_sg(sgl, sg, use_sg, i)
381 pages[i] = sg_page(sg);
383 mdata->null_mapped = 1;
385 mdata->page_order = get_order(sgl[0].length);
386 mdata->nr_entries =
387 DIV_ROUND_UP(bufflen, PAGE_SIZE << mdata->page_order);
388 mdata->offset = 0;
390 err = blk_rq_map_user(req->q, req, mdata, NULL, bufflen, GFP_KERNEL);
391 if (err) {
392 kfree(pages);
393 goto free_req;
395 SRpnt->bio = req->bio;
396 mdata->pages = pages;
398 } else if (bufflen) {
399 err = blk_rq_map_kern(req->q, req, buffer, bufflen, GFP_KERNEL);
400 if (err)
401 goto free_req;
404 req->cmd_len = cmd_len;
405 memset(req->cmd, 0, BLK_MAX_CDB); /* ATAPI hates garbage after CDB */
406 memcpy(req->cmd, cmd, req->cmd_len);
407 req->sense = SRpnt->sense;
408 req->sense_len = 0;
409 req->timeout = timeout;
410 req->retries = retries;
411 req->end_io_data = SRpnt;
413 blk_execute_rq_nowait(req->q, NULL, req, 1, osst_end_async);
414 return 0;
415 free_req:
416 blk_put_request(req);
417 return DRIVER_ERROR << 24;
420 /* Do the scsi command. Waits until command performed if do_wait is true.
421 Otherwise osst_write_behind_check() is used to check that the command
422 has finished. */
423 static struct osst_request * osst_do_scsi(struct osst_request *SRpnt, struct osst_tape *STp,
424 unsigned char *cmd, int bytes, int direction, int timeout, int retries, int do_wait)
426 unsigned char *bp;
427 unsigned short use_sg;
428 #ifdef OSST_INJECT_ERRORS
429 static int inject = 0;
430 static int repeat = 0;
431 #endif
432 struct completion *waiting;
434 /* if async, make sure there's no command outstanding */
435 if (!do_wait && ((STp->buffer)->last_SRpnt)) {
436 printk(KERN_ERR "%s: Async command already active.\n",
437 tape_name(STp));
438 if (signal_pending(current))
439 (STp->buffer)->syscall_result = (-EINTR);
440 else
441 (STp->buffer)->syscall_result = (-EBUSY);
442 return NULL;
445 if (SRpnt == NULL) {
446 SRpnt = osst_allocate_request();
447 if (SRpnt == NULL) {
448 printk(KERN_ERR "%s: Can't allocate SCSI request.\n",
449 tape_name(STp));
450 if (signal_pending(current))
451 (STp->buffer)->syscall_result = (-EINTR);
452 else
453 (STp->buffer)->syscall_result = (-EBUSY);
454 return NULL;
456 SRpnt->stp = STp;
459 /* If async IO, set last_SRpnt. This ptr tells write_behind_check
460 which IO is outstanding. It's nulled out when the IO completes. */
461 if (!do_wait)
462 (STp->buffer)->last_SRpnt = SRpnt;
464 waiting = &STp->wait;
465 init_completion(waiting);
466 SRpnt->waiting = waiting;
468 use_sg = (bytes > STp->buffer->sg[0].length) ? STp->buffer->use_sg : 0;
469 if (use_sg) {
470 bp = (char *)&(STp->buffer->sg[0]);
471 if (STp->buffer->sg_segs < use_sg)
472 use_sg = STp->buffer->sg_segs;
474 else
475 bp = (STp->buffer)->b_data;
477 memcpy(SRpnt->cmd, cmd, sizeof(SRpnt->cmd));
478 STp->buffer->cmdstat.have_sense = 0;
479 STp->buffer->syscall_result = 0;
481 if (osst_execute(SRpnt, cmd, COMMAND_SIZE(cmd[0]), direction, bp, bytes,
482 use_sg, timeout, retries))
483 /* could not allocate the buffer or request was too large */
484 (STp->buffer)->syscall_result = (-EBUSY);
485 else if (do_wait) {
486 wait_for_completion(waiting);
487 SRpnt->waiting = NULL;
488 STp->buffer->syscall_result = osst_chk_result(STp, SRpnt);
489 #ifdef OSST_INJECT_ERRORS
490 if (STp->buffer->syscall_result == 0 &&
491 cmd[0] == READ_6 &&
492 cmd[4] &&
493 ( (++ inject % 83) == 29 ||
494 (STp->first_frame_position == 240
495 /* or STp->read_error_frame to fail again on the block calculated above */ &&
496 ++repeat < 3))) {
497 printk(OSST_DEB_MSG "%s:D: Injecting read error\n", tape_name(STp));
498 STp->buffer->last_result_fatal = 1;
500 #endif
502 return SRpnt;
506 /* Handle the write-behind checking (downs the semaphore) */
507 static void osst_write_behind_check(struct osst_tape *STp)
509 struct osst_buffer * STbuffer;
511 STbuffer = STp->buffer;
513 #if DEBUG
514 if (STp->write_pending)
515 STp->nbr_waits++;
516 else
517 STp->nbr_finished++;
518 #endif
519 wait_for_completion(&(STp->wait));
520 STp->buffer->last_SRpnt->waiting = NULL;
522 STp->buffer->syscall_result = osst_chk_result(STp, STp->buffer->last_SRpnt);
524 if (STp->buffer->syscall_result)
525 STp->buffer->syscall_result =
526 osst_write_error_recovery(STp, &(STp->buffer->last_SRpnt), 1);
527 else
528 STp->first_frame_position++;
530 osst_release_request(STp->buffer->last_SRpnt);
532 if (STbuffer->writing < STbuffer->buffer_bytes)
533 printk(KERN_WARNING "osst :A: write_behind_check: something left in buffer!\n");
535 STbuffer->last_SRpnt = NULL;
536 STbuffer->buffer_bytes -= STbuffer->writing;
537 STbuffer->writing = 0;
539 return;
544 /* Onstream specific Routines */
546 * Initialize the OnStream AUX
548 static void osst_init_aux(struct osst_tape * STp, int frame_type, int frame_seq_number,
549 int logical_blk_num, int blk_sz, int blk_cnt)
551 os_aux_t *aux = STp->buffer->aux;
552 os_partition_t *par = &aux->partition;
553 os_dat_t *dat = &aux->dat;
555 if (STp->raw) return;
557 memset(aux, 0, sizeof(*aux));
558 aux->format_id = htonl(0);
559 memcpy(aux->application_sig, "LIN4", 4);
560 aux->hdwr = htonl(0);
561 aux->frame_type = frame_type;
563 switch (frame_type) {
564 case OS_FRAME_TYPE_HEADER:
565 aux->update_frame_cntr = htonl(STp->update_frame_cntr);
566 par->partition_num = OS_CONFIG_PARTITION;
567 par->par_desc_ver = OS_PARTITION_VERSION;
568 par->wrt_pass_cntr = htons(0xffff);
569 /* 0-4 = reserved, 5-9 = header, 2990-2994 = header, 2995-2999 = reserved */
570 par->first_frame_ppos = htonl(0);
571 par->last_frame_ppos = htonl(0xbb7);
572 aux->frame_seq_num = htonl(0);
573 aux->logical_blk_num_high = htonl(0);
574 aux->logical_blk_num = htonl(0);
575 aux->next_mark_ppos = htonl(STp->first_mark_ppos);
576 break;
577 case OS_FRAME_TYPE_DATA:
578 case OS_FRAME_TYPE_MARKER:
579 dat->dat_sz = 8;
580 dat->reserved1 = 0;
581 dat->entry_cnt = 1;
582 dat->reserved3 = 0;
583 dat->dat_list[0].blk_sz = htonl(blk_sz);
584 dat->dat_list[0].blk_cnt = htons(blk_cnt);
585 dat->dat_list[0].flags = frame_type==OS_FRAME_TYPE_MARKER?
586 OS_DAT_FLAGS_MARK:OS_DAT_FLAGS_DATA;
587 dat->dat_list[0].reserved = 0;
588 case OS_FRAME_TYPE_EOD:
589 aux->update_frame_cntr = htonl(0);
590 par->partition_num = OS_DATA_PARTITION;
591 par->par_desc_ver = OS_PARTITION_VERSION;
592 par->wrt_pass_cntr = htons(STp->wrt_pass_cntr);
593 par->first_frame_ppos = htonl(STp->first_data_ppos);
594 par->last_frame_ppos = htonl(STp->capacity);
595 aux->frame_seq_num = htonl(frame_seq_number);
596 aux->logical_blk_num_high = htonl(0);
597 aux->logical_blk_num = htonl(logical_blk_num);
598 break;
599 default: ; /* probably FILL */
601 aux->filemark_cnt = htonl(STp->filemark_cnt);
602 aux->phys_fm = htonl(0xffffffff);
603 aux->last_mark_ppos = htonl(STp->last_mark_ppos);
604 aux->last_mark_lbn = htonl(STp->last_mark_lbn);
608 * Verify that we have the correct tape frame
610 static int osst_verify_frame(struct osst_tape * STp, int frame_seq_number, int quiet)
612 char * name = tape_name(STp);
613 os_aux_t * aux = STp->buffer->aux;
614 os_partition_t * par = &(aux->partition);
615 struct st_partstat * STps = &(STp->ps[STp->partition]);
616 int blk_cnt, blk_sz, i;
618 if (STp->raw) {
619 if (STp->buffer->syscall_result) {
620 for (i=0; i < STp->buffer->sg_segs; i++)
621 memset(page_address(sg_page(&STp->buffer->sg[i])),
622 0, STp->buffer->sg[i].length);
623 strcpy(STp->buffer->b_data, "READ ERROR ON FRAME");
624 } else
625 STp->buffer->buffer_bytes = OS_FRAME_SIZE;
626 return 1;
628 if (STp->buffer->syscall_result) {
629 #if DEBUG
630 printk(OSST_DEB_MSG "%s:D: Skipping frame, read error\n", name);
631 #endif
632 return 0;
634 if (ntohl(aux->format_id) != 0) {
635 #if DEBUG
636 printk(OSST_DEB_MSG "%s:D: Skipping frame, format_id %u\n", name, ntohl(aux->format_id));
637 #endif
638 goto err_out;
640 if (memcmp(aux->application_sig, STp->application_sig, 4) != 0 &&
641 (memcmp(aux->application_sig, "LIN3", 4) != 0 || STp->linux_media_version != 4)) {
642 #if DEBUG
643 printk(OSST_DEB_MSG "%s:D: Skipping frame, incorrect application signature\n", name);
644 #endif
645 goto err_out;
647 if (par->partition_num != OS_DATA_PARTITION) {
648 if (!STp->linux_media || STp->linux_media_version != 2) {
649 #if DEBUG
650 printk(OSST_DEB_MSG "%s:D: Skipping frame, partition num %d\n",
651 name, par->partition_num);
652 #endif
653 goto err_out;
656 if (par->par_desc_ver != OS_PARTITION_VERSION) {
657 #if DEBUG
658 printk(OSST_DEB_MSG "%s:D: Skipping frame, partition version %d\n", name, par->par_desc_ver);
659 #endif
660 goto err_out;
662 if (ntohs(par->wrt_pass_cntr) != STp->wrt_pass_cntr) {
663 #if DEBUG
664 printk(OSST_DEB_MSG "%s:D: Skipping frame, wrt_pass_cntr %d (expected %d)\n",
665 name, ntohs(par->wrt_pass_cntr), STp->wrt_pass_cntr);
666 #endif
667 goto err_out;
669 if (aux->frame_type != OS_FRAME_TYPE_DATA &&
670 aux->frame_type != OS_FRAME_TYPE_EOD &&
671 aux->frame_type != OS_FRAME_TYPE_MARKER) {
672 if (!quiet) {
673 #if DEBUG
674 printk(OSST_DEB_MSG "%s:D: Skipping frame, frame type %x\n", name, aux->frame_type);
675 #endif
677 goto err_out;
679 if (aux->frame_type == OS_FRAME_TYPE_EOD &&
680 STp->first_frame_position < STp->eod_frame_ppos) {
681 printk(KERN_INFO "%s:I: Skipping premature EOD frame %d\n", name,
682 STp->first_frame_position);
683 goto err_out;
685 if (frame_seq_number != -1 && ntohl(aux->frame_seq_num) != frame_seq_number) {
686 if (!quiet) {
687 #if DEBUG
688 printk(OSST_DEB_MSG "%s:D: Skipping frame, sequence number %u (expected %d)\n",
689 name, ntohl(aux->frame_seq_num), frame_seq_number);
690 #endif
692 goto err_out;
694 if (aux->frame_type == OS_FRAME_TYPE_MARKER) {
695 STps->eof = ST_FM_HIT;
697 i = ntohl(aux->filemark_cnt);
698 if (STp->header_cache != NULL && i < OS_FM_TAB_MAX && (i > STp->filemark_cnt ||
699 STp->first_frame_position - 1 != ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[i]))) {
700 #if DEBUG
701 printk(OSST_DEB_MSG "%s:D: %s filemark %d at frame pos %d\n", name,
702 STp->header_cache->dat_fm_tab.fm_tab_ent[i] == 0?"Learned":"Corrected",
703 i, STp->first_frame_position - 1);
704 #endif
705 STp->header_cache->dat_fm_tab.fm_tab_ent[i] = htonl(STp->first_frame_position - 1);
706 if (i >= STp->filemark_cnt)
707 STp->filemark_cnt = i+1;
710 if (aux->frame_type == OS_FRAME_TYPE_EOD) {
711 STps->eof = ST_EOD_1;
712 STp->frame_in_buffer = 1;
714 if (aux->frame_type == OS_FRAME_TYPE_DATA) {
715 blk_cnt = ntohs(aux->dat.dat_list[0].blk_cnt);
716 blk_sz = ntohl(aux->dat.dat_list[0].blk_sz);
717 STp->buffer->buffer_bytes = blk_cnt * blk_sz;
718 STp->buffer->read_pointer = 0;
719 STp->frame_in_buffer = 1;
721 /* See what block size was used to write file */
722 if (STp->block_size != blk_sz && blk_sz > 0) {
723 printk(KERN_INFO
724 "%s:I: File was written with block size %d%c, currently %d%c, adjusted to match.\n",
725 name, blk_sz<1024?blk_sz:blk_sz/1024,blk_sz<1024?'b':'k',
726 STp->block_size<1024?STp->block_size:STp->block_size/1024,
727 STp->block_size<1024?'b':'k');
728 STp->block_size = blk_sz;
729 STp->buffer->buffer_blocks = OS_DATA_SIZE / blk_sz;
731 STps->eof = ST_NOEOF;
733 STp->frame_seq_number = ntohl(aux->frame_seq_num);
734 STp->logical_blk_num = ntohl(aux->logical_blk_num);
735 return 1;
737 err_out:
738 if (STp->read_error_frame == 0)
739 STp->read_error_frame = STp->first_frame_position - 1;
740 return 0;
744 * Wait for the unit to become Ready
746 static int osst_wait_ready(struct osst_tape * STp, struct osst_request ** aSRpnt,
747 unsigned timeout, int initial_delay)
749 unsigned char cmd[MAX_COMMAND_SIZE];
750 struct osst_request * SRpnt;
751 unsigned long startwait = jiffies;
752 #if DEBUG
753 int dbg = debugging;
754 char * name = tape_name(STp);
756 printk(OSST_DEB_MSG "%s:D: Reached onstream wait ready\n", name);
757 #endif
759 if (initial_delay > 0)
760 msleep(jiffies_to_msecs(initial_delay));
762 memset(cmd, 0, MAX_COMMAND_SIZE);
763 cmd[0] = TEST_UNIT_READY;
765 SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1);
766 *aSRpnt = SRpnt;
767 if (!SRpnt) return (-EBUSY);
769 while ( STp->buffer->syscall_result && time_before(jiffies, startwait + timeout*HZ) &&
770 (( SRpnt->sense[2] == 2 && SRpnt->sense[12] == 4 &&
771 (SRpnt->sense[13] == 1 || SRpnt->sense[13] == 8) ) ||
772 ( SRpnt->sense[2] == 6 && SRpnt->sense[12] == 0x28 &&
773 SRpnt->sense[13] == 0 ) )) {
774 #if DEBUG
775 if (debugging) {
776 printk(OSST_DEB_MSG "%s:D: Sleeping in onstream wait ready\n", name);
777 printk(OSST_DEB_MSG "%s:D: Turning off debugging for a while\n", name);
778 debugging = 0;
780 #endif
781 msleep(100);
783 memset(cmd, 0, MAX_COMMAND_SIZE);
784 cmd[0] = TEST_UNIT_READY;
786 SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1);
788 *aSRpnt = SRpnt;
789 #if DEBUG
790 debugging = dbg;
791 #endif
792 if ( STp->buffer->syscall_result &&
793 osst_write_error_recovery(STp, aSRpnt, 0) ) {
794 #if DEBUG
795 printk(OSST_DEB_MSG "%s:D: Abnormal exit from onstream wait ready\n", name);
796 printk(OSST_DEB_MSG "%s:D: Result = %d, Sense: 0=%02x, 2=%02x, 12=%02x, 13=%02x\n", name,
797 STp->buffer->syscall_result, SRpnt->sense[0], SRpnt->sense[2],
798 SRpnt->sense[12], SRpnt->sense[13]);
799 #endif
800 return (-EIO);
802 #if DEBUG
803 printk(OSST_DEB_MSG "%s:D: Normal exit from onstream wait ready\n", name);
804 #endif
805 return 0;
809 * Wait for a tape to be inserted in the unit
811 static int osst_wait_for_medium(struct osst_tape * STp, struct osst_request ** aSRpnt, unsigned timeout)
813 unsigned char cmd[MAX_COMMAND_SIZE];
814 struct osst_request * SRpnt;
815 unsigned long startwait = jiffies;
816 #if DEBUG
817 int dbg = debugging;
818 char * name = tape_name(STp);
820 printk(OSST_DEB_MSG "%s:D: Reached onstream wait for medium\n", name);
821 #endif
823 memset(cmd, 0, MAX_COMMAND_SIZE);
824 cmd[0] = TEST_UNIT_READY;
826 SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1);
827 *aSRpnt = SRpnt;
828 if (!SRpnt) return (-EBUSY);
830 while ( STp->buffer->syscall_result && time_before(jiffies, startwait + timeout*HZ) &&
831 SRpnt->sense[2] == 2 && SRpnt->sense[12] == 0x3a && SRpnt->sense[13] == 0 ) {
832 #if DEBUG
833 if (debugging) {
834 printk(OSST_DEB_MSG "%s:D: Sleeping in onstream wait medium\n", name);
835 printk(OSST_DEB_MSG "%s:D: Turning off debugging for a while\n", name);
836 debugging = 0;
838 #endif
839 msleep(100);
841 memset(cmd, 0, MAX_COMMAND_SIZE);
842 cmd[0] = TEST_UNIT_READY;
844 SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1);
846 *aSRpnt = SRpnt;
847 #if DEBUG
848 debugging = dbg;
849 #endif
850 if ( STp->buffer->syscall_result && SRpnt->sense[2] != 2 &&
851 SRpnt->sense[12] != 4 && SRpnt->sense[13] == 1) {
852 #if DEBUG
853 printk(OSST_DEB_MSG "%s:D: Abnormal exit from onstream wait medium\n", name);
854 printk(OSST_DEB_MSG "%s:D: Result = %d, Sense: 0=%02x, 2=%02x, 12=%02x, 13=%02x\n", name,
855 STp->buffer->syscall_result, SRpnt->sense[0], SRpnt->sense[2],
856 SRpnt->sense[12], SRpnt->sense[13]);
857 #endif
858 return 0;
860 #if DEBUG
861 printk(OSST_DEB_MSG "%s:D: Normal exit from onstream wait medium\n", name);
862 #endif
863 return 1;
866 static int osst_position_tape_and_confirm(struct osst_tape * STp, struct osst_request ** aSRpnt, int frame)
868 int retval;
870 osst_wait_ready(STp, aSRpnt, 15 * 60, 0); /* TODO - can this catch a write error? */
871 retval = osst_set_frame_position(STp, aSRpnt, frame, 0);
872 if (retval) return (retval);
873 osst_wait_ready(STp, aSRpnt, 15 * 60, OSST_WAIT_POSITION_COMPLETE);
874 return (osst_get_frame_position(STp, aSRpnt));
878 * Wait for write(s) to complete
880 static int osst_flush_drive_buffer(struct osst_tape * STp, struct osst_request ** aSRpnt)
882 unsigned char cmd[MAX_COMMAND_SIZE];
883 struct osst_request * SRpnt;
884 int result = 0;
885 int delay = OSST_WAIT_WRITE_COMPLETE;
886 #if DEBUG
887 char * name = tape_name(STp);
889 printk(OSST_DEB_MSG "%s:D: Reached onstream flush drive buffer (write filemark)\n", name);
890 #endif
892 memset(cmd, 0, MAX_COMMAND_SIZE);
893 cmd[0] = WRITE_FILEMARKS;
894 cmd[1] = 1;
896 SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1);
897 *aSRpnt = SRpnt;
898 if (!SRpnt) return (-EBUSY);
899 if (STp->buffer->syscall_result) {
900 if ((SRpnt->sense[2] & 0x0f) == 2 && SRpnt->sense[12] == 4) {
901 if (SRpnt->sense[13] == 8) {
902 delay = OSST_WAIT_LONG_WRITE_COMPLETE;
904 } else
905 result = osst_write_error_recovery(STp, aSRpnt, 0);
907 result |= osst_wait_ready(STp, aSRpnt, 5 * 60, delay);
908 STp->ps[STp->partition].rw = OS_WRITING_COMPLETE;
910 return (result);
913 #define OSST_POLL_PER_SEC 10
914 static int osst_wait_frame(struct osst_tape * STp, struct osst_request ** aSRpnt, int curr, int minlast, int to)
916 unsigned long startwait = jiffies;
917 char * name = tape_name(STp);
918 #if DEBUG
919 char notyetprinted = 1;
920 #endif
921 if (minlast >= 0 && STp->ps[STp->partition].rw != ST_READING)
922 printk(KERN_ERR "%s:A: Waiting for frame without having initialized read!\n", name);
924 while (time_before (jiffies, startwait + to*HZ))
926 int result;
927 result = osst_get_frame_position(STp, aSRpnt);
928 if (result == -EIO)
929 if ((result = osst_write_error_recovery(STp, aSRpnt, 0)) == 0)
930 return 0; /* successful recovery leaves drive ready for frame */
931 if (result < 0) break;
932 if (STp->first_frame_position == curr &&
933 ((minlast < 0 &&
934 (signed)STp->last_frame_position > (signed)curr + minlast) ||
935 (minlast >= 0 && STp->cur_frames > minlast)
936 ) && result >= 0)
938 #if DEBUG
939 if (debugging || time_after_eq(jiffies, startwait + 2*HZ/OSST_POLL_PER_SEC))
940 printk (OSST_DEB_MSG
941 "%s:D: Succ wait f fr %i (>%i): %i-%i %i (%i): %3li.%li s\n",
942 name, curr, curr+minlast, STp->first_frame_position,
943 STp->last_frame_position, STp->cur_frames,
944 result, (jiffies-startwait)/HZ,
945 (((jiffies-startwait)%HZ)*10)/HZ);
946 #endif
947 return 0;
949 #if DEBUG
950 if (time_after_eq(jiffies, startwait + 2*HZ/OSST_POLL_PER_SEC) && notyetprinted)
952 printk (OSST_DEB_MSG "%s:D: Wait for frame %i (>%i): %i-%i %i (%i)\n",
953 name, curr, curr+minlast, STp->first_frame_position,
954 STp->last_frame_position, STp->cur_frames, result);
955 notyetprinted--;
957 #endif
958 msleep(1000 / OSST_POLL_PER_SEC);
960 #if DEBUG
961 printk (OSST_DEB_MSG "%s:D: Fail wait f fr %i (>%i): %i-%i %i: %3li.%li s\n",
962 name, curr, curr+minlast, STp->first_frame_position,
963 STp->last_frame_position, STp->cur_frames,
964 (jiffies-startwait)/HZ, (((jiffies-startwait)%HZ)*10)/HZ);
965 #endif
966 return -EBUSY;
969 static int osst_recover_wait_frame(struct osst_tape * STp, struct osst_request ** aSRpnt, int writing)
971 struct osst_request * SRpnt;
972 unsigned char cmd[MAX_COMMAND_SIZE];
973 unsigned long startwait = jiffies;
974 int retval = 1;
975 char * name = tape_name(STp);
977 if (writing) {
978 char mybuf[24];
979 char * olddata = STp->buffer->b_data;
980 int oldsize = STp->buffer->buffer_size;
982 /* write zero fm then read pos - if shows write error, try to recover - if no progress, wait */
984 memset(cmd, 0, MAX_COMMAND_SIZE);
985 cmd[0] = WRITE_FILEMARKS;
986 cmd[1] = 1;
987 SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, DMA_NONE, STp->timeout,
988 MAX_RETRIES, 1);
990 while (retval && time_before (jiffies, startwait + 5*60*HZ)) {
992 if (STp->buffer->syscall_result && (SRpnt->sense[2] & 0x0f) != 2) {
994 /* some failure - not just not-ready */
995 retval = osst_write_error_recovery(STp, aSRpnt, 0);
996 break;
998 schedule_timeout_interruptible(HZ / OSST_POLL_PER_SEC);
1000 STp->buffer->b_data = mybuf; STp->buffer->buffer_size = 24;
1001 memset(cmd, 0, MAX_COMMAND_SIZE);
1002 cmd[0] = READ_POSITION;
1004 SRpnt = osst_do_scsi(SRpnt, STp, cmd, 20, DMA_FROM_DEVICE, STp->timeout,
1005 MAX_RETRIES, 1);
1007 retval = ( STp->buffer->syscall_result || (STp->buffer)->b_data[15] > 25 );
1008 STp->buffer->b_data = olddata; STp->buffer->buffer_size = oldsize;
1010 if (retval)
1011 printk(KERN_ERR "%s:E: Device did not succeed to write buffered data\n", name);
1012 } else
1013 /* TODO - figure out which error conditions can be handled */
1014 if (STp->buffer->syscall_result)
1015 printk(KERN_WARNING
1016 "%s:W: Recover_wait_frame(read) cannot handle %02x:%02x:%02x\n", name,
1017 (*aSRpnt)->sense[ 2] & 0x0f,
1018 (*aSRpnt)->sense[12],
1019 (*aSRpnt)->sense[13]);
1021 return retval;
1025 * Read the next OnStream tape frame at the current location
1027 static int osst_read_frame(struct osst_tape * STp, struct osst_request ** aSRpnt, int timeout)
1029 unsigned char cmd[MAX_COMMAND_SIZE];
1030 struct osst_request * SRpnt;
1031 int retval = 0;
1032 #if DEBUG
1033 os_aux_t * aux = STp->buffer->aux;
1034 char * name = tape_name(STp);
1035 #endif
1037 if (STp->poll)
1038 if (osst_wait_frame (STp, aSRpnt, STp->first_frame_position, 0, timeout))
1039 retval = osst_recover_wait_frame(STp, aSRpnt, 0);
1041 memset(cmd, 0, MAX_COMMAND_SIZE);
1042 cmd[0] = READ_6;
1043 cmd[1] = 1;
1044 cmd[4] = 1;
1046 #if DEBUG
1047 if (debugging)
1048 printk(OSST_DEB_MSG "%s:D: Reading frame from OnStream tape\n", name);
1049 #endif
1050 SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, OS_FRAME_SIZE, DMA_FROM_DEVICE,
1051 STp->timeout, MAX_RETRIES, 1);
1052 *aSRpnt = SRpnt;
1053 if (!SRpnt)
1054 return (-EBUSY);
1056 if ((STp->buffer)->syscall_result) {
1057 retval = 1;
1058 if (STp->read_error_frame == 0) {
1059 STp->read_error_frame = STp->first_frame_position;
1060 #if DEBUG
1061 printk(OSST_DEB_MSG "%s:D: Recording read error at %d\n", name, STp->read_error_frame);
1062 #endif
1064 #if DEBUG
1065 if (debugging)
1066 printk(OSST_DEB_MSG "%s:D: Sense: %2x %2x %2x %2x %2x %2x %2x %2x\n",
1067 name,
1068 SRpnt->sense[0], SRpnt->sense[1],
1069 SRpnt->sense[2], SRpnt->sense[3],
1070 SRpnt->sense[4], SRpnt->sense[5],
1071 SRpnt->sense[6], SRpnt->sense[7]);
1072 #endif
1074 else
1075 STp->first_frame_position++;
1076 #if DEBUG
1077 if (debugging) {
1078 char sig[8]; int i;
1079 for (i=0;i<4;i++)
1080 sig[i] = aux->application_sig[i]<32?'^':aux->application_sig[i];
1081 sig[4] = '\0';
1082 printk(OSST_DEB_MSG
1083 "%s:D: AUX: %s UpdFrCt#%d Wpass#%d %s FrSeq#%d LogBlk#%d Qty=%d Sz=%d\n", name, sig,
1084 ntohl(aux->update_frame_cntr), ntohs(aux->partition.wrt_pass_cntr),
1085 aux->frame_type==1?"EOD":aux->frame_type==2?"MARK":
1086 aux->frame_type==8?"HEADR":aux->frame_type==0x80?"DATA":"FILL",
1087 ntohl(aux->frame_seq_num), ntohl(aux->logical_blk_num),
1088 ntohs(aux->dat.dat_list[0].blk_cnt), ntohl(aux->dat.dat_list[0].blk_sz) );
1089 if (aux->frame_type==2)
1090 printk(OSST_DEB_MSG "%s:D: mark_cnt=%d, last_mark_ppos=%d, last_mark_lbn=%d\n", name,
1091 ntohl(aux->filemark_cnt), ntohl(aux->last_mark_ppos), ntohl(aux->last_mark_lbn));
1092 printk(OSST_DEB_MSG "%s:D: Exit read frame from OnStream tape with code %d\n", name, retval);
1094 #endif
1095 return (retval);
1098 static int osst_initiate_read(struct osst_tape * STp, struct osst_request ** aSRpnt)
1100 struct st_partstat * STps = &(STp->ps[STp->partition]);
1101 struct osst_request * SRpnt ;
1102 unsigned char cmd[MAX_COMMAND_SIZE];
1103 int retval = 0;
1104 char * name = tape_name(STp);
1106 if (STps->rw != ST_READING) { /* Initialize read operation */
1107 if (STps->rw == ST_WRITING || STp->dirty) {
1108 STp->write_type = OS_WRITE_DATA;
1109 osst_flush_write_buffer(STp, aSRpnt);
1110 osst_flush_drive_buffer(STp, aSRpnt);
1112 STps->rw = ST_READING;
1113 STp->frame_in_buffer = 0;
1116 * Issue a read 0 command to get the OnStream drive
1117 * read frames into its buffer.
1119 memset(cmd, 0, MAX_COMMAND_SIZE);
1120 cmd[0] = READ_6;
1121 cmd[1] = 1;
1123 #if DEBUG
1124 printk(OSST_DEB_MSG "%s:D: Start Read Ahead on OnStream tape\n", name);
1125 #endif
1126 SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1);
1127 *aSRpnt = SRpnt;
1128 if ((retval = STp->buffer->syscall_result))
1129 printk(KERN_WARNING "%s:W: Error starting read ahead\n", name);
1132 return retval;
1135 static int osst_get_logical_frame(struct osst_tape * STp, struct osst_request ** aSRpnt,
1136 int frame_seq_number, int quiet)
1138 struct st_partstat * STps = &(STp->ps[STp->partition]);
1139 char * name = tape_name(STp);
1140 int cnt = 0,
1141 bad = 0,
1142 past = 0,
1144 position;
1147 * If we want just any frame (-1) and there is a frame in the buffer, return it
1149 if (frame_seq_number == -1 && STp->frame_in_buffer) {
1150 #if DEBUG
1151 printk(OSST_DEB_MSG "%s:D: Frame %d still in buffer\n", name, STp->frame_seq_number);
1152 #endif
1153 return (STps->eof);
1156 * Search and wait for the next logical tape frame
1158 while (1) {
1159 if (cnt++ > 400) {
1160 printk(KERN_ERR "%s:E: Couldn't find logical frame %d, aborting\n",
1161 name, frame_seq_number);
1162 if (STp->read_error_frame) {
1163 osst_set_frame_position(STp, aSRpnt, STp->read_error_frame, 0);
1164 #if DEBUG
1165 printk(OSST_DEB_MSG "%s:D: Repositioning tape to bad frame %d\n",
1166 name, STp->read_error_frame);
1167 #endif
1168 STp->read_error_frame = 0;
1169 STp->abort_count++;
1171 return (-EIO);
1173 #if DEBUG
1174 if (debugging)
1175 printk(OSST_DEB_MSG "%s:D: Looking for frame %d, attempt %d\n",
1176 name, frame_seq_number, cnt);
1177 #endif
1178 if ( osst_initiate_read(STp, aSRpnt)
1179 || ( (!STp->frame_in_buffer) && osst_read_frame(STp, aSRpnt, 30) ) ) {
1180 if (STp->raw)
1181 return (-EIO);
1182 position = osst_get_frame_position(STp, aSRpnt);
1183 if (position >= 0xbae && position < 0xbb8)
1184 position = 0xbb8;
1185 else if (position > STp->eod_frame_ppos || ++bad == 10) {
1186 position = STp->read_error_frame - 1;
1187 bad = 0;
1189 else {
1190 position += 29;
1191 cnt += 19;
1193 #if DEBUG
1194 printk(OSST_DEB_MSG "%s:D: Bad frame detected, positioning tape to block %d\n",
1195 name, position);
1196 #endif
1197 osst_set_frame_position(STp, aSRpnt, position, 0);
1198 continue;
1200 if (osst_verify_frame(STp, frame_seq_number, quiet))
1201 break;
1202 if (osst_verify_frame(STp, -1, quiet)) {
1203 x = ntohl(STp->buffer->aux->frame_seq_num);
1204 if (STp->fast_open) {
1205 printk(KERN_WARNING
1206 "%s:W: Found logical frame %d instead of %d after fast open\n",
1207 name, x, frame_seq_number);
1208 STp->header_ok = 0;
1209 STp->read_error_frame = 0;
1210 return (-EIO);
1212 if (x > frame_seq_number) {
1213 if (++past > 3) {
1214 /* positioning backwards did not bring us to the desired frame */
1215 position = STp->read_error_frame - 1;
1217 else {
1218 position = osst_get_frame_position(STp, aSRpnt)
1219 + frame_seq_number - x - 1;
1221 if (STp->first_frame_position >= 3000 && position < 3000)
1222 position -= 10;
1224 #if DEBUG
1225 printk(OSST_DEB_MSG
1226 "%s:D: Found logical frame %d while looking for %d: back up %d\n",
1227 name, x, frame_seq_number,
1228 STp->first_frame_position - position);
1229 #endif
1230 osst_set_frame_position(STp, aSRpnt, position, 0);
1231 cnt += 10;
1233 else
1234 past = 0;
1236 if (osst_get_frame_position(STp, aSRpnt) == 0xbaf) {
1237 #if DEBUG
1238 printk(OSST_DEB_MSG "%s:D: Skipping config partition\n", name);
1239 #endif
1240 osst_set_frame_position(STp, aSRpnt, 0xbb8, 0);
1241 cnt--;
1243 STp->frame_in_buffer = 0;
1245 if (cnt > 1) {
1246 STp->recover_count++;
1247 STp->recover_erreg++;
1248 printk(KERN_WARNING "%s:I: Don't worry, Read error at position %d recovered\n",
1249 name, STp->read_error_frame);
1251 STp->read_count++;
1253 #if DEBUG
1254 if (debugging || STps->eof)
1255 printk(OSST_DEB_MSG
1256 "%s:D: Exit get logical frame (%d=>%d) from OnStream tape with code %d\n",
1257 name, frame_seq_number, STp->frame_seq_number, STps->eof);
1258 #endif
1259 STp->fast_open = 0;
1260 STp->read_error_frame = 0;
1261 return (STps->eof);
1264 static int osst_seek_logical_blk(struct osst_tape * STp, struct osst_request ** aSRpnt, int logical_blk_num)
1266 struct st_partstat * STps = &(STp->ps[STp->partition]);
1267 char * name = tape_name(STp);
1268 int retries = 0;
1269 int frame_seq_estimate, ppos_estimate, move;
1271 if (logical_blk_num < 0) logical_blk_num = 0;
1272 #if DEBUG
1273 printk(OSST_DEB_MSG "%s:D: Seeking logical block %d (now at %d, size %d%c)\n",
1274 name, logical_blk_num, STp->logical_blk_num,
1275 STp->block_size<1024?STp->block_size:STp->block_size/1024,
1276 STp->block_size<1024?'b':'k');
1277 #endif
1278 /* Do we know where we are? */
1279 if (STps->drv_block >= 0) {
1280 move = logical_blk_num - STp->logical_blk_num;
1281 if (move < 0) move -= (OS_DATA_SIZE / STp->block_size) - 1;
1282 move /= (OS_DATA_SIZE / STp->block_size);
1283 frame_seq_estimate = STp->frame_seq_number + move;
1284 } else
1285 frame_seq_estimate = logical_blk_num * STp->block_size / OS_DATA_SIZE;
1287 if (frame_seq_estimate < 2980) ppos_estimate = frame_seq_estimate + 10;
1288 else ppos_estimate = frame_seq_estimate + 20;
1289 while (++retries < 10) {
1290 if (ppos_estimate > STp->eod_frame_ppos-2) {
1291 frame_seq_estimate += STp->eod_frame_ppos - 2 - ppos_estimate;
1292 ppos_estimate = STp->eod_frame_ppos - 2;
1294 if (frame_seq_estimate < 0) {
1295 frame_seq_estimate = 0;
1296 ppos_estimate = 10;
1298 osst_set_frame_position(STp, aSRpnt, ppos_estimate, 0);
1299 if (osst_get_logical_frame(STp, aSRpnt, frame_seq_estimate, 1) >= 0) {
1300 /* we've located the estimated frame, now does it have our block? */
1301 if (logical_blk_num < STp->logical_blk_num ||
1302 logical_blk_num >= STp->logical_blk_num + ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt)) {
1303 if (STps->eof == ST_FM_HIT)
1304 move = logical_blk_num < STp->logical_blk_num? -2 : 1;
1305 else {
1306 move = logical_blk_num - STp->logical_blk_num;
1307 if (move < 0) move -= (OS_DATA_SIZE / STp->block_size) - 1;
1308 move /= (OS_DATA_SIZE / STp->block_size);
1310 if (!move) move = logical_blk_num > STp->logical_blk_num ? 1 : -1;
1311 #if DEBUG
1312 printk(OSST_DEB_MSG
1313 "%s:D: Seek retry %d at ppos %d fsq %d (est %d) lbn %d (need %d) move %d\n",
1314 name, retries, ppos_estimate, STp->frame_seq_number, frame_seq_estimate,
1315 STp->logical_blk_num, logical_blk_num, move);
1316 #endif
1317 frame_seq_estimate += move;
1318 ppos_estimate += move;
1319 continue;
1320 } else {
1321 STp->buffer->read_pointer = (logical_blk_num - STp->logical_blk_num) * STp->block_size;
1322 STp->buffer->buffer_bytes -= STp->buffer->read_pointer;
1323 STp->logical_blk_num = logical_blk_num;
1324 #if DEBUG
1325 printk(OSST_DEB_MSG
1326 "%s:D: Seek success at ppos %d fsq %d in_buf %d, bytes %d, ptr %d*%d\n",
1327 name, ppos_estimate, STp->frame_seq_number, STp->frame_in_buffer,
1328 STp->buffer->buffer_bytes, STp->buffer->read_pointer / STp->block_size,
1329 STp->block_size);
1330 #endif
1331 STps->drv_file = ntohl(STp->buffer->aux->filemark_cnt);
1332 if (STps->eof == ST_FM_HIT) {
1333 STps->drv_file++;
1334 STps->drv_block = 0;
1335 } else {
1336 STps->drv_block = ntohl(STp->buffer->aux->last_mark_lbn)?
1337 STp->logical_blk_num -
1338 (STps->drv_file ? ntohl(STp->buffer->aux->last_mark_lbn) + 1 : 0):
1341 STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD:ST_NOEOF;
1342 return 0;
1345 if (osst_get_logical_frame(STp, aSRpnt, -1, 1) < 0)
1346 goto error;
1347 /* we are not yet at the estimated frame, adjust our estimate of its physical position */
1348 #if DEBUG
1349 printk(OSST_DEB_MSG "%s:D: Seek retry %d at ppos %d fsq %d (est %d) lbn %d (need %d)\n",
1350 name, retries, ppos_estimate, STp->frame_seq_number, frame_seq_estimate,
1351 STp->logical_blk_num, logical_blk_num);
1352 #endif
1353 if (frame_seq_estimate != STp->frame_seq_number)
1354 ppos_estimate += frame_seq_estimate - STp->frame_seq_number;
1355 else
1356 break;
1358 error:
1359 printk(KERN_ERR "%s:E: Couldn't seek to logical block %d (at %d), %d retries\n",
1360 name, logical_blk_num, STp->logical_blk_num, retries);
1361 return (-EIO);
1364 /* The values below are based on the OnStream frame payload size of 32K == 2**15,
1365 * that is, OSST_FRAME_SHIFT + OSST_SECTOR_SHIFT must be 15. With a minimum block
1366 * size of 512 bytes, we need to be able to resolve 32K/512 == 64 == 2**6 positions
1367 * inside each frame. Finaly, OSST_SECTOR_MASK == 2**OSST_FRAME_SHIFT - 1.
1369 #define OSST_FRAME_SHIFT 6
1370 #define OSST_SECTOR_SHIFT 9
1371 #define OSST_SECTOR_MASK 0x03F
1373 static int osst_get_sector(struct osst_tape * STp, struct osst_request ** aSRpnt)
1375 int sector;
1376 #if DEBUG
1377 char * name = tape_name(STp);
1379 printk(OSST_DEB_MSG
1380 "%s:D: Positioned at ppos %d, frame %d, lbn %d, file %d, blk %d, %cptr %d, eof %d\n",
1381 name, STp->first_frame_position, STp->frame_seq_number, STp->logical_blk_num,
1382 STp->ps[STp->partition].drv_file, STp->ps[STp->partition].drv_block,
1383 STp->ps[STp->partition].rw == ST_WRITING?'w':'r',
1384 STp->ps[STp->partition].rw == ST_WRITING?STp->buffer->buffer_bytes:
1385 STp->buffer->read_pointer, STp->ps[STp->partition].eof);
1386 #endif
1387 /* do we know where we are inside a file? */
1388 if (STp->ps[STp->partition].drv_block >= 0) {
1389 sector = (STp->frame_in_buffer ? STp->first_frame_position-1 :
1390 STp->first_frame_position) << OSST_FRAME_SHIFT;
1391 if (STp->ps[STp->partition].rw == ST_WRITING)
1392 sector |= (STp->buffer->buffer_bytes >> OSST_SECTOR_SHIFT) & OSST_SECTOR_MASK;
1393 else
1394 sector |= (STp->buffer->read_pointer >> OSST_SECTOR_SHIFT) & OSST_SECTOR_MASK;
1395 } else {
1396 sector = osst_get_frame_position(STp, aSRpnt);
1397 if (sector > 0)
1398 sector <<= OSST_FRAME_SHIFT;
1400 return sector;
1403 static int osst_seek_sector(struct osst_tape * STp, struct osst_request ** aSRpnt, int sector)
1405 struct st_partstat * STps = &(STp->ps[STp->partition]);
1406 int frame = sector >> OSST_FRAME_SHIFT,
1407 offset = (sector & OSST_SECTOR_MASK) << OSST_SECTOR_SHIFT,
1409 #if DEBUG
1410 char * name = tape_name(STp);
1412 printk(OSST_DEB_MSG "%s:D: Seeking sector %d in frame %d at offset %d\n",
1413 name, sector, frame, offset);
1414 #endif
1415 if (frame < 0 || frame >= STp->capacity) return (-ENXIO);
1417 if (frame <= STp->first_data_ppos) {
1418 STp->frame_seq_number = STp->logical_blk_num = STps->drv_file = STps->drv_block = 0;
1419 return (osst_set_frame_position(STp, aSRpnt, frame, 0));
1421 r = osst_set_frame_position(STp, aSRpnt, offset?frame:frame-1, 0);
1422 if (r < 0) return r;
1424 r = osst_get_logical_frame(STp, aSRpnt, -1, 1);
1425 if (r < 0) return r;
1427 if (osst_get_frame_position(STp, aSRpnt) != (offset?frame+1:frame)) return (-EIO);
1429 if (offset) {
1430 STp->logical_blk_num += offset / STp->block_size;
1431 STp->buffer->read_pointer = offset;
1432 STp->buffer->buffer_bytes -= offset;
1433 } else {
1434 STp->frame_seq_number++;
1435 STp->frame_in_buffer = 0;
1436 STp->logical_blk_num += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
1437 STp->buffer->buffer_bytes = STp->buffer->read_pointer = 0;
1439 STps->drv_file = ntohl(STp->buffer->aux->filemark_cnt);
1440 if (STps->eof == ST_FM_HIT) {
1441 STps->drv_file++;
1442 STps->drv_block = 0;
1443 } else {
1444 STps->drv_block = ntohl(STp->buffer->aux->last_mark_lbn)?
1445 STp->logical_blk_num -
1446 (STps->drv_file ? ntohl(STp->buffer->aux->last_mark_lbn) + 1 : 0):
1449 STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD:ST_NOEOF;
1450 #if DEBUG
1451 printk(OSST_DEB_MSG
1452 "%s:D: Now positioned at ppos %d, frame %d, lbn %d, file %d, blk %d, rptr %d, eof %d\n",
1453 name, STp->first_frame_position, STp->frame_seq_number, STp->logical_blk_num,
1454 STps->drv_file, STps->drv_block, STp->buffer->read_pointer, STps->eof);
1455 #endif
1456 return 0;
1460 * Read back the drive's internal buffer contents, as a part
1461 * of the write error recovery mechanism for old OnStream
1462 * firmware revisions.
1463 * Precondition for this function to work: all frames in the
1464 * drive's buffer must be of one type (DATA, MARK or EOD)!
1466 static int osst_read_back_buffer_and_rewrite(struct osst_tape * STp, struct osst_request ** aSRpnt,
1467 unsigned int frame, unsigned int skip, int pending)
1469 struct osst_request * SRpnt = * aSRpnt;
1470 unsigned char * buffer, * p;
1471 unsigned char cmd[MAX_COMMAND_SIZE];
1472 int flag, new_frame, i;
1473 int nframes = STp->cur_frames;
1474 int blks_per_frame = ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
1475 int frame_seq_number = ntohl(STp->buffer->aux->frame_seq_num)
1476 - (nframes + pending - 1);
1477 int logical_blk_num = ntohl(STp->buffer->aux->logical_blk_num)
1478 - (nframes + pending - 1) * blks_per_frame;
1479 char * name = tape_name(STp);
1480 unsigned long startwait = jiffies;
1481 #if DEBUG
1482 int dbg = debugging;
1483 #endif
1485 if ((buffer = (unsigned char *)vmalloc((nframes + 1) * OS_DATA_SIZE)) == NULL)
1486 return (-EIO);
1488 printk(KERN_INFO "%s:I: Reading back %d frames from drive buffer%s\n",
1489 name, nframes, pending?" and one that was pending":"");
1491 osst_copy_from_buffer(STp->buffer, (p = &buffer[nframes * OS_DATA_SIZE]));
1492 #if DEBUG
1493 if (pending && debugging)
1494 printk(OSST_DEB_MSG "%s:D: Pending frame %d (lblk %d), data %02x %02x %02x %02x\n",
1495 name, frame_seq_number + nframes,
1496 logical_blk_num + nframes * blks_per_frame,
1497 p[0], p[1], p[2], p[3]);
1498 #endif
1499 for (i = 0, p = buffer; i < nframes; i++, p += OS_DATA_SIZE) {
1501 memset(cmd, 0, MAX_COMMAND_SIZE);
1502 cmd[0] = 0x3C; /* Buffer Read */
1503 cmd[1] = 6; /* Retrieve Faulty Block */
1504 cmd[7] = 32768 >> 8;
1505 cmd[8] = 32768 & 0xff;
1507 SRpnt = osst_do_scsi(SRpnt, STp, cmd, OS_FRAME_SIZE, DMA_FROM_DEVICE,
1508 STp->timeout, MAX_RETRIES, 1);
1510 if ((STp->buffer)->syscall_result || !SRpnt) {
1511 printk(KERN_ERR "%s:E: Failed to read frame back from OnStream buffer\n", name);
1512 vfree(buffer);
1513 *aSRpnt = SRpnt;
1514 return (-EIO);
1516 osst_copy_from_buffer(STp->buffer, p);
1517 #if DEBUG
1518 if (debugging)
1519 printk(OSST_DEB_MSG "%s:D: Read back logical frame %d, data %02x %02x %02x %02x\n",
1520 name, frame_seq_number + i, p[0], p[1], p[2], p[3]);
1521 #endif
1523 *aSRpnt = SRpnt;
1524 osst_get_frame_position(STp, aSRpnt);
1526 #if DEBUG
1527 printk(OSST_DEB_MSG "%s:D: Frames left in buffer: %d\n", name, STp->cur_frames);
1528 #endif
1529 /* Write synchronously so we can be sure we're OK again and don't have to recover recursively */
1530 /* In the header we don't actually re-write the frames that fail, just the ones after them */
1532 for (flag=1, new_frame=frame, p=buffer, i=0; i < nframes + pending; ) {
1534 if (flag) {
1535 if (STp->write_type == OS_WRITE_HEADER) {
1536 i += skip;
1537 p += skip * OS_DATA_SIZE;
1539 else if (new_frame < 2990 && new_frame+skip+nframes+pending >= 2990)
1540 new_frame = 3000-i;
1541 else
1542 new_frame += skip;
1543 #if DEBUG
1544 printk(OSST_DEB_MSG "%s:D: Position to frame %d, write fseq %d\n",
1545 name, new_frame+i, frame_seq_number+i);
1546 #endif
1547 osst_set_frame_position(STp, aSRpnt, new_frame + i, 0);
1548 osst_wait_ready(STp, aSRpnt, 60, OSST_WAIT_POSITION_COMPLETE);
1549 osst_get_frame_position(STp, aSRpnt);
1550 SRpnt = * aSRpnt;
1552 if (new_frame > frame + 1000) {
1553 printk(KERN_ERR "%s:E: Failed to find writable tape media\n", name);
1554 vfree(buffer);
1555 return (-EIO);
1557 if ( i >= nframes + pending ) break;
1558 flag = 0;
1560 osst_copy_to_buffer(STp->buffer, p);
1562 * IMPORTANT: for error recovery to work, _never_ queue frames with mixed frame type!
1564 osst_init_aux(STp, STp->buffer->aux->frame_type, frame_seq_number+i,
1565 logical_blk_num + i*blks_per_frame,
1566 ntohl(STp->buffer->aux->dat.dat_list[0].blk_sz), blks_per_frame);
1567 memset(cmd, 0, MAX_COMMAND_SIZE);
1568 cmd[0] = WRITE_6;
1569 cmd[1] = 1;
1570 cmd[4] = 1;
1572 #if DEBUG
1573 if (debugging)
1574 printk(OSST_DEB_MSG
1575 "%s:D: About to write frame %d, seq %d, lbn %d, data %02x %02x %02x %02x\n",
1576 name, new_frame+i, frame_seq_number+i, logical_blk_num + i*blks_per_frame,
1577 p[0], p[1], p[2], p[3]);
1578 #endif
1579 SRpnt = osst_do_scsi(SRpnt, STp, cmd, OS_FRAME_SIZE, DMA_TO_DEVICE,
1580 STp->timeout, MAX_RETRIES, 1);
1582 if (STp->buffer->syscall_result)
1583 flag = 1;
1584 else {
1585 p += OS_DATA_SIZE; i++;
1587 /* if we just sent the last frame, wait till all successfully written */
1588 if ( i == nframes + pending ) {
1589 #if DEBUG
1590 printk(OSST_DEB_MSG "%s:D: Check re-write successful\n", name);
1591 #endif
1592 memset(cmd, 0, MAX_COMMAND_SIZE);
1593 cmd[0] = WRITE_FILEMARKS;
1594 cmd[1] = 1;
1595 SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE,
1596 STp->timeout, MAX_RETRIES, 1);
1597 #if DEBUG
1598 if (debugging) {
1599 printk(OSST_DEB_MSG "%s:D: Sleeping in re-write wait ready\n", name);
1600 printk(OSST_DEB_MSG "%s:D: Turning off debugging for a while\n", name);
1601 debugging = 0;
1603 #endif
1604 flag = STp->buffer->syscall_result;
1605 while ( !flag && time_before(jiffies, startwait + 60*HZ) ) {
1607 memset(cmd, 0, MAX_COMMAND_SIZE);
1608 cmd[0] = TEST_UNIT_READY;
1610 SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE, STp->timeout,
1611 MAX_RETRIES, 1);
1613 if (SRpnt->sense[2] == 2 && SRpnt->sense[12] == 4 &&
1614 (SRpnt->sense[13] == 1 || SRpnt->sense[13] == 8)) {
1615 /* in the process of becoming ready */
1616 msleep(100);
1617 continue;
1619 if (STp->buffer->syscall_result)
1620 flag = 1;
1621 break;
1623 #if DEBUG
1624 debugging = dbg;
1625 printk(OSST_DEB_MSG "%s:D: Wait re-write finished\n", name);
1626 #endif
1629 *aSRpnt = SRpnt;
1630 if (flag) {
1631 if ((SRpnt->sense[ 2] & 0x0f) == 13 &&
1632 SRpnt->sense[12] == 0 &&
1633 SRpnt->sense[13] == 2) {
1634 printk(KERN_ERR "%s:E: Volume overflow in write error recovery\n", name);
1635 vfree(buffer);
1636 return (-EIO); /* hit end of tape = fail */
1638 i = ((SRpnt->sense[3] << 24) |
1639 (SRpnt->sense[4] << 16) |
1640 (SRpnt->sense[5] << 8) |
1641 SRpnt->sense[6] ) - new_frame;
1642 p = &buffer[i * OS_DATA_SIZE];
1643 #if DEBUG
1644 printk(OSST_DEB_MSG "%s:D: Additional write error at %d\n", name, new_frame+i);
1645 #endif
1646 osst_get_frame_position(STp, aSRpnt);
1647 #if DEBUG
1648 printk(OSST_DEB_MSG "%s:D: reported frame positions: host = %d, tape = %d, buffer = %d\n",
1649 name, STp->first_frame_position, STp->last_frame_position, STp->cur_frames);
1650 #endif
1653 if (flag) {
1654 /* error recovery did not successfully complete */
1655 printk(KERN_ERR "%s:D: Write error recovery failed in %s\n", name,
1656 STp->write_type == OS_WRITE_HEADER?"header":"body");
1658 if (!pending)
1659 osst_copy_to_buffer(STp->buffer, p); /* so buffer content == at entry in all cases */
1660 vfree(buffer);
1661 return 0;
1664 static int osst_reposition_and_retry(struct osst_tape * STp, struct osst_request ** aSRpnt,
1665 unsigned int frame, unsigned int skip, int pending)
1667 unsigned char cmd[MAX_COMMAND_SIZE];
1668 struct osst_request * SRpnt;
1669 char * name = tape_name(STp);
1670 int expected = 0;
1671 int attempts = 1000 / skip;
1672 int flag = 1;
1673 unsigned long startwait = jiffies;
1674 #if DEBUG
1675 int dbg = debugging;
1676 #endif
1678 while (attempts && time_before(jiffies, startwait + 60*HZ)) {
1679 if (flag) {
1680 #if DEBUG
1681 debugging = dbg;
1682 #endif
1683 if (frame < 2990 && frame+skip+STp->cur_frames+pending >= 2990)
1684 frame = 3000-skip;
1685 expected = frame+skip+STp->cur_frames+pending;
1686 #if DEBUG
1687 printk(OSST_DEB_MSG "%s:D: Position to fppos %d, re-write from fseq %d\n",
1688 name, frame+skip, STp->frame_seq_number-STp->cur_frames-pending);
1689 #endif
1690 osst_set_frame_position(STp, aSRpnt, frame + skip, 1);
1691 flag = 0;
1692 attempts--;
1693 schedule_timeout_interruptible(msecs_to_jiffies(100));
1695 if (osst_get_frame_position(STp, aSRpnt) < 0) { /* additional write error */
1696 #if DEBUG
1697 printk(OSST_DEB_MSG "%s:D: Addl error, host %d, tape %d, buffer %d\n",
1698 name, STp->first_frame_position,
1699 STp->last_frame_position, STp->cur_frames);
1700 #endif
1701 frame = STp->last_frame_position;
1702 flag = 1;
1703 continue;
1705 if (pending && STp->cur_frames < 50) {
1707 memset(cmd, 0, MAX_COMMAND_SIZE);
1708 cmd[0] = WRITE_6;
1709 cmd[1] = 1;
1710 cmd[4] = 1;
1711 #if DEBUG
1712 printk(OSST_DEB_MSG "%s:D: About to write pending fseq %d at fppos %d\n",
1713 name, STp->frame_seq_number-1, STp->first_frame_position);
1714 #endif
1715 SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, OS_FRAME_SIZE, DMA_TO_DEVICE,
1716 STp->timeout, MAX_RETRIES, 1);
1717 *aSRpnt = SRpnt;
1719 if (STp->buffer->syscall_result) { /* additional write error */
1720 if ((SRpnt->sense[ 2] & 0x0f) == 13 &&
1721 SRpnt->sense[12] == 0 &&
1722 SRpnt->sense[13] == 2) {
1723 printk(KERN_ERR
1724 "%s:E: Volume overflow in write error recovery\n",
1725 name);
1726 break; /* hit end of tape = fail */
1728 flag = 1;
1730 else
1731 pending = 0;
1733 continue;
1735 if (STp->cur_frames == 0) {
1736 #if DEBUG
1737 debugging = dbg;
1738 printk(OSST_DEB_MSG "%s:D: Wait re-write finished\n", name);
1739 #endif
1740 if (STp->first_frame_position != expected) {
1741 printk(KERN_ERR "%s:A: Actual position %d - expected %d\n",
1742 name, STp->first_frame_position, expected);
1743 return (-EIO);
1745 return 0;
1747 #if DEBUG
1748 if (debugging) {
1749 printk(OSST_DEB_MSG "%s:D: Sleeping in re-write wait ready\n", name);
1750 printk(OSST_DEB_MSG "%s:D: Turning off debugging for a while\n", name);
1751 debugging = 0;
1753 #endif
1754 schedule_timeout_interruptible(msecs_to_jiffies(100));
1756 printk(KERN_ERR "%s:E: Failed to find valid tape media\n", name);
1757 #if DEBUG
1758 debugging = dbg;
1759 #endif
1760 return (-EIO);
1764 * Error recovery algorithm for the OnStream tape.
1767 static int osst_write_error_recovery(struct osst_tape * STp, struct osst_request ** aSRpnt, int pending)
1769 struct osst_request * SRpnt = * aSRpnt;
1770 struct st_partstat * STps = & STp->ps[STp->partition];
1771 char * name = tape_name(STp);
1772 int retval = 0;
1773 int rw_state;
1774 unsigned int frame, skip;
1776 rw_state = STps->rw;
1778 if ((SRpnt->sense[ 2] & 0x0f) != 3
1779 || SRpnt->sense[12] != 12
1780 || SRpnt->sense[13] != 0) {
1781 #if DEBUG
1782 printk(OSST_DEB_MSG "%s:D: Write error recovery cannot handle %02x:%02x:%02x\n", name,
1783 SRpnt->sense[2], SRpnt->sense[12], SRpnt->sense[13]);
1784 #endif
1785 return (-EIO);
1787 frame = (SRpnt->sense[3] << 24) |
1788 (SRpnt->sense[4] << 16) |
1789 (SRpnt->sense[5] << 8) |
1790 SRpnt->sense[6];
1791 skip = SRpnt->sense[9];
1793 #if DEBUG
1794 printk(OSST_DEB_MSG "%s:D: Detected physical bad frame at %u, advised to skip %d\n", name, frame, skip);
1795 #endif
1796 osst_get_frame_position(STp, aSRpnt);
1797 #if DEBUG
1798 printk(OSST_DEB_MSG "%s:D: reported frame positions: host = %d, tape = %d\n",
1799 name, STp->first_frame_position, STp->last_frame_position);
1800 #endif
1801 switch (STp->write_type) {
1802 case OS_WRITE_DATA:
1803 case OS_WRITE_EOD:
1804 case OS_WRITE_NEW_MARK:
1805 printk(KERN_WARNING
1806 "%s:I: Relocating %d buffered logical frames from position %u to %u\n",
1807 name, STp->cur_frames, frame, (frame + skip > 3000 && frame < 3000)?3000:frame + skip);
1808 if (STp->os_fw_rev >= 10600)
1809 retval = osst_reposition_and_retry(STp, aSRpnt, frame, skip, pending);
1810 else
1811 retval = osst_read_back_buffer_and_rewrite(STp, aSRpnt, frame, skip, pending);
1812 printk(KERN_WARNING "%s:%s: %sWrite error%srecovered\n", name,
1813 retval?"E" :"I",
1814 retval?"" :"Don't worry, ",
1815 retval?" not ":" ");
1816 break;
1817 case OS_WRITE_LAST_MARK:
1818 printk(KERN_ERR "%s:E: Bad frame in update last marker, fatal\n", name);
1819 osst_set_frame_position(STp, aSRpnt, frame + STp->cur_frames + pending, 0);
1820 retval = -EIO;
1821 break;
1822 case OS_WRITE_HEADER:
1823 printk(KERN_WARNING "%s:I: Bad frame in header partition, skipped\n", name);
1824 retval = osst_read_back_buffer_and_rewrite(STp, aSRpnt, frame, 1, pending);
1825 break;
1826 default:
1827 printk(KERN_INFO "%s:I: Bad frame in filler, ignored\n", name);
1828 osst_set_frame_position(STp, aSRpnt, frame + STp->cur_frames + pending, 0);
1830 osst_get_frame_position(STp, aSRpnt);
1831 #if DEBUG
1832 printk(OSST_DEB_MSG "%s:D: Positioning complete, cur_frames %d, pos %d, tape pos %d\n",
1833 name, STp->cur_frames, STp->first_frame_position, STp->last_frame_position);
1834 printk(OSST_DEB_MSG "%s:D: next logical frame to write: %d\n", name, STp->logical_blk_num);
1835 #endif
1836 if (retval == 0) {
1837 STp->recover_count++;
1838 STp->recover_erreg++;
1839 } else
1840 STp->abort_count++;
1842 STps->rw = rw_state;
1843 return retval;
1846 static int osst_space_over_filemarks_backward(struct osst_tape * STp, struct osst_request ** aSRpnt,
1847 int mt_op, int mt_count)
1849 char * name = tape_name(STp);
1850 int cnt;
1851 int last_mark_ppos = -1;
1853 #if DEBUG
1854 printk(OSST_DEB_MSG "%s:D: Reached space_over_filemarks_backwards %d %d\n", name, mt_op, mt_count);
1855 #endif
1856 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
1857 #if DEBUG
1858 printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks_bwd\n", name);
1859 #endif
1860 return -EIO;
1862 if (STp->linux_media_version >= 4) {
1864 * direct lookup in header filemark list
1866 cnt = ntohl(STp->buffer->aux->filemark_cnt);
1867 if (STp->header_ok &&
1868 STp->header_cache != NULL &&
1869 (cnt - mt_count) >= 0 &&
1870 (cnt - mt_count) < OS_FM_TAB_MAX &&
1871 (cnt - mt_count) < STp->filemark_cnt &&
1872 STp->header_cache->dat_fm_tab.fm_tab_ent[cnt-1] == STp->buffer->aux->last_mark_ppos)
1874 last_mark_ppos = ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[cnt - mt_count]);
1875 #if DEBUG
1876 if (STp->header_cache == NULL || (cnt - mt_count) < 0 || (cnt - mt_count) >= OS_FM_TAB_MAX)
1877 printk(OSST_DEB_MSG "%s:D: Filemark lookup fail due to %s\n", name,
1878 STp->header_cache == NULL?"lack of header cache":"count out of range");
1879 else
1880 printk(OSST_DEB_MSG "%s:D: Filemark lookup: prev mark %d (%s), skip %d to %d\n",
1881 name, cnt,
1882 ((cnt == -1 && ntohl(STp->buffer->aux->last_mark_ppos) == -1) ||
1883 (STp->header_cache->dat_fm_tab.fm_tab_ent[cnt-1] ==
1884 STp->buffer->aux->last_mark_ppos))?"match":"error",
1885 mt_count, last_mark_ppos);
1886 #endif
1887 if (last_mark_ppos > 10 && last_mark_ppos < STp->eod_frame_ppos) {
1888 osst_position_tape_and_confirm(STp, aSRpnt, last_mark_ppos);
1889 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
1890 #if DEBUG
1891 printk(OSST_DEB_MSG
1892 "%s:D: Couldn't get logical blk num in space_filemarks\n", name);
1893 #endif
1894 return (-EIO);
1896 if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
1897 printk(KERN_WARNING "%s:W: Expected to find marker at ppos %d, not found\n",
1898 name, last_mark_ppos);
1899 return (-EIO);
1901 goto found;
1903 #if DEBUG
1904 printk(OSST_DEB_MSG "%s:D: Reverting to scan filemark backwards\n", name);
1905 #endif
1907 cnt = 0;
1908 while (cnt != mt_count) {
1909 last_mark_ppos = ntohl(STp->buffer->aux->last_mark_ppos);
1910 if (last_mark_ppos == -1)
1911 return (-EIO);
1912 #if DEBUG
1913 printk(OSST_DEB_MSG "%s:D: Positioning to last mark at %d\n", name, last_mark_ppos);
1914 #endif
1915 osst_position_tape_and_confirm(STp, aSRpnt, last_mark_ppos);
1916 cnt++;
1917 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
1918 #if DEBUG
1919 printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks\n", name);
1920 #endif
1921 return (-EIO);
1923 if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
1924 printk(KERN_WARNING "%s:W: Expected to find marker at ppos %d, not found\n",
1925 name, last_mark_ppos);
1926 return (-EIO);
1929 found:
1930 if (mt_op == MTBSFM) {
1931 STp->frame_seq_number++;
1932 STp->frame_in_buffer = 0;
1933 STp->buffer->buffer_bytes = 0;
1934 STp->buffer->read_pointer = 0;
1935 STp->logical_blk_num += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
1937 return 0;
1941 * ADRL 1.1 compatible "slow" space filemarks fwd version
1943 * Just scans for the filemark sequentially.
1945 static int osst_space_over_filemarks_forward_slow(struct osst_tape * STp, struct osst_request ** aSRpnt,
1946 int mt_op, int mt_count)
1948 int cnt = 0;
1949 #if DEBUG
1950 char * name = tape_name(STp);
1952 printk(OSST_DEB_MSG "%s:D: Reached space_over_filemarks_forward_slow %d %d\n", name, mt_op, mt_count);
1953 #endif
1954 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
1955 #if DEBUG
1956 printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks_fwd\n", name);
1957 #endif
1958 return (-EIO);
1960 while (1) {
1961 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
1962 #if DEBUG
1963 printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks\n", name);
1964 #endif
1965 return (-EIO);
1967 if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_MARKER)
1968 cnt++;
1969 if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_EOD) {
1970 #if DEBUG
1971 printk(OSST_DEB_MSG "%s:D: space_fwd: EOD reached\n", name);
1972 #endif
1973 if (STp->first_frame_position > STp->eod_frame_ppos+1) {
1974 #if DEBUG
1975 printk(OSST_DEB_MSG "%s:D: EOD position corrected (%d=>%d)\n",
1976 name, STp->eod_frame_ppos, STp->first_frame_position-1);
1977 #endif
1978 STp->eod_frame_ppos = STp->first_frame_position-1;
1980 return (-EIO);
1982 if (cnt == mt_count)
1983 break;
1984 STp->frame_in_buffer = 0;
1986 if (mt_op == MTFSF) {
1987 STp->frame_seq_number++;
1988 STp->frame_in_buffer = 0;
1989 STp->buffer->buffer_bytes = 0;
1990 STp->buffer->read_pointer = 0;
1991 STp->logical_blk_num += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
1993 return 0;
1997 * Fast linux specific version of OnStream FSF
1999 static int osst_space_over_filemarks_forward_fast(struct osst_tape * STp, struct osst_request ** aSRpnt,
2000 int mt_op, int mt_count)
2002 char * name = tape_name(STp);
2003 int cnt = 0,
2004 next_mark_ppos = -1;
2006 #if DEBUG
2007 printk(OSST_DEB_MSG "%s:D: Reached space_over_filemarks_forward_fast %d %d\n", name, mt_op, mt_count);
2008 #endif
2009 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
2010 #if DEBUG
2011 printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks_fwd\n", name);
2012 #endif
2013 return (-EIO);
2016 if (STp->linux_media_version >= 4) {
2018 * direct lookup in header filemark list
2020 cnt = ntohl(STp->buffer->aux->filemark_cnt) - 1;
2021 if (STp->header_ok &&
2022 STp->header_cache != NULL &&
2023 (cnt + mt_count) < OS_FM_TAB_MAX &&
2024 (cnt + mt_count) < STp->filemark_cnt &&
2025 ((cnt == -1 && ntohl(STp->buffer->aux->last_mark_ppos) == -1) ||
2026 (STp->header_cache->dat_fm_tab.fm_tab_ent[cnt] == STp->buffer->aux->last_mark_ppos)))
2028 next_mark_ppos = ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[cnt + mt_count]);
2029 #if DEBUG
2030 if (STp->header_cache == NULL || (cnt + mt_count) >= OS_FM_TAB_MAX)
2031 printk(OSST_DEB_MSG "%s:D: Filemark lookup fail due to %s\n", name,
2032 STp->header_cache == NULL?"lack of header cache":"count out of range");
2033 else
2034 printk(OSST_DEB_MSG "%s:D: Filemark lookup: prev mark %d (%s), skip %d to %d\n",
2035 name, cnt,
2036 ((cnt == -1 && ntohl(STp->buffer->aux->last_mark_ppos) == -1) ||
2037 (STp->header_cache->dat_fm_tab.fm_tab_ent[cnt] ==
2038 STp->buffer->aux->last_mark_ppos))?"match":"error",
2039 mt_count, next_mark_ppos);
2040 #endif
2041 if (next_mark_ppos <= 10 || next_mark_ppos > STp->eod_frame_ppos) {
2042 #if DEBUG
2043 printk(OSST_DEB_MSG "%s:D: Reverting to slow filemark space\n", name);
2044 #endif
2045 return osst_space_over_filemarks_forward_slow(STp, aSRpnt, mt_op, mt_count);
2046 } else {
2047 osst_position_tape_and_confirm(STp, aSRpnt, next_mark_ppos);
2048 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
2049 #if DEBUG
2050 printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks\n",
2051 name);
2052 #endif
2053 return (-EIO);
2055 if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
2056 printk(KERN_WARNING "%s:W: Expected to find marker at ppos %d, not found\n",
2057 name, next_mark_ppos);
2058 return (-EIO);
2060 if (ntohl(STp->buffer->aux->filemark_cnt) != cnt + mt_count) {
2061 printk(KERN_WARNING "%s:W: Expected to find marker %d at ppos %d, not %d\n",
2062 name, cnt+mt_count, next_mark_ppos,
2063 ntohl(STp->buffer->aux->filemark_cnt));
2064 return (-EIO);
2067 } else {
2069 * Find nearest (usually previous) marker, then jump from marker to marker
2071 while (1) {
2072 if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_MARKER)
2073 break;
2074 if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_EOD) {
2075 #if DEBUG
2076 printk(OSST_DEB_MSG "%s:D: space_fwd: EOD reached\n", name);
2077 #endif
2078 return (-EIO);
2080 if (ntohl(STp->buffer->aux->filemark_cnt) == 0) {
2081 if (STp->first_mark_ppos == -1) {
2082 #if DEBUG
2083 printk(OSST_DEB_MSG "%s:D: Reverting to slow filemark space\n", name);
2084 #endif
2085 return osst_space_over_filemarks_forward_slow(STp, aSRpnt, mt_op, mt_count);
2087 osst_position_tape_and_confirm(STp, aSRpnt, STp->first_mark_ppos);
2088 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
2089 #if DEBUG
2090 printk(OSST_DEB_MSG
2091 "%s:D: Couldn't get logical blk num in space_filemarks_fwd_fast\n",
2092 name);
2093 #endif
2094 return (-EIO);
2096 if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
2097 printk(KERN_WARNING "%s:W: Expected to find filemark at %d\n",
2098 name, STp->first_mark_ppos);
2099 return (-EIO);
2101 } else {
2102 if (osst_space_over_filemarks_backward(STp, aSRpnt, MTBSF, 1) < 0)
2103 return (-EIO);
2104 mt_count++;
2107 cnt++;
2108 while (cnt != mt_count) {
2109 next_mark_ppos = ntohl(STp->buffer->aux->next_mark_ppos);
2110 if (!next_mark_ppos || next_mark_ppos > STp->eod_frame_ppos) {
2111 #if DEBUG
2112 printk(OSST_DEB_MSG "%s:D: Reverting to slow filemark space\n", name);
2113 #endif
2114 return osst_space_over_filemarks_forward_slow(STp, aSRpnt, mt_op, mt_count - cnt);
2116 #if DEBUG
2117 else printk(OSST_DEB_MSG "%s:D: Positioning to next mark at %d\n", name, next_mark_ppos);
2118 #endif
2119 osst_position_tape_and_confirm(STp, aSRpnt, next_mark_ppos);
2120 cnt++;
2121 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
2122 #if DEBUG
2123 printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks\n",
2124 name);
2125 #endif
2126 return (-EIO);
2128 if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
2129 printk(KERN_WARNING "%s:W: Expected to find marker at ppos %d, not found\n",
2130 name, next_mark_ppos);
2131 return (-EIO);
2135 if (mt_op == MTFSF) {
2136 STp->frame_seq_number++;
2137 STp->frame_in_buffer = 0;
2138 STp->buffer->buffer_bytes = 0;
2139 STp->buffer->read_pointer = 0;
2140 STp->logical_blk_num += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
2142 return 0;
2146 * In debug mode, we want to see as many errors as possible
2147 * to test the error recovery mechanism.
2149 #if DEBUG
2150 static void osst_set_retries(struct osst_tape * STp, struct osst_request ** aSRpnt, int retries)
2152 unsigned char cmd[MAX_COMMAND_SIZE];
2153 struct osst_request * SRpnt = * aSRpnt;
2154 char * name = tape_name(STp);
2156 memset(cmd, 0, MAX_COMMAND_SIZE);
2157 cmd[0] = MODE_SELECT;
2158 cmd[1] = 0x10;
2159 cmd[4] = NUMBER_RETRIES_PAGE_LENGTH + MODE_HEADER_LENGTH;
2161 (STp->buffer)->b_data[0] = cmd[4] - 1;
2162 (STp->buffer)->b_data[1] = 0; /* Medium Type - ignoring */
2163 (STp->buffer)->b_data[2] = 0; /* Reserved */
2164 (STp->buffer)->b_data[3] = 0; /* Block Descriptor Length */
2165 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 0] = NUMBER_RETRIES_PAGE | (1 << 7);
2166 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 1] = 2;
2167 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] = 4;
2168 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] = retries;
2170 if (debugging)
2171 printk(OSST_DEB_MSG "%s:D: Setting number of retries on OnStream tape to %d\n", name, retries);
2173 SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_TO_DEVICE, STp->timeout, 0, 1);
2174 *aSRpnt = SRpnt;
2176 if ((STp->buffer)->syscall_result)
2177 printk (KERN_ERR "%s:D: Couldn't set retries to %d\n", name, retries);
2179 #endif
2182 static int osst_write_filemark(struct osst_tape * STp, struct osst_request ** aSRpnt)
2184 int result;
2185 int this_mark_ppos = STp->first_frame_position;
2186 int this_mark_lbn = STp->logical_blk_num;
2187 #if DEBUG
2188 char * name = tape_name(STp);
2189 #endif
2191 if (STp->raw) return 0;
2193 STp->write_type = OS_WRITE_NEW_MARK;
2194 #if DEBUG
2195 printk(OSST_DEB_MSG "%s:D: Writing Filemark %i at fppos %d (fseq %d, lblk %d)\n",
2196 name, STp->filemark_cnt, this_mark_ppos, STp->frame_seq_number, this_mark_lbn);
2197 #endif
2198 STp->dirty = 1;
2199 result = osst_flush_write_buffer(STp, aSRpnt);
2200 result |= osst_flush_drive_buffer(STp, aSRpnt);
2201 STp->last_mark_ppos = this_mark_ppos;
2202 STp->last_mark_lbn = this_mark_lbn;
2203 if (STp->header_cache != NULL && STp->filemark_cnt < OS_FM_TAB_MAX)
2204 STp->header_cache->dat_fm_tab.fm_tab_ent[STp->filemark_cnt] = htonl(this_mark_ppos);
2205 if (STp->filemark_cnt++ == 0)
2206 STp->first_mark_ppos = this_mark_ppos;
2207 return result;
2210 static int osst_write_eod(struct osst_tape * STp, struct osst_request ** aSRpnt)
2212 int result;
2213 #if DEBUG
2214 char * name = tape_name(STp);
2215 #endif
2217 if (STp->raw) return 0;
2219 STp->write_type = OS_WRITE_EOD;
2220 STp->eod_frame_ppos = STp->first_frame_position;
2221 #if DEBUG
2222 printk(OSST_DEB_MSG "%s:D: Writing EOD at fppos %d (fseq %d, lblk %d)\n", name,
2223 STp->eod_frame_ppos, STp->frame_seq_number, STp->logical_blk_num);
2224 #endif
2225 STp->dirty = 1;
2227 result = osst_flush_write_buffer(STp, aSRpnt);
2228 result |= osst_flush_drive_buffer(STp, aSRpnt);
2229 STp->eod_frame_lfa = --(STp->frame_seq_number);
2230 return result;
2233 static int osst_write_filler(struct osst_tape * STp, struct osst_request ** aSRpnt, int where, int count)
2235 char * name = tape_name(STp);
2237 #if DEBUG
2238 printk(OSST_DEB_MSG "%s:D: Reached onstream write filler group %d\n", name, where);
2239 #endif
2240 osst_wait_ready(STp, aSRpnt, 60 * 5, 0);
2241 osst_set_frame_position(STp, aSRpnt, where, 0);
2242 STp->write_type = OS_WRITE_FILLER;
2243 while (count--) {
2244 memcpy(STp->buffer->b_data, "Filler", 6);
2245 STp->buffer->buffer_bytes = 6;
2246 STp->dirty = 1;
2247 if (osst_flush_write_buffer(STp, aSRpnt)) {
2248 printk(KERN_INFO "%s:I: Couldn't write filler frame\n", name);
2249 return (-EIO);
2252 #if DEBUG
2253 printk(OSST_DEB_MSG "%s:D: Exiting onstream write filler group\n", name);
2254 #endif
2255 return osst_flush_drive_buffer(STp, aSRpnt);
2258 static int __osst_write_header(struct osst_tape * STp, struct osst_request ** aSRpnt, int where, int count)
2260 char * name = tape_name(STp);
2261 int result;
2263 #if DEBUG
2264 printk(OSST_DEB_MSG "%s:D: Reached onstream write header group %d\n", name, where);
2265 #endif
2266 osst_wait_ready(STp, aSRpnt, 60 * 5, 0);
2267 osst_set_frame_position(STp, aSRpnt, where, 0);
2268 STp->write_type = OS_WRITE_HEADER;
2269 while (count--) {
2270 osst_copy_to_buffer(STp->buffer, (unsigned char *)STp->header_cache);
2271 STp->buffer->buffer_bytes = sizeof(os_header_t);
2272 STp->dirty = 1;
2273 if (osst_flush_write_buffer(STp, aSRpnt)) {
2274 printk(KERN_INFO "%s:I: Couldn't write header frame\n", name);
2275 return (-EIO);
2278 result = osst_flush_drive_buffer(STp, aSRpnt);
2279 #if DEBUG
2280 printk(OSST_DEB_MSG "%s:D: Write onstream header group %s\n", name, result?"failed":"done");
2281 #endif
2282 return result;
2285 static int osst_write_header(struct osst_tape * STp, struct osst_request ** aSRpnt, int locate_eod)
2287 os_header_t * header;
2288 int result;
2289 char * name = tape_name(STp);
2291 #if DEBUG
2292 printk(OSST_DEB_MSG "%s:D: Writing tape header\n", name);
2293 #endif
2294 if (STp->raw) return 0;
2296 if (STp->header_cache == NULL) {
2297 if ((STp->header_cache = (os_header_t *)vmalloc(sizeof(os_header_t))) == NULL) {
2298 printk(KERN_ERR "%s:E: Failed to allocate header cache\n", name);
2299 return (-ENOMEM);
2301 memset(STp->header_cache, 0, sizeof(os_header_t));
2302 #if DEBUG
2303 printk(OSST_DEB_MSG "%s:D: Allocated and cleared memory for header cache\n", name);
2304 #endif
2306 if (STp->header_ok) STp->update_frame_cntr++;
2307 else STp->update_frame_cntr = 0;
2309 header = STp->header_cache;
2310 strcpy(header->ident_str, "ADR_SEQ");
2311 header->major_rev = 1;
2312 header->minor_rev = 4;
2313 header->ext_trk_tb_off = htons(17192);
2314 header->pt_par_num = 1;
2315 header->partition[0].partition_num = OS_DATA_PARTITION;
2316 header->partition[0].par_desc_ver = OS_PARTITION_VERSION;
2317 header->partition[0].wrt_pass_cntr = htons(STp->wrt_pass_cntr);
2318 header->partition[0].first_frame_ppos = htonl(STp->first_data_ppos);
2319 header->partition[0].last_frame_ppos = htonl(STp->capacity);
2320 header->partition[0].eod_frame_ppos = htonl(STp->eod_frame_ppos);
2321 header->cfg_col_width = htonl(20);
2322 header->dat_col_width = htonl(1500);
2323 header->qfa_col_width = htonl(0);
2324 header->ext_track_tb.nr_stream_part = 1;
2325 header->ext_track_tb.et_ent_sz = 32;
2326 header->ext_track_tb.dat_ext_trk_ey.et_part_num = 0;
2327 header->ext_track_tb.dat_ext_trk_ey.fmt = 1;
2328 header->ext_track_tb.dat_ext_trk_ey.fm_tab_off = htons(17736);
2329 header->ext_track_tb.dat_ext_trk_ey.last_hlb_hi = 0;
2330 header->ext_track_tb.dat_ext_trk_ey.last_hlb = htonl(STp->eod_frame_lfa);
2331 header->ext_track_tb.dat_ext_trk_ey.last_pp = htonl(STp->eod_frame_ppos);
2332 header->dat_fm_tab.fm_part_num = 0;
2333 header->dat_fm_tab.fm_tab_ent_sz = 4;
2334 header->dat_fm_tab.fm_tab_ent_cnt = htons(STp->filemark_cnt<OS_FM_TAB_MAX?
2335 STp->filemark_cnt:OS_FM_TAB_MAX);
2337 result = __osst_write_header(STp, aSRpnt, 0xbae, 5);
2338 if (STp->update_frame_cntr == 0)
2339 osst_write_filler(STp, aSRpnt, 0xbb3, 5);
2340 result &= __osst_write_header(STp, aSRpnt, 5, 5);
2342 if (locate_eod) {
2343 #if DEBUG
2344 printk(OSST_DEB_MSG "%s:D: Locating back to eod frame addr %d\n", name, STp->eod_frame_ppos);
2345 #endif
2346 osst_set_frame_position(STp, aSRpnt, STp->eod_frame_ppos, 0);
2348 if (result)
2349 printk(KERN_ERR "%s:E: Write header failed\n", name);
2350 else {
2351 memcpy(STp->application_sig, "LIN4", 4);
2352 STp->linux_media = 1;
2353 STp->linux_media_version = 4;
2354 STp->header_ok = 1;
2356 return result;
2359 static int osst_reset_header(struct osst_tape * STp, struct osst_request ** aSRpnt)
2361 if (STp->header_cache != NULL)
2362 memset(STp->header_cache, 0, sizeof(os_header_t));
2364 STp->logical_blk_num = STp->frame_seq_number = 0;
2365 STp->frame_in_buffer = 0;
2366 STp->eod_frame_ppos = STp->first_data_ppos = 0x0000000A;
2367 STp->filemark_cnt = 0;
2368 STp->first_mark_ppos = STp->last_mark_ppos = STp->last_mark_lbn = -1;
2369 return osst_write_header(STp, aSRpnt, 1);
2372 static int __osst_analyze_headers(struct osst_tape * STp, struct osst_request ** aSRpnt, int ppos)
2374 char * name = tape_name(STp);
2375 os_header_t * header;
2376 os_aux_t * aux;
2377 char id_string[8];
2378 int linux_media_version,
2379 update_frame_cntr;
2381 if (STp->raw)
2382 return 1;
2384 if (ppos == 5 || ppos == 0xbae || STp->buffer->syscall_result) {
2385 if (osst_set_frame_position(STp, aSRpnt, ppos, 0))
2386 printk(KERN_WARNING "%s:W: Couldn't position tape\n", name);
2387 osst_wait_ready(STp, aSRpnt, 60 * 15, 0);
2388 if (osst_initiate_read (STp, aSRpnt)) {
2389 printk(KERN_WARNING "%s:W: Couldn't initiate read\n", name);
2390 return 0;
2393 if (osst_read_frame(STp, aSRpnt, 180)) {
2394 #if DEBUG
2395 printk(OSST_DEB_MSG "%s:D: Couldn't read header frame\n", name);
2396 #endif
2397 return 0;
2399 header = (os_header_t *) STp->buffer->b_data; /* warning: only first segment addressable */
2400 aux = STp->buffer->aux;
2401 if (aux->frame_type != OS_FRAME_TYPE_HEADER) {
2402 #if DEBUG
2403 printk(OSST_DEB_MSG "%s:D: Skipping non-header frame (%d)\n", name, ppos);
2404 #endif
2405 return 0;
2407 if (ntohl(aux->frame_seq_num) != 0 ||
2408 ntohl(aux->logical_blk_num) != 0 ||
2409 aux->partition.partition_num != OS_CONFIG_PARTITION ||
2410 ntohl(aux->partition.first_frame_ppos) != 0 ||
2411 ntohl(aux->partition.last_frame_ppos) != 0xbb7 ) {
2412 #if DEBUG
2413 printk(OSST_DEB_MSG "%s:D: Invalid header frame (%d,%d,%d,%d,%d)\n", name,
2414 ntohl(aux->frame_seq_num), ntohl(aux->logical_blk_num),
2415 aux->partition.partition_num, ntohl(aux->partition.first_frame_ppos),
2416 ntohl(aux->partition.last_frame_ppos));
2417 #endif
2418 return 0;
2420 if (strncmp(header->ident_str, "ADR_SEQ", 7) != 0 &&
2421 strncmp(header->ident_str, "ADR-SEQ", 7) != 0) {
2422 strlcpy(id_string, header->ident_str, 8);
2423 #if DEBUG
2424 printk(OSST_DEB_MSG "%s:D: Invalid header identification string %s\n", name, id_string);
2425 #endif
2426 return 0;
2428 update_frame_cntr = ntohl(aux->update_frame_cntr);
2429 if (update_frame_cntr < STp->update_frame_cntr) {
2430 #if DEBUG
2431 printk(OSST_DEB_MSG "%s:D: Skipping frame %d with update_frame_counter %d<%d\n",
2432 name, ppos, update_frame_cntr, STp->update_frame_cntr);
2433 #endif
2434 return 0;
2436 if (header->major_rev != 1 || header->minor_rev != 4 ) {
2437 #if DEBUG
2438 printk(OSST_DEB_MSG "%s:D: %s revision %d.%d detected (1.4 supported)\n",
2439 name, (header->major_rev != 1 || header->minor_rev < 2 ||
2440 header->minor_rev > 4 )? "Invalid" : "Warning:",
2441 header->major_rev, header->minor_rev);
2442 #endif
2443 if (header->major_rev != 1 || header->minor_rev < 2 || header->minor_rev > 4)
2444 return 0;
2446 #if DEBUG
2447 if (header->pt_par_num != 1)
2448 printk(KERN_INFO "%s:W: %d partitions defined, only one supported\n",
2449 name, header->pt_par_num);
2450 #endif
2451 memcpy(id_string, aux->application_sig, 4);
2452 id_string[4] = 0;
2453 if (memcmp(id_string, "LIN", 3) == 0) {
2454 STp->linux_media = 1;
2455 linux_media_version = id_string[3] - '0';
2456 if (linux_media_version != 4)
2457 printk(KERN_INFO "%s:I: Linux media version %d detected (current 4)\n",
2458 name, linux_media_version);
2459 } else {
2460 printk(KERN_WARNING "%s:W: Non Linux media detected (%s)\n", name, id_string);
2461 return 0;
2463 if (linux_media_version < STp->linux_media_version) {
2464 #if DEBUG
2465 printk(OSST_DEB_MSG "%s:D: Skipping frame %d with linux_media_version %d\n",
2466 name, ppos, linux_media_version);
2467 #endif
2468 return 0;
2470 if (linux_media_version > STp->linux_media_version) {
2471 #if DEBUG
2472 printk(OSST_DEB_MSG "%s:D: Frame %d sets linux_media_version to %d\n",
2473 name, ppos, linux_media_version);
2474 #endif
2475 memcpy(STp->application_sig, id_string, 5);
2476 STp->linux_media_version = linux_media_version;
2477 STp->update_frame_cntr = -1;
2479 if (update_frame_cntr > STp->update_frame_cntr) {
2480 #if DEBUG
2481 printk(OSST_DEB_MSG "%s:D: Frame %d sets update_frame_counter to %d\n",
2482 name, ppos, update_frame_cntr);
2483 #endif
2484 if (STp->header_cache == NULL) {
2485 if ((STp->header_cache = (os_header_t *)vmalloc(sizeof(os_header_t))) == NULL) {
2486 printk(KERN_ERR "%s:E: Failed to allocate header cache\n", name);
2487 return 0;
2489 #if DEBUG
2490 printk(OSST_DEB_MSG "%s:D: Allocated memory for header cache\n", name);
2491 #endif
2493 osst_copy_from_buffer(STp->buffer, (unsigned char *)STp->header_cache);
2494 header = STp->header_cache; /* further accesses from cached (full) copy */
2496 STp->wrt_pass_cntr = ntohs(header->partition[0].wrt_pass_cntr);
2497 STp->first_data_ppos = ntohl(header->partition[0].first_frame_ppos);
2498 STp->eod_frame_ppos = ntohl(header->partition[0].eod_frame_ppos);
2499 STp->eod_frame_lfa = ntohl(header->ext_track_tb.dat_ext_trk_ey.last_hlb);
2500 STp->filemark_cnt = ntohl(aux->filemark_cnt);
2501 STp->first_mark_ppos = ntohl(aux->next_mark_ppos);
2502 STp->last_mark_ppos = ntohl(aux->last_mark_ppos);
2503 STp->last_mark_lbn = ntohl(aux->last_mark_lbn);
2504 STp->update_frame_cntr = update_frame_cntr;
2505 #if DEBUG
2506 printk(OSST_DEB_MSG "%s:D: Detected write pass %d, update frame counter %d, filemark counter %d\n",
2507 name, STp->wrt_pass_cntr, STp->update_frame_cntr, STp->filemark_cnt);
2508 printk(OSST_DEB_MSG "%s:D: first data frame on tape = %d, last = %d, eod frame = %d\n", name,
2509 STp->first_data_ppos,
2510 ntohl(header->partition[0].last_frame_ppos),
2511 ntohl(header->partition[0].eod_frame_ppos));
2512 printk(OSST_DEB_MSG "%s:D: first mark on tape = %d, last = %d, eod frame = %d\n",
2513 name, STp->first_mark_ppos, STp->last_mark_ppos, STp->eod_frame_ppos);
2514 #endif
2515 if (header->minor_rev < 4 && STp->linux_media_version == 4) {
2516 #if DEBUG
2517 printk(OSST_DEB_MSG "%s:D: Moving filemark list to ADR 1.4 location\n", name);
2518 #endif
2519 memcpy((void *)header->dat_fm_tab.fm_tab_ent,
2520 (void *)header->old_filemark_list, sizeof(header->dat_fm_tab.fm_tab_ent));
2521 memset((void *)header->old_filemark_list, 0, sizeof(header->old_filemark_list));
2523 if (header->minor_rev == 4 &&
2524 (header->ext_trk_tb_off != htons(17192) ||
2525 header->partition[0].partition_num != OS_DATA_PARTITION ||
2526 header->partition[0].par_desc_ver != OS_PARTITION_VERSION ||
2527 header->partition[0].last_frame_ppos != htonl(STp->capacity) ||
2528 header->cfg_col_width != htonl(20) ||
2529 header->dat_col_width != htonl(1500) ||
2530 header->qfa_col_width != htonl(0) ||
2531 header->ext_track_tb.nr_stream_part != 1 ||
2532 header->ext_track_tb.et_ent_sz != 32 ||
2533 header->ext_track_tb.dat_ext_trk_ey.et_part_num != OS_DATA_PARTITION ||
2534 header->ext_track_tb.dat_ext_trk_ey.fmt != 1 ||
2535 header->ext_track_tb.dat_ext_trk_ey.fm_tab_off != htons(17736) ||
2536 header->ext_track_tb.dat_ext_trk_ey.last_hlb_hi != 0 ||
2537 header->ext_track_tb.dat_ext_trk_ey.last_pp != htonl(STp->eod_frame_ppos) ||
2538 header->dat_fm_tab.fm_part_num != OS_DATA_PARTITION ||
2539 header->dat_fm_tab.fm_tab_ent_sz != 4 ||
2540 header->dat_fm_tab.fm_tab_ent_cnt !=
2541 htons(STp->filemark_cnt<OS_FM_TAB_MAX?STp->filemark_cnt:OS_FM_TAB_MAX)))
2542 printk(KERN_WARNING "%s:W: Failed consistency check ADR 1.4 format\n", name);
2546 return 1;
2549 static int osst_analyze_headers(struct osst_tape * STp, struct osst_request ** aSRpnt)
2551 int position, ppos;
2552 int first, last;
2553 int valid = 0;
2554 char * name = tape_name(STp);
2556 position = osst_get_frame_position(STp, aSRpnt);
2558 if (STp->raw) {
2559 STp->header_ok = STp->linux_media = 1;
2560 STp->linux_media_version = 0;
2561 return 1;
2563 STp->header_ok = STp->linux_media = STp->linux_media_version = 0;
2564 STp->wrt_pass_cntr = STp->update_frame_cntr = -1;
2565 STp->eod_frame_ppos = STp->first_data_ppos = -1;
2566 STp->first_mark_ppos = STp->last_mark_ppos = STp->last_mark_lbn = -1;
2567 #if DEBUG
2568 printk(OSST_DEB_MSG "%s:D: Reading header\n", name);
2569 #endif
2571 /* optimization for speed - if we are positioned at ppos 10, read second group first */
2572 /* TODO try the ADR 1.1 locations for the second group if we have no valid one yet... */
2574 first = position==10?0xbae: 5;
2575 last = position==10?0xbb3:10;
2577 for (ppos = first; ppos < last; ppos++)
2578 if (__osst_analyze_headers(STp, aSRpnt, ppos))
2579 valid = 1;
2581 first = position==10? 5:0xbae;
2582 last = position==10?10:0xbb3;
2584 for (ppos = first; ppos < last; ppos++)
2585 if (__osst_analyze_headers(STp, aSRpnt, ppos))
2586 valid = 1;
2588 if (!valid) {
2589 printk(KERN_ERR "%s:E: Failed to find valid ADRL header, new media?\n", name);
2590 STp->eod_frame_ppos = STp->first_data_ppos = 0;
2591 osst_set_frame_position(STp, aSRpnt, 10, 0);
2592 return 0;
2594 if (position <= STp->first_data_ppos) {
2595 position = STp->first_data_ppos;
2596 STp->ps[0].drv_file = STp->ps[0].drv_block = STp->frame_seq_number = STp->logical_blk_num = 0;
2598 osst_set_frame_position(STp, aSRpnt, position, 0);
2599 STp->header_ok = 1;
2601 return 1;
2604 static int osst_verify_position(struct osst_tape * STp, struct osst_request ** aSRpnt)
2606 int frame_position = STp->first_frame_position;
2607 int frame_seq_numbr = STp->frame_seq_number;
2608 int logical_blk_num = STp->logical_blk_num;
2609 int halfway_frame = STp->frame_in_buffer;
2610 int read_pointer = STp->buffer->read_pointer;
2611 int prev_mark_ppos = -1;
2612 int actual_mark_ppos, i, n;
2613 #if DEBUG
2614 char * name = tape_name(STp);
2616 printk(OSST_DEB_MSG "%s:D: Verify that the tape is really the one we think before writing\n", name);
2617 #endif
2618 osst_set_frame_position(STp, aSRpnt, frame_position - 1, 0);
2619 if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
2620 #if DEBUG
2621 printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in verify_position\n", name);
2622 #endif
2623 return (-EIO);
2625 if (STp->linux_media_version >= 4) {
2626 for (i=0; i<STp->filemark_cnt; i++)
2627 if ((n=ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[i])) < frame_position)
2628 prev_mark_ppos = n;
2629 } else
2630 prev_mark_ppos = frame_position - 1; /* usually - we don't really know */
2631 actual_mark_ppos = STp->buffer->aux->frame_type == OS_FRAME_TYPE_MARKER ?
2632 frame_position - 1 : ntohl(STp->buffer->aux->last_mark_ppos);
2633 if (frame_position != STp->first_frame_position ||
2634 frame_seq_numbr != STp->frame_seq_number + (halfway_frame?0:1) ||
2635 prev_mark_ppos != actual_mark_ppos ) {
2636 #if DEBUG
2637 printk(OSST_DEB_MSG "%s:D: Block mismatch: fppos %d-%d, fseq %d-%d, mark %d-%d\n", name,
2638 STp->first_frame_position, frame_position,
2639 STp->frame_seq_number + (halfway_frame?0:1),
2640 frame_seq_numbr, actual_mark_ppos, prev_mark_ppos);
2641 #endif
2642 return (-EIO);
2644 if (halfway_frame) {
2645 /* prepare buffer for append and rewrite on top of original */
2646 osst_set_frame_position(STp, aSRpnt, frame_position - 1, 0);
2647 STp->buffer->buffer_bytes = read_pointer;
2648 STp->ps[STp->partition].rw = ST_WRITING;
2649 STp->dirty = 1;
2651 STp->frame_in_buffer = halfway_frame;
2652 STp->frame_seq_number = frame_seq_numbr;
2653 STp->logical_blk_num = logical_blk_num;
2654 return 0;
2657 /* Acc. to OnStream, the vers. numbering is the following:
2658 * X.XX for released versions (X=digit),
2659 * XXXY for unreleased versions (Y=letter)
2660 * Ordering 1.05 < 106A < 106B < ... < 106a < ... < 1.06
2661 * This fn makes monoton numbers out of this scheme ...
2663 static unsigned int osst_parse_firmware_rev (const char * str)
2665 if (str[1] == '.') {
2666 return (str[0]-'0')*10000
2667 +(str[2]-'0')*1000
2668 +(str[3]-'0')*100;
2669 } else {
2670 return (str[0]-'0')*10000
2671 +(str[1]-'0')*1000
2672 +(str[2]-'0')*100 - 100
2673 +(str[3]-'@');
2678 * Configure the OnStream SCII tape drive for default operation
2680 static int osst_configure_onstream(struct osst_tape *STp, struct osst_request ** aSRpnt)
2682 unsigned char cmd[MAX_COMMAND_SIZE];
2683 char * name = tape_name(STp);
2684 struct osst_request * SRpnt = * aSRpnt;
2685 osst_mode_parameter_header_t * header;
2686 osst_block_size_page_t * bs;
2687 osst_capabilities_page_t * cp;
2688 osst_tape_paramtr_page_t * prm;
2689 int drive_buffer_size;
2691 if (STp->ready != ST_READY) {
2692 #if DEBUG
2693 printk(OSST_DEB_MSG "%s:D: Not Ready\n", name);
2694 #endif
2695 return (-EIO);
2698 if (STp->os_fw_rev < 10600) {
2699 printk(KERN_INFO "%s:I: Old OnStream firmware revision detected (%s),\n", name, STp->device->rev);
2700 printk(KERN_INFO "%s:I: an upgrade to version 1.06 or above is recommended\n", name);
2704 * Configure 32.5KB (data+aux) frame size.
2705 * Get the current frame size from the block size mode page
2707 memset(cmd, 0, MAX_COMMAND_SIZE);
2708 cmd[0] = MODE_SENSE;
2709 cmd[1] = 8;
2710 cmd[2] = BLOCK_SIZE_PAGE;
2711 cmd[4] = BLOCK_SIZE_PAGE_LENGTH + MODE_HEADER_LENGTH;
2713 SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_FROM_DEVICE, STp->timeout, 0, 1);
2714 if (SRpnt == NULL) {
2715 #if DEBUG
2716 printk(OSST_DEB_MSG "osst :D: Busy\n");
2717 #endif
2718 return (-EBUSY);
2720 *aSRpnt = SRpnt;
2721 if ((STp->buffer)->syscall_result != 0) {
2722 printk (KERN_ERR "%s:E: Can't get tape block size mode page\n", name);
2723 return (-EIO);
2726 header = (osst_mode_parameter_header_t *) (STp->buffer)->b_data;
2727 bs = (osst_block_size_page_t *) ((STp->buffer)->b_data + sizeof(osst_mode_parameter_header_t) + header->bdl);
2729 #if DEBUG
2730 printk(OSST_DEB_MSG "%s:D: 32KB play back: %s\n", name, bs->play32 ? "Yes" : "No");
2731 printk(OSST_DEB_MSG "%s:D: 32.5KB play back: %s\n", name, bs->play32_5 ? "Yes" : "No");
2732 printk(OSST_DEB_MSG "%s:D: 32KB record: %s\n", name, bs->record32 ? "Yes" : "No");
2733 printk(OSST_DEB_MSG "%s:D: 32.5KB record: %s\n", name, bs->record32_5 ? "Yes" : "No");
2734 #endif
2737 * Configure default auto columns mode, 32.5KB transfer mode
2739 bs->one = 1;
2740 bs->play32 = 0;
2741 bs->play32_5 = 1;
2742 bs->record32 = 0;
2743 bs->record32_5 = 1;
2745 memset(cmd, 0, MAX_COMMAND_SIZE);
2746 cmd[0] = MODE_SELECT;
2747 cmd[1] = 0x10;
2748 cmd[4] = BLOCK_SIZE_PAGE_LENGTH + MODE_HEADER_LENGTH;
2750 SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_TO_DEVICE, STp->timeout, 0, 1);
2751 *aSRpnt = SRpnt;
2752 if ((STp->buffer)->syscall_result != 0) {
2753 printk (KERN_ERR "%s:E: Couldn't set tape block size mode page\n", name);
2754 return (-EIO);
2757 #if DEBUG
2758 printk(KERN_INFO "%s:D: Drive Block Size changed to 32.5K\n", name);
2760 * In debug mode, we want to see as many errors as possible
2761 * to test the error recovery mechanism.
2763 osst_set_retries(STp, aSRpnt, 0);
2764 SRpnt = * aSRpnt;
2765 #endif
2768 * Set vendor name to 'LIN4' for "Linux support version 4".
2771 memset(cmd, 0, MAX_COMMAND_SIZE);
2772 cmd[0] = MODE_SELECT;
2773 cmd[1] = 0x10;
2774 cmd[4] = VENDOR_IDENT_PAGE_LENGTH + MODE_HEADER_LENGTH;
2776 header->mode_data_length = VENDOR_IDENT_PAGE_LENGTH + MODE_HEADER_LENGTH - 1;
2777 header->medium_type = 0; /* Medium Type - ignoring */
2778 header->dsp = 0; /* Reserved */
2779 header->bdl = 0; /* Block Descriptor Length */
2781 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 0] = VENDOR_IDENT_PAGE | (1 << 7);
2782 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 1] = 6;
2783 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] = 'L';
2784 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] = 'I';
2785 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 4] = 'N';
2786 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 5] = '4';
2787 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 6] = 0;
2788 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 7] = 0;
2790 SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_TO_DEVICE, STp->timeout, 0, 1);
2791 *aSRpnt = SRpnt;
2793 if ((STp->buffer)->syscall_result != 0) {
2794 printk (KERN_ERR "%s:E: Couldn't set vendor name to %s\n", name,
2795 (char *) ((STp->buffer)->b_data + MODE_HEADER_LENGTH + 2));
2796 return (-EIO);
2799 memset(cmd, 0, MAX_COMMAND_SIZE);
2800 cmd[0] = MODE_SENSE;
2801 cmd[1] = 8;
2802 cmd[2] = CAPABILITIES_PAGE;
2803 cmd[4] = CAPABILITIES_PAGE_LENGTH + MODE_HEADER_LENGTH;
2805 SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_FROM_DEVICE, STp->timeout, 0, 1);
2806 *aSRpnt = SRpnt;
2808 if ((STp->buffer)->syscall_result != 0) {
2809 printk (KERN_ERR "%s:E: Can't get capabilities page\n", name);
2810 return (-EIO);
2813 header = (osst_mode_parameter_header_t *) (STp->buffer)->b_data;
2814 cp = (osst_capabilities_page_t *) ((STp->buffer)->b_data +
2815 sizeof(osst_mode_parameter_header_t) + header->bdl);
2817 drive_buffer_size = ntohs(cp->buffer_size) / 2;
2819 memset(cmd, 0, MAX_COMMAND_SIZE);
2820 cmd[0] = MODE_SENSE;
2821 cmd[1] = 8;
2822 cmd[2] = TAPE_PARAMTR_PAGE;
2823 cmd[4] = TAPE_PARAMTR_PAGE_LENGTH + MODE_HEADER_LENGTH;
2825 SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_FROM_DEVICE, STp->timeout, 0, 1);
2826 *aSRpnt = SRpnt;
2828 if ((STp->buffer)->syscall_result != 0) {
2829 printk (KERN_ERR "%s:E: Can't get tape parameter page\n", name);
2830 return (-EIO);
2833 header = (osst_mode_parameter_header_t *) (STp->buffer)->b_data;
2834 prm = (osst_tape_paramtr_page_t *) ((STp->buffer)->b_data +
2835 sizeof(osst_mode_parameter_header_t) + header->bdl);
2837 STp->density = prm->density;
2838 STp->capacity = ntohs(prm->segtrk) * ntohs(prm->trks);
2839 #if DEBUG
2840 printk(OSST_DEB_MSG "%s:D: Density %d, tape length: %dMB, drive buffer size: %dKB\n",
2841 name, STp->density, STp->capacity / 32, drive_buffer_size);
2842 #endif
2844 return 0;
2849 /* Step over EOF if it has been inadvertently crossed (ioctl not used because
2850 it messes up the block number). */
2851 static int cross_eof(struct osst_tape *STp, struct osst_request ** aSRpnt, int forward)
2853 int result;
2854 char * name = tape_name(STp);
2856 #if DEBUG
2857 if (debugging)
2858 printk(OSST_DEB_MSG "%s:D: Stepping over filemark %s.\n",
2859 name, forward ? "forward" : "backward");
2860 #endif
2862 if (forward) {
2863 /* assumes that the filemark is already read by the drive, so this is low cost */
2864 result = osst_space_over_filemarks_forward_slow(STp, aSRpnt, MTFSF, 1);
2866 else
2867 /* assumes this is only called if we just read the filemark! */
2868 result = osst_seek_logical_blk(STp, aSRpnt, STp->logical_blk_num - 1);
2870 if (result < 0)
2871 printk(KERN_WARNING "%s:W: Stepping over filemark %s failed.\n",
2872 name, forward ? "forward" : "backward");
2874 return result;
2878 /* Get the tape position. */
2880 static int osst_get_frame_position(struct osst_tape *STp, struct osst_request ** aSRpnt)
2882 unsigned char scmd[MAX_COMMAND_SIZE];
2883 struct osst_request * SRpnt;
2884 int result = 0;
2885 char * name = tape_name(STp);
2887 /* KG: We want to be able to use it for checking Write Buffer availability
2888 * and thus don't want to risk to overwrite anything. Exchange buffers ... */
2889 char mybuf[24];
2890 char * olddata = STp->buffer->b_data;
2891 int oldsize = STp->buffer->buffer_size;
2893 if (STp->ready != ST_READY) return (-EIO);
2895 memset (scmd, 0, MAX_COMMAND_SIZE);
2896 scmd[0] = READ_POSITION;
2898 STp->buffer->b_data = mybuf; STp->buffer->buffer_size = 24;
2899 SRpnt = osst_do_scsi(*aSRpnt, STp, scmd, 20, DMA_FROM_DEVICE,
2900 STp->timeout, MAX_RETRIES, 1);
2901 if (!SRpnt) {
2902 STp->buffer->b_data = olddata; STp->buffer->buffer_size = oldsize;
2903 return (-EBUSY);
2905 *aSRpnt = SRpnt;
2907 if (STp->buffer->syscall_result)
2908 result = ((SRpnt->sense[2] & 0x0f) == 3) ? -EIO : -EINVAL; /* 3: Write Error */
2910 if (result == -EINVAL)
2911 printk(KERN_ERR "%s:E: Can't read tape position.\n", name);
2912 else {
2913 if (result == -EIO) { /* re-read position - this needs to preserve media errors */
2914 unsigned char mysense[16];
2915 memcpy (mysense, SRpnt->sense, 16);
2916 memset (scmd, 0, MAX_COMMAND_SIZE);
2917 scmd[0] = READ_POSITION;
2918 STp->buffer->b_data = mybuf; STp->buffer->buffer_size = 24;
2919 SRpnt = osst_do_scsi(SRpnt, STp, scmd, 20, DMA_FROM_DEVICE,
2920 STp->timeout, MAX_RETRIES, 1);
2921 #if DEBUG
2922 printk(OSST_DEB_MSG "%s:D: Reread position, reason=[%02x:%02x:%02x], result=[%s%02x:%02x:%02x]\n",
2923 name, mysense[2], mysense[12], mysense[13], STp->buffer->syscall_result?"":"ok:",
2924 SRpnt->sense[2],SRpnt->sense[12],SRpnt->sense[13]);
2925 #endif
2926 if (!STp->buffer->syscall_result)
2927 memcpy (SRpnt->sense, mysense, 16);
2928 else
2929 printk(KERN_WARNING "%s:W: Double error in get position\n", name);
2931 STp->first_frame_position = ((STp->buffer)->b_data[4] << 24)
2932 + ((STp->buffer)->b_data[5] << 16)
2933 + ((STp->buffer)->b_data[6] << 8)
2934 + (STp->buffer)->b_data[7];
2935 STp->last_frame_position = ((STp->buffer)->b_data[ 8] << 24)
2936 + ((STp->buffer)->b_data[ 9] << 16)
2937 + ((STp->buffer)->b_data[10] << 8)
2938 + (STp->buffer)->b_data[11];
2939 STp->cur_frames = (STp->buffer)->b_data[15];
2940 #if DEBUG
2941 if (debugging) {
2942 printk(OSST_DEB_MSG "%s:D: Drive Positions: host %d, tape %d%s, buffer %d\n", name,
2943 STp->first_frame_position, STp->last_frame_position,
2944 ((STp->buffer)->b_data[0]&0x80)?" (BOP)":
2945 ((STp->buffer)->b_data[0]&0x40)?" (EOP)":"",
2946 STp->cur_frames);
2948 #endif
2949 if (STp->cur_frames == 0 && STp->first_frame_position != STp->last_frame_position) {
2950 #if DEBUG
2951 printk(OSST_DEB_MSG "%s:D: Correcting read position %d, %d, %d\n", name,
2952 STp->first_frame_position, STp->last_frame_position, STp->cur_frames);
2953 #endif
2954 STp->first_frame_position = STp->last_frame_position;
2957 STp->buffer->b_data = olddata; STp->buffer->buffer_size = oldsize;
2959 return (result == 0 ? STp->first_frame_position : result);
2963 /* Set the tape block */
2964 static int osst_set_frame_position(struct osst_tape *STp, struct osst_request ** aSRpnt, int ppos, int skip)
2966 unsigned char scmd[MAX_COMMAND_SIZE];
2967 struct osst_request * SRpnt;
2968 struct st_partstat * STps;
2969 int result = 0;
2970 int pp = (ppos == 3000 && !skip)? 0 : ppos;
2971 char * name = tape_name(STp);
2973 if (STp->ready != ST_READY) return (-EIO);
2975 STps = &(STp->ps[STp->partition]);
2977 if (ppos < 0 || ppos > STp->capacity) {
2978 printk(KERN_WARNING "%s:W: Reposition request %d out of range\n", name, ppos);
2979 pp = ppos = ppos < 0 ? 0 : (STp->capacity - 1);
2980 result = (-EINVAL);
2983 do {
2984 #if DEBUG
2985 if (debugging)
2986 printk(OSST_DEB_MSG "%s:D: Setting ppos to %d.\n", name, pp);
2987 #endif
2988 memset (scmd, 0, MAX_COMMAND_SIZE);
2989 scmd[0] = SEEK_10;
2990 scmd[1] = 1;
2991 scmd[3] = (pp >> 24);
2992 scmd[4] = (pp >> 16);
2993 scmd[5] = (pp >> 8);
2994 scmd[6] = pp;
2995 if (skip)
2996 scmd[9] = 0x80;
2998 SRpnt = osst_do_scsi(*aSRpnt, STp, scmd, 0, DMA_NONE, STp->long_timeout,
2999 MAX_RETRIES, 1);
3000 if (!SRpnt)
3001 return (-EBUSY);
3002 *aSRpnt = SRpnt;
3004 if ((STp->buffer)->syscall_result != 0) {
3005 #if DEBUG
3006 printk(OSST_DEB_MSG "%s:D: SEEK command from %d to %d failed.\n",
3007 name, STp->first_frame_position, pp);
3008 #endif
3009 result = (-EIO);
3011 if (pp != ppos)
3012 osst_wait_ready(STp, aSRpnt, 5 * 60, OSST_WAIT_POSITION_COMPLETE);
3013 } while ((pp != ppos) && (pp = ppos));
3014 STp->first_frame_position = STp->last_frame_position = ppos;
3015 STps->eof = ST_NOEOF;
3016 STps->at_sm = 0;
3017 STps->rw = ST_IDLE;
3018 STp->frame_in_buffer = 0;
3019 return result;
3022 static int osst_write_trailer(struct osst_tape *STp, struct osst_request ** aSRpnt, int leave_at_EOT)
3024 struct st_partstat * STps = &(STp->ps[STp->partition]);
3025 int result = 0;
3027 if (STp->write_type != OS_WRITE_NEW_MARK) {
3028 /* true unless the user wrote the filemark for us */
3029 result = osst_flush_drive_buffer(STp, aSRpnt);
3030 if (result < 0) goto out;
3031 result = osst_write_filemark(STp, aSRpnt);
3032 if (result < 0) goto out;
3034 if (STps->drv_file >= 0)
3035 STps->drv_file++ ;
3036 STps->drv_block = 0;
3038 result = osst_write_eod(STp, aSRpnt);
3039 osst_write_header(STp, aSRpnt, leave_at_EOT);
3041 STps->eof = ST_FM;
3042 out:
3043 return result;
3046 /* osst versions of st functions - augmented and stripped to suit OnStream only */
3048 /* Flush the write buffer (never need to write if variable blocksize). */
3049 static int osst_flush_write_buffer(struct osst_tape *STp, struct osst_request ** aSRpnt)
3051 int offset, transfer, blks = 0;
3052 int result = 0;
3053 unsigned char cmd[MAX_COMMAND_SIZE];
3054 struct osst_request * SRpnt = *aSRpnt;
3055 struct st_partstat * STps;
3056 char * name = tape_name(STp);
3058 if ((STp->buffer)->writing) {
3059 if (SRpnt == (STp->buffer)->last_SRpnt)
3060 #if DEBUG
3061 { printk(OSST_DEB_MSG
3062 "%s:D: aSRpnt points to osst_request that write_behind_check will release -- cleared\n", name);
3063 #endif
3064 *aSRpnt = SRpnt = NULL;
3065 #if DEBUG
3066 } else if (SRpnt)
3067 printk(OSST_DEB_MSG
3068 "%s:D: aSRpnt does not point to osst_request that write_behind_check will release -- strange\n", name);
3069 #endif
3070 osst_write_behind_check(STp);
3071 if ((STp->buffer)->syscall_result) {
3072 #if DEBUG
3073 if (debugging)
3074 printk(OSST_DEB_MSG "%s:D: Async write error (flush) %x.\n",
3075 name, (STp->buffer)->midlevel_result);
3076 #endif
3077 if ((STp->buffer)->midlevel_result == INT_MAX)
3078 return (-ENOSPC);
3079 return (-EIO);
3083 result = 0;
3084 if (STp->dirty == 1) {
3086 STp->write_count++;
3087 STps = &(STp->ps[STp->partition]);
3088 STps->rw = ST_WRITING;
3089 offset = STp->buffer->buffer_bytes;
3090 blks = (offset + STp->block_size - 1) / STp->block_size;
3091 transfer = OS_FRAME_SIZE;
3093 if (offset < OS_DATA_SIZE)
3094 osst_zero_buffer_tail(STp->buffer);
3096 if (STp->poll)
3097 if (osst_wait_frame (STp, aSRpnt, STp->first_frame_position, -50, 120))
3098 result = osst_recover_wait_frame(STp, aSRpnt, 1);
3100 memset(cmd, 0, MAX_COMMAND_SIZE);
3101 cmd[0] = WRITE_6;
3102 cmd[1] = 1;
3103 cmd[4] = 1;
3105 switch (STp->write_type) {
3106 case OS_WRITE_DATA:
3107 #if DEBUG
3108 if (debugging)
3109 printk(OSST_DEB_MSG "%s:D: Writing %d blocks to frame %d, lblks %d-%d\n",
3110 name, blks, STp->frame_seq_number,
3111 STp->logical_blk_num - blks, STp->logical_blk_num - 1);
3112 #endif
3113 osst_init_aux(STp, OS_FRAME_TYPE_DATA, STp->frame_seq_number++,
3114 STp->logical_blk_num - blks, STp->block_size, blks);
3115 break;
3116 case OS_WRITE_EOD:
3117 osst_init_aux(STp, OS_FRAME_TYPE_EOD, STp->frame_seq_number++,
3118 STp->logical_blk_num, 0, 0);
3119 break;
3120 case OS_WRITE_NEW_MARK:
3121 osst_init_aux(STp, OS_FRAME_TYPE_MARKER, STp->frame_seq_number++,
3122 STp->logical_blk_num++, 0, blks=1);
3123 break;
3124 case OS_WRITE_HEADER:
3125 osst_init_aux(STp, OS_FRAME_TYPE_HEADER, 0, 0, 0, blks=0);
3126 break;
3127 default: /* probably FILLER */
3128 osst_init_aux(STp, OS_FRAME_TYPE_FILL, 0, 0, 0, 0);
3130 #if DEBUG
3131 if (debugging)
3132 printk(OSST_DEB_MSG "%s:D: Flushing %d bytes, Transfering %d bytes in %d lblocks.\n",
3133 name, offset, transfer, blks);
3134 #endif
3136 SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, transfer, DMA_TO_DEVICE,
3137 STp->timeout, MAX_RETRIES, 1);
3138 *aSRpnt = SRpnt;
3139 if (!SRpnt)
3140 return (-EBUSY);
3142 if ((STp->buffer)->syscall_result != 0) {
3143 #if DEBUG
3144 printk(OSST_DEB_MSG
3145 "%s:D: write sense [0]=0x%02x [2]=%02x [12]=%02x [13]=%02x\n",
3146 name, SRpnt->sense[0], SRpnt->sense[2],
3147 SRpnt->sense[12], SRpnt->sense[13]);
3148 #endif
3149 if ((SRpnt->sense[0] & 0x70) == 0x70 &&
3150 (SRpnt->sense[2] & 0x40) && /* FIXME - SC-30 drive doesn't assert EOM bit */
3151 (SRpnt->sense[2] & 0x0f) == NO_SENSE) {
3152 STp->dirty = 0;
3153 (STp->buffer)->buffer_bytes = 0;
3154 result = (-ENOSPC);
3156 else {
3157 if (osst_write_error_recovery(STp, aSRpnt, 1)) {
3158 printk(KERN_ERR "%s:E: Error on flush write.\n", name);
3159 result = (-EIO);
3162 STps->drv_block = (-1); /* FIXME - even if write recovery succeeds? */
3164 else {
3165 STp->first_frame_position++;
3166 STp->dirty = 0;
3167 (STp->buffer)->buffer_bytes = 0;
3170 #if DEBUG
3171 printk(OSST_DEB_MSG "%s:D: Exit flush write buffer with code %d\n", name, result);
3172 #endif
3173 return result;
3177 /* Flush the tape buffer. The tape will be positioned correctly unless
3178 seek_next is true. */
3179 static int osst_flush_buffer(struct osst_tape * STp, struct osst_request ** aSRpnt, int seek_next)
3181 struct st_partstat * STps;
3182 int backspace = 0, result = 0;
3183 #if DEBUG
3184 char * name = tape_name(STp);
3185 #endif
3188 * If there was a bus reset, block further access
3189 * to this device.
3191 if( STp->pos_unknown)
3192 return (-EIO);
3194 if (STp->ready != ST_READY)
3195 return 0;
3197 STps = &(STp->ps[STp->partition]);
3198 if (STps->rw == ST_WRITING || STp->dirty) { /* Writing */
3199 STp->write_type = OS_WRITE_DATA;
3200 return osst_flush_write_buffer(STp, aSRpnt);
3202 if (STp->block_size == 0)
3203 return 0;
3205 #if DEBUG
3206 printk(OSST_DEB_MSG "%s:D: Reached flush (read) buffer\n", name);
3207 #endif
3209 if (!STp->can_bsr) {
3210 backspace = ((STp->buffer)->buffer_bytes + (STp->buffer)->read_pointer) / STp->block_size -
3211 ((STp->buffer)->read_pointer + STp->block_size - 1 ) / STp->block_size ;
3212 (STp->buffer)->buffer_bytes = 0;
3213 (STp->buffer)->read_pointer = 0;
3214 STp->frame_in_buffer = 0; /* FIXME is this relevant w. OSST? */
3217 if (!seek_next) {
3218 if (STps->eof == ST_FM_HIT) {
3219 result = cross_eof(STp, aSRpnt, 0); /* Back over the EOF hit */
3220 if (!result)
3221 STps->eof = ST_NOEOF;
3222 else {
3223 if (STps->drv_file >= 0)
3224 STps->drv_file++;
3225 STps->drv_block = 0;
3228 if (!result && backspace > 0) /* TODO -- design and run a test case for this */
3229 result = osst_seek_logical_blk(STp, aSRpnt, STp->logical_blk_num - backspace);
3231 else if (STps->eof == ST_FM_HIT) {
3232 if (STps->drv_file >= 0)
3233 STps->drv_file++;
3234 STps->drv_block = 0;
3235 STps->eof = ST_NOEOF;
3238 return result;
3241 static int osst_write_frame(struct osst_tape * STp, struct osst_request ** aSRpnt, int synchronous)
3243 unsigned char cmd[MAX_COMMAND_SIZE];
3244 struct osst_request * SRpnt;
3245 int blks;
3246 #if DEBUG
3247 char * name = tape_name(STp);
3248 #endif
3250 if ((!STp-> raw) && (STp->first_frame_position == 0xbae)) { /* _must_ preserve buffer! */
3251 #if DEBUG
3252 printk(OSST_DEB_MSG "%s:D: Reaching config partition.\n", name);
3253 #endif
3254 if (osst_flush_drive_buffer(STp, aSRpnt) < 0) {
3255 return (-EIO);
3257 /* error recovery may have bumped us past the header partition */
3258 if (osst_get_frame_position(STp, aSRpnt) < 0xbb8) {
3259 #if DEBUG
3260 printk(OSST_DEB_MSG "%s:D: Skipping over config partition.\n", name);
3261 #endif
3262 osst_position_tape_and_confirm(STp, aSRpnt, 0xbb8);
3266 if (STp->poll)
3267 if (osst_wait_frame (STp, aSRpnt, STp->first_frame_position, -48, 120))
3268 if (osst_recover_wait_frame(STp, aSRpnt, 1))
3269 return (-EIO);
3271 // osst_build_stats(STp, &SRpnt);
3273 STp->ps[STp->partition].rw = ST_WRITING;
3274 STp->write_type = OS_WRITE_DATA;
3276 memset(cmd, 0, MAX_COMMAND_SIZE);
3277 cmd[0] = WRITE_6;
3278 cmd[1] = 1;
3279 cmd[4] = 1; /* one frame at a time... */
3280 blks = STp->buffer->buffer_bytes / STp->block_size;
3281 #if DEBUG
3282 if (debugging)
3283 printk(OSST_DEB_MSG "%s:D: Writing %d blocks to frame %d, lblks %d-%d\n", name, blks,
3284 STp->frame_seq_number, STp->logical_blk_num - blks, STp->logical_blk_num - 1);
3285 #endif
3286 osst_init_aux(STp, OS_FRAME_TYPE_DATA, STp->frame_seq_number++,
3287 STp->logical_blk_num - blks, STp->block_size, blks);
3289 #if DEBUG
3290 if (!synchronous)
3291 STp->write_pending = 1;
3292 #endif
3293 SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, OS_FRAME_SIZE, DMA_TO_DEVICE, STp->timeout,
3294 MAX_RETRIES, synchronous);
3295 if (!SRpnt)
3296 return (-EBUSY);
3297 *aSRpnt = SRpnt;
3299 if (synchronous) {
3300 if (STp->buffer->syscall_result != 0) {
3301 #if DEBUG
3302 if (debugging)
3303 printk(OSST_DEB_MSG "%s:D: Error on write:\n", name);
3304 #endif
3305 if ((SRpnt->sense[0] & 0x70) == 0x70 &&
3306 (SRpnt->sense[2] & 0x40)) {
3307 if ((SRpnt->sense[2] & 0x0f) == VOLUME_OVERFLOW)
3308 return (-ENOSPC);
3310 else {
3311 if (osst_write_error_recovery(STp, aSRpnt, 1))
3312 return (-EIO);
3315 else
3316 STp->first_frame_position++;
3319 STp->write_count++;
3321 return 0;
3324 /* Lock or unlock the drive door. Don't use when struct osst_request allocated. */
3325 static int do_door_lock(struct osst_tape * STp, int do_lock)
3327 int retval, cmd;
3329 cmd = do_lock ? SCSI_IOCTL_DOORLOCK : SCSI_IOCTL_DOORUNLOCK;
3330 #if DEBUG
3331 printk(OSST_DEB_MSG "%s:D: %socking drive door.\n", tape_name(STp), do_lock ? "L" : "Unl");
3332 #endif
3333 retval = scsi_ioctl(STp->device, cmd, NULL);
3334 if (!retval) {
3335 STp->door_locked = do_lock ? ST_LOCKED_EXPLICIT : ST_UNLOCKED;
3337 else {
3338 STp->door_locked = ST_LOCK_FAILS;
3340 return retval;
3343 /* Set the internal state after reset */
3344 static void reset_state(struct osst_tape *STp)
3346 int i;
3347 struct st_partstat *STps;
3349 STp->pos_unknown = 0;
3350 for (i = 0; i < ST_NBR_PARTITIONS; i++) {
3351 STps = &(STp->ps[i]);
3352 STps->rw = ST_IDLE;
3353 STps->eof = ST_NOEOF;
3354 STps->at_sm = 0;
3355 STps->last_block_valid = 0;
3356 STps->drv_block = -1;
3357 STps->drv_file = -1;
3362 /* Entry points to osst */
3364 /* Write command */
3365 static ssize_t osst_write(struct file * filp, const char __user * buf, size_t count, loff_t *ppos)
3367 ssize_t total, retval = 0;
3368 ssize_t i, do_count, blks, transfer;
3369 int write_threshold;
3370 int doing_write = 0;
3371 const char __user * b_point;
3372 struct osst_request * SRpnt = NULL;
3373 struct st_modedef * STm;
3374 struct st_partstat * STps;
3375 struct osst_tape * STp = filp->private_data;
3376 char * name = tape_name(STp);
3379 if (mutex_lock_interruptible(&STp->lock))
3380 return (-ERESTARTSYS);
3383 * If we are in the middle of error recovery, don't let anyone
3384 * else try and use this device. Also, if error recovery fails, it
3385 * may try and take the device offline, in which case all further
3386 * access to the device is prohibited.
3388 if( !scsi_block_when_processing_errors(STp->device) ) {
3389 retval = (-ENXIO);
3390 goto out;
3393 if (STp->ready != ST_READY) {
3394 if (STp->ready == ST_NO_TAPE)
3395 retval = (-ENOMEDIUM);
3396 else
3397 retval = (-EIO);
3398 goto out;
3400 STm = &(STp->modes[STp->current_mode]);
3401 if (!STm->defined) {
3402 retval = (-ENXIO);
3403 goto out;
3405 if (count == 0)
3406 goto out;
3409 * If there was a bus reset, block further access
3410 * to this device.
3412 if (STp->pos_unknown) {
3413 retval = (-EIO);
3414 goto out;
3417 #if DEBUG
3418 if (!STp->in_use) {
3419 printk(OSST_DEB_MSG "%s:D: Incorrect device.\n", name);
3420 retval = (-EIO);
3421 goto out;
3423 #endif
3425 if (STp->write_prot) {
3426 retval = (-EACCES);
3427 goto out;
3430 /* Write must be integral number of blocks */
3431 if (STp->block_size != 0 && (count % STp->block_size) != 0) {
3432 printk(KERN_ERR "%s:E: Write (%Zd bytes) not multiple of tape block size (%d%c).\n",
3433 name, count, STp->block_size<1024?
3434 STp->block_size:STp->block_size/1024, STp->block_size<1024?'b':'k');
3435 retval = (-EINVAL);
3436 goto out;
3439 if (STp->first_frame_position >= STp->capacity - OSST_EOM_RESERVE) {
3440 printk(KERN_ERR "%s:E: Write truncated at EOM early warning (frame %d).\n",
3441 name, STp->first_frame_position);
3442 retval = (-ENOSPC);
3443 goto out;
3446 if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED && !do_door_lock(STp, 1))
3447 STp->door_locked = ST_LOCKED_AUTO;
3449 STps = &(STp->ps[STp->partition]);
3451 if (STps->rw == ST_READING) {
3452 #if DEBUG
3453 printk(OSST_DEB_MSG "%s:D: Switching from read to write at file %d, block %d\n", name,
3454 STps->drv_file, STps->drv_block);
3455 #endif
3456 retval = osst_flush_buffer(STp, &SRpnt, 0);
3457 if (retval)
3458 goto out;
3459 STps->rw = ST_IDLE;
3461 if (STps->rw != ST_WRITING) {
3462 /* Are we totally rewriting this tape? */
3463 if (!STp->header_ok ||
3464 (STp->first_frame_position == STp->first_data_ppos && STps->drv_block < 0) ||
3465 (STps->drv_file == 0 && STps->drv_block == 0)) {
3466 STp->wrt_pass_cntr++;
3467 #if DEBUG
3468 printk(OSST_DEB_MSG "%s:D: Allocating next write pass counter: %d\n",
3469 name, STp->wrt_pass_cntr);
3470 #endif
3471 osst_reset_header(STp, &SRpnt);
3472 STps->drv_file = STps->drv_block = 0;
3474 /* Do we know where we'll be writing on the tape? */
3475 else {
3476 if ((STp->fast_open && osst_verify_position(STp, &SRpnt)) ||
3477 STps->drv_file < 0 || STps->drv_block < 0) {
3478 if (STp->first_frame_position == STp->eod_frame_ppos) { /* at EOD */
3479 STps->drv_file = STp->filemark_cnt;
3480 STps->drv_block = 0;
3482 else {
3483 /* We have no idea where the tape is positioned - give up */
3484 #if DEBUG
3485 printk(OSST_DEB_MSG
3486 "%s:D: Cannot write at indeterminate position.\n", name);
3487 #endif
3488 retval = (-EIO);
3489 goto out;
3492 if ((STps->drv_file + STps->drv_block) > 0 && STps->drv_file < STp->filemark_cnt) {
3493 STp->filemark_cnt = STps->drv_file;
3494 STp->last_mark_ppos =
3495 ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[STp->filemark_cnt-1]);
3496 printk(KERN_WARNING
3497 "%s:W: Overwriting file %d with old write pass counter %d\n",
3498 name, STps->drv_file, STp->wrt_pass_cntr);
3499 printk(KERN_WARNING
3500 "%s:W: may lead to stale data being accepted on reading back!\n",
3501 name);
3502 #if DEBUG
3503 printk(OSST_DEB_MSG
3504 "%s:D: resetting filemark count to %d and last mark ppos,lbn to %d,%d\n",
3505 name, STp->filemark_cnt, STp->last_mark_ppos, STp->last_mark_lbn);
3506 #endif
3509 STp->fast_open = 0;
3511 if (!STp->header_ok) {
3512 #if DEBUG
3513 printk(OSST_DEB_MSG "%s:D: Write cannot proceed without valid headers\n", name);
3514 #endif
3515 retval = (-EIO);
3516 goto out;
3519 if ((STp->buffer)->writing) {
3520 if (SRpnt) printk(KERN_ERR "%s:A: Not supposed to have SRpnt at line %d\n", name, __LINE__);
3521 osst_write_behind_check(STp);
3522 if ((STp->buffer)->syscall_result) {
3523 #if DEBUG
3524 if (debugging)
3525 printk(OSST_DEB_MSG "%s:D: Async write error (write) %x.\n", name,
3526 (STp->buffer)->midlevel_result);
3527 #endif
3528 if ((STp->buffer)->midlevel_result == INT_MAX)
3529 STps->eof = ST_EOM_OK;
3530 else
3531 STps->eof = ST_EOM_ERROR;
3534 if (STps->eof == ST_EOM_OK) {
3535 retval = (-ENOSPC);
3536 goto out;
3538 else if (STps->eof == ST_EOM_ERROR) {
3539 retval = (-EIO);
3540 goto out;
3543 /* Check the buffer readability in cases where copy_user might catch
3544 the problems after some tape movement. */
3545 if ((copy_from_user(&i, buf, 1) != 0 ||
3546 copy_from_user(&i, buf + count - 1, 1) != 0)) {
3547 retval = (-EFAULT);
3548 goto out;
3551 if (!STm->do_buffer_writes) {
3552 write_threshold = 1;
3554 else
3555 write_threshold = (STp->buffer)->buffer_blocks * STp->block_size;
3556 if (!STm->do_async_writes)
3557 write_threshold--;
3559 total = count;
3560 #if DEBUG
3561 if (debugging)
3562 printk(OSST_DEB_MSG "%s:D: Writing %d bytes to file %d block %d lblk %d fseq %d fppos %d\n",
3563 name, (int) count, STps->drv_file, STps->drv_block,
3564 STp->logical_blk_num, STp->frame_seq_number, STp->first_frame_position);
3565 #endif
3566 b_point = buf;
3567 while ((STp->buffer)->buffer_bytes + count > write_threshold)
3569 doing_write = 1;
3570 do_count = (STp->buffer)->buffer_blocks * STp->block_size -
3571 (STp->buffer)->buffer_bytes;
3572 if (do_count > count)
3573 do_count = count;
3575 i = append_to_buffer(b_point, STp->buffer, do_count);
3576 if (i) {
3577 retval = i;
3578 goto out;
3581 blks = do_count / STp->block_size;
3582 STp->logical_blk_num += blks; /* logical_blk_num is incremented as data is moved from user */
3584 i = osst_write_frame(STp, &SRpnt, 1);
3586 if (i == (-ENOSPC)) {
3587 transfer = STp->buffer->writing; /* FIXME -- check this logic */
3588 if (transfer <= do_count) {
3589 filp->f_pos += do_count - transfer;
3590 count -= do_count - transfer;
3591 if (STps->drv_block >= 0) {
3592 STps->drv_block += (do_count - transfer) / STp->block_size;
3594 STps->eof = ST_EOM_OK;
3595 retval = (-ENOSPC); /* EOM within current request */
3596 #if DEBUG
3597 if (debugging)
3598 printk(OSST_DEB_MSG "%s:D: EOM with %d bytes unwritten.\n",
3599 name, (int) transfer);
3600 #endif
3602 else {
3603 STps->eof = ST_EOM_ERROR;
3604 STps->drv_block = (-1); /* Too cautious? */
3605 retval = (-EIO); /* EOM for old data */
3606 #if DEBUG
3607 if (debugging)
3608 printk(OSST_DEB_MSG "%s:D: EOM with lost data.\n", name);
3609 #endif
3612 else
3613 retval = i;
3615 if (retval < 0) {
3616 if (SRpnt != NULL) {
3617 osst_release_request(SRpnt);
3618 SRpnt = NULL;
3620 STp->buffer->buffer_bytes = 0;
3621 STp->dirty = 0;
3622 if (count < total)
3623 retval = total - count;
3624 goto out;
3627 filp->f_pos += do_count;
3628 b_point += do_count;
3629 count -= do_count;
3630 if (STps->drv_block >= 0) {
3631 STps->drv_block += blks;
3633 STp->buffer->buffer_bytes = 0;
3634 STp->dirty = 0;
3635 } /* end while write threshold exceeded */
3637 if (count != 0) {
3638 STp->dirty = 1;
3639 i = append_to_buffer(b_point, STp->buffer, count);
3640 if (i) {
3641 retval = i;
3642 goto out;
3644 blks = count / STp->block_size;
3645 STp->logical_blk_num += blks;
3646 if (STps->drv_block >= 0) {
3647 STps->drv_block += blks;
3649 filp->f_pos += count;
3650 count = 0;
3653 if (doing_write && (STp->buffer)->syscall_result != 0) {
3654 retval = (STp->buffer)->syscall_result;
3655 goto out;
3658 if (STm->do_async_writes && ((STp->buffer)->buffer_bytes >= STp->write_threshold)) {
3659 /* Schedule an asynchronous write */
3660 (STp->buffer)->writing = ((STp->buffer)->buffer_bytes /
3661 STp->block_size) * STp->block_size;
3662 STp->dirty = !((STp->buffer)->writing ==
3663 (STp->buffer)->buffer_bytes);
3665 i = osst_write_frame(STp, &SRpnt, 0);
3666 if (i < 0) {
3667 retval = (-EIO);
3668 goto out;
3670 SRpnt = NULL; /* Prevent releasing this request! */
3672 STps->at_sm &= (total == 0);
3673 if (total > 0)
3674 STps->eof = ST_NOEOF;
3676 retval = total;
3678 out:
3679 if (SRpnt != NULL) osst_release_request(SRpnt);
3681 mutex_unlock(&STp->lock);
3683 return retval;
3687 /* Read command */
3688 static ssize_t osst_read(struct file * filp, char __user * buf, size_t count, loff_t *ppos)
3690 ssize_t total, retval = 0;
3691 ssize_t i, transfer;
3692 int special;
3693 struct st_modedef * STm;
3694 struct st_partstat * STps;
3695 struct osst_request * SRpnt = NULL;
3696 struct osst_tape * STp = filp->private_data;
3697 char * name = tape_name(STp);
3700 if (mutex_lock_interruptible(&STp->lock))
3701 return (-ERESTARTSYS);
3704 * If we are in the middle of error recovery, don't let anyone
3705 * else try and use this device. Also, if error recovery fails, it
3706 * may try and take the device offline, in which case all further
3707 * access to the device is prohibited.
3709 if( !scsi_block_when_processing_errors(STp->device) ) {
3710 retval = (-ENXIO);
3711 goto out;
3714 if (STp->ready != ST_READY) {
3715 if (STp->ready == ST_NO_TAPE)
3716 retval = (-ENOMEDIUM);
3717 else
3718 retval = (-EIO);
3719 goto out;
3721 STm = &(STp->modes[STp->current_mode]);
3722 if (!STm->defined) {
3723 retval = (-ENXIO);
3724 goto out;
3726 #if DEBUG
3727 if (!STp->in_use) {
3728 printk(OSST_DEB_MSG "%s:D: Incorrect device.\n", name);
3729 retval = (-EIO);
3730 goto out;
3732 #endif
3733 /* Must have initialized medium */
3734 if (!STp->header_ok) {
3735 retval = (-EIO);
3736 goto out;
3739 if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED && !do_door_lock(STp, 1))
3740 STp->door_locked = ST_LOCKED_AUTO;
3742 STps = &(STp->ps[STp->partition]);
3743 if (STps->rw == ST_WRITING) {
3744 retval = osst_flush_buffer(STp, &SRpnt, 0);
3745 if (retval)
3746 goto out;
3747 STps->rw = ST_IDLE;
3748 /* FIXME -- this may leave the tape without EOD and up2date headers */
3751 if ((count % STp->block_size) != 0) {
3752 printk(KERN_WARNING
3753 "%s:W: Read (%Zd bytes) not multiple of tape block size (%d%c).\n", name, count,
3754 STp->block_size<1024?STp->block_size:STp->block_size/1024, STp->block_size<1024?'b':'k');
3757 #if DEBUG
3758 if (debugging && STps->eof != ST_NOEOF)
3759 printk(OSST_DEB_MSG "%s:D: EOF/EOM flag up (%d). Bytes %d\n", name,
3760 STps->eof, (STp->buffer)->buffer_bytes);
3761 #endif
3762 if ((STp->buffer)->buffer_bytes == 0 &&
3763 STps->eof >= ST_EOD_1) {
3764 if (STps->eof < ST_EOD) {
3765 STps->eof += 1;
3766 retval = 0;
3767 goto out;
3769 retval = (-EIO); /* EOM or Blank Check */
3770 goto out;
3773 /* Check the buffer writability before any tape movement. Don't alter
3774 buffer data. */
3775 if (copy_from_user(&i, buf, 1) != 0 ||
3776 copy_to_user (buf, &i, 1) != 0 ||
3777 copy_from_user(&i, buf + count - 1, 1) != 0 ||
3778 copy_to_user (buf + count - 1, &i, 1) != 0) {
3779 retval = (-EFAULT);
3780 goto out;
3783 /* Loop until enough data in buffer or a special condition found */
3784 for (total = 0, special = 0; total < count - STp->block_size + 1 && !special; ) {
3786 /* Get new data if the buffer is empty */
3787 if ((STp->buffer)->buffer_bytes == 0) {
3788 if (STps->eof == ST_FM_HIT)
3789 break;
3790 special = osst_get_logical_frame(STp, &SRpnt, STp->frame_seq_number, 0);
3791 if (special < 0) { /* No need to continue read */
3792 STp->frame_in_buffer = 0;
3793 retval = special;
3794 goto out;
3798 /* Move the data from driver buffer to user buffer */
3799 if ((STp->buffer)->buffer_bytes > 0) {
3800 #if DEBUG
3801 if (debugging && STps->eof != ST_NOEOF)
3802 printk(OSST_DEB_MSG "%s:D: EOF up (%d). Left %d, needed %d.\n", name,
3803 STps->eof, (STp->buffer)->buffer_bytes, (int) (count - total));
3804 #endif
3805 /* force multiple of block size, note block_size may have been adjusted */
3806 transfer = (((STp->buffer)->buffer_bytes < count - total ?
3807 (STp->buffer)->buffer_bytes : count - total)/
3808 STp->block_size) * STp->block_size;
3810 if (transfer == 0) {
3811 printk(KERN_WARNING
3812 "%s:W: Nothing can be transfered, requested %Zd, tape block size (%d%c).\n",
3813 name, count, STp->block_size < 1024?
3814 STp->block_size:STp->block_size/1024,
3815 STp->block_size<1024?'b':'k');
3816 break;
3818 i = from_buffer(STp->buffer, buf, transfer);
3819 if (i) {
3820 retval = i;
3821 goto out;
3823 STp->logical_blk_num += transfer / STp->block_size;
3824 STps->drv_block += transfer / STp->block_size;
3825 filp->f_pos += transfer;
3826 buf += transfer;
3827 total += transfer;
3830 if ((STp->buffer)->buffer_bytes == 0) {
3831 #if DEBUG
3832 if (debugging)
3833 printk(OSST_DEB_MSG "%s:D: Finished with frame %d\n",
3834 name, STp->frame_seq_number);
3835 #endif
3836 STp->frame_in_buffer = 0;
3837 STp->frame_seq_number++; /* frame to look for next time */
3839 } /* for (total = 0, special = 0; total < count && !special; ) */
3841 /* Change the eof state if no data from tape or buffer */
3842 if (total == 0) {
3843 if (STps->eof == ST_FM_HIT) {
3844 STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD_2:ST_FM;
3845 STps->drv_block = 0;
3846 if (STps->drv_file >= 0)
3847 STps->drv_file++;
3849 else if (STps->eof == ST_EOD_1) {
3850 STps->eof = ST_EOD_2;
3851 if (STps->drv_block > 0 && STps->drv_file >= 0)
3852 STps->drv_file++;
3853 STps->drv_block = 0;
3855 else if (STps->eof == ST_EOD_2)
3856 STps->eof = ST_EOD;
3858 else if (STps->eof == ST_FM)
3859 STps->eof = ST_NOEOF;
3861 retval = total;
3863 out:
3864 if (SRpnt != NULL) osst_release_request(SRpnt);
3866 mutex_unlock(&STp->lock);
3868 return retval;
3872 /* Set the driver options */
3873 static void osst_log_options(struct osst_tape *STp, struct st_modedef *STm, char *name)
3875 printk(KERN_INFO
3876 "%s:I: Mode %d options: buffer writes: %d, async writes: %d, read ahead: %d\n",
3877 name, STp->current_mode, STm->do_buffer_writes, STm->do_async_writes,
3878 STm->do_read_ahead);
3879 printk(KERN_INFO
3880 "%s:I: can bsr: %d, two FMs: %d, fast mteom: %d, auto lock: %d,\n",
3881 name, STp->can_bsr, STp->two_fm, STp->fast_mteom, STp->do_auto_lock);
3882 printk(KERN_INFO
3883 "%s:I: defs for wr: %d, no block limits: %d, partitions: %d, s2 log: %d\n",
3884 name, STm->defaults_for_writes, STp->omit_blklims, STp->can_partitions,
3885 STp->scsi2_logical);
3886 printk(KERN_INFO
3887 "%s:I: sysv: %d\n", name, STm->sysv);
3888 #if DEBUG
3889 printk(KERN_INFO
3890 "%s:D: debugging: %d\n",
3891 name, debugging);
3892 #endif
3896 static int osst_set_options(struct osst_tape *STp, long options)
3898 int value;
3899 long code;
3900 struct st_modedef * STm;
3901 char * name = tape_name(STp);
3903 STm = &(STp->modes[STp->current_mode]);
3904 if (!STm->defined) {
3905 memcpy(STm, &(STp->modes[0]), sizeof(*STm));
3906 modes_defined = 1;
3907 #if DEBUG
3908 if (debugging)
3909 printk(OSST_DEB_MSG "%s:D: Initialized mode %d definition from mode 0\n",
3910 name, STp->current_mode);
3911 #endif
3914 code = options & MT_ST_OPTIONS;
3915 if (code == MT_ST_BOOLEANS) {
3916 STm->do_buffer_writes = (options & MT_ST_BUFFER_WRITES) != 0;
3917 STm->do_async_writes = (options & MT_ST_ASYNC_WRITES) != 0;
3918 STm->defaults_for_writes = (options & MT_ST_DEF_WRITES) != 0;
3919 STm->do_read_ahead = (options & MT_ST_READ_AHEAD) != 0;
3920 STp->two_fm = (options & MT_ST_TWO_FM) != 0;
3921 STp->fast_mteom = (options & MT_ST_FAST_MTEOM) != 0;
3922 STp->do_auto_lock = (options & MT_ST_AUTO_LOCK) != 0;
3923 STp->can_bsr = (options & MT_ST_CAN_BSR) != 0;
3924 STp->omit_blklims = (options & MT_ST_NO_BLKLIMS) != 0;
3925 if ((STp->device)->scsi_level >= SCSI_2)
3926 STp->can_partitions = (options & MT_ST_CAN_PARTITIONS) != 0;
3927 STp->scsi2_logical = (options & MT_ST_SCSI2LOGICAL) != 0;
3928 STm->sysv = (options & MT_ST_SYSV) != 0;
3929 #if DEBUG
3930 debugging = (options & MT_ST_DEBUGGING) != 0;
3931 #endif
3932 osst_log_options(STp, STm, name);
3934 else if (code == MT_ST_SETBOOLEANS || code == MT_ST_CLEARBOOLEANS) {
3935 value = (code == MT_ST_SETBOOLEANS);
3936 if ((options & MT_ST_BUFFER_WRITES) != 0)
3937 STm->do_buffer_writes = value;
3938 if ((options & MT_ST_ASYNC_WRITES) != 0)
3939 STm->do_async_writes = value;
3940 if ((options & MT_ST_DEF_WRITES) != 0)
3941 STm->defaults_for_writes = value;
3942 if ((options & MT_ST_READ_AHEAD) != 0)
3943 STm->do_read_ahead = value;
3944 if ((options & MT_ST_TWO_FM) != 0)
3945 STp->two_fm = value;
3946 if ((options & MT_ST_FAST_MTEOM) != 0)
3947 STp->fast_mteom = value;
3948 if ((options & MT_ST_AUTO_LOCK) != 0)
3949 STp->do_auto_lock = value;
3950 if ((options & MT_ST_CAN_BSR) != 0)
3951 STp->can_bsr = value;
3952 if ((options & MT_ST_NO_BLKLIMS) != 0)
3953 STp->omit_blklims = value;
3954 if ((STp->device)->scsi_level >= SCSI_2 &&
3955 (options & MT_ST_CAN_PARTITIONS) != 0)
3956 STp->can_partitions = value;
3957 if ((options & MT_ST_SCSI2LOGICAL) != 0)
3958 STp->scsi2_logical = value;
3959 if ((options & MT_ST_SYSV) != 0)
3960 STm->sysv = value;
3961 #if DEBUG
3962 if ((options & MT_ST_DEBUGGING) != 0)
3963 debugging = value;
3964 #endif
3965 osst_log_options(STp, STm, name);
3967 else if (code == MT_ST_WRITE_THRESHOLD) {
3968 value = (options & ~MT_ST_OPTIONS) * ST_KILOBYTE;
3969 if (value < 1 || value > osst_buffer_size) {
3970 printk(KERN_WARNING "%s:W: Write threshold %d too small or too large.\n",
3971 name, value);
3972 return (-EIO);
3974 STp->write_threshold = value;
3975 printk(KERN_INFO "%s:I: Write threshold set to %d bytes.\n",
3976 name, value);
3978 else if (code == MT_ST_DEF_BLKSIZE) {
3979 value = (options & ~MT_ST_OPTIONS);
3980 if (value == ~MT_ST_OPTIONS) {
3981 STm->default_blksize = (-1);
3982 printk(KERN_INFO "%s:I: Default block size disabled.\n", name);
3984 else {
3985 if (value < 512 || value > OS_DATA_SIZE || OS_DATA_SIZE % value) {
3986 printk(KERN_WARNING "%s:W: Default block size cannot be set to %d.\n",
3987 name, value);
3988 return (-EINVAL);
3990 STm->default_blksize = value;
3991 printk(KERN_INFO "%s:I: Default block size set to %d bytes.\n",
3992 name, STm->default_blksize);
3995 else if (code == MT_ST_TIMEOUTS) {
3996 value = (options & ~MT_ST_OPTIONS);
3997 if ((value & MT_ST_SET_LONG_TIMEOUT) != 0) {
3998 STp->long_timeout = (value & ~MT_ST_SET_LONG_TIMEOUT) * HZ;
3999 printk(KERN_INFO "%s:I: Long timeout set to %d seconds.\n", name,
4000 (value & ~MT_ST_SET_LONG_TIMEOUT));
4002 else {
4003 STp->timeout = value * HZ;
4004 printk(KERN_INFO "%s:I: Normal timeout set to %d seconds.\n", name, value);
4007 else if (code == MT_ST_DEF_OPTIONS) {
4008 code = (options & ~MT_ST_CLEAR_DEFAULT);
4009 value = (options & MT_ST_CLEAR_DEFAULT);
4010 if (code == MT_ST_DEF_DENSITY) {
4011 if (value == MT_ST_CLEAR_DEFAULT) {
4012 STm->default_density = (-1);
4013 printk(KERN_INFO "%s:I: Density default disabled.\n", name);
4015 else {
4016 STm->default_density = value & 0xff;
4017 printk(KERN_INFO "%s:I: Density default set to %x\n",
4018 name, STm->default_density);
4021 else if (code == MT_ST_DEF_DRVBUFFER) {
4022 if (value == MT_ST_CLEAR_DEFAULT) {
4023 STp->default_drvbuffer = 0xff;
4024 printk(KERN_INFO "%s:I: Drive buffer default disabled.\n", name);
4026 else {
4027 STp->default_drvbuffer = value & 7;
4028 printk(KERN_INFO "%s:I: Drive buffer default set to %x\n",
4029 name, STp->default_drvbuffer);
4032 else if (code == MT_ST_DEF_COMPRESSION) {
4033 if (value == MT_ST_CLEAR_DEFAULT) {
4034 STm->default_compression = ST_DONT_TOUCH;
4035 printk(KERN_INFO "%s:I: Compression default disabled.\n", name);
4037 else {
4038 STm->default_compression = (value & 1 ? ST_YES : ST_NO);
4039 printk(KERN_INFO "%s:I: Compression default set to %x\n",
4040 name, (value & 1));
4044 else
4045 return (-EIO);
4047 return 0;
4051 /* Internal ioctl function */
4052 static int osst_int_ioctl(struct osst_tape * STp, struct osst_request ** aSRpnt,
4053 unsigned int cmd_in, unsigned long arg)
4055 int timeout;
4056 long ltmp;
4057 int i, ioctl_result;
4058 int chg_eof = 1;
4059 unsigned char cmd[MAX_COMMAND_SIZE];
4060 struct osst_request * SRpnt = * aSRpnt;
4061 struct st_partstat * STps;
4062 int fileno, blkno, at_sm, frame_seq_numbr, logical_blk_num;
4063 int datalen = 0, direction = DMA_NONE;
4064 char * name = tape_name(STp);
4066 if (STp->ready != ST_READY && cmd_in != MTLOAD) {
4067 if (STp->ready == ST_NO_TAPE)
4068 return (-ENOMEDIUM);
4069 else
4070 return (-EIO);
4072 timeout = STp->long_timeout;
4073 STps = &(STp->ps[STp->partition]);
4074 fileno = STps->drv_file;
4075 blkno = STps->drv_block;
4076 at_sm = STps->at_sm;
4077 frame_seq_numbr = STp->frame_seq_number;
4078 logical_blk_num = STp->logical_blk_num;
4080 memset(cmd, 0, MAX_COMMAND_SIZE);
4081 switch (cmd_in) {
4082 case MTFSFM:
4083 chg_eof = 0; /* Changed from the FSF after this */
4084 case MTFSF:
4085 if (STp->raw)
4086 return (-EIO);
4087 if (STp->linux_media)
4088 ioctl_result = osst_space_over_filemarks_forward_fast(STp, &SRpnt, cmd_in, arg);
4089 else
4090 ioctl_result = osst_space_over_filemarks_forward_slow(STp, &SRpnt, cmd_in, arg);
4091 if (fileno >= 0)
4092 fileno += arg;
4093 blkno = 0;
4094 at_sm &= (arg == 0);
4095 goto os_bypass;
4097 case MTBSF:
4098 chg_eof = 0; /* Changed from the FSF after this */
4099 case MTBSFM:
4100 if (STp->raw)
4101 return (-EIO);
4102 ioctl_result = osst_space_over_filemarks_backward(STp, &SRpnt, cmd_in, arg);
4103 if (fileno >= 0)
4104 fileno -= arg;
4105 blkno = (-1); /* We can't know the block number */
4106 at_sm &= (arg == 0);
4107 goto os_bypass;
4109 case MTFSR:
4110 case MTBSR:
4111 #if DEBUG
4112 if (debugging)
4113 printk(OSST_DEB_MSG "%s:D: Skipping %lu blocks %s from logical block %d\n",
4114 name, arg, cmd_in==MTFSR?"forward":"backward", logical_blk_num);
4115 #endif
4116 if (cmd_in == MTFSR) {
4117 logical_blk_num += arg;
4118 if (blkno >= 0) blkno += arg;
4120 else {
4121 logical_blk_num -= arg;
4122 if (blkno >= 0) blkno -= arg;
4124 ioctl_result = osst_seek_logical_blk(STp, &SRpnt, logical_blk_num);
4125 fileno = STps->drv_file;
4126 blkno = STps->drv_block;
4127 at_sm &= (arg == 0);
4128 goto os_bypass;
4130 case MTFSS:
4131 cmd[0] = SPACE;
4132 cmd[1] = 0x04; /* Space Setmarks */ /* FIXME -- OS can't do this? */
4133 cmd[2] = (arg >> 16);
4134 cmd[3] = (arg >> 8);
4135 cmd[4] = arg;
4136 #if DEBUG
4137 if (debugging)
4138 printk(OSST_DEB_MSG "%s:D: Spacing tape forward %d setmarks.\n", name,
4139 cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
4140 #endif
4141 if (arg != 0) {
4142 blkno = fileno = (-1);
4143 at_sm = 1;
4145 break;
4146 case MTBSS:
4147 cmd[0] = SPACE;
4148 cmd[1] = 0x04; /* Space Setmarks */ /* FIXME -- OS can't do this? */
4149 ltmp = (-arg);
4150 cmd[2] = (ltmp >> 16);
4151 cmd[3] = (ltmp >> 8);
4152 cmd[4] = ltmp;
4153 #if DEBUG
4154 if (debugging) {
4155 if (cmd[2] & 0x80)
4156 ltmp = 0xff000000;
4157 ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4];
4158 printk(OSST_DEB_MSG "%s:D: Spacing tape backward %ld setmarks.\n",
4159 name, (-ltmp));
4161 #endif
4162 if (arg != 0) {
4163 blkno = fileno = (-1);
4164 at_sm = 1;
4166 break;
4167 case MTWEOF:
4168 if ((STps->rw == ST_WRITING || STp->dirty) && !STp->pos_unknown) {
4169 STp->write_type = OS_WRITE_DATA;
4170 ioctl_result = osst_flush_write_buffer(STp, &SRpnt);
4171 } else
4172 ioctl_result = 0;
4173 #if DEBUG
4174 if (debugging)
4175 printk(OSST_DEB_MSG "%s:D: Writing %ld filemark(s).\n", name, arg);
4176 #endif
4177 for (i=0; i<arg; i++)
4178 ioctl_result |= osst_write_filemark(STp, &SRpnt);
4179 if (fileno >= 0) fileno += arg;
4180 if (blkno >= 0) blkno = 0;
4181 goto os_bypass;
4183 case MTWSM:
4184 if (STp->write_prot)
4185 return (-EACCES);
4186 if (!STp->raw)
4187 return 0;
4188 cmd[0] = WRITE_FILEMARKS; /* FIXME -- need OS version */
4189 if (cmd_in == MTWSM)
4190 cmd[1] = 2;
4191 cmd[2] = (arg >> 16);
4192 cmd[3] = (arg >> 8);
4193 cmd[4] = arg;
4194 timeout = STp->timeout;
4195 #if DEBUG
4196 if (debugging)
4197 printk(OSST_DEB_MSG "%s:D: Writing %d setmark(s).\n", name,
4198 cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
4199 #endif
4200 if (fileno >= 0)
4201 fileno += arg;
4202 blkno = 0;
4203 at_sm = (cmd_in == MTWSM);
4204 break;
4205 case MTOFFL:
4206 case MTLOAD:
4207 case MTUNLOAD:
4208 case MTRETEN:
4209 cmd[0] = START_STOP;
4210 cmd[1] = 1; /* Don't wait for completion */
4211 if (cmd_in == MTLOAD) {
4212 if (STp->ready == ST_NO_TAPE)
4213 cmd[4] = 4; /* open tray */
4214 else
4215 cmd[4] = 1; /* load */
4217 if (cmd_in == MTRETEN)
4218 cmd[4] = 3; /* retension then mount */
4219 if (cmd_in == MTOFFL)
4220 cmd[4] = 4; /* rewind then eject */
4221 timeout = STp->timeout;
4222 #if DEBUG
4223 if (debugging) {
4224 switch (cmd_in) {
4225 case MTUNLOAD:
4226 printk(OSST_DEB_MSG "%s:D: Unloading tape.\n", name);
4227 break;
4228 case MTLOAD:
4229 printk(OSST_DEB_MSG "%s:D: Loading tape.\n", name);
4230 break;
4231 case MTRETEN:
4232 printk(OSST_DEB_MSG "%s:D: Retensioning tape.\n", name);
4233 break;
4234 case MTOFFL:
4235 printk(OSST_DEB_MSG "%s:D: Ejecting tape.\n", name);
4236 break;
4239 #endif
4240 fileno = blkno = at_sm = frame_seq_numbr = logical_blk_num = 0 ;
4241 break;
4242 case MTNOP:
4243 #if DEBUG
4244 if (debugging)
4245 printk(OSST_DEB_MSG "%s:D: No-op on tape.\n", name);
4246 #endif
4247 return 0; /* Should do something ? */
4248 break;
4249 case MTEOM:
4250 #if DEBUG
4251 if (debugging)
4252 printk(OSST_DEB_MSG "%s:D: Spacing to end of recorded medium.\n", name);
4253 #endif
4254 if ((osst_position_tape_and_confirm(STp, &SRpnt, STp->eod_frame_ppos) < 0) ||
4255 (osst_get_logical_frame(STp, &SRpnt, -1, 0) < 0)) {
4256 ioctl_result = -EIO;
4257 goto os_bypass;
4259 if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_EOD) {
4260 #if DEBUG
4261 printk(OSST_DEB_MSG "%s:D: No EOD frame found where expected.\n", name);
4262 #endif
4263 ioctl_result = -EIO;
4264 goto os_bypass;
4266 ioctl_result = osst_set_frame_position(STp, &SRpnt, STp->eod_frame_ppos, 0);
4267 fileno = STp->filemark_cnt;
4268 blkno = at_sm = 0;
4269 goto os_bypass;
4271 case MTERASE:
4272 if (STp->write_prot)
4273 return (-EACCES);
4274 ioctl_result = osst_reset_header(STp, &SRpnt);
4275 i = osst_write_eod(STp, &SRpnt);
4276 if (i < ioctl_result) ioctl_result = i;
4277 i = osst_position_tape_and_confirm(STp, &SRpnt, STp->eod_frame_ppos);
4278 if (i < ioctl_result) ioctl_result = i;
4279 fileno = blkno = at_sm = 0 ;
4280 goto os_bypass;
4282 case MTREW:
4283 cmd[0] = REZERO_UNIT; /* rewind */
4284 cmd[1] = 1;
4285 #if DEBUG
4286 if (debugging)
4287 printk(OSST_DEB_MSG "%s:D: Rewinding tape, Immed=%d.\n", name, cmd[1]);
4288 #endif
4289 fileno = blkno = at_sm = frame_seq_numbr = logical_blk_num = 0 ;
4290 break;
4292 case MTSETBLK: /* Set block length */
4293 if ((STps->drv_block == 0 ) &&
4294 !STp->dirty &&
4295 ((STp->buffer)->buffer_bytes == 0) &&
4296 ((arg & MT_ST_BLKSIZE_MASK) >= 512 ) &&
4297 ((arg & MT_ST_BLKSIZE_MASK) <= OS_DATA_SIZE) &&
4298 !(OS_DATA_SIZE % (arg & MT_ST_BLKSIZE_MASK)) ) {
4300 * Only allowed to change the block size if you opened the
4301 * device at the beginning of a file before writing anything.
4302 * Note, that when reading, changing block_size is futile,
4303 * as the size used when writing overrides it.
4305 STp->block_size = (arg & MT_ST_BLKSIZE_MASK);
4306 printk(KERN_INFO "%s:I: Block size set to %d bytes.\n",
4307 name, STp->block_size);
4308 return 0;
4310 case MTSETDENSITY: /* Set tape density */
4311 case MTSETDRVBUFFER: /* Set drive buffering */
4312 case SET_DENS_AND_BLK: /* Set density and block size */
4313 chg_eof = 0;
4314 if (STp->dirty || (STp->buffer)->buffer_bytes != 0)
4315 return (-EIO); /* Not allowed if data in buffer */
4316 if ((cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) &&
4317 (arg & MT_ST_BLKSIZE_MASK) != 0 &&
4318 (arg & MT_ST_BLKSIZE_MASK) != STp->block_size ) {
4319 printk(KERN_WARNING "%s:W: Illegal to set block size to %d%s.\n",
4320 name, (int)(arg & MT_ST_BLKSIZE_MASK),
4321 (OS_DATA_SIZE % (arg & MT_ST_BLKSIZE_MASK))?"":" now");
4322 return (-EINVAL);
4324 return 0; /* FIXME silently ignore if block size didn't change */
4326 default:
4327 return (-ENOSYS);
4330 SRpnt = osst_do_scsi(SRpnt, STp, cmd, datalen, direction, timeout, MAX_RETRIES, 1);
4332 ioctl_result = (STp->buffer)->syscall_result;
4334 if (!SRpnt) {
4335 #if DEBUG
4336 printk(OSST_DEB_MSG "%s:D: Couldn't exec scsi cmd for IOCTL\n", name);
4337 #endif
4338 return ioctl_result;
4341 if (!ioctl_result) { /* SCSI command successful */
4342 STp->frame_seq_number = frame_seq_numbr;
4343 STp->logical_blk_num = logical_blk_num;
4346 os_bypass:
4347 #if DEBUG
4348 if (debugging)
4349 printk(OSST_DEB_MSG "%s:D: IOCTL (%d) Result=%d\n", name, cmd_in, ioctl_result);
4350 #endif
4352 if (!ioctl_result) { /* success */
4354 if (cmd_in == MTFSFM) {
4355 fileno--;
4356 blkno--;
4358 if (cmd_in == MTBSFM) {
4359 fileno++;
4360 blkno++;
4362 STps->drv_block = blkno;
4363 STps->drv_file = fileno;
4364 STps->at_sm = at_sm;
4366 if (cmd_in == MTEOM)
4367 STps->eof = ST_EOD;
4368 else if ((cmd_in == MTFSFM || cmd_in == MTBSF) && STps->eof == ST_FM_HIT) {
4369 ioctl_result = osst_seek_logical_blk(STp, &SRpnt, STp->logical_blk_num-1);
4370 STps->drv_block++;
4371 STp->logical_blk_num++;
4372 STp->frame_seq_number++;
4373 STp->frame_in_buffer = 0;
4374 STp->buffer->read_pointer = 0;
4376 else if (cmd_in == MTFSF)
4377 STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD:ST_FM;
4378 else if (chg_eof)
4379 STps->eof = ST_NOEOF;
4381 if (cmd_in == MTOFFL || cmd_in == MTUNLOAD)
4382 STp->rew_at_close = 0;
4383 else if (cmd_in == MTLOAD) {
4384 for (i=0; i < ST_NBR_PARTITIONS; i++) {
4385 STp->ps[i].rw = ST_IDLE;
4386 STp->ps[i].last_block_valid = 0;/* FIXME - where else is this field maintained? */
4388 STp->partition = 0;
4391 if (cmd_in == MTREW) {
4392 ioctl_result = osst_position_tape_and_confirm(STp, &SRpnt, STp->first_data_ppos);
4393 if (ioctl_result > 0)
4394 ioctl_result = 0;
4397 } else if (cmd_in == MTBSF || cmd_in == MTBSFM ) {
4398 if (osst_position_tape_and_confirm(STp, &SRpnt, STp->first_data_ppos) < 0)
4399 STps->drv_file = STps->drv_block = -1;
4400 else
4401 STps->drv_file = STps->drv_block = 0;
4402 STps->eof = ST_NOEOF;
4403 } else if (cmd_in == MTFSF || cmd_in == MTFSFM) {
4404 if (osst_position_tape_and_confirm(STp, &SRpnt, STp->eod_frame_ppos) < 0)
4405 STps->drv_file = STps->drv_block = -1;
4406 else {
4407 STps->drv_file = STp->filemark_cnt;
4408 STps->drv_block = 0;
4410 STps->eof = ST_EOD;
4411 } else if (cmd_in == MTBSR || cmd_in == MTFSR || cmd_in == MTWEOF || cmd_in == MTEOM) {
4412 STps->drv_file = STps->drv_block = (-1);
4413 STps->eof = ST_NOEOF;
4414 STp->header_ok = 0;
4415 } else if (cmd_in == MTERASE) {
4416 STp->header_ok = 0;
4417 } else if (SRpnt) { /* SCSI command was not completely successful. */
4418 if (SRpnt->sense[2] & 0x40) {
4419 STps->eof = ST_EOM_OK;
4420 STps->drv_block = 0;
4422 if (chg_eof)
4423 STps->eof = ST_NOEOF;
4425 if ((SRpnt->sense[2] & 0x0f) == BLANK_CHECK)
4426 STps->eof = ST_EOD;
4428 if (cmd_in == MTLOAD && osst_wait_for_medium(STp, &SRpnt, 60))
4429 ioctl_result = osst_wait_ready(STp, &SRpnt, 5 * 60, OSST_WAIT_POSITION_COMPLETE);
4431 *aSRpnt = SRpnt;
4433 return ioctl_result;
4437 /* Open the device */
4438 static int __os_scsi_tape_open(struct inode * inode, struct file * filp)
4440 unsigned short flags;
4441 int i, b_size, new_session = 0, retval = 0;
4442 unsigned char cmd[MAX_COMMAND_SIZE];
4443 struct osst_request * SRpnt = NULL;
4444 struct osst_tape * STp;
4445 struct st_modedef * STm;
4446 struct st_partstat * STps;
4447 char * name;
4448 int dev = TAPE_NR(inode);
4449 int mode = TAPE_MODE(inode);
4452 * We really want to do nonseekable_open(inode, filp); here, but some
4453 * versions of tar incorrectly call lseek on tapes and bail out if that
4454 * fails. So we disallow pread() and pwrite(), but permit lseeks.
4456 filp->f_mode &= ~(FMODE_PREAD | FMODE_PWRITE);
4458 write_lock(&os_scsi_tapes_lock);
4459 if (dev >= osst_max_dev || os_scsi_tapes == NULL ||
4460 (STp = os_scsi_tapes[dev]) == NULL || !STp->device) {
4461 write_unlock(&os_scsi_tapes_lock);
4462 return (-ENXIO);
4465 name = tape_name(STp);
4467 if (STp->in_use) {
4468 write_unlock(&os_scsi_tapes_lock);
4469 #if DEBUG
4470 printk(OSST_DEB_MSG "%s:D: Device already in use.\n", name);
4471 #endif
4472 return (-EBUSY);
4474 if (scsi_device_get(STp->device)) {
4475 write_unlock(&os_scsi_tapes_lock);
4476 #if DEBUG
4477 printk(OSST_DEB_MSG "%s:D: Failed scsi_device_get.\n", name);
4478 #endif
4479 return (-ENXIO);
4481 filp->private_data = STp;
4482 STp->in_use = 1;
4483 write_unlock(&os_scsi_tapes_lock);
4484 STp->rew_at_close = TAPE_REWIND(inode);
4486 if( !scsi_block_when_processing_errors(STp->device) ) {
4487 return -ENXIO;
4490 if (mode != STp->current_mode) {
4491 #if DEBUG
4492 if (debugging)
4493 printk(OSST_DEB_MSG "%s:D: Mode change from %d to %d.\n",
4494 name, STp->current_mode, mode);
4495 #endif
4496 new_session = 1;
4497 STp->current_mode = mode;
4499 STm = &(STp->modes[STp->current_mode]);
4501 flags = filp->f_flags;
4502 STp->write_prot = ((flags & O_ACCMODE) == O_RDONLY);
4504 STp->raw = TAPE_IS_RAW(inode);
4505 if (STp->raw)
4506 STp->header_ok = 0;
4508 /* Allocate data segments for this device's tape buffer */
4509 if (!enlarge_buffer(STp->buffer, STp->restr_dma)) {
4510 printk(KERN_ERR "%s:E: Unable to allocate memory segments for tape buffer.\n", name);
4511 retval = (-EOVERFLOW);
4512 goto err_out;
4514 if (STp->buffer->buffer_size >= OS_FRAME_SIZE) {
4515 for (i = 0, b_size = 0;
4516 (i < STp->buffer->sg_segs) && ((b_size + STp->buffer->sg[i].length) <= OS_DATA_SIZE);
4517 b_size += STp->buffer->sg[i++].length);
4518 STp->buffer->aux = (os_aux_t *) (page_address(sg_page(&STp->buffer->sg[i])) + OS_DATA_SIZE - b_size);
4519 #if DEBUG
4520 printk(OSST_DEB_MSG "%s:D: b_data points to %p in segment 0 at %p\n", name,
4521 STp->buffer->b_data, page_address(STp->buffer->sg[0].page));
4522 printk(OSST_DEB_MSG "%s:D: AUX points to %p in segment %d at %p\n", name,
4523 STp->buffer->aux, i, page_address(STp->buffer->sg[i].page));
4524 #endif
4525 } else {
4526 STp->buffer->aux = NULL; /* this had better never happen! */
4527 printk(KERN_NOTICE "%s:A: Framesize %d too large for buffer.\n", name, OS_FRAME_SIZE);
4528 retval = (-EIO);
4529 goto err_out;
4531 STp->buffer->writing = 0;
4532 STp->buffer->syscall_result = 0;
4533 STp->dirty = 0;
4534 for (i=0; i < ST_NBR_PARTITIONS; i++) {
4535 STps = &(STp->ps[i]);
4536 STps->rw = ST_IDLE;
4538 STp->ready = ST_READY;
4539 #if DEBUG
4540 STp->nbr_waits = STp->nbr_finished = 0;
4541 #endif
4543 memset (cmd, 0, MAX_COMMAND_SIZE);
4544 cmd[0] = TEST_UNIT_READY;
4546 SRpnt = osst_do_scsi(NULL, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1);
4547 if (!SRpnt) {
4548 retval = (STp->buffer)->syscall_result; /* FIXME - valid? */
4549 goto err_out;
4551 if ((SRpnt->sense[0] & 0x70) == 0x70 &&
4552 (SRpnt->sense[2] & 0x0f) == NOT_READY &&
4553 SRpnt->sense[12] == 4 ) {
4554 #if DEBUG
4555 printk(OSST_DEB_MSG "%s:D: Unit not ready, cause %x\n", name, SRpnt->sense[13]);
4556 #endif
4557 if (filp->f_flags & O_NONBLOCK) {
4558 retval = -EAGAIN;
4559 goto err_out;
4561 if (SRpnt->sense[13] == 2) { /* initialize command required (LOAD) */
4562 memset (cmd, 0, MAX_COMMAND_SIZE);
4563 cmd[0] = START_STOP;
4564 cmd[1] = 1;
4565 cmd[4] = 1;
4566 SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE,
4567 STp->timeout, MAX_RETRIES, 1);
4569 osst_wait_ready(STp, &SRpnt, (SRpnt->sense[13]==1?15:3) * 60, 0);
4571 if ((SRpnt->sense[0] & 0x70) == 0x70 &&
4572 (SRpnt->sense[2] & 0x0f) == UNIT_ATTENTION) { /* New media? */
4573 #if DEBUG
4574 printk(OSST_DEB_MSG "%s:D: Unit wants attention\n", name);
4575 #endif
4576 STp->header_ok = 0;
4578 for (i=0; i < 10; i++) {
4580 memset (cmd, 0, MAX_COMMAND_SIZE);
4581 cmd[0] = TEST_UNIT_READY;
4583 SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE,
4584 STp->timeout, MAX_RETRIES, 1);
4585 if ((SRpnt->sense[0] & 0x70) != 0x70 ||
4586 (SRpnt->sense[2] & 0x0f) != UNIT_ATTENTION)
4587 break;
4590 STp->pos_unknown = 0;
4591 STp->partition = STp->new_partition = 0;
4592 if (STp->can_partitions)
4593 STp->nbr_partitions = 1; /* This guess will be updated later if necessary */
4594 for (i=0; i < ST_NBR_PARTITIONS; i++) {
4595 STps = &(STp->ps[i]);
4596 STps->rw = ST_IDLE; /* FIXME - seems to be redundant... */
4597 STps->eof = ST_NOEOF;
4598 STps->at_sm = 0;
4599 STps->last_block_valid = 0;
4600 STps->drv_block = 0;
4601 STps->drv_file = 0 ;
4603 new_session = 1;
4604 STp->recover_count = 0;
4605 STp->abort_count = 0;
4608 * if we have valid headers from before, and the drive/tape seem untouched,
4609 * open without reconfiguring and re-reading the headers
4611 if (!STp->buffer->syscall_result && STp->header_ok &&
4612 !SRpnt->result && SRpnt->sense[0] == 0) {
4614 memset(cmd, 0, MAX_COMMAND_SIZE);
4615 cmd[0] = MODE_SENSE;
4616 cmd[1] = 8;
4617 cmd[2] = VENDOR_IDENT_PAGE;
4618 cmd[4] = VENDOR_IDENT_PAGE_LENGTH + MODE_HEADER_LENGTH;
4620 SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_FROM_DEVICE, STp->timeout, 0, 1);
4622 if (STp->buffer->syscall_result ||
4623 STp->buffer->b_data[MODE_HEADER_LENGTH + 2] != 'L' ||
4624 STp->buffer->b_data[MODE_HEADER_LENGTH + 3] != 'I' ||
4625 STp->buffer->b_data[MODE_HEADER_LENGTH + 4] != 'N' ||
4626 STp->buffer->b_data[MODE_HEADER_LENGTH + 5] != '4' ) {
4627 #if DEBUG
4628 printk(OSST_DEB_MSG "%s:D: Signature was changed to %c%c%c%c\n", name,
4629 STp->buffer->b_data[MODE_HEADER_LENGTH + 2],
4630 STp->buffer->b_data[MODE_HEADER_LENGTH + 3],
4631 STp->buffer->b_data[MODE_HEADER_LENGTH + 4],
4632 STp->buffer->b_data[MODE_HEADER_LENGTH + 5]);
4633 #endif
4634 STp->header_ok = 0;
4636 i = STp->first_frame_position;
4637 if (STp->header_ok && i == osst_get_frame_position(STp, &SRpnt)) {
4638 if (STp->door_locked == ST_UNLOCKED) {
4639 if (do_door_lock(STp, 1))
4640 printk(KERN_INFO "%s:I: Can't lock drive door\n", name);
4641 else
4642 STp->door_locked = ST_LOCKED_AUTO;
4644 if (!STp->frame_in_buffer) {
4645 STp->block_size = (STm->default_blksize > 0) ?
4646 STm->default_blksize : OS_DATA_SIZE;
4647 STp->buffer->buffer_bytes = STp->buffer->read_pointer = 0;
4649 STp->buffer->buffer_blocks = OS_DATA_SIZE / STp->block_size;
4650 STp->fast_open = 1;
4651 osst_release_request(SRpnt);
4652 return 0;
4654 #if DEBUG
4655 if (i != STp->first_frame_position)
4656 printk(OSST_DEB_MSG "%s:D: Tape position changed from %d to %d\n",
4657 name, i, STp->first_frame_position);
4658 #endif
4659 STp->header_ok = 0;
4661 STp->fast_open = 0;
4663 if ((STp->buffer)->syscall_result != 0 && /* in all error conditions except no medium */
4664 (SRpnt->sense[2] != 2 || SRpnt->sense[12] != 0x3A) ) {
4666 memset(cmd, 0, MAX_COMMAND_SIZE);
4667 cmd[0] = MODE_SELECT;
4668 cmd[1] = 0x10;
4669 cmd[4] = 4 + MODE_HEADER_LENGTH;
4671 (STp->buffer)->b_data[0] = cmd[4] - 1;
4672 (STp->buffer)->b_data[1] = 0; /* Medium Type - ignoring */
4673 (STp->buffer)->b_data[2] = 0; /* Reserved */
4674 (STp->buffer)->b_data[3] = 0; /* Block Descriptor Length */
4675 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 0] = 0x3f;
4676 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 1] = 1;
4677 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] = 2;
4678 (STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] = 3;
4680 #if DEBUG
4681 printk(OSST_DEB_MSG "%s:D: Applying soft reset\n", name);
4682 #endif
4683 SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_TO_DEVICE, STp->timeout, 0, 1);
4685 STp->header_ok = 0;
4687 for (i=0; i < 10; i++) {
4689 memset (cmd, 0, MAX_COMMAND_SIZE);
4690 cmd[0] = TEST_UNIT_READY;
4692 SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE,
4693 STp->timeout, MAX_RETRIES, 1);
4694 if ((SRpnt->sense[0] & 0x70) != 0x70 ||
4695 (SRpnt->sense[2] & 0x0f) == NOT_READY)
4696 break;
4698 if ((SRpnt->sense[2] & 0x0f) == UNIT_ATTENTION) {
4699 STp->pos_unknown = 0;
4700 STp->partition = STp->new_partition = 0;
4701 if (STp->can_partitions)
4702 STp->nbr_partitions = 1; /* This guess will be updated later if necessary */
4703 for (i=0; i < ST_NBR_PARTITIONS; i++) {
4704 STps = &(STp->ps[i]);
4705 STps->rw = ST_IDLE;
4706 STps->eof = ST_NOEOF;
4707 STps->at_sm = 0;
4708 STps->last_block_valid = 0;
4709 STps->drv_block = 0;
4710 STps->drv_file = 0 ;
4712 new_session = 1;
4717 if (osst_wait_ready(STp, &SRpnt, 15 * 60, 0)) /* FIXME - not allowed with NOBLOCK */
4718 printk(KERN_INFO "%s:I: Device did not become Ready in open\n", name);
4720 if ((STp->buffer)->syscall_result != 0) {
4721 if ((STp->device)->scsi_level >= SCSI_2 &&
4722 (SRpnt->sense[0] & 0x70) == 0x70 &&
4723 (SRpnt->sense[2] & 0x0f) == NOT_READY &&
4724 SRpnt->sense[12] == 0x3a) { /* Check ASC */
4725 STp->ready = ST_NO_TAPE;
4726 } else
4727 STp->ready = ST_NOT_READY;
4728 osst_release_request(SRpnt);
4729 SRpnt = NULL;
4730 STp->density = 0; /* Clear the erroneous "residue" */
4731 STp->write_prot = 0;
4732 STp->block_size = 0;
4733 STp->ps[0].drv_file = STp->ps[0].drv_block = (-1);
4734 STp->partition = STp->new_partition = 0;
4735 STp->door_locked = ST_UNLOCKED;
4736 return 0;
4739 osst_configure_onstream(STp, &SRpnt);
4741 STp->block_size = STp->raw ? OS_FRAME_SIZE : (
4742 (STm->default_blksize > 0) ? STm->default_blksize : OS_DATA_SIZE);
4743 STp->buffer->buffer_blocks = STp->raw ? 1 : OS_DATA_SIZE / STp->block_size;
4744 STp->buffer->buffer_bytes =
4745 STp->buffer->read_pointer =
4746 STp->frame_in_buffer = 0;
4748 #if DEBUG
4749 if (debugging)
4750 printk(OSST_DEB_MSG "%s:D: Block size: %d, frame size: %d, buffer size: %d (%d blocks).\n",
4751 name, STp->block_size, OS_FRAME_SIZE, (STp->buffer)->buffer_size,
4752 (STp->buffer)->buffer_blocks);
4753 #endif
4755 if (STp->drv_write_prot) {
4756 STp->write_prot = 1;
4757 #if DEBUG
4758 if (debugging)
4759 printk(OSST_DEB_MSG "%s:D: Write protected\n", name);
4760 #endif
4761 if ((flags & O_ACCMODE) == O_WRONLY || (flags & O_ACCMODE) == O_RDWR) {
4762 retval = (-EROFS);
4763 goto err_out;
4767 if (new_session) { /* Change the drive parameters for the new mode */
4768 #if DEBUG
4769 if (debugging)
4770 printk(OSST_DEB_MSG "%s:D: New Session\n", name);
4771 #endif
4772 STp->density_changed = STp->blksize_changed = 0;
4773 STp->compression_changed = 0;
4777 * properly position the tape and check the ADR headers
4779 if (STp->door_locked == ST_UNLOCKED) {
4780 if (do_door_lock(STp, 1))
4781 printk(KERN_INFO "%s:I: Can't lock drive door\n", name);
4782 else
4783 STp->door_locked = ST_LOCKED_AUTO;
4786 osst_analyze_headers(STp, &SRpnt);
4788 osst_release_request(SRpnt);
4789 SRpnt = NULL;
4791 return 0;
4793 err_out:
4794 if (SRpnt != NULL)
4795 osst_release_request(SRpnt);
4796 normalize_buffer(STp->buffer);
4797 STp->header_ok = 0;
4798 STp->in_use = 0;
4799 scsi_device_put(STp->device);
4801 return retval;
4804 /* BKL pushdown: spaghetti avoidance wrapper */
4805 static int os_scsi_tape_open(struct inode * inode, struct file * filp)
4807 int ret;
4809 lock_kernel();
4810 ret = __os_scsi_tape_open(inode, filp);
4811 unlock_kernel();
4812 return ret;
4817 /* Flush the tape buffer before close */
4818 static int os_scsi_tape_flush(struct file * filp, fl_owner_t id)
4820 int result = 0, result2;
4821 struct osst_tape * STp = filp->private_data;
4822 struct st_modedef * STm = &(STp->modes[STp->current_mode]);
4823 struct st_partstat * STps = &(STp->ps[STp->partition]);
4824 struct osst_request * SRpnt = NULL;
4825 char * name = tape_name(STp);
4827 if (file_count(filp) > 1)
4828 return 0;
4830 if ((STps->rw == ST_WRITING || STp->dirty) && !STp->pos_unknown) {
4831 STp->write_type = OS_WRITE_DATA;
4832 result = osst_flush_write_buffer(STp, &SRpnt);
4833 if (result != 0 && result != (-ENOSPC))
4834 goto out;
4836 if ( STps->rw >= ST_WRITING && !STp->pos_unknown) {
4838 #if DEBUG
4839 if (debugging) {
4840 printk(OSST_DEB_MSG "%s:D: File length %ld bytes.\n",
4841 name, (long)(filp->f_pos));
4842 printk(OSST_DEB_MSG "%s:D: Async write waits %d, finished %d.\n",
4843 name, STp->nbr_waits, STp->nbr_finished);
4845 #endif
4846 result = osst_write_trailer(STp, &SRpnt, !(STp->rew_at_close));
4847 #if DEBUG
4848 if (debugging)
4849 printk(OSST_DEB_MSG "%s:D: Buffer flushed, %d EOF(s) written\n",
4850 name, 1+STp->two_fm);
4851 #endif
4853 else if (!STp->rew_at_close) {
4854 STps = &(STp->ps[STp->partition]);
4855 if (!STm->sysv || STps->rw != ST_READING) {
4856 if (STp->can_bsr)
4857 result = osst_flush_buffer(STp, &SRpnt, 0); /* this is the default path */
4858 else if (STps->eof == ST_FM_HIT) {
4859 result = cross_eof(STp, &SRpnt, 0);
4860 if (result) {
4861 if (STps->drv_file >= 0)
4862 STps->drv_file++;
4863 STps->drv_block = 0;
4864 STps->eof = ST_FM;
4866 else
4867 STps->eof = ST_NOEOF;
4870 else if ((STps->eof == ST_NOEOF &&
4871 !(result = cross_eof(STp, &SRpnt, 1))) ||
4872 STps->eof == ST_FM_HIT) {
4873 if (STps->drv_file >= 0)
4874 STps->drv_file++;
4875 STps->drv_block = 0;
4876 STps->eof = ST_FM;
4880 out:
4881 if (STp->rew_at_close) {
4882 result2 = osst_position_tape_and_confirm(STp, &SRpnt, STp->first_data_ppos);
4883 STps->drv_file = STps->drv_block = STp->frame_seq_number = STp->logical_blk_num = 0;
4884 if (result == 0 && result2 < 0)
4885 result = result2;
4887 if (SRpnt) osst_release_request(SRpnt);
4889 if (STp->abort_count || STp->recover_count) {
4890 printk(KERN_INFO "%s:I:", name);
4891 if (STp->abort_count)
4892 printk(" %d unrecovered errors", STp->abort_count);
4893 if (STp->recover_count)
4894 printk(" %d recovered errors", STp->recover_count);
4895 if (STp->write_count)
4896 printk(" in %d frames written", STp->write_count);
4897 if (STp->read_count)
4898 printk(" in %d frames read", STp->read_count);
4899 printk("\n");
4900 STp->recover_count = 0;
4901 STp->abort_count = 0;
4903 STp->write_count = 0;
4904 STp->read_count = 0;
4906 return result;
4910 /* Close the device and release it */
4911 static int os_scsi_tape_close(struct inode * inode, struct file * filp)
4913 int result = 0;
4914 struct osst_tape * STp = filp->private_data;
4916 if (STp->door_locked == ST_LOCKED_AUTO)
4917 do_door_lock(STp, 0);
4919 if (STp->raw)
4920 STp->header_ok = 0;
4922 normalize_buffer(STp->buffer);
4923 write_lock(&os_scsi_tapes_lock);
4924 STp->in_use = 0;
4925 write_unlock(&os_scsi_tapes_lock);
4927 scsi_device_put(STp->device);
4929 return result;
4933 /* The ioctl command */
4934 static int osst_ioctl(struct inode * inode,struct file * file,
4935 unsigned int cmd_in, unsigned long arg)
4937 int i, cmd_nr, cmd_type, blk, retval = 0;
4938 struct st_modedef * STm;
4939 struct st_partstat * STps;
4940 struct osst_request * SRpnt = NULL;
4941 struct osst_tape * STp = file->private_data;
4942 char * name = tape_name(STp);
4943 void __user * p = (void __user *)arg;
4945 if (mutex_lock_interruptible(&STp->lock))
4946 return -ERESTARTSYS;
4948 #if DEBUG
4949 if (debugging && !STp->in_use) {
4950 printk(OSST_DEB_MSG "%s:D: Incorrect device.\n", name);
4951 retval = (-EIO);
4952 goto out;
4954 #endif
4955 STm = &(STp->modes[STp->current_mode]);
4956 STps = &(STp->ps[STp->partition]);
4959 * If we are in the middle of error recovery, don't let anyone
4960 * else try and use this device. Also, if error recovery fails, it
4961 * may try and take the device offline, in which case all further
4962 * access to the device is prohibited.
4964 if( !scsi_block_when_processing_errors(STp->device) ) {
4965 retval = (-ENXIO);
4966 goto out;
4969 cmd_type = _IOC_TYPE(cmd_in);
4970 cmd_nr = _IOC_NR(cmd_in);
4971 #if DEBUG
4972 printk(OSST_DEB_MSG "%s:D: Ioctl %d,%d in %s mode\n", name,
4973 cmd_type, cmd_nr, STp->raw?"raw":"normal");
4974 #endif
4975 if (cmd_type == _IOC_TYPE(MTIOCTOP) && cmd_nr == _IOC_NR(MTIOCTOP)) {
4976 struct mtop mtc;
4977 int auto_weof = 0;
4979 if (_IOC_SIZE(cmd_in) != sizeof(mtc)) {
4980 retval = (-EINVAL);
4981 goto out;
4984 i = copy_from_user((char *) &mtc, p, sizeof(struct mtop));
4985 if (i) {
4986 retval = (-EFAULT);
4987 goto out;
4990 if (mtc.mt_op == MTSETDRVBUFFER && !capable(CAP_SYS_ADMIN)) {
4991 printk(KERN_WARNING "%s:W: MTSETDRVBUFFER only allowed for root.\n", name);
4992 retval = (-EPERM);
4993 goto out;
4996 if (!STm->defined && (mtc.mt_op != MTSETDRVBUFFER && (mtc.mt_count & MT_ST_OPTIONS) == 0)) {
4997 retval = (-ENXIO);
4998 goto out;
5001 if (!STp->pos_unknown) {
5003 if (STps->eof == ST_FM_HIT) {
5004 if (mtc.mt_op == MTFSF || mtc.mt_op == MTFSFM|| mtc.mt_op == MTEOM) {
5005 mtc.mt_count -= 1;
5006 if (STps->drv_file >= 0)
5007 STps->drv_file += 1;
5009 else if (mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM) {
5010 mtc.mt_count += 1;
5011 if (STps->drv_file >= 0)
5012 STps->drv_file += 1;
5016 if (mtc.mt_op == MTSEEK) {
5017 /* Old position must be restored if partition will be changed */
5018 i = !STp->can_partitions || (STp->new_partition != STp->partition);
5020 else {
5021 i = mtc.mt_op == MTREW || mtc.mt_op == MTOFFL ||
5022 mtc.mt_op == MTRETEN || mtc.mt_op == MTEOM ||
5023 mtc.mt_op == MTLOCK || mtc.mt_op == MTLOAD ||
5024 mtc.mt_op == MTFSF || mtc.mt_op == MTFSFM ||
5025 mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM ||
5026 mtc.mt_op == MTCOMPRESSION;
5028 i = osst_flush_buffer(STp, &SRpnt, i);
5029 if (i < 0) {
5030 retval = i;
5031 goto out;
5034 else {
5036 * If there was a bus reset, block further access
5037 * to this device. If the user wants to rewind the tape,
5038 * then reset the flag and allow access again.
5040 if(mtc.mt_op != MTREW &&
5041 mtc.mt_op != MTOFFL &&
5042 mtc.mt_op != MTRETEN &&
5043 mtc.mt_op != MTERASE &&
5044 mtc.mt_op != MTSEEK &&
5045 mtc.mt_op != MTEOM) {
5046 retval = (-EIO);
5047 goto out;
5049 reset_state(STp);
5050 /* remove this when the midlevel properly clears was_reset */
5051 STp->device->was_reset = 0;
5054 if (mtc.mt_op != MTCOMPRESSION && mtc.mt_op != MTLOCK &&
5055 mtc.mt_op != MTNOP && mtc.mt_op != MTSETBLK &&
5056 mtc.mt_op != MTSETDENSITY && mtc.mt_op != MTSETDRVBUFFER &&
5057 mtc.mt_op != MTMKPART && mtc.mt_op != MTSETPART &&
5058 mtc.mt_op != MTWEOF && mtc.mt_op != MTWSM ) {
5061 * The user tells us to move to another position on the tape.
5062 * If we were appending to the tape content, that would leave
5063 * the tape without proper end, in that case write EOD and
5064 * update the header to reflect its position.
5066 #if DEBUG
5067 printk(KERN_WARNING "%s:D: auto_weod %s at ffp=%d,efp=%d,fsn=%d,lbn=%d,fn=%d,bn=%d\n", name,
5068 STps->rw >= ST_WRITING ? "write" : STps->rw == ST_READING ? "read" : "idle",
5069 STp->first_frame_position, STp->eod_frame_ppos, STp->frame_seq_number,
5070 STp->logical_blk_num, STps->drv_file, STps->drv_block );
5071 #endif
5072 if (STps->rw >= ST_WRITING && STp->first_frame_position >= STp->eod_frame_ppos) {
5073 auto_weof = ((STp->write_type != OS_WRITE_NEW_MARK) &&
5074 !(mtc.mt_op == MTREW || mtc.mt_op == MTOFFL));
5075 i = osst_write_trailer(STp, &SRpnt,
5076 !(mtc.mt_op == MTREW || mtc.mt_op == MTOFFL));
5077 #if DEBUG
5078 printk(KERN_WARNING "%s:D: post trailer xeof=%d,ffp=%d,efp=%d,fsn=%d,lbn=%d,fn=%d,bn=%d\n",
5079 name, auto_weof, STp->first_frame_position, STp->eod_frame_ppos,
5080 STp->frame_seq_number, STp->logical_blk_num, STps->drv_file, STps->drv_block );
5081 #endif
5082 if (i < 0) {
5083 retval = i;
5084 goto out;
5087 STps->rw = ST_IDLE;
5090 if (mtc.mt_op == MTOFFL && STp->door_locked != ST_UNLOCKED)
5091 do_door_lock(STp, 0); /* Ignore result! */
5093 if (mtc.mt_op == MTSETDRVBUFFER &&
5094 (mtc.mt_count & MT_ST_OPTIONS) != 0) {
5095 retval = osst_set_options(STp, mtc.mt_count);
5096 goto out;
5099 if (mtc.mt_op == MTSETPART) {
5100 if (mtc.mt_count >= STp->nbr_partitions)
5101 retval = -EINVAL;
5102 else {
5103 STp->new_partition = mtc.mt_count;
5104 retval = 0;
5106 goto out;
5109 if (mtc.mt_op == MTMKPART) {
5110 if (!STp->can_partitions) {
5111 retval = (-EINVAL);
5112 goto out;
5114 if ((i = osst_int_ioctl(STp, &SRpnt, MTREW, 0)) < 0 /*||
5115 (i = partition_tape(inode, mtc.mt_count)) < 0*/) {
5116 retval = i;
5117 goto out;
5119 for (i=0; i < ST_NBR_PARTITIONS; i++) {
5120 STp->ps[i].rw = ST_IDLE;
5121 STp->ps[i].at_sm = 0;
5122 STp->ps[i].last_block_valid = 0;
5124 STp->partition = STp->new_partition = 0;
5125 STp->nbr_partitions = 1; /* Bad guess ?-) */
5126 STps->drv_block = STps->drv_file = 0;
5127 retval = 0;
5128 goto out;
5131 if (mtc.mt_op == MTSEEK) {
5132 if (STp->raw)
5133 i = osst_set_frame_position(STp, &SRpnt, mtc.mt_count, 0);
5134 else
5135 i = osst_seek_sector(STp, &SRpnt, mtc.mt_count);
5136 if (!STp->can_partitions)
5137 STp->ps[0].rw = ST_IDLE;
5138 retval = i;
5139 goto out;
5142 if (mtc.mt_op == MTLOCK || mtc.mt_op == MTUNLOCK) {
5143 retval = do_door_lock(STp, (mtc.mt_op == MTLOCK));
5144 goto out;
5147 if (auto_weof)
5148 cross_eof(STp, &SRpnt, 0);
5150 if (mtc.mt_op == MTCOMPRESSION)
5151 retval = -EINVAL; /* OnStream drives don't have compression hardware */
5152 else
5153 /* MTBSF MTBSFM MTBSR MTBSS MTEOM MTERASE MTFSF MTFSFB MTFSR MTFSS
5154 * MTLOAD MTOFFL MTRESET MTRETEN MTREW MTUNLOAD MTWEOF MTWSM */
5155 retval = osst_int_ioctl(STp, &SRpnt, mtc.mt_op, mtc.mt_count);
5156 goto out;
5159 if (!STm->defined) {
5160 retval = (-ENXIO);
5161 goto out;
5164 if ((i = osst_flush_buffer(STp, &SRpnt, 0)) < 0) {
5165 retval = i;
5166 goto out;
5169 if (cmd_type == _IOC_TYPE(MTIOCGET) && cmd_nr == _IOC_NR(MTIOCGET)) {
5170 struct mtget mt_status;
5172 if (_IOC_SIZE(cmd_in) != sizeof(struct mtget)) {
5173 retval = (-EINVAL);
5174 goto out;
5177 mt_status.mt_type = MT_ISONSTREAM_SC;
5178 mt_status.mt_erreg = STp->recover_erreg << MT_ST_SOFTERR_SHIFT;
5179 mt_status.mt_dsreg =
5180 ((STp->block_size << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK) |
5181 ((STp->density << MT_ST_DENSITY_SHIFT) & MT_ST_DENSITY_MASK);
5182 mt_status.mt_blkno = STps->drv_block;
5183 mt_status.mt_fileno = STps->drv_file;
5184 if (STp->block_size != 0) {
5185 if (STps->rw == ST_WRITING)
5186 mt_status.mt_blkno += (STp->buffer)->buffer_bytes / STp->block_size;
5187 else if (STps->rw == ST_READING)
5188 mt_status.mt_blkno -= ((STp->buffer)->buffer_bytes +
5189 STp->block_size - 1) / STp->block_size;
5192 mt_status.mt_gstat = 0;
5193 if (STp->drv_write_prot)
5194 mt_status.mt_gstat |= GMT_WR_PROT(0xffffffff);
5195 if (mt_status.mt_blkno == 0) {
5196 if (mt_status.mt_fileno == 0)
5197 mt_status.mt_gstat |= GMT_BOT(0xffffffff);
5198 else
5199 mt_status.mt_gstat |= GMT_EOF(0xffffffff);
5201 mt_status.mt_resid = STp->partition;
5202 if (STps->eof == ST_EOM_OK || STps->eof == ST_EOM_ERROR)
5203 mt_status.mt_gstat |= GMT_EOT(0xffffffff);
5204 else if (STps->eof >= ST_EOM_OK)
5205 mt_status.mt_gstat |= GMT_EOD(0xffffffff);
5206 if (STp->density == 1)
5207 mt_status.mt_gstat |= GMT_D_800(0xffffffff);
5208 else if (STp->density == 2)
5209 mt_status.mt_gstat |= GMT_D_1600(0xffffffff);
5210 else if (STp->density == 3)
5211 mt_status.mt_gstat |= GMT_D_6250(0xffffffff);
5212 if (STp->ready == ST_READY)
5213 mt_status.mt_gstat |= GMT_ONLINE(0xffffffff);
5214 if (STp->ready == ST_NO_TAPE)
5215 mt_status.mt_gstat |= GMT_DR_OPEN(0xffffffff);
5216 if (STps->at_sm)
5217 mt_status.mt_gstat |= GMT_SM(0xffffffff);
5218 if (STm->do_async_writes || (STm->do_buffer_writes && STp->block_size != 0) ||
5219 STp->drv_buffer != 0)
5220 mt_status.mt_gstat |= GMT_IM_REP_EN(0xffffffff);
5222 i = copy_to_user(p, &mt_status, sizeof(struct mtget));
5223 if (i) {
5224 retval = (-EFAULT);
5225 goto out;
5228 STp->recover_erreg = 0; /* Clear after read */
5229 retval = 0;
5230 goto out;
5231 } /* End of MTIOCGET */
5233 if (cmd_type == _IOC_TYPE(MTIOCPOS) && cmd_nr == _IOC_NR(MTIOCPOS)) {
5234 struct mtpos mt_pos;
5236 if (_IOC_SIZE(cmd_in) != sizeof(struct mtpos)) {
5237 retval = (-EINVAL);
5238 goto out;
5240 if (STp->raw)
5241 blk = osst_get_frame_position(STp, &SRpnt);
5242 else
5243 blk = osst_get_sector(STp, &SRpnt);
5244 if (blk < 0) {
5245 retval = blk;
5246 goto out;
5248 mt_pos.mt_blkno = blk;
5249 i = copy_to_user(p, &mt_pos, sizeof(struct mtpos));
5250 if (i)
5251 retval = -EFAULT;
5252 goto out;
5254 if (SRpnt) osst_release_request(SRpnt);
5256 mutex_unlock(&STp->lock);
5258 return scsi_ioctl(STp->device, cmd_in, p);
5260 out:
5261 if (SRpnt) osst_release_request(SRpnt);
5263 mutex_unlock(&STp->lock);
5265 return retval;
5268 #ifdef CONFIG_COMPAT
5269 static long osst_compat_ioctl(struct file * file, unsigned int cmd_in, unsigned long arg)
5271 struct osst_tape *STp = file->private_data;
5272 struct scsi_device *sdev = STp->device;
5273 int ret = -ENOIOCTLCMD;
5274 if (sdev->host->hostt->compat_ioctl) {
5276 ret = sdev->host->hostt->compat_ioctl(sdev, cmd_in, (void __user *)arg);
5279 return ret;
5281 #endif
5285 /* Memory handling routines */
5287 /* Try to allocate a new tape buffer skeleton. Caller must not hold os_scsi_tapes_lock */
5288 static struct osst_buffer * new_tape_buffer( int from_initialization, int need_dma, int max_sg )
5290 int i;
5291 gfp_t priority;
5292 struct osst_buffer *tb;
5294 if (from_initialization)
5295 priority = GFP_ATOMIC;
5296 else
5297 priority = GFP_KERNEL;
5299 i = sizeof(struct osst_buffer) + (osst_max_sg_segs - 1) * sizeof(struct scatterlist);
5300 tb = kzalloc(i, priority);
5301 if (!tb) {
5302 printk(KERN_NOTICE "osst :I: Can't allocate new tape buffer.\n");
5303 return NULL;
5306 tb->sg_segs = tb->orig_sg_segs = 0;
5307 tb->use_sg = max_sg;
5308 tb->in_use = 1;
5309 tb->dma = need_dma;
5310 tb->buffer_size = 0;
5311 #if DEBUG
5312 if (debugging)
5313 printk(OSST_DEB_MSG
5314 "osst :D: Allocated tape buffer skeleton (%d bytes, %d segments, dma: %d).\n",
5315 i, max_sg, need_dma);
5316 #endif
5317 return tb;
5320 /* Try to allocate a temporary (while a user has the device open) enlarged tape buffer */
5321 static int enlarge_buffer(struct osst_buffer *STbuffer, int need_dma)
5323 int segs, nbr, max_segs, b_size, order, got;
5324 gfp_t priority;
5326 if (STbuffer->buffer_size >= OS_FRAME_SIZE)
5327 return 1;
5329 if (STbuffer->sg_segs) {
5330 printk(KERN_WARNING "osst :A: Buffer not previously normalized.\n");
5331 normalize_buffer(STbuffer);
5333 /* See how many segments we can use -- need at least two */
5334 nbr = max_segs = STbuffer->use_sg;
5335 if (nbr <= 2)
5336 return 0;
5338 priority = GFP_KERNEL /* | __GFP_NOWARN */;
5339 if (need_dma)
5340 priority |= GFP_DMA;
5342 /* Try to allocate the first segment up to OS_DATA_SIZE and the others
5343 big enough to reach the goal (code assumes no segments in place) */
5344 for (b_size = OS_DATA_SIZE, order = OSST_FIRST_ORDER; b_size >= PAGE_SIZE; order--, b_size /= 2) {
5345 struct page *page = alloc_pages(priority, order);
5347 STbuffer->sg[0].offset = 0;
5348 if (page != NULL) {
5349 sg_set_page(&STbuffer->sg[0], page, b_size, 0);
5350 STbuffer->b_data = page_address(page);
5351 break;
5354 if (sg_page(&STbuffer->sg[0]) == NULL) {
5355 printk(KERN_NOTICE "osst :I: Can't allocate tape buffer main segment.\n");
5356 return 0;
5358 /* Got initial segment of 'bsize,order', continue with same size if possible, except for AUX */
5359 for (segs=STbuffer->sg_segs=1, got=b_size;
5360 segs < max_segs && got < OS_FRAME_SIZE; ) {
5361 struct page *page = alloc_pages(priority, (OS_FRAME_SIZE - got <= PAGE_SIZE) ? 0 : order);
5362 STbuffer->sg[segs].offset = 0;
5363 if (page == NULL) {
5364 printk(KERN_WARNING "osst :W: Failed to enlarge buffer to %d bytes.\n",
5365 OS_FRAME_SIZE);
5366 #if DEBUG
5367 STbuffer->buffer_size = got;
5368 #endif
5369 normalize_buffer(STbuffer);
5370 return 0;
5372 sg_set_page(&STbuffer->sg[segs], page, (OS_FRAME_SIZE - got <= PAGE_SIZE / 2) ? (OS_FRAME_SIZE - got) : b_size, 0);
5373 got += STbuffer->sg[segs].length;
5374 STbuffer->buffer_size = got;
5375 STbuffer->sg_segs = ++segs;
5377 #if DEBUG
5378 if (debugging) {
5379 printk(OSST_DEB_MSG
5380 "osst :D: Expanded tape buffer (%d bytes, %d->%d segments, dma: %d, at: %p).\n",
5381 got, STbuffer->orig_sg_segs, STbuffer->sg_segs, need_dma, STbuffer->b_data);
5382 printk(OSST_DEB_MSG
5383 "osst :D: segment sizes: first %d at %p, last %d bytes at %p.\n",
5384 STbuffer->sg[0].length, page_address(STbuffer->sg[0].page),
5385 STbuffer->sg[segs-1].length, page_address(STbuffer->sg[segs-1].page));
5387 #endif
5389 return 1;
5393 /* Release the segments */
5394 static void normalize_buffer(struct osst_buffer *STbuffer)
5396 int i, order, b_size;
5398 for (i=0; i < STbuffer->sg_segs; i++) {
5400 for (b_size = PAGE_SIZE, order = 0;
5401 b_size < STbuffer->sg[i].length;
5402 b_size *= 2, order++);
5404 __free_pages(sg_page(&STbuffer->sg[i]), order);
5405 STbuffer->buffer_size -= STbuffer->sg[i].length;
5407 #if DEBUG
5408 if (debugging && STbuffer->orig_sg_segs < STbuffer->sg_segs)
5409 printk(OSST_DEB_MSG "osst :D: Buffer at %p normalized to %d bytes (segs %d).\n",
5410 STbuffer->b_data, STbuffer->buffer_size, STbuffer->sg_segs);
5411 #endif
5412 STbuffer->sg_segs = STbuffer->orig_sg_segs = 0;
5416 /* Move data from the user buffer to the tape buffer. Returns zero (success) or
5417 negative error code. */
5418 static int append_to_buffer(const char __user *ubp, struct osst_buffer *st_bp, int do_count)
5420 int i, cnt, res, offset;
5422 for (i=0, offset=st_bp->buffer_bytes;
5423 i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++)
5424 offset -= st_bp->sg[i].length;
5425 if (i == st_bp->sg_segs) { /* Should never happen */
5426 printk(KERN_WARNING "osst :A: Append_to_buffer offset overflow.\n");
5427 return (-EIO);
5429 for ( ; i < st_bp->sg_segs && do_count > 0; i++) {
5430 cnt = st_bp->sg[i].length - offset < do_count ?
5431 st_bp->sg[i].length - offset : do_count;
5432 res = copy_from_user(page_address(sg_page(&st_bp->sg[i])) + offset, ubp, cnt);
5433 if (res)
5434 return (-EFAULT);
5435 do_count -= cnt;
5436 st_bp->buffer_bytes += cnt;
5437 ubp += cnt;
5438 offset = 0;
5440 if (do_count) { /* Should never happen */
5441 printk(KERN_WARNING "osst :A: Append_to_buffer overflow (left %d).\n",
5442 do_count);
5443 return (-EIO);
5445 return 0;
5449 /* Move data from the tape buffer to the user buffer. Returns zero (success) or
5450 negative error code. */
5451 static int from_buffer(struct osst_buffer *st_bp, char __user *ubp, int do_count)
5453 int i, cnt, res, offset;
5455 for (i=0, offset=st_bp->read_pointer;
5456 i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++)
5457 offset -= st_bp->sg[i].length;
5458 if (i == st_bp->sg_segs) { /* Should never happen */
5459 printk(KERN_WARNING "osst :A: From_buffer offset overflow.\n");
5460 return (-EIO);
5462 for ( ; i < st_bp->sg_segs && do_count > 0; i++) {
5463 cnt = st_bp->sg[i].length - offset < do_count ?
5464 st_bp->sg[i].length - offset : do_count;
5465 res = copy_to_user(ubp, page_address(sg_page(&st_bp->sg[i])) + offset, cnt);
5466 if (res)
5467 return (-EFAULT);
5468 do_count -= cnt;
5469 st_bp->buffer_bytes -= cnt;
5470 st_bp->read_pointer += cnt;
5471 ubp += cnt;
5472 offset = 0;
5474 if (do_count) { /* Should never happen */
5475 printk(KERN_WARNING "osst :A: From_buffer overflow (left %d).\n", do_count);
5476 return (-EIO);
5478 return 0;
5481 /* Sets the tail of the buffer after fill point to zero.
5482 Returns zero (success) or negative error code. */
5483 static int osst_zero_buffer_tail(struct osst_buffer *st_bp)
5485 int i, offset, do_count, cnt;
5487 for (i = 0, offset = st_bp->buffer_bytes;
5488 i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++)
5489 offset -= st_bp->sg[i].length;
5490 if (i == st_bp->sg_segs) { /* Should never happen */
5491 printk(KERN_WARNING "osst :A: Zero_buffer offset overflow.\n");
5492 return (-EIO);
5494 for (do_count = OS_DATA_SIZE - st_bp->buffer_bytes;
5495 i < st_bp->sg_segs && do_count > 0; i++) {
5496 cnt = st_bp->sg[i].length - offset < do_count ?
5497 st_bp->sg[i].length - offset : do_count ;
5498 memset(page_address(sg_page(&st_bp->sg[i])) + offset, 0, cnt);
5499 do_count -= cnt;
5500 offset = 0;
5502 if (do_count) { /* Should never happen */
5503 printk(KERN_WARNING "osst :A: Zero_buffer overflow (left %d).\n", do_count);
5504 return (-EIO);
5506 return 0;
5509 /* Copy a osst 32K chunk of memory into the buffer.
5510 Returns zero (success) or negative error code. */
5511 static int osst_copy_to_buffer(struct osst_buffer *st_bp, unsigned char *ptr)
5513 int i, cnt, do_count = OS_DATA_SIZE;
5515 for (i = 0; i < st_bp->sg_segs && do_count > 0; i++) {
5516 cnt = st_bp->sg[i].length < do_count ?
5517 st_bp->sg[i].length : do_count ;
5518 memcpy(page_address(sg_page(&st_bp->sg[i])), ptr, cnt);
5519 do_count -= cnt;
5520 ptr += cnt;
5522 if (do_count || i != st_bp->sg_segs-1) { /* Should never happen */
5523 printk(KERN_WARNING "osst :A: Copy_to_buffer overflow (left %d at sg %d).\n",
5524 do_count, i);
5525 return (-EIO);
5527 return 0;
5530 /* Copy a osst 32K chunk of memory from the buffer.
5531 Returns zero (success) or negative error code. */
5532 static int osst_copy_from_buffer(struct osst_buffer *st_bp, unsigned char *ptr)
5534 int i, cnt, do_count = OS_DATA_SIZE;
5536 for (i = 0; i < st_bp->sg_segs && do_count > 0; i++) {
5537 cnt = st_bp->sg[i].length < do_count ?
5538 st_bp->sg[i].length : do_count ;
5539 memcpy(ptr, page_address(sg_page(&st_bp->sg[i])), cnt);
5540 do_count -= cnt;
5541 ptr += cnt;
5543 if (do_count || i != st_bp->sg_segs-1) { /* Should never happen */
5544 printk(KERN_WARNING "osst :A: Copy_from_buffer overflow (left %d at sg %d).\n",
5545 do_count, i);
5546 return (-EIO);
5548 return 0;
5552 /* Module housekeeping */
5554 static void validate_options (void)
5556 if (max_dev > 0)
5557 osst_max_dev = max_dev;
5558 if (write_threshold_kbs > 0)
5559 osst_write_threshold = write_threshold_kbs * ST_KILOBYTE;
5560 if (osst_write_threshold > osst_buffer_size)
5561 osst_write_threshold = osst_buffer_size;
5562 if (max_sg_segs >= OSST_FIRST_SG)
5563 osst_max_sg_segs = max_sg_segs;
5564 #if DEBUG
5565 printk(OSST_DEB_MSG "osst :D: max tapes %d, write threshold %d, max s/g segs %d.\n",
5566 osst_max_dev, osst_write_threshold, osst_max_sg_segs);
5567 #endif
5570 #ifndef MODULE
5571 /* Set the boot options. Syntax: osst=xxx,yyy,...
5572 where xxx is write threshold in 1024 byte blocks,
5573 and yyy is number of s/g segments to use. */
5574 static int __init osst_setup (char *str)
5576 int i, ints[5];
5577 char *stp;
5579 stp = get_options(str, ARRAY_SIZE(ints), ints);
5581 if (ints[0] > 0) {
5582 for (i = 0; i < ints[0] && i < ARRAY_SIZE(parms); i++)
5583 *parms[i].val = ints[i + 1];
5584 } else {
5585 while (stp != NULL) {
5586 for (i = 0; i < ARRAY_SIZE(parms); i++) {
5587 int len = strlen(parms[i].name);
5588 if (!strncmp(stp, parms[i].name, len) &&
5589 (*(stp + len) == ':' || *(stp + len) == '=')) {
5590 *parms[i].val =
5591 simple_strtoul(stp + len + 1, NULL, 0);
5592 break;
5595 if (i >= ARRAY_SIZE(parms))
5596 printk(KERN_INFO "osst :I: Illegal parameter in '%s'\n",
5597 stp);
5598 stp = strchr(stp, ',');
5599 if (stp)
5600 stp++;
5604 return 1;
5607 __setup("osst=", osst_setup);
5609 #endif
5611 static const struct file_operations osst_fops = {
5612 .owner = THIS_MODULE,
5613 .read = osst_read,
5614 .write = osst_write,
5615 .ioctl = osst_ioctl,
5616 #ifdef CONFIG_COMPAT
5617 .compat_ioctl = osst_compat_ioctl,
5618 #endif
5619 .open = os_scsi_tape_open,
5620 .flush = os_scsi_tape_flush,
5621 .release = os_scsi_tape_close,
5624 static int osst_supports(struct scsi_device * SDp)
5626 struct osst_support_data {
5627 char *vendor;
5628 char *model;
5629 char *rev;
5630 char *driver_hint; /* Name of the correct driver, NULL if unknown */
5633 static struct osst_support_data support_list[] = {
5634 /* {"XXX", "Yy-", "", NULL}, example */
5635 SIGS_FROM_OSST,
5636 {NULL, }};
5638 struct osst_support_data *rp;
5640 /* We are willing to drive OnStream SC-x0 as well as the
5641 * * IDE, ParPort, FireWire, USB variants, if accessible by
5642 * * emulation layer (ide-scsi, usb-storage, ...) */
5644 for (rp=&(support_list[0]); rp->vendor != NULL; rp++)
5645 if (!strncmp(rp->vendor, SDp->vendor, strlen(rp->vendor)) &&
5646 !strncmp(rp->model, SDp->model, strlen(rp->model)) &&
5647 !strncmp(rp->rev, SDp->rev, strlen(rp->rev)))
5648 return 1;
5649 return 0;
5653 * sysfs support for osst driver parameter information
5656 static ssize_t osst_version_show(struct device_driver *ddd, char *buf)
5658 return snprintf(buf, PAGE_SIZE, "%s\n", osst_version);
5661 static DRIVER_ATTR(version, S_IRUGO, osst_version_show, NULL);
5663 static int osst_create_sysfs_files(struct device_driver *sysfs)
5665 return driver_create_file(sysfs, &driver_attr_version);
5668 static void osst_remove_sysfs_files(struct device_driver *sysfs)
5670 driver_remove_file(sysfs, &driver_attr_version);
5674 * sysfs support for accessing ADR header information
5677 static ssize_t osst_adr_rev_show(struct device *dev,
5678 struct device_attribute *attr, char *buf)
5680 struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev);
5681 ssize_t l = 0;
5683 if (STp && STp->header_ok && STp->linux_media)
5684 l = snprintf(buf, PAGE_SIZE, "%d.%d\n", STp->header_cache->major_rev, STp->header_cache->minor_rev);
5685 return l;
5688 DEVICE_ATTR(ADR_rev, S_IRUGO, osst_adr_rev_show, NULL);
5690 static ssize_t osst_linux_media_version_show(struct device *dev,
5691 struct device_attribute *attr,
5692 char *buf)
5694 struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev);
5695 ssize_t l = 0;
5697 if (STp && STp->header_ok && STp->linux_media)
5698 l = snprintf(buf, PAGE_SIZE, "LIN%d\n", STp->linux_media_version);
5699 return l;
5702 DEVICE_ATTR(media_version, S_IRUGO, osst_linux_media_version_show, NULL);
5704 static ssize_t osst_capacity_show(struct device *dev,
5705 struct device_attribute *attr, char *buf)
5707 struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev);
5708 ssize_t l = 0;
5710 if (STp && STp->header_ok && STp->linux_media)
5711 l = snprintf(buf, PAGE_SIZE, "%d\n", STp->capacity);
5712 return l;
5715 DEVICE_ATTR(capacity, S_IRUGO, osst_capacity_show, NULL);
5717 static ssize_t osst_first_data_ppos_show(struct device *dev,
5718 struct device_attribute *attr,
5719 char *buf)
5721 struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev);
5722 ssize_t l = 0;
5724 if (STp && STp->header_ok && STp->linux_media)
5725 l = snprintf(buf, PAGE_SIZE, "%d\n", STp->first_data_ppos);
5726 return l;
5729 DEVICE_ATTR(BOT_frame, S_IRUGO, osst_first_data_ppos_show, NULL);
5731 static ssize_t osst_eod_frame_ppos_show(struct device *dev,
5732 struct device_attribute *attr,
5733 char *buf)
5735 struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev);
5736 ssize_t l = 0;
5738 if (STp && STp->header_ok && STp->linux_media)
5739 l = snprintf(buf, PAGE_SIZE, "%d\n", STp->eod_frame_ppos);
5740 return l;
5743 DEVICE_ATTR(EOD_frame, S_IRUGO, osst_eod_frame_ppos_show, NULL);
5745 static ssize_t osst_filemark_cnt_show(struct device *dev,
5746 struct device_attribute *attr, char *buf)
5748 struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev);
5749 ssize_t l = 0;
5751 if (STp && STp->header_ok && STp->linux_media)
5752 l = snprintf(buf, PAGE_SIZE, "%d\n", STp->filemark_cnt);
5753 return l;
5756 DEVICE_ATTR(file_count, S_IRUGO, osst_filemark_cnt_show, NULL);
5758 static struct class *osst_sysfs_class;
5760 static int osst_sysfs_init(void)
5762 osst_sysfs_class = class_create(THIS_MODULE, "onstream_tape");
5763 if (IS_ERR(osst_sysfs_class)) {
5764 printk(KERN_ERR "osst :W: Unable to register sysfs class\n");
5765 return PTR_ERR(osst_sysfs_class);
5768 return 0;
5771 static void osst_sysfs_destroy(dev_t dev)
5773 device_destroy(osst_sysfs_class, dev);
5776 static int osst_sysfs_add(dev_t dev, struct device *device, struct osst_tape * STp, char * name)
5778 struct device *osst_member;
5779 int err;
5781 osst_member = device_create(osst_sysfs_class, device, dev, STp,
5782 "%s", name);
5783 if (IS_ERR(osst_member)) {
5784 printk(KERN_WARNING "osst :W: Unable to add sysfs class member %s\n", name);
5785 return PTR_ERR(osst_member);
5788 err = device_create_file(osst_member, &dev_attr_ADR_rev);
5789 if (err)
5790 goto err_out;
5791 err = device_create_file(osst_member, &dev_attr_media_version);
5792 if (err)
5793 goto err_out;
5794 err = device_create_file(osst_member, &dev_attr_capacity);
5795 if (err)
5796 goto err_out;
5797 err = device_create_file(osst_member, &dev_attr_BOT_frame);
5798 if (err)
5799 goto err_out;
5800 err = device_create_file(osst_member, &dev_attr_EOD_frame);
5801 if (err)
5802 goto err_out;
5803 err = device_create_file(osst_member, &dev_attr_file_count);
5804 if (err)
5805 goto err_out;
5807 return 0;
5809 err_out:
5810 osst_sysfs_destroy(dev);
5811 return err;
5814 static void osst_sysfs_cleanup(void)
5816 class_destroy(osst_sysfs_class);
5820 * osst startup / cleanup code
5823 static int osst_probe(struct device *dev)
5825 struct scsi_device * SDp = to_scsi_device(dev);
5826 struct osst_tape * tpnt;
5827 struct st_modedef * STm;
5828 struct st_partstat * STps;
5829 struct osst_buffer * buffer;
5830 struct gendisk * drive;
5831 int i, dev_num, err = -ENODEV;
5833 if (SDp->type != TYPE_TAPE || !osst_supports(SDp))
5834 return -ENODEV;
5836 drive = alloc_disk(1);
5837 if (!drive) {
5838 printk(KERN_ERR "osst :E: Out of memory. Device not attached.\n");
5839 return -ENODEV;
5842 /* if this is the first attach, build the infrastructure */
5843 write_lock(&os_scsi_tapes_lock);
5844 if (os_scsi_tapes == NULL) {
5845 os_scsi_tapes =
5846 (struct osst_tape **)kmalloc(osst_max_dev * sizeof(struct osst_tape *),
5847 GFP_ATOMIC);
5848 if (os_scsi_tapes == NULL) {
5849 write_unlock(&os_scsi_tapes_lock);
5850 printk(KERN_ERR "osst :E: Unable to allocate array for OnStream SCSI tapes.\n");
5851 goto out_put_disk;
5853 for (i=0; i < osst_max_dev; ++i) os_scsi_tapes[i] = NULL;
5856 if (osst_nr_dev >= osst_max_dev) {
5857 write_unlock(&os_scsi_tapes_lock);
5858 printk(KERN_ERR "osst :E: Too many tape devices (max. %d).\n", osst_max_dev);
5859 goto out_put_disk;
5862 /* find a free minor number */
5863 for (i=0; os_scsi_tapes[i] && i<osst_max_dev; i++);
5864 if(i >= osst_max_dev) panic ("Scsi_devices corrupt (osst)");
5865 dev_num = i;
5867 /* allocate a struct osst_tape for this device */
5868 tpnt = kzalloc(sizeof(struct osst_tape), GFP_ATOMIC);
5869 if (!tpnt) {
5870 write_unlock(&os_scsi_tapes_lock);
5871 printk(KERN_ERR "osst :E: Can't allocate device descriptor, device not attached.\n");
5872 goto out_put_disk;
5875 /* allocate a buffer for this device */
5876 i = SDp->host->sg_tablesize;
5877 if (osst_max_sg_segs < i)
5878 i = osst_max_sg_segs;
5879 buffer = new_tape_buffer(1, SDp->host->unchecked_isa_dma, i);
5880 if (buffer == NULL) {
5881 write_unlock(&os_scsi_tapes_lock);
5882 printk(KERN_ERR "osst :E: Unable to allocate a tape buffer, device not attached.\n");
5883 kfree(tpnt);
5884 goto out_put_disk;
5886 os_scsi_tapes[dev_num] = tpnt;
5887 tpnt->buffer = buffer;
5888 tpnt->device = SDp;
5889 drive->private_data = &tpnt->driver;
5890 sprintf(drive->disk_name, "osst%d", dev_num);
5891 tpnt->driver = &osst_template;
5892 tpnt->drive = drive;
5893 tpnt->in_use = 0;
5894 tpnt->capacity = 0xfffff;
5895 tpnt->dirty = 0;
5896 tpnt->drv_buffer = 1; /* Try buffering if no mode sense */
5897 tpnt->restr_dma = (SDp->host)->unchecked_isa_dma;
5898 tpnt->density = 0;
5899 tpnt->do_auto_lock = OSST_AUTO_LOCK;
5900 tpnt->can_bsr = OSST_IN_FILE_POS;
5901 tpnt->can_partitions = 0;
5902 tpnt->two_fm = OSST_TWO_FM;
5903 tpnt->fast_mteom = OSST_FAST_MTEOM;
5904 tpnt->scsi2_logical = OSST_SCSI2LOGICAL; /* FIXME */
5905 tpnt->write_threshold = osst_write_threshold;
5906 tpnt->default_drvbuffer = 0xff; /* No forced buffering */
5907 tpnt->partition = 0;
5908 tpnt->new_partition = 0;
5909 tpnt->nbr_partitions = 0;
5910 tpnt->min_block = 512;
5911 tpnt->max_block = OS_DATA_SIZE;
5912 tpnt->timeout = OSST_TIMEOUT;
5913 tpnt->long_timeout = OSST_LONG_TIMEOUT;
5915 /* Recognize OnStream tapes */
5916 /* We don't need to test for OnStream, as this has been done in detect () */
5917 tpnt->os_fw_rev = osst_parse_firmware_rev (SDp->rev);
5918 tpnt->omit_blklims = 1;
5920 tpnt->poll = (strncmp(SDp->model, "DI-", 3) == 0) ||
5921 (strncmp(SDp->model, "FW-", 3) == 0) || OSST_FW_NEED_POLL(tpnt->os_fw_rev,SDp);
5922 tpnt->frame_in_buffer = 0;
5923 tpnt->header_ok = 0;
5924 tpnt->linux_media = 0;
5925 tpnt->header_cache = NULL;
5927 for (i=0; i < ST_NBR_MODES; i++) {
5928 STm = &(tpnt->modes[i]);
5929 STm->defined = 0;
5930 STm->sysv = OSST_SYSV;
5931 STm->defaults_for_writes = 0;
5932 STm->do_async_writes = OSST_ASYNC_WRITES;
5933 STm->do_buffer_writes = OSST_BUFFER_WRITES;
5934 STm->do_read_ahead = OSST_READ_AHEAD;
5935 STm->default_compression = ST_DONT_TOUCH;
5936 STm->default_blksize = 512;
5937 STm->default_density = (-1); /* No forced density */
5940 for (i=0; i < ST_NBR_PARTITIONS; i++) {
5941 STps = &(tpnt->ps[i]);
5942 STps->rw = ST_IDLE;
5943 STps->eof = ST_NOEOF;
5944 STps->at_sm = 0;
5945 STps->last_block_valid = 0;
5946 STps->drv_block = (-1);
5947 STps->drv_file = (-1);
5950 tpnt->current_mode = 0;
5951 tpnt->modes[0].defined = 1;
5952 tpnt->modes[2].defined = 1;
5953 tpnt->density_changed = tpnt->compression_changed = tpnt->blksize_changed = 0;
5955 mutex_init(&tpnt->lock);
5956 osst_nr_dev++;
5957 write_unlock(&os_scsi_tapes_lock);
5960 char name[8];
5962 /* Rewind entry */
5963 err = osst_sysfs_add(MKDEV(OSST_MAJOR, dev_num), dev, tpnt, tape_name(tpnt));
5964 if (err)
5965 goto out_free_buffer;
5967 /* No-rewind entry */
5968 snprintf(name, 8, "%s%s", "n", tape_name(tpnt));
5969 err = osst_sysfs_add(MKDEV(OSST_MAJOR, dev_num + 128), dev, tpnt, name);
5970 if (err)
5971 goto out_free_sysfs1;
5974 sdev_printk(KERN_INFO, SDp,
5975 "osst :I: Attached OnStream %.5s tape as %s\n",
5976 SDp->model, tape_name(tpnt));
5978 return 0;
5980 out_free_sysfs1:
5981 osst_sysfs_destroy(MKDEV(OSST_MAJOR, dev_num));
5982 out_free_buffer:
5983 kfree(buffer);
5984 out_put_disk:
5985 put_disk(drive);
5986 return err;
5989 static int osst_remove(struct device *dev)
5991 struct scsi_device * SDp = to_scsi_device(dev);
5992 struct osst_tape * tpnt;
5993 int i;
5995 if ((SDp->type != TYPE_TAPE) || (osst_nr_dev <= 0))
5996 return 0;
5998 write_lock(&os_scsi_tapes_lock);
5999 for(i=0; i < osst_max_dev; i++) {
6000 if((tpnt = os_scsi_tapes[i]) && (tpnt->device == SDp)) {
6001 osst_sysfs_destroy(MKDEV(OSST_MAJOR, i));
6002 osst_sysfs_destroy(MKDEV(OSST_MAJOR, i+128));
6003 tpnt->device = NULL;
6004 put_disk(tpnt->drive);
6005 os_scsi_tapes[i] = NULL;
6006 osst_nr_dev--;
6007 write_unlock(&os_scsi_tapes_lock);
6008 vfree(tpnt->header_cache);
6009 if (tpnt->buffer) {
6010 normalize_buffer(tpnt->buffer);
6011 kfree(tpnt->buffer);
6013 kfree(tpnt);
6014 return 0;
6017 write_unlock(&os_scsi_tapes_lock);
6018 return 0;
6021 static int __init init_osst(void)
6023 int err;
6025 printk(KERN_INFO "osst :I: Tape driver with OnStream support version %s\nosst :I: %s\n", osst_version, cvsid);
6027 validate_options();
6029 err = osst_sysfs_init();
6030 if (err)
6031 return err;
6033 err = register_chrdev(OSST_MAJOR, "osst", &osst_fops);
6034 if (err < 0) {
6035 printk(KERN_ERR "osst :E: Unable to register major %d for OnStream tapes\n", OSST_MAJOR);
6036 goto err_out;
6039 err = scsi_register_driver(&osst_template.gendrv);
6040 if (err)
6041 goto err_out_chrdev;
6043 err = osst_create_sysfs_files(&osst_template.gendrv);
6044 if (err)
6045 goto err_out_scsidrv;
6047 return 0;
6049 err_out_scsidrv:
6050 scsi_unregister_driver(&osst_template.gendrv);
6051 err_out_chrdev:
6052 unregister_chrdev(OSST_MAJOR, "osst");
6053 err_out:
6054 osst_sysfs_cleanup();
6055 return err;
6058 static void __exit exit_osst (void)
6060 int i;
6061 struct osst_tape * STp;
6063 osst_remove_sysfs_files(&osst_template.gendrv);
6064 scsi_unregister_driver(&osst_template.gendrv);
6065 unregister_chrdev(OSST_MAJOR, "osst");
6066 osst_sysfs_cleanup();
6068 if (os_scsi_tapes) {
6069 for (i=0; i < osst_max_dev; ++i) {
6070 if (!(STp = os_scsi_tapes[i])) continue;
6071 /* This is defensive, supposed to happen during detach */
6072 vfree(STp->header_cache);
6073 if (STp->buffer) {
6074 normalize_buffer(STp->buffer);
6075 kfree(STp->buffer);
6077 put_disk(STp->drive);
6078 kfree(STp);
6080 kfree(os_scsi_tapes);
6082 printk(KERN_INFO "osst :I: Unloaded.\n");
6085 module_init(init_osst);
6086 module_exit(exit_osst);