linux-old/drivers/scsi/osst.c
<<
>>
Prefs
   1/*
   2  SCSI Tape Driver for Linux version 1.1 and newer. See the accompanying
   3  file README.st for more information.
   4
   5  History:
   6
   7  OnStream SCSI Tape support (osst) cloned from st.c by
   8  Willem Riede (osst@riede.org) Feb 2000
   9  Fixes ... Kurt Garloff <garloff@suse.de> Mar 2000
  10
  11  Rewritten from Dwayne Forsyth's SCSI tape driver by Kai Makisara.
  12  Contribution and ideas from several people including (in alphabetical
  13  order) Klaus Ehrenfried, Wolfgang Denk, Steve Hirsch, Andreas Koppenh"ofer,
  14  Michael Leodolter, Eyal Lebedinsky, J"org Weule, and Eric Youngdale.
  15
  16  Copyright 1992 - 2000 Kai Makisara
  17                 email Kai.Makisara@metla.fi
  18
  19  $Header: /home/cvsroot/Driver/osst.c,v 1.65 2001/11/11 20:38:56 riede Exp $
  20
  21  Microscopic alterations - Rik Ling, 2000/12/21
  22  Last modified: Wed Feb  2 22:04:05 2000 by makisara@kai.makisara.local
  23  Some small formal changes - aeb, 950809
  24*/
  25
  26static const char * cvsid = "$Id: osst.c,v 1.65 2001/11/11 20:38:56 riede Exp $";
  27const char * osst_version = "0.9.10";
  28
  29/* The "failure to reconnect" firmware bug */
  30#define OSST_FW_NEED_POLL_MIN 10601 /*(107A)*/
  31#define OSST_FW_NEED_POLL_MAX 10704 /*(108D)*/
  32#define OSST_FW_NEED_POLL(x,d) ((x) >= OSST_FW_NEED_POLL_MIN && (x) <= OSST_FW_NEED_POLL_MAX && d->host->this_id != 7)
  33
  34#include <linux/module.h>
  35
  36#include <linux/fs.h>
  37#include <linux/kernel.h>
  38#include <linux/sched.h>
  39#include <linux/mm.h>
  40#include <linux/init.h>
  41#include <linux/string.h>
  42#include <linux/errno.h>
  43#include <linux/mtio.h>
  44#include <linux/ioctl.h>
  45#include <linux/fcntl.h>
  46#include <linux/spinlock.h>
  47#include <linux/vmalloc.h>
  48#include <linux/version.h>
  49#include <asm/uaccess.h>
  50#include <asm/dma.h>
  51#include <asm/system.h>
  52
  53/* The driver prints some debugging information on the console if DEBUG
  54   is defined and non-zero. */
  55#define DEBUG 0
  56
  57/* The message level for the debug messages is currently set to KERN_NOTICE
  58   so that people can easily see the messages. Later when the debugging messages
  59   in the drivers are more widely classified, this may be changed to KERN_DEBUG. */
  60#define OSST_DEB_MSG  KERN_NOTICE
  61
  62#define MAJOR_NR OSST_MAJOR
  63#include <linux/blk.h>
  64
  65#include "scsi.h"
  66#include "hosts.h"
  67#include <scsi/scsi_ioctl.h>
  68
  69#define ST_KILOBYTE 1024
  70
  71#include "st.h"
  72#include "osst.h"
  73#include "osst_options.h"
  74#include "osst_detect.h"
  75
  76#include "constants.h"
  77
  78static int buffer_kbs = 0;
  79static int write_threshold_kbs = 0;
  80static int max_buffers = 0;
  81static int max_sg_segs = 0;
  82
  83#ifdef MODULE
  84MODULE_AUTHOR("Willem Riede");
  85MODULE_DESCRIPTION("OnStream SCSI Tape Driver");
  86MODULE_LICENSE("GPL");
  87
  88MODULE_PARM(buffer_kbs, "i");
  89MODULE_PARM(write_threshold_kbs, "i");
  90MODULE_PARM(max_buffers, "i");
  91MODULE_PARM(max_sg_segs, "i");
  92#else
  93static struct osst_dev_parm {
  94       char   *name;
  95       int    *val;
  96} parms[] __initdata = {
  97       { "buffer_kbs",          &buffer_kbs          },
  98       { "write_threshold_kbs", &write_threshold_kbs },
  99       { "max_buffers",         &max_buffers         },
 100       { "max_sg_segs",         &max_sg_segs         }
 101       };
 102#endif
 103
 104/* Some default definitions have been moved to osst_options.h */
 105#define OSST_BUFFER_SIZE (OSST_BUFFER_BLOCKS * ST_KILOBYTE)
 106#define OSST_WRITE_THRESHOLD (OSST_WRITE_THRESHOLD_BLOCKS * ST_KILOBYTE)
 107
 108/* The buffer size should fit into the 24 bits for length in the
 109   6-byte SCSI read and write commands. */
 110#if OSST_BUFFER_SIZE >= (2 << 24 - 1)
 111#error "Buffer size should not exceed (2 << 24 - 1) bytes!"
 112#endif
 113
 114#if DEBUG
 115static int debugging = 1;
 116/* uncomment define below to test error recovery */
 117// #define OSST_INJECT_ERRORS 1 
 118#endif
 119
 120#define MAX_RETRIES 0
 121#define MAX_WRITE_RETRIES 0
 122#define MAX_READY_RETRIES 5
 123#define NO_TAPE  NOT_READY
 124
 125#define OSST_TIMEOUT (200 * HZ)
 126#define OSST_LONG_TIMEOUT (1800 * HZ)
 127
 128#define TAPE_NR(x) (MINOR(x) & ~(128 | ST_MODE_MASK))
 129#define TAPE_MODE(x) ((MINOR(x) & ST_MODE_MASK) >> ST_MODE_SHIFT)
 130
 131/* Internal ioctl to set both density (uppermost 8 bits) and blocksize (lower
 132   24 bits) */
 133#define SET_DENS_AND_BLK 0x10001
 134
 135static int osst_nbr_buffers;
 136static int osst_buffer_size       = OSST_BUFFER_SIZE;
 137static int osst_write_threshold   = OSST_WRITE_THRESHOLD;
 138static int osst_max_buffers       = OSST_MAX_BUFFERS;
 139static int osst_max_sg_segs       = OSST_MAX_SG;
 140
 141static OS_Scsi_Tape **os_scsi_tapes = NULL;
 142static OSST_buffer  **osst_buffers  = NULL;
 143
 144static int modes_defined = FALSE;
 145
 146static OSST_buffer *new_tape_buffer(int, int);
 147static int enlarge_buffer(OSST_buffer *, int, int);
 148static void normalize_buffer(OSST_buffer *);
 149static int append_to_buffer(const char *, OSST_buffer *, int);
 150static int from_buffer(OSST_buffer *, char *, int);
 151static int osst_zero_buffer_tail(OSST_buffer *);
 152static int osst_copy_to_buffer(OSST_buffer *, unsigned char *);
 153static int osst_copy_from_buffer(OSST_buffer *, unsigned char *);
 154
 155static int osst_init(void);
 156static int osst_attach(Scsi_Device *);
 157static int osst_detect(Scsi_Device *);
 158static void osst_detach(Scsi_Device *);
 159
 160struct Scsi_Device_Template osst_template =
 161{
 162       name:            "OnStream tape",
 163       tag:             "osst",
 164       scsi_type:       TYPE_TAPE,
 165       major:           OSST_MAJOR,
 166       detect:          osst_detect,
 167       init:            osst_init,
 168       attach:          osst_attach,
 169       detach:          osst_detach
 170};
 171
 172static int osst_int_ioctl(OS_Scsi_Tape *STp, Scsi_Request ** aSRpnt, unsigned int cmd_in,unsigned long arg);
 173
 174static int osst_set_frame_position(OS_Scsi_Tape *STp, Scsi_Request ** aSRpnt, int frame, int skip);
 175
 176static int osst_get_frame_position(OS_Scsi_Tape *STp, Scsi_Request ** aSRpnt);
 177
 178static int osst_flush_write_buffer(OS_Scsi_Tape *STp, Scsi_Request ** aSRpnt);
 179
 180static int osst_write_error_recovery(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int pending);
 181
 182
 183/* Routines that handle the interaction with mid-layer SCSI routines */
 184
 185/* Convert the result to success code */
 186static int osst_chk_result(OS_Scsi_Tape * STp, Scsi_Request * SRpnt)
 187{
 188        int dev = TAPE_NR(STp->devt);
 189        int result = SRpnt->sr_result;
 190        unsigned char * sense = SRpnt->sr_sense_buffer, scode;
 191#if DEBUG
 192        const char *stp;
 193#endif
 194
 195        if (!result) {
 196                sense[0] = 0;    /* We don't have sense data if this byte is zero */
 197                return 0;
 198        }
 199        if (driver_byte(result) & DRIVER_SENSE)
 200                scode = sense[2] & 0x0f;
 201        else {
 202                sense[0] = 0;    /* We don't have sense data if this byte is zero */
 203                scode = 0;
 204        }
 205
 206#if DEBUG
 207        if (debugging) {
 208                printk(OSST_DEB_MSG "osst%d:D: Error: %x, cmd: %x %x %x %x %x %x Len: %d\n",
 209                   dev, result,
 210                   SRpnt->sr_cmnd[0], SRpnt->sr_cmnd[1], SRpnt->sr_cmnd[2],
 211                   SRpnt->sr_cmnd[3], SRpnt->sr_cmnd[4], SRpnt->sr_cmnd[5],
 212                   SRpnt->sr_bufflen);
 213                if (driver_byte(result) & DRIVER_SENSE)
 214                        print_req_sense("osst", SRpnt);
 215        }
 216        else
 217#endif
 218        if (!(driver_byte(result) & DRIVER_SENSE) ||
 219                ((sense[0] & 0x70) == 0x70 &&
 220                 scode != NO_SENSE &&
 221                 scode != RECOVERED_ERROR &&
 222/*               scode != UNIT_ATTENTION && */
 223                 scode != BLANK_CHECK &&
 224                 scode != VOLUME_OVERFLOW &&
 225                 SRpnt->sr_cmnd[0] != MODE_SENSE &&
 226                 SRpnt->sr_cmnd[0] != TEST_UNIT_READY)) { /* Abnormal conditions for tape */
 227                if (driver_byte(result) & DRIVER_SENSE) {
 228                        printk(KERN_WARNING "osst%d:W: Command with sense data: ", dev);
 229                        print_req_sense("osst:", SRpnt);
 230                }
 231                else {
 232                        static  int     notyetprinted = 1;
 233
 234                        printk(KERN_WARNING
 235                             "osst%d:W: Warning %x (sugg. bt 0x%x, driver bt 0x%x, host bt 0x%x).\n",
 236                             dev, result, suggestion(result), driver_byte(result) & DRIVER_MASK,
 237                             host_byte(result));
 238                        if (notyetprinted) {
 239                                notyetprinted = 0;
 240                                printk(KERN_INFO
 241                                        "osst%d:I: This warning may be caused by your scsi controller,\n", dev);
 242                                printk(KERN_INFO
 243                                        "osst%d:I: it has been reported with some Buslogic cards.\n", dev);
 244                        }
 245                }
 246        }
 247        if ((sense[0] & 0x70) == 0x70 &&
 248             scode == RECOVERED_ERROR) {
 249                STp->recover_count++;
 250                STp->recover_erreg++;
 251#if DEBUG
 252                if (debugging) {
 253                        if (SRpnt->sr_cmnd[0] == READ_6)
 254                                stp = "read";
 255                        else if (SRpnt->sr_cmnd[0] == WRITE_6)
 256                                stp = "write";
 257                        else
 258                                stp = "ioctl";
 259                        printk(OSST_DEB_MSG "osst%d:D: Recovered %s error (%d).\n", dev, stp,
 260                                             os_scsi_tapes[dev]->recover_count);
 261                }
 262#endif
 263                if ((sense[2] & 0xe0) == 0)
 264                        return 0;
 265        }
 266        return (-EIO);
 267}
 268
 269
 270/* Wakeup from interrupt */
 271static void osst_sleep_done (Scsi_Cmnd * SCpnt)
 272{
 273        unsigned int dev = TAPE_NR(SCpnt->request.rq_dev);
 274        OS_Scsi_Tape * STp;
 275
 276        if (os_scsi_tapes && (STp = os_scsi_tapes[dev])) {
 277                if ((STp->buffer)->writing &&
 278                    (SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
 279                    (SCpnt->sense_buffer[2] & 0x40)) {
 280                        /* EOM at write-behind, has all been written? */
 281                        if ((SCpnt->sense_buffer[2] & 0x0f) == VOLUME_OVERFLOW)
 282                                (STp->buffer)->midlevel_result = SCpnt->result; /* Error */
 283                        else
 284                                (STp->buffer)->midlevel_result = INT_MAX;       /* OK */
 285                }
 286                else
 287                        (STp->buffer)->midlevel_result = SCpnt->result;
 288                SCpnt->request.rq_status = RQ_SCSI_DONE;
 289                (STp->buffer)->last_SRpnt = SCpnt->sc_request;
 290
 291#if DEBUG
 292                STp->write_pending = 0;
 293#endif
 294                complete(SCpnt->request.waiting);
 295        }
 296#if DEBUG
 297        else if (debugging)
 298                printk(OSST_DEB_MSG "osst?:D: Illegal interrupt device %x\n", dev);
 299#endif
 300}
 301
 302
 303/* Do the scsi command. Waits until command performed if do_wait is true.
 304   Otherwise osst_write_behind_check() is used to check that the command
 305   has finished. */
 306static  Scsi_Request * osst_do_scsi(Scsi_Request *SRpnt, OS_Scsi_Tape *STp, 
 307        unsigned char *cmd, int bytes, int direction, int timeout, int retries, int do_wait)
 308{
 309        unsigned char *bp;
 310#ifdef OSST_INJECT_ERRORS
 311        static   int   inject = 0;
 312        static   int   repeat = 0;
 313#endif
 314        if (SRpnt == NULL) {
 315                if ((SRpnt = scsi_allocate_request(STp->device)) == NULL) {
 316                        printk(KERN_ERR "osst%d:E: Can't get SCSI request.\n", TAPE_NR(STp->devt));
 317                        if (signal_pending(current))
 318                                (STp->buffer)->syscall_result = (-EINTR);
 319                        else
 320                                (STp->buffer)->syscall_result = (-EBUSY);
 321                        return NULL;
 322                }
 323        }
 324
 325        if (SRpnt->sr_device->scsi_level <= SCSI_2)
 326                cmd[1] |= (SRpnt->sr_device->lun << 5) & 0xe0;
 327        init_completion(&STp->wait);
 328        SRpnt->sr_use_sg = (bytes > (STp->buffer)->sg[0].length) ?
 329                                    (STp->buffer)->use_sg : 0;
 330        if (SRpnt->sr_use_sg) {
 331                bp = (char *)&(STp->buffer->sg[0]);
 332                if (STp->buffer->sg_segs < SRpnt->sr_use_sg)
 333                        SRpnt->sr_use_sg = STp->buffer->sg_segs;
 334        }
 335        else
 336                bp = (STp->buffer)->b_data;
 337        SRpnt->sr_data_direction = direction;
 338        SRpnt->sr_cmd_len = 0;
 339        SRpnt->sr_request.waiting = &(STp->wait);
 340        SRpnt->sr_request.rq_status = RQ_SCSI_BUSY;
 341        SRpnt->sr_request.rq_dev = STp->devt;
 342
 343        scsi_do_req(SRpnt, (void *)cmd, bp, bytes, osst_sleep_done, timeout, retries);
 344
 345        if (do_wait) {
 346                wait_for_completion(SRpnt->sr_request.waiting);
 347                SRpnt->sr_request.waiting = NULL;
 348                STp->buffer->syscall_result = osst_chk_result(STp, SRpnt);
 349#ifdef OSST_INJECT_ERRORS
 350                if (STp->buffer->syscall_result == 0 &&
 351                    cmd[0] == READ_6 &&
 352                    cmd[4] && 
 353                    ( (++ inject % 83) == 29  ||
 354                      (STp->first_frame_position == 240 
 355                                 /* or STp->read_error_frame to fail again on the block calculated above */ &&
 356                                 ++repeat < 3))) {
 357                        printk(OSST_DEB_MSG "osst%d:D: Injecting read error\n", TAPE_NR(STp->devt));
 358                        STp->buffer->last_result_fatal = 1;
 359                }
 360#endif
 361        }
 362        return SRpnt;
 363}
 364
 365
 366/* Handle the write-behind checking (downs the semaphore) */
 367static void osst_write_behind_check(OS_Scsi_Tape *STp)
 368{
 369        OSST_buffer * STbuffer;
 370
 371        STbuffer = STp->buffer;
 372
 373#if DEBUG
 374        if (STp->write_pending)
 375                STp->nbr_waits++;
 376        else
 377                STp->nbr_finished++;
 378#endif
 379        wait_for_completion(&(STp->wait));
 380        (STp->buffer)->last_SRpnt->sr_request.waiting = NULL;
 381
 382        STp->buffer->syscall_result = osst_chk_result(STp, STp->buffer->last_SRpnt);
 383
 384        if ((STp->buffer)->syscall_result)
 385                (STp->buffer)->syscall_result =
 386                        osst_write_error_recovery(STp, &((STp->buffer)->last_SRpnt), 1);
 387        else
 388                STp->first_frame_position++;
 389
 390        scsi_release_request((STp->buffer)->last_SRpnt);
 391
 392        if (STbuffer->writing < STbuffer->buffer_bytes)
 393                printk(KERN_WARNING "osst:A: write_behind_check: something left in buffer!\n");
 394
 395        STbuffer->buffer_bytes -= STbuffer->writing;
 396        STbuffer->writing = 0;
 397
 398        return;
 399}
 400
 401
 402
 403/* Onstream specific Routines */
 404/*
 405 * Initialize the OnStream AUX
 406 */
 407static void osst_init_aux(OS_Scsi_Tape * STp, int frame_type, int frame_seq_number,
 408                                         int logical_blk_num, int blk_sz, int blk_cnt)
 409{
 410        os_aux_t       *aux = STp->buffer->aux;
 411        os_partition_t *par = &aux->partition;
 412        os_dat_t       *dat = &aux->dat;
 413
 414        if (STp->raw) return;
 415
 416        memset(aux, 0, sizeof(*aux));
 417        aux->format_id = htonl(0);
 418        memcpy(aux->application_sig, "LIN4", 4);
 419        aux->hdwr = htonl(0);
 420        aux->frame_type = frame_type;
 421
 422        switch (frame_type) {
 423          case  OS_FRAME_TYPE_HEADER:
 424                aux->update_frame_cntr    = htonl(STp->update_frame_cntr);
 425                par->partition_num        = OS_CONFIG_PARTITION;
 426                par->par_desc_ver         = OS_PARTITION_VERSION;
 427                par->wrt_pass_cntr        = htons(0xffff);
 428                /* 0-4 = reserved, 5-9 = header, 2990-2994 = header, 2995-2999 = reserved */
 429                par->first_frame_ppos     = htonl(0);
 430                par->last_frame_ppos      = htonl(0xbb7);
 431                aux->frame_seq_num        = htonl(0);
 432                aux->logical_blk_num_high = htonl(0);
 433                aux->logical_blk_num      = htonl(0);
 434                aux->next_mark_ppos       = htonl(STp->first_mark_ppos);
 435                break;
 436          case  OS_FRAME_TYPE_DATA:
 437          case  OS_FRAME_TYPE_MARKER:
 438                dat->dat_sz = 8;
 439                dat->reserved1 = 0;
 440                dat->entry_cnt = 1;
 441                dat->reserved3 = 0;
 442                dat->dat_list[0].blk_sz   = htonl(blk_sz);
 443                dat->dat_list[0].blk_cnt  = htons(blk_cnt);
 444                dat->dat_list[0].flags    = frame_type==OS_FRAME_TYPE_MARKER?
 445                                                        OS_DAT_FLAGS_MARK:OS_DAT_FLAGS_DATA;
 446                dat->dat_list[0].reserved = 0;
 447          case  OS_FRAME_TYPE_EOD:
 448                aux->update_frame_cntr    = htonl(0);
 449                par->partition_num        = OS_DATA_PARTITION;
 450                par->par_desc_ver         = OS_PARTITION_VERSION;
 451                par->wrt_pass_cntr        = htons(STp->wrt_pass_cntr);
 452                par->first_frame_ppos     = htonl(STp->first_data_ppos);
 453                par->last_frame_ppos      = htonl(STp->capacity);
 454                aux->frame_seq_num        = htonl(frame_seq_number);
 455                aux->logical_blk_num_high = htonl(0);
 456                aux->logical_blk_num      = htonl(logical_blk_num);
 457                break;
 458          default: ; /* probably FILL */
 459        }
 460        aux->filemark_cnt = ntohl(STp->filemark_cnt);
 461        aux->phys_fm = ntohl(0xffffffff);
 462        aux->last_mark_ppos = ntohl(STp->last_mark_ppos);
 463        aux->last_mark_lbn  = ntohl(STp->last_mark_lbn);
 464}
 465
 466/*
 467 * Verify that we have the correct tape frame
 468 */
 469static int osst_verify_frame(OS_Scsi_Tape * STp, int frame_seq_number, int quiet)
 470{
 471        os_aux_t       * aux  = STp->buffer->aux;
 472        os_partition_t * par  = &(aux->partition);
 473        ST_partstat    * STps = &(STp->ps[STp->partition]);
 474        int              dev  = TAPE_NR(STp->devt);
 475        int              blk_cnt, blk_sz, i;
 476
 477        if (STp->raw) {
 478                if (STp->buffer->syscall_result) {
 479                        for (i=0; i < STp->buffer->sg_segs; i++)
 480                                memset(STp->buffer->sg[i].address, 0, STp->buffer->sg[i].length);
 481                        strcpy(STp->buffer->b_data, "READ ERROR ON FRAME");
 482                } else
 483                        STp->buffer->buffer_bytes = OS_FRAME_SIZE;
 484                return 1;
 485        }
 486        if (STp->buffer->syscall_result) {
 487#if DEBUG
 488                printk(OSST_DEB_MSG "osst%d:D: Skipping frame, read error\n", dev);
 489#endif
 490                return 0;
 491        }
 492        if (ntohl(aux->format_id) != 0) {
 493#if DEBUG
 494                printk(OSST_DEB_MSG "osst%d:D: Skipping frame, format_id %u\n", dev, ntohl(aux->format_id));
 495#endif
 496                goto err_out;
 497        }
 498        if (memcmp(aux->application_sig, STp->application_sig, 4) != 0 &&
 499            (memcmp(aux->application_sig, "LIN3", 4) != 0 || STp->linux_media_version != 4)) {
 500#if DEBUG
 501                printk(OSST_DEB_MSG "osst%d:D: Skipping frame, incorrect application signature\n", dev);
 502#endif
 503                goto err_out;
 504        }
 505        if (par->partition_num != OS_DATA_PARTITION) {
 506                if (!STp->linux_media || STp->linux_media_version != 2) {
 507#if DEBUG
 508                        printk(OSST_DEB_MSG "osst%d:D: Skipping frame, partition num %d\n",
 509                                            dev, par->partition_num);
 510#endif
 511                        goto err_out;
 512                }
 513        }
 514        if (par->par_desc_ver != OS_PARTITION_VERSION) {
 515#if DEBUG
 516                printk(OSST_DEB_MSG "osst%d:D: Skipping frame, partition version %d\n", dev, par->par_desc_ver);
 517#endif
 518                goto err_out;
 519        }
 520        if (ntohs(par->wrt_pass_cntr) != STp->wrt_pass_cntr) {
 521#if DEBUG
 522                printk(OSST_DEB_MSG "osst%d:D: Skipping frame, wrt_pass_cntr %d (expected %d)\n", 
 523                                    dev, ntohs(par->wrt_pass_cntr), STp->wrt_pass_cntr);
 524#endif
 525                goto err_out;
 526        }
 527        if (aux->frame_type != OS_FRAME_TYPE_DATA &&
 528            aux->frame_type != OS_FRAME_TYPE_EOD &&
 529            aux->frame_type != OS_FRAME_TYPE_MARKER) {
 530                if (!quiet)
 531#if DEBUG
 532                        printk(OSST_DEB_MSG "osst%d:D: Skipping frame, frame type %x\n", dev, aux->frame_type);
 533#endif
 534                goto err_out;
 535        }
 536        if (aux->frame_type == OS_FRAME_TYPE_EOD &&
 537            STp->first_frame_position < STp->eod_frame_ppos) {
 538                printk(KERN_INFO "osst%d:I: Skipping premature EOD frame %d\n", dev,
 539                                 STp->first_frame_position);
 540                goto err_out;
 541        }
 542        STp->frame_in_buffer = 1;
 543
 544        if (frame_seq_number != -1 && ntohl(aux->frame_seq_num) != frame_seq_number) {
 545                if (!quiet)
 546#if DEBUG
 547                        printk(OSST_DEB_MSG "osst%d:D: Skipping frame, sequence number %u (expected %d)\n", 
 548                                            dev, ntohl(aux->frame_seq_num), frame_seq_number);
 549#endif
 550                goto err_out;
 551        }
 552        if (aux->frame_type == OS_FRAME_TYPE_MARKER) {
 553                STps->eof = ST_FM_HIT;
 554
 555                i = ntohl(aux->filemark_cnt);
 556                if (STp->header_cache != NULL && i < OS_FM_TAB_MAX && (i > STp->filemark_cnt ||
 557                    STp->first_frame_position - 1 != ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[i]))) {
 558#if DEBUG
 559                        printk(OSST_DEB_MSG "osst%d:D: %s filemark %d at frame pos %d\n", dev,
 560                                  STp->header_cache->dat_fm_tab.fm_tab_ent[i] == 0?"Learned":"Corrected",
 561                                  i, STp->first_frame_position - 1);
 562#endif
 563                        STp->header_cache->dat_fm_tab.fm_tab_ent[i] = htonl(STp->first_frame_position - 1);
 564                        if (i >= STp->filemark_cnt)
 565                                 STp->filemark_cnt = i+1;
 566                }
 567        }
 568        if (aux->frame_type == OS_FRAME_TYPE_EOD) {
 569                STps->eof = ST_EOD_1;
 570        }
 571        if (aux->frame_type == OS_FRAME_TYPE_DATA) {
 572                blk_cnt = ntohs(aux->dat.dat_list[0].blk_cnt);
 573                blk_sz  = ntohl(aux->dat.dat_list[0].blk_sz);
 574                STp->buffer->buffer_bytes = blk_cnt * blk_sz;
 575                STp->buffer->read_pointer = 0;
 576
 577                /* See what block size was used to write file */
 578                if (STp->block_size != blk_sz && blk_sz > 0) {
 579                        printk(KERN_INFO
 580                "osst%d:I: File was written with block size %d%c, currently %d%c, adjusted to match.\n",
 581                                dev, blk_sz<1024?blk_sz:blk_sz/1024,blk_sz<1024?'b':'k',
 582                                STp->block_size<1024?STp->block_size:STp->block_size/1024,
 583                                STp->block_size<1024?'b':'k');
 584                        STp->block_size            = blk_sz;
 585                        STp->buffer->buffer_blocks = OS_DATA_SIZE / blk_sz;
 586                }
 587                STps->eof = ST_NOEOF;
 588        }
 589        STp->frame_seq_number = ntohl(aux->frame_seq_num);
 590        STp->logical_blk_num  = ntohl(aux->logical_blk_num);
 591        return 1;
 592
 593err_out:
 594        if (STp->read_error_frame == 0)
 595                STp->read_error_frame = STp->first_frame_position - 1;
 596        return 0;
 597}
 598
 599/*
 600 * Wait for the unit to become Ready
 601 */
 602static int osst_wait_ready(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, unsigned timeout)
 603{
 604        unsigned char   cmd[MAX_COMMAND_SIZE];
 605        Scsi_Request  * SRpnt;
 606        long            startwait = jiffies;
 607#if DEBUG
 608        int             dbg = debugging;
 609        int             dev  = TAPE_NR(STp->devt);
 610
 611        printk(OSST_DEB_MSG "osst%d:D: Reached onstream wait ready\n", dev);
 612#endif
 613
 614        memset(cmd, 0, MAX_COMMAND_SIZE);
 615        cmd[0] = TEST_UNIT_READY;
 616
 617        SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, SCSI_DATA_NONE, STp->timeout, MAX_READY_RETRIES, TRUE);
 618        *aSRpnt = SRpnt;
 619        if (!SRpnt) return (-EBUSY);
 620
 621        while ( STp->buffer->syscall_result && time_before(jiffies, startwait + timeout*HZ) &&
 622               (( SRpnt->sr_sense_buffer[2]  == 2 && SRpnt->sr_sense_buffer[12] == 4    &&
 623                 (SRpnt->sr_sense_buffer[13] == 1 || SRpnt->sr_sense_buffer[13] == 8)    ) ||
 624                ( SRpnt->sr_sense_buffer[2]  == 6 && SRpnt->sr_sense_buffer[12] == 0x28 &&
 625                  SRpnt->sr_sense_buffer[13] == 0                                        )  )) {
 626#if DEBUG
 627            if (debugging) {
 628                printk(OSST_DEB_MSG "osst%d:D: Sleeping in onstream wait ready\n", dev);
 629                printk(OSST_DEB_MSG "osst%d:D: Turning off debugging for a while\n", dev);
 630                debugging = 0;
 631            }
 632#endif
 633            set_current_state(TASK_INTERRUPTIBLE);
 634            schedule_timeout(HZ / 10);
 635
 636            memset(cmd, 0, MAX_COMMAND_SIZE);
 637            cmd[0] = TEST_UNIT_READY;
 638
 639            SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, SCSI_DATA_NONE, STp->timeout, MAX_READY_RETRIES, TRUE);
 640        }
 641        *aSRpnt = SRpnt;
 642#if DEBUG
 643        debugging = dbg;
 644#endif
 645        if ( STp->buffer->syscall_result &&
 646             osst_write_error_recovery(STp, aSRpnt, 0) ) {
 647#if DEBUG
 648            printk(OSST_DEB_MSG "osst%d:D: Abnormal exit from onstream wait ready\n", dev);
 649            printk(OSST_DEB_MSG "osst%d:D: Result = %d, Sense: 0=%02x, 2=%02x, 12=%02x, 13=%02x\n", dev,
 650                        STp->buffer->syscall_result, SRpnt->sr_sense_buffer[0], SRpnt->sr_sense_buffer[2],
 651                        SRpnt->sr_sense_buffer[12], SRpnt->sr_sense_buffer[13]);
 652#endif
 653            return (-EIO);
 654        }
 655#if DEBUG
 656        printk(OSST_DEB_MSG "osst%d:D: Normal exit from onstream wait ready\n", dev);
 657#endif
 658        return 0;
 659}
 660
 661/*
 662 * Wait for a tape to be inserted in the unit
 663 */
 664static int osst_wait_for_medium(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, unsigned timeout)
 665{
 666        unsigned char   cmd[MAX_COMMAND_SIZE];
 667        Scsi_Request  * SRpnt;
 668        long            startwait = jiffies;
 669#if DEBUG
 670        int             dbg = debugging;
 671        int             dev  = TAPE_NR(STp->devt);
 672
 673        printk(OSST_DEB_MSG "osst%d:D: Reached onstream wait for medium\n", dev);
 674#endif
 675
 676        memset(cmd, 0, MAX_COMMAND_SIZE);
 677        cmd[0] = TEST_UNIT_READY;
 678
 679        SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, SCSI_DATA_NONE, STp->timeout, MAX_READY_RETRIES, TRUE);
 680        *aSRpnt = SRpnt;
 681        if (!SRpnt) return (-EBUSY);
 682
 683        while ( STp->buffer->syscall_result && time_before(jiffies, startwait + timeout*HZ) &&
 684                SRpnt->sr_sense_buffer[2]  == 2 && SRpnt->sr_sense_buffer[12] == 0x3a       &&
 685                SRpnt->sr_sense_buffer[13] == 0                                             ) {
 686#if DEBUG
 687            if (debugging) {
 688                printk(OSST_DEB_MSG "osst%d:D: Sleeping in onstream wait medium\n", dev);
 689                printk(OSST_DEB_MSG "osst%d:D: Turning off debugging for a while\n", dev);
 690                debugging = 0;
 691            }
 692#endif
 693            set_current_state(TASK_INTERRUPTIBLE);
 694            schedule_timeout(HZ / 10);
 695
 696            memset(cmd, 0, MAX_COMMAND_SIZE);
 697            cmd[0] = TEST_UNIT_READY;
 698
 699            SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, SCSI_DATA_NONE, STp->timeout, MAX_READY_RETRIES, TRUE);
 700        }
 701        *aSRpnt = SRpnt;
 702#if DEBUG
 703        debugging = dbg;
 704#endif
 705        if ( STp->buffer->syscall_result     && SRpnt->sr_sense_buffer[2]  != 2 &&
 706             SRpnt->sr_sense_buffer[12] != 4 && SRpnt->sr_sense_buffer[13] == 1) {
 707#if DEBUG
 708            printk(OSST_DEB_MSG "osst%d:D: Abnormal exit from onstream wait medium\n", dev);
 709            printk(OSST_DEB_MSG "osst%d:D: Result = %d, Sense: 0=%02x, 2=%02x, 12=%02x, 13=%02x\n", dev,
 710                        STp->buffer->syscall_result, SRpnt->sr_sense_buffer[0], SRpnt->sr_sense_buffer[2],
 711                        SRpnt->sr_sense_buffer[12], SRpnt->sr_sense_buffer[13]);
 712#endif
 713            return 0;
 714        }
 715#if DEBUG
 716        printk(OSST_DEB_MSG "osst%d:D: Normal exit from onstream wait medium\n", dev);
 717#endif
 718        return 1;
 719}
 720
 721static int osst_position_tape_and_confirm(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int frame)
 722{
 723        int     retval;
 724
 725        osst_wait_ready(STp, aSRpnt, 15 * 60);                  /* TODO - can this catch a write error? */
 726        retval = osst_set_frame_position(STp, aSRpnt, frame, 0);
 727        if (retval) return (retval);
 728        osst_wait_ready(STp, aSRpnt, 15 * 60);
 729        return (osst_get_frame_position(STp, aSRpnt));
 730}
 731
 732/*
 733 * Wait for write(s) to complete
 734 */
 735static int osst_flush_drive_buffer(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt)
 736{
 737        unsigned char   cmd[MAX_COMMAND_SIZE];
 738        Scsi_Request  * SRpnt;
 739
 740        int             result = 0;
 741#if DEBUG
 742        int             dev  = TAPE_NR(STp->devt);
 743
 744        printk(OSST_DEB_MSG "osst%d:D: Reached onstream flush drive buffer (write filemark)\n", dev);
 745#endif
 746
 747        memset(cmd, 0, MAX_COMMAND_SIZE);
 748        cmd[0] = WRITE_FILEMARKS;
 749        cmd[1] = 1;
 750
 751        SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, SCSI_DATA_NONE, STp->timeout, MAX_WRITE_RETRIES, TRUE);
 752        *aSRpnt = SRpnt;
 753        if (!SRpnt) return (-EBUSY);
 754
 755        if ((STp->buffer)->syscall_result)
 756                result = osst_write_error_recovery(STp, aSRpnt, 0);
 757
 758        result |= osst_wait_ready(STp, aSRpnt, 5 * 60);
 759        STp->ps[STp->partition].rw = OS_WRITING_COMPLETE;
 760        return (result);
 761}
 762
 763#define OSST_POLL_PER_SEC 10
 764static int osst_wait_frame(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int curr, int minlast, int to)
 765{
 766        long    startwait     = jiffies;
 767        int     dev           = TAPE_NR(STp->devt);
 768#if DEBUG
 769        char    notyetprinted = 1;
 770#endif
 771        if (minlast >= 0 && STp->ps[STp->partition].rw != ST_READING)
 772                printk(KERN_ERR "osst%i:A: Waiting for frame without having initialized read!\n", dev);
 773
 774        while (time_before (jiffies, startwait + to*HZ))
 775        { 
 776                int result;
 777                result = osst_get_frame_position (STp, aSRpnt);
 778                if (result == -EIO)
 779                        if ((result = osst_write_error_recovery(STp, aSRpnt, 0)) == 0)
 780                                return 0;       /* successful recovery leaves drive ready for frame */
 781                if (result < 0) break;
 782                if (STp->first_frame_position == curr &&
 783                    ((minlast < 0 &&
 784                      (signed)STp->last_frame_position > (signed)curr + minlast) ||
 785                     (minlast >= 0 && STp->cur_frames > minlast)
 786                    ) && result >= 0)
 787                {
 788#if DEBUG                       
 789                        if (debugging || jiffies - startwait >= 2*HZ/OSST_POLL_PER_SEC)
 790                                printk (OSST_DEB_MSG
 791                                        "osst%d:D: Succ wait f fr %i (>%i): %i-%i %i (%i): %3li.%li s\n",
 792                                        dev, curr, curr+minlast, STp->first_frame_position,
 793                                        STp->last_frame_position, STp->cur_frames,
 794                                        result, (jiffies-startwait)/HZ, 
 795                                        (((jiffies-startwait)%HZ)*10)/HZ);
 796#endif
 797                        return 0;
 798                }
 799#if DEBUG
 800                if (jiffies - startwait >= 2*HZ/OSST_POLL_PER_SEC && notyetprinted)
 801                {
 802                        printk (OSST_DEB_MSG "osst%d:D: Wait for frame %i (>%i): %i-%i %i (%i)\n",
 803                                dev, curr, curr+minlast, STp->first_frame_position,
 804                                STp->last_frame_position, STp->cur_frames, result);
 805                        notyetprinted--;
 806                }
 807#endif
 808                set_current_state(TASK_INTERRUPTIBLE);
 809                schedule_timeout (HZ / OSST_POLL_PER_SEC);
 810        }
 811#if DEBUG
 812        printk (OSST_DEB_MSG "osst%d:D: Fail wait f fr %i (>%i): %i-%i %i: %3li.%li s\n",
 813                dev, curr, curr+minlast, STp->first_frame_position,
 814                STp->last_frame_position, STp->cur_frames,
 815                (jiffies-startwait)/HZ, (((jiffies-startwait)%HZ)*10)/HZ);
 816#endif  
 817        return -EBUSY;
 818}
 819
 820/*
 821 * Read the next OnStream tape frame at the current location
 822 */
 823static int osst_read_frame(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int timeout)
 824{
 825        unsigned char   cmd[MAX_COMMAND_SIZE];
 826        Scsi_Request  * SRpnt;
 827        int             retval = 0;
 828#if DEBUG
 829        os_aux_t      * aux    = STp->buffer->aux;
 830        int             dev    = TAPE_NR(STp->devt);
 831#endif
 832
 833        /* TODO: Error handling */
 834        if (STp->poll)
 835                retval = osst_wait_frame (STp, aSRpnt, STp->first_frame_position, 0, timeout);
 836#if 0// DEBUG
 837        printk ("osst_read: wait for frame returned %i\n", retval);
 838#endif
 839        
 840        memset(cmd, 0, MAX_COMMAND_SIZE);
 841        cmd[0] = READ_6;
 842        cmd[1] = 1;
 843        cmd[4] = 1;
 844
 845#if DEBUG
 846        if (debugging)
 847            printk(OSST_DEB_MSG "osst%d:D: Reading frame from OnStream tape\n", dev);
 848#endif
 849        SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, OS_FRAME_SIZE, SCSI_DATA_READ,
 850                                      STp->timeout, MAX_RETRIES, TRUE);
 851        *aSRpnt = SRpnt;
 852        if (!SRpnt)
 853            return (-EBUSY);
 854
 855        if ((STp->buffer)->syscall_result) {
 856            retval = 1;
 857            if (STp->read_error_frame == 0) {
 858                STp->read_error_frame = STp->first_frame_position;
 859#if DEBUG
 860                printk(OSST_DEB_MSG "osst%d:D: Recording read error at %d\n", dev, STp->read_error_frame);
 861#endif
 862            }
 863#if DEBUG
 864            if (debugging)
 865                printk(OSST_DEB_MSG "osst%d:D: Sense: %2x %2x %2x %2x %2x %2x %2x %2x\n",
 866                   dev,
 867                   SRpnt->sr_sense_buffer[0], SRpnt->sr_sense_buffer[1],
 868                   SRpnt->sr_sense_buffer[2], SRpnt->sr_sense_buffer[3],
 869                   SRpnt->sr_sense_buffer[4], SRpnt->sr_sense_buffer[5],
 870                   SRpnt->sr_sense_buffer[6], SRpnt->sr_sense_buffer[7]);
 871#endif
 872        }
 873        else
 874            STp->first_frame_position++;
 875#if DEBUG
 876        if (debugging) {
 877           printk(OSST_DEB_MSG 
 878                "osst%d:D: AUX: %c%c%c%c UpdFrCt#%d Wpass#%d %s FrSeq#%d LogBlk#%d Qty=%d Sz=%d\n", dev,
 879                        aux->application_sig[0], aux->application_sig[1],
 880                        aux->application_sig[2], aux->application_sig[3], 
 881                        ntohl(aux->update_frame_cntr), ntohs(aux->partition.wrt_pass_cntr),
 882                        aux->frame_type==1?"EOD":aux->frame_type==2?"MARK":
 883                        aux->frame_type==8?"HEADR":aux->frame_type==0x80?"DATA":"FILL", 
 884                        ntohl(aux->frame_seq_num), ntohl(aux->logical_blk_num),
 885                        ntohs(aux->dat.dat_list[0].blk_cnt), ntohl(aux->dat.dat_list[0].blk_sz) );
 886           if (aux->frame_type==2)
 887                printk(OSST_DEB_MSG "osst%d:D: mark_cnt=%d, last_mark_ppos=%d, last_mark_lbn=%d\n", dev,
 888                        ntohl(aux->filemark_cnt), ntohl(aux->last_mark_ppos), ntohl(aux->last_mark_lbn));
 889           printk(OSST_DEB_MSG "osst%d:D: Exit read frame from OnStream tape with code %d\n", dev, retval);
 890        }
 891#endif
 892        return (retval);
 893}
 894
 895static int osst_initiate_read(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt)
 896{
 897        ST_partstat   * STps   = &(STp->ps[STp->partition]);
 898        Scsi_Request  * SRpnt  ;
 899        unsigned char   cmd[MAX_COMMAND_SIZE];
 900        int             retval = 0;
 901#if DEBUG
 902        int             dev    = TAPE_NR(STp->devt);
 903#endif
 904
 905        if (STps->rw != ST_READING) {         /* Initialize read operation */
 906                if (STps->rw == ST_WRITING) {
 907                        osst_flush_write_buffer(STp, aSRpnt);
 908                        osst_flush_drive_buffer(STp, aSRpnt);
 909                }
 910                STps->rw = ST_READING;
 911                STp->frame_in_buffer = 0;
 912
 913                /*
 914                 *      Issue a read 0 command to get the OnStream drive
 915                 *      read frames into its buffer.
 916                 */
 917                memset(cmd, 0, MAX_COMMAND_SIZE);
 918                cmd[0] = READ_6;
 919                cmd[1] = 1;
 920
 921#if DEBUG
 922                printk(OSST_DEB_MSG "osst%d:D: Start Read Ahead on OnStream tape\n", dev);
 923#endif
 924                SRpnt   = osst_do_scsi(*aSRpnt, STp, cmd, 0, SCSI_DATA_NONE, STp->timeout, MAX_RETRIES, TRUE);
 925                *aSRpnt = SRpnt;
 926                retval  = STp->buffer->syscall_result;
 927        }
 928
 929        return retval;
 930}
 931
 932static int osst_get_logical_frame(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int frame_seq_number, int quiet)
 933{
 934        ST_partstat * STps  = &(STp->ps[STp->partition]);
 935        int           dev   = TAPE_NR(STp->devt);
 936        int           cnt   = 0,
 937                      bad   = 0,
 938                      past  = 0,
 939                      x,
 940                      position;
 941
 942        /*
 943         * Search and wait for the next logical tape frame
 944         */
 945        while (1) {
 946                if (cnt++ > 400) {
 947                        printk(KERN_ERR "osst%d:E: Couldn't find logical frame %d, aborting\n",
 948                                            dev, frame_seq_number);
 949                        if (STp->read_error_frame) {
 950                                osst_set_frame_position(STp, aSRpnt, STp->read_error_frame, 0);
 951#if DEBUG
 952                                printk(OSST_DEB_MSG "osst%d:D: Repositioning tape to bad frame %d\n",
 953                                                    dev, STp->read_error_frame);
 954#endif
 955                                STp->read_error_frame = 0;
 956                        }
 957                        return (-EIO);
 958                }
 959#if DEBUG
 960                if (debugging)
 961                        printk(OSST_DEB_MSG "osst%d:D: Looking for frame %d, attempt %d\n",
 962                                          dev, frame_seq_number, cnt);
 963#endif
 964                if ( osst_initiate_read(STp, aSRpnt)
 965                || ( (!STp->frame_in_buffer) && osst_read_frame(STp, aSRpnt, 30) ) ) {
 966                        if (STp->raw)
 967                                return (-EIO);
 968                        position = osst_get_frame_position(STp, aSRpnt);
 969                        if (position >= 0xbae && position < 0xbb8)
 970                                position = 0xbb8;
 971                        else if (position > STp->eod_frame_ppos || ++bad == 10) {
 972                                position = STp->read_error_frame - 1;
 973                        }
 974                        else {
 975                                position += 39;
 976                                cnt += 20;
 977                        }
 978#if DEBUG
 979                        printk(OSST_DEB_MSG "osst%d:D: Bad frame detected, positioning tape to block %d\n",
 980                                         dev, position);
 981#endif
 982                        osst_set_frame_position(STp, aSRpnt, position, 0);
 983                        continue;
 984                }
 985                if (osst_verify_frame(STp, frame_seq_number, quiet))
 986                        break;
 987                if (osst_verify_frame(STp, -1, quiet)) {
 988                        x = ntohl(STp->buffer->aux->frame_seq_num);
 989                        if (STp->fast_open) {
 990                                printk(KERN_WARNING
 991                                       "osst%d:W: Found logical frame %d instead of %d after fast open\n",
 992                                       dev, x, frame_seq_number);
 993                                STp->header_ok = 0;
 994                                STp->read_error_frame = 0;
 995                                return (-EIO);
 996                        }
 997                        if (x > frame_seq_number) {
 998                                if (++past > 3) {
 999                                        /* positioning backwards did not bring us to the desired frame */
1000                                        position = STp->read_error_frame - 1;
1001                                }
1002                                else {
1003                                        position = osst_get_frame_position(STp, aSRpnt)
1004                                                 + frame_seq_number - x - 1;
1005
1006                                        if (STp->first_frame_position >= 3000 && position < 3000)
1007                                                position -= 10;
1008                                }
1009#if DEBUG
1010                                printk(OSST_DEB_MSG
1011                                       "osst%d:D: Found logical frame %d while looking for %d: back up %d\n",
1012                                                dev, x, frame_seq_number,
1013                                                STp->first_frame_position - position);
1014#endif
1015                                osst_set_frame_position(STp, aSRpnt, position, 0);
1016                                cnt += 10;
1017                        }
1018                        else
1019                                past = 0;
1020                }
1021                if (osst_get_frame_position(STp, aSRpnt) == 0xbaf) {
1022#if DEBUG
1023                        printk(OSST_DEB_MSG "osst%d:D: Skipping config partition\n", dev);
1024#endif
1025                        osst_set_frame_position(STp, aSRpnt, 0xbb8, 0);
1026                        cnt--;
1027                }
1028                STp->frame_in_buffer = 0;
1029        }
1030        if (cnt > 1) {
1031                STp->recover_count++;
1032                STp->recover_erreg++;
1033                printk(KERN_WARNING "osst%d:I: Don't worry, Read error at position %d recovered\n", 
1034                                        dev, STp->read_error_frame);
1035        }
1036        STp->read_count++;
1037
1038#if DEBUG
1039        if (debugging || STps->eof)
1040                printk(OSST_DEB_MSG
1041                        "osst%d:D: Exit get logical frame (%d=>%d) from OnStream tape with code %d\n",
1042                        dev, frame_seq_number, STp->frame_seq_number, STps->eof);
1043#endif
1044        STp->fast_open = FALSE;
1045        STp->read_error_frame = 0;
1046        return (STps->eof);
1047}
1048
1049static int osst_seek_logical_blk(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int logical_blk_num)
1050{
1051        ST_partstat * STps = &(STp->ps[STp->partition]);
1052        int     dev        = TAPE_NR(STp->devt);
1053        int     retries    = 0;
1054        int     frame_seq_estimate, ppos_estimate, move;
1055        
1056        if (logical_blk_num < 0) logical_blk_num = 0;
1057#if DEBUG
1058        printk(OSST_DEB_MSG "osst%d:D: Seeking logical block %d (now at %d, size %d%c)\n",
1059                                dev, logical_blk_num, STp->logical_blk_num, 
1060                                STp->block_size<1024?STp->block_size:STp->block_size/1024,
1061                                STp->block_size<1024?'b':'k');
1062#endif
1063        /* Do we know where we are? */
1064        if (STps->drv_block >= 0) {
1065                move                = logical_blk_num - STp->logical_blk_num;
1066                if (move < 0) move -= (OS_DATA_SIZE / STp->block_size) - 1;
1067                move               /= (OS_DATA_SIZE / STp->block_size);
1068                frame_seq_estimate  = STp->frame_seq_number + move;
1069        } else
1070                frame_seq_estimate  = logical_blk_num * STp->block_size / OS_DATA_SIZE;
1071
1072        if (frame_seq_estimate < 2980) ppos_estimate = frame_seq_estimate + 10;
1073        else                           ppos_estimate = frame_seq_estimate + 20;
1074        while (++retries < 10) {
1075           if (ppos_estimate > STp->eod_frame_ppos-2) {
1076               frame_seq_estimate += STp->eod_frame_ppos - 2 - ppos_estimate;
1077               ppos_estimate       = STp->eod_frame_ppos - 2;
1078           }
1079           if (frame_seq_estimate < 0) {
1080               frame_seq_estimate = 0;
1081               ppos_estimate      = 10;
1082           }
1083           osst_set_frame_position(STp, aSRpnt, ppos_estimate, 0);
1084           if (osst_get_logical_frame(STp, aSRpnt, frame_seq_estimate, 1) >= 0) {
1085              /* we've located the estimated frame, now does it have our block? */
1086              if (logical_blk_num <  STp->logical_blk_num ||
1087                  logical_blk_num >= STp->logical_blk_num + ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt)) {
1088                 if (STps->eof == ST_FM_HIT)
1089                    move = logical_blk_num < STp->logical_blk_num? -2 : 1;
1090                 else {
1091                    move                = logical_blk_num - STp->logical_blk_num;
1092                    if (move < 0) move -= (OS_DATA_SIZE / STp->block_size) - 1;
1093                    move               /= (OS_DATA_SIZE / STp->block_size);
1094                 }
1095#if DEBUG
1096                 printk(OSST_DEB_MSG
1097                        "osst%d:D: Seek retry %d at ppos %d fsq %d (est %d) lbn %d (need %d) move %d\n",
1098                                dev, retries, ppos_estimate, STp->frame_seq_number, frame_seq_estimate, 
1099                                STp->logical_blk_num, logical_blk_num, move);
1100#endif
1101                 frame_seq_estimate += move;
1102                 ppos_estimate      += move;
1103                 continue;
1104              } else {
1105                 STp->buffer->read_pointer  = (logical_blk_num - STp->logical_blk_num) * STp->block_size;
1106                 STp->buffer->buffer_bytes -= STp->buffer->read_pointer;
1107                 STp->logical_blk_num       =  logical_blk_num;
1108#if DEBUG
1109                 printk(OSST_DEB_MSG 
1110                        "osst%d:D: Seek success at ppos %d fsq %d in_buf %d, bytes %d, ptr %d*%d\n",
1111                                dev, ppos_estimate, STp->frame_seq_number, STp->frame_in_buffer, 
1112                                STp->buffer->buffer_bytes, STp->buffer->read_pointer / STp->block_size, 
1113                                STp->block_size);
1114#endif
1115                 STps->drv_file = ntohl(STp->buffer->aux->filemark_cnt);
1116                 if (STps->eof == ST_FM_HIT) {
1117                     STps->drv_file++;
1118                     STps->drv_block = 0;
1119                 } else {
1120                     STps->drv_block = ntohl(STp->buffer->aux->last_mark_lbn)?
1121                                          STp->logical_blk_num -
1122                                             (STps->drv_file ? ntohl(STp->buffer->aux->last_mark_lbn) + 1 : 0):
1123                                        -1;
1124                 }
1125                 STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD:ST_NOEOF;
1126                 return 0;
1127              }
1128           }
1129           if (osst_get_logical_frame(STp, aSRpnt, -1, 1) < 0)
1130              goto error;
1131           /* we are not yet at the estimated frame, adjust our estimate of its physical position */
1132#if DEBUG
1133           printk(OSST_DEB_MSG "osst%d:D: Seek retry %d at ppos %d fsq %d (est %d) lbn %d (need %d)\n", 
1134                           dev, retries, ppos_estimate, STp->frame_seq_number, frame_seq_estimate, 
1135                           STp->logical_blk_num, logical_blk_num);
1136#endif
1137           if (frame_seq_estimate != STp->frame_seq_number)
1138              ppos_estimate += frame_seq_estimate - STp->frame_seq_number;
1139           else
1140              break;
1141        }
1142error:
1143        printk(KERN_ERR "osst%d:E: Couldn't seek to logical block %d (at %d), %d retries\n", 
1144                            dev, logical_blk_num, STp->logical_blk_num, retries);
1145        return (-EIO);
1146}
1147
1148/* The values below are based on the OnStream frame payload size of 32K == 2**15,
1149 * that is, OSST_FRAME_SHIFT + OSST_SECTOR_SHIFT must be 15. With a minimum block
1150 * size of 512 bytes, we need to be able to resolve 32K/512 == 64 == 2**6 positions
1151 * inside each frame. Finaly, OSST_SECTOR_MASK == 2**OSST_FRAME_SHIFT - 1.
1152 */
1153#define OSST_FRAME_SHIFT  6
1154#define OSST_SECTOR_SHIFT 9
1155#define OSST_SECTOR_MASK  0x03F
1156
1157static int osst_get_sector(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt)
1158{
1159        int     sector;
1160#if DEBUG
1161        int     dev = TAPE_NR(STp->devt);
1162        
1163        printk(OSST_DEB_MSG 
1164                "osst%d:D: Positioned at ppos %d, frame %d, lbn %d, file %d, blk %d, %cptr %d, eof %d\n",
1165                dev, STp->first_frame_position, STp->frame_seq_number, STp->logical_blk_num,
1166                STp->ps[STp->partition].drv_file, STp->ps[STp->partition].drv_block, 
1167                STp->ps[STp->partition].rw == ST_WRITING?'w':'r',
1168                STp->ps[STp->partition].rw == ST_WRITING?STp->buffer->buffer_bytes:
1169                STp->buffer->read_pointer, STp->ps[STp->partition].eof);
1170#endif
1171        /* do we know where we are inside a file? */
1172        if (STp->ps[STp->partition].drv_block >= 0) {
1173                sector = (STp->frame_in_buffer ? STp->first_frame_position-1 :
1174                                STp->first_frame_position) << OSST_FRAME_SHIFT;
1175                if (STp->ps[STp->partition].rw == ST_WRITING)
1176                        sector |= (STp->buffer->buffer_bytes >> OSST_SECTOR_SHIFT) & OSST_SECTOR_MASK;
1177                else
1178                        sector |= (STp->buffer->read_pointer >> OSST_SECTOR_SHIFT) & OSST_SECTOR_MASK;
1179        } else {
1180                sector = osst_get_frame_position(STp, aSRpnt);
1181                if (sector > 0)
1182                        sector <<= OSST_FRAME_SHIFT;
1183        }
1184        return sector;
1185}
1186
1187static int osst_seek_sector(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int sector)
1188{
1189        ST_partstat   * STps   = &(STp->ps[STp->partition]);
1190        int             frame  = sector >> OSST_FRAME_SHIFT,
1191                        offset = (sector & OSST_SECTOR_MASK) << OSST_SECTOR_SHIFT, 
1192                        r;
1193#if DEBUG
1194        int             dev    = TAPE_NR(STp->devt);
1195
1196        printk(OSST_DEB_MSG "osst%d:D: Seeking sector %d in frame %d at offset %d\n",
1197                                dev, sector, frame, offset);
1198#endif
1199        if (frame < 0 || frame >= STp->capacity) return (-ENXIO);
1200
1201        if (frame <= STp->first_data_ppos) {
1202                STp->frame_seq_number = STp->logical_blk_num = STps->drv_file = STps->drv_block = 0;
1203                return (osst_set_frame_position(STp, aSRpnt, frame, 0));
1204        }
1205        r = osst_set_frame_position(STp, aSRpnt, offset?frame:frame-1, 0);
1206        if (r < 0) return r;
1207
1208        r = osst_get_logical_frame(STp, aSRpnt, -1, 1);
1209        if (r < 0) return r;
1210
1211        if (osst_get_frame_position(STp, aSRpnt) != (offset?frame+1:frame)) return (-EIO);
1212
1213        if (offset) {
1214                STp->logical_blk_num      += offset / STp->block_size;
1215                STp->buffer->read_pointer  = offset;
1216                STp->buffer->buffer_bytes -= offset;
1217        } else {
1218                STp->frame_seq_number++;
1219                STp->frame_in_buffer       = 0;
1220                STp->logical_blk_num      += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
1221                STp->buffer->buffer_bytes  = STp->buffer->read_pointer = 0;
1222        }
1223        STps->drv_file = ntohl(STp->buffer->aux->filemark_cnt);
1224        if (STps->eof == ST_FM_HIT) {
1225                STps->drv_file++;
1226                STps->drv_block = 0;
1227        } else {
1228                STps->drv_block = ntohl(STp->buffer->aux->last_mark_lbn)?
1229                                    STp->logical_blk_num -
1230                                        (STps->drv_file ? ntohl(STp->buffer->aux->last_mark_lbn) + 1 : 0):
1231                                  -1;
1232        }
1233        STps->eof       = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD:ST_NOEOF;
1234#if DEBUG
1235        printk(OSST_DEB_MSG 
1236                "osst%d:D: Now positioned at ppos %d, frame %d, lbn %d, file %d, blk %d, rptr %d, eof %d\n",
1237                dev, STp->first_frame_position, STp->frame_seq_number, STp->logical_blk_num,
1238                STps->drv_file, STps->drv_block, STp->buffer->read_pointer, STps->eof);
1239#endif
1240        return 0;
1241}
1242
1243/*
1244 * Read back the drive's internal buffer contents, as a part
1245 * of the write error recovery mechanism for old OnStream
1246 * firmware revisions.
1247 * Precondition for this function to work: all frames in the
1248 * drive's buffer must be of one type (DATA, MARK or EOD)!
1249 */
1250static int osst_read_back_buffer_and_rewrite(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt,
1251                                        unsigned int frame, unsigned int skip, int pending)
1252{
1253        Scsi_Request  * SRpnt = * aSRpnt;
1254        unsigned char * buffer, * p;
1255        unsigned char   cmd[MAX_COMMAND_SIZE];
1256        int             flag, new_frame, i;
1257        int             nframes          = STp->cur_frames;
1258        int             blks_per_frame   = ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
1259        int             frame_seq_number = ntohl(STp->buffer->aux->frame_seq_num)
1260                                                - (nframes + pending - 1);
1261        int             logical_blk_num  = ntohl(STp->buffer->aux->logical_blk_num) 
1262                                                - (nframes + pending - 1) * blks_per_frame;
1263        int             dev              = TAPE_NR(STp->devt);
1264        long            startwait        = jiffies;
1265#if DEBUG
1266        int             dbg              = debugging;
1267#endif
1268
1269        if ((buffer = (unsigned char *)vmalloc((nframes + 1) * OS_DATA_SIZE)) == NULL)
1270                return (-EIO);
1271
1272        printk(KERN_INFO "osst%d:I: Reading back %d frames from drive buffer%s\n",
1273                         dev, nframes, pending?" and one that was pending":"");
1274
1275        osst_copy_from_buffer(STp->buffer, (p = &buffer[nframes * OS_DATA_SIZE]));
1276#if DEBUG
1277        if (pending && debugging)
1278                printk(OSST_DEB_MSG "osst%d:D: Pending frame %d (lblk %d), data %02x %02x %02x %02x\n",
1279                                dev, frame_seq_number + nframes,
1280                                logical_blk_num + nframes * blks_per_frame,
1281                                p[0], p[1], p[2], p[3]);
1282#endif
1283        for (i = 0, p = buffer; i < nframes; i++, p += OS_DATA_SIZE) {
1284
1285                memset(cmd, 0, MAX_COMMAND_SIZE);
1286                cmd[0] = 0x3C;          /* Buffer Read           */
1287                cmd[1] = 6;             /* Retrieve Faulty Block */
1288                cmd[7] = 32768 >> 8;
1289                cmd[8] = 32768 & 0xff;
1290
1291                SRpnt = osst_do_scsi(SRpnt, STp, cmd, OS_FRAME_SIZE, SCSI_DATA_READ,
1292                                            STp->timeout, MAX_RETRIES, TRUE);
1293        
1294                if ((STp->buffer)->syscall_result || !SRpnt) {
1295                        printk(KERN_ERR "osst%d:E: Failed to read frame back from OnStream buffer\n", dev);
1296                        vfree((void *)buffer);
1297                        *aSRpnt = SRpnt;
1298                        return (-EIO);
1299                }
1300                osst_copy_from_buffer(STp->buffer, p);
1301#if DEBUG
1302                if (debugging)
1303                        printk(OSST_DEB_MSG "osst%d:D: Read back logical frame %d, data %02x %02x %02x %02x\n",
1304                                          dev, frame_seq_number + i, p[0], p[1], p[2], p[3]);
1305#endif
1306        }
1307        *aSRpnt = SRpnt;
1308        osst_get_frame_position(STp, aSRpnt);
1309
1310#if DEBUG
1311        printk(OSST_DEB_MSG "osst%d:D: Frames left in buffer: %d\n", dev, STp->cur_frames);
1312#endif
1313        /* Write synchronously so we can be sure we're OK again and don't have to recover recursively */
1314        /* In the header we don't actually re-write the frames that fail, just the ones after them */
1315
1316        for (flag=1, new_frame=frame, p=buffer, i=0; i < nframes + pending; ) {
1317
1318                if (flag) {
1319                        if (STp->write_type == OS_WRITE_HEADER) {
1320                                i += skip;
1321                                p += skip * OS_DATA_SIZE;
1322                        }
1323                        else if (new_frame < 2990 && new_frame+skip+nframes+pending >= 2990)
1324                                new_frame = 3000-i;
1325                        else
1326                                new_frame += skip;
1327#if DEBUG
1328                        printk(OSST_DEB_MSG "osst%d:D: Position to frame %d, write fseq %d\n",
1329                                                dev, new_frame+i, frame_seq_number+i);
1330#endif
1331                        osst_set_frame_position(STp, aSRpnt, new_frame + i, 0);
1332                        osst_wait_ready(STp, aSRpnt, 60);
1333                        osst_get_frame_position(STp, aSRpnt);
1334                        SRpnt = * aSRpnt;
1335
1336                        if (new_frame > frame + 1000) {
1337                                printk(KERN_ERR "osst%d:E: Failed to find writable tape media\n", dev);
1338                                vfree((void *)buffer);
1339                                return (-EIO);
1340                        }
1341                        flag = 0;
1342                        if ( i >= nframes + pending ) break;
1343                }
1344                osst_copy_to_buffer(STp->buffer, p);
1345                /*
1346                 * IMPORTANT: for error recovery to work, _never_ queue frames with mixed frame type!
1347                 */
1348                osst_init_aux(STp, STp->buffer->aux->frame_type, frame_seq_number+i,
1349                                logical_blk_num + i*blks_per_frame,
1350                                ntohl(STp->buffer->aux->dat.dat_list[0].blk_sz), blks_per_frame);
1351                memset(cmd, 0, MAX_COMMAND_SIZE);
1352                cmd[0] = WRITE_6;
1353                cmd[1] = 1;
1354                cmd[4] = 1;
1355
1356#if DEBUG
1357                if (debugging)
1358                        printk(OSST_DEB_MSG
1359                                "osst%d:D: About to write frame %d, seq %d, lbn %d, data %02x %02x %02x %02x\n",
1360                                dev, new_frame+i, frame_seq_number+i, logical_blk_num + i*blks_per_frame,
1361                                p[0], p[1], p[2], p[3]);
1362#endif
1363                SRpnt = osst_do_scsi(SRpnt, STp, cmd, OS_FRAME_SIZE, SCSI_DATA_WRITE,
1364                                            STp->timeout, MAX_WRITE_RETRIES, TRUE);
1365
1366                if (STp->buffer->syscall_result)
1367                        flag = 1;
1368                else {
1369                        p += OS_DATA_SIZE; i++;
1370
1371                        /* if we just sent the last frame, wait till all successfully written */
1372                        if ( i == nframes + pending ) {
1373#if DEBUG
1374                                printk(OSST_DEB_MSG "osst%d:D: Check re-write successful\n", dev);
1375#endif
1376                                memset(cmd, 0, MAX_COMMAND_SIZE);
1377                                cmd[0] = WRITE_FILEMARKS;
1378                                cmd[1] = 1;
1379                                SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, SCSI_DATA_NONE,
1380                                                            STp->timeout, MAX_WRITE_RETRIES, TRUE);
1381#if DEBUG
1382                                if (debugging) {
1383                                        printk(OSST_DEB_MSG "osst%d:D: Sleeping in re-write wait ready\n", dev);
1384                                        printk(OSST_DEB_MSG "osst%d:D: Turning off debugging for a while\n", dev);
1385                                        debugging = 0;
1386                                }
1387#endif
1388                                flag = STp->buffer->syscall_result;
1389                                while ( !flag && time_before(jiffies, startwait + 60*HZ) ) {
1390
1391                                        memset(cmd, 0, MAX_COMMAND_SIZE);
1392                                        cmd[0] = TEST_UNIT_READY;
1393
1394                                        SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, SCSI_DATA_NONE, STp->timeout,
1395                                                                         MAX_READY_RETRIES, TRUE);
1396
1397                                        if (SRpnt->sr_sense_buffer[2] == 2 && SRpnt->sr_sense_buffer[12] == 4 &&
1398                                            (SRpnt->sr_sense_buffer[13] == 1 || SRpnt->sr_sense_buffer[13] == 8)) {
1399                                                /* in the process of becoming ready */
1400                                                schedule_timeout(HZ / 10);
1401                                                continue;
1402                                        }
1403                                        if (STp->buffer->syscall_result)
1404                                                flag = 1;
1405                                        break;
1406                                }
1407#if DEBUG
1408                                debugging = dbg;
1409                                printk(OSST_DEB_MSG "osst%d:D: Wait re-write finished\n", dev);
1410#endif
1411                        }
1412                }
1413                *aSRpnt = SRpnt;
1414                if (flag) {
1415                        if ((SRpnt->sr_sense_buffer[ 2] & 0x0f) == 13 &&
1416                             SRpnt->sr_sense_buffer[12]         ==  0 &&
1417                             SRpnt->sr_sense_buffer[13]         ==  2) {
1418                                printk(KERN_ERR "osst%d:E: Volume overflow in write error recovery\n", dev);
1419                                vfree((void *)buffer);
1420                                return (-EIO);                  /* hit end of tape = fail */
1421                        }
1422                        i = ((SRpnt->sr_sense_buffer[3] << 24) |
1423                             (SRpnt->sr_sense_buffer[4] << 16) |
1424                             (SRpnt->sr_sense_buffer[5] <<  8) |
1425                              SRpnt->sr_sense_buffer[6]        ) - new_frame;
1426                        p = &buffer[i * OS_DATA_SIZE];
1427#if DEBUG
1428                        printk(OSST_DEB_MSG "osst%d:D: Additional write error at %d\n", dev, new_frame+i);
1429#endif
1430                        osst_get_frame_position(STp, aSRpnt);
1431#if DEBUG
1432                        printk(OSST_DEB_MSG "osst%d:D: reported frame positions: host = %d, tape = %d\n",
1433                                          dev, STp->first_frame_position, STp->last_frame_position);
1434#endif
1435                }
1436        }    
1437        if (!pending)
1438                osst_copy_to_buffer(STp->buffer, p);    /* so buffer content == at entry in all cases */
1439        vfree((void *)buffer);
1440        return 0;
1441}
1442
1443static int osst_reposition_and_retry(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt,
1444                                        unsigned int frame, unsigned int skip, int pending)
1445{
1446        unsigned char   cmd[MAX_COMMAND_SIZE];
1447        Scsi_Request  * SRpnt;
1448        int             dev       = TAPE_NR(STp->devt);
1449        int             expected  = 0;
1450        int             attempts  = 1000 / skip;
1451        int             flag      = 1;
1452        long            startwait = jiffies;
1453#if DEBUG
1454        int             dbg       = debugging;
1455#endif
1456
1457        while (attempts && time_before(jiffies, startwait + 60*HZ)) {
1458                if (flag) {
1459#if DEBUG
1460                        debugging = dbg;
1461#endif
1462                        if (frame < 2990 && frame+skip+STp->cur_frames+pending >= 2990)
1463                                frame = 3000-skip;
1464                        expected = frame+skip+STp->cur_frames+pending;
1465#if DEBUG
1466                        printk(OSST_DEB_MSG "osst%d:D: Position to fppos %d, re-write from fseq %d\n",
1467                                          dev, frame+skip, STp->frame_seq_number-STp->cur_frames-pending);
1468#endif
1469                        osst_set_frame_position(STp, aSRpnt, frame + skip, 1);
1470                        flag = 0;
1471                        attempts--;
1472                }
1473                if (osst_get_frame_position(STp, aSRpnt) < 0) {         /* additional write error */
1474#if DEBUG
1475                        printk(OSST_DEB_MSG "osst%d:D: Addl error, host %d, tape %d, buffer %d\n",
1476                                          dev, STp->first_frame_position,
1477                                          STp->last_frame_position, STp->cur_frames);
1478#endif
1479                        frame = STp->last_frame_position;
1480                        flag = 1;
1481                        continue;
1482                }
1483                if (pending && STp->cur_frames < 50) {
1484
1485                        memset(cmd, 0, MAX_COMMAND_SIZE);
1486                        cmd[0] = WRITE_6;
1487                        cmd[1] = 1;
1488                        cmd[4] = 1;
1489#if DEBUG
1490                        printk(OSST_DEB_MSG "osst%d:D: About to write pending fseq %d at fppos %d\n",
1491                                          dev, STp->frame_seq_number-1, STp->first_frame_position);
1492#endif
1493                        SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, OS_FRAME_SIZE, SCSI_DATA_WRITE,
1494                                                      STp->timeout, MAX_WRITE_RETRIES, TRUE);
1495                        *aSRpnt = SRpnt;
1496
1497                        if (STp->buffer->syscall_result) {              /* additional write error */
1498                                if ((SRpnt->sr_sense_buffer[ 2] & 0x0f) == 13 &&
1499                                     SRpnt->sr_sense_buffer[12]         ==  0 &&
1500                                     SRpnt->sr_sense_buffer[13]         ==  2) {
1501                                        printk(KERN_ERR
1502                                               "osst%d:E: Volume overflow in write error recovery\n",
1503                                               dev);
1504                                        break;                          /* hit end of tape = fail */
1505                                }
1506                                flag = 1;
1507                        }
1508                        else
1509                                pending = 0;
1510
1511                        continue;
1512                }
1513                if (STp->cur_frames == 0) {
1514#if DEBUG
1515                        debugging = dbg;
1516                        printk(OSST_DEB_MSG "osst%d:D: Wait re-write finished\n", dev);
1517#endif
1518                        if (STp->first_frame_position != expected) {
1519                                printk(KERN_ERR "osst%d:A: Actual position %d - expected %d\n", 
1520                                                dev, STp->first_frame_position, expected);
1521                                return (-EIO);
1522                        }
1523                        return 0;
1524                }
1525#if DEBUG
1526                if (debugging) {
1527                        printk(OSST_DEB_MSG "osst%d:D: Sleeping in re-write wait ready\n", dev);
1528                        printk(OSST_DEB_MSG "osst%d:D: Turning off debugging for a while\n", dev);
1529                        debugging = 0;
1530                }
1531#endif
1532                schedule_timeout(HZ / 10);
1533        }
1534        printk(KERN_ERR "osst%d:E: Failed to find valid tape media\n", dev);
1535#if DEBUG
1536        debugging = dbg;
1537#endif
1538        return (-EIO);
1539}
1540
1541/*
1542 * Error recovery algorithm for the OnStream tape.
1543 */
1544
1545static int osst_write_error_recovery(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int pending)
1546{
1547        Scsi_Request * SRpnt  = * aSRpnt;
1548        ST_partstat  * STps   = & STp->ps[STp->partition];
1549        int            dev    = TAPE_NR(STp->devt);
1550        int            retval = 0;
1551        int            rw_state;
1552        unsigned int  frame, skip;
1553
1554        rw_state = STps->rw;
1555
1556        if ((SRpnt->sr_sense_buffer[ 2] & 0x0f) != 3
1557          || SRpnt->sr_sense_buffer[12]         != 12
1558          || SRpnt->sr_sense_buffer[13]         != 0) {
1559#if DEBUG
1560                printk(OSST_DEB_MSG "osst%d:D: Write error recovery cannot handle %02x:%02x:%02x\n", dev,
1561                        SRpnt->sr_sense_buffer[2], SRpnt->sr_sense_buffer[12], SRpnt->sr_sense_buffer[13]);
1562#endif
1563                return (-EIO);
1564        }
1565        frame = (SRpnt->sr_sense_buffer[3] << 24) |
1566                (SRpnt->sr_sense_buffer[4] << 16) |
1567                (SRpnt->sr_sense_buffer[5] <<  8) |
1568                 SRpnt->sr_sense_buffer[6];
1569        skip  =  SRpnt->sr_sense_buffer[9];
1570 
1571#if DEBUG
1572        printk(OSST_DEB_MSG "osst%d:D: Detected physical bad frame at %u, advised to skip %d\n", dev, frame, skip);
1573#endif
1574        osst_get_frame_position(STp, aSRpnt);
1575#if DEBUG
1576        printk(OSST_DEB_MSG "osst%d:D: reported frame positions: host = %d, tape = %d\n",
1577                        dev, STp->first_frame_position, STp->last_frame_position);
1578#endif
1579        switch (STp->write_type) {
1580           case OS_WRITE_DATA:
1581           case OS_WRITE_EOD:
1582           case OS_WRITE_NEW_MARK:
1583                printk(KERN_WARNING 
1584                        "osst%d:I: Relocating %d buffered logical frames from position %u to %u\n",
1585                        dev, STp->cur_frames, frame, (frame + skip > 3000 && frame < 3000)?3000:frame + skip);
1586                if (STp->os_fw_rev >= 10600)
1587                        retval = osst_reposition_and_retry(STp, aSRpnt, frame, skip, pending);
1588                else
1589                        retval = osst_read_back_buffer_and_rewrite(STp, aSRpnt, frame, skip, pending);
1590                printk(KERN_WARNING "osst%d:%s: %sWrite error%srecovered\n", dev,
1591                                retval?"E"    :"I",
1592                                retval?""     :"Don't worry, ",
1593                                retval?" not ":" ");
1594                break;
1595           case OS_WRITE_LAST_MARK:
1596                printk(KERN_ERR "osst%d:E: Bad frame in update last marker, fatal\n", dev);
1597                osst_set_frame_position(STp, aSRpnt, frame + STp->cur_frames + pending, 0);
1598                retval = -EIO;
1599                break;
1600           case OS_WRITE_HEADER:
1601                printk(KERN_WARNING "osst%d:I: Bad frame in header partition, skipped\n", dev);
1602                retval = osst_read_back_buffer_and_rewrite(STp, aSRpnt, frame, 1, pending);
1603                break;
1604           default:
1605                printk(KERN_INFO "osst%d:I: Bad frame in filler, ignored\n", dev);
1606                osst_set_frame_position(STp, aSRpnt, frame + STp->cur_frames + pending, 0);
1607        }
1608        osst_get_frame_position(STp, aSRpnt);
1609#if DEBUG
1610        printk(OSST_DEB_MSG "osst%d:D: Positioning complete, cur_frames %d, pos %d, tape pos %d\n", 
1611                        dev, STp->cur_frames, STp->first_frame_position, STp->last_frame_position);
1612        printk(OSST_DEB_MSG "osst%d:D: next logical frame to write: %d\n", dev, STp->logical_blk_num);
1613#endif
1614        if (retval == 0) {
1615                STp->recover_count++;
1616                STp->recover_erreg++;
1617        }
1618        STps->rw = rw_state;
1619        return retval;
1620}
1621
1622static int osst_space_over_filemarks_backward(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt,
1623                                                                 int mt_op, int mt_count)
1624{
1625        int     dev = TAPE_NR(STp->devt);
1626        int     cnt;
1627        int     last_mark_ppos = -1;
1628
1629#if DEBUG
1630        printk(OSST_DEB_MSG "osst%d:D: Reached space_over_filemarks_backwards %d %d\n", dev, mt_op, mt_count);
1631#endif
1632        if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
1633#if DEBUG
1634                printk(OSST_DEB_MSG "osst%d:D: Couldn't get logical blk num in space_filemarks_bwd\n", dev);
1635#endif
1636                return -EIO;
1637        }
1638        if (STp->linux_media_version >= 4) {
1639                /*
1640                 * direct lookup in header filemark list
1641                 */
1642                cnt = ntohl(STp->buffer->aux->filemark_cnt);
1643                if (STp->header_ok                         && 
1644                    STp->header_cache != NULL              &&
1645                    (cnt - mt_count)  >= 0                 &&
1646                    (cnt - mt_count)   < OS_FM_TAB_MAX     &&
1647                    (cnt - mt_count)   < STp->filemark_cnt &&
1648                    STp->header_cache->dat_fm_tab.fm_tab_ent[cnt-1] == STp->buffer->aux->last_mark_ppos)
1649
1650                        last_mark_ppos = ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[cnt - mt_count]);
1651#if DEBUG
1652                if (STp->header_cache == NULL || (cnt - mt_count) < 0 || (cnt - mt_count) >= OS_FM_TAB_MAX)
1653                        printk(OSST_DEB_MSG "osst%d:D: Filemark lookup fail due to %s\n", dev,
1654                               STp->header_cache == NULL?"lack of header cache":"count out of range");
1655                else
1656                        printk(OSST_DEB_MSG "osst%d:D: Filemark lookup: prev mark %d (%s), skip %d to %d\n",
1657                                dev, cnt,
1658                                ((cnt == -1 && ntohl(STp->buffer->aux->last_mark_ppos) == -1) ||
1659                                 (STp->header_cache->dat_fm_tab.fm_tab_ent[cnt-1] ==
1660                                         STp->buffer->aux->last_mark_ppos))?"match":"error",
1661                               mt_count, last_mark_ppos);
1662#endif
1663                if (last_mark_ppos > 10 && last_mark_ppos < STp->eod_frame_ppos) {
1664                        osst_position_tape_and_confirm(STp, aSRpnt, last_mark_ppos);
1665                        if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
1666#if DEBUG
1667                                printk(OSST_DEB_MSG 
1668                                        "osst%d:D: Couldn't get logical blk num in space_filemarks\n", dev);
1669#endif
1670                                return (-EIO);
1671                        }
1672                        if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
1673                                printk(KERN_WARNING "osst%d:W: Expected to find marker at ppos %d, not found\n",
1674                                                 dev, last_mark_ppos);
1675                                return (-EIO);
1676                        }
1677                        if (mt_op == MTBSFM) {
1678                                STp->frame_seq_number++;
1679                                STp->frame_in_buffer  = 0;
1680                                STp->logical_blk_num += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
1681                        }
1682                        return 0;
1683                }
1684#if DEBUG
1685                printk(OSST_DEB_MSG "osst%d:D: Reverting to scan filemark backwards\n", dev);
1686#endif
1687        }
1688        cnt = 0;
1689        while (cnt != mt_count) {
1690                last_mark_ppos = ntohl(STp->buffer->aux->last_mark_ppos);
1691                if (last_mark_ppos == -1)
1692                        return (-EIO);
1693#if DEBUG
1694                printk(OSST_DEB_MSG "osst%d:D: Positioning to last mark at %d\n", dev, last_mark_ppos);
1695#endif
1696                osst_position_tape_and_confirm(STp, aSRpnt, last_mark_ppos);
1697                cnt++;
1698                if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
1699#if DEBUG
1700                        printk(OSST_DEB_MSG "osst%d:D: Couldn't get logical blk num in space_filemarks\n", dev);
1701#endif
1702                        return (-EIO);
1703                }
1704                if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
1705                        printk(KERN_WARNING "osst%d:W: Expected to find marker at ppos %d, not found\n",
1706                                         dev, last_mark_ppos);
1707                        return (-EIO);
1708                }
1709        }
1710        if (mt_op == MTBSFM) {
1711                STp->frame_seq_number++;
1712                STp->frame_in_buffer  = 0;
1713                STp->logical_blk_num += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
1714        }
1715        return 0;
1716}
1717
1718/*
1719 * ADRL 1.1 compatible "slow" space filemarks fwd version
1720 *
1721 * Just scans for the filemark sequentially.
1722 */
1723static int osst_space_over_filemarks_forward_slow(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt,
1724                                                                     int mt_op, int mt_count)
1725{
1726        int     cnt = 0;
1727#if DEBUG
1728        int     dev = TAPE_NR(STp->devt);
1729
1730        printk(OSST_DEB_MSG "osst%d:D: Reached space_over_filemarks_forward_slow %d %d\n", dev, mt_op, mt_count);
1731#endif
1732        if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
1733#if DEBUG
1734                printk(OSST_DEB_MSG "osst%d:D: Couldn't get logical blk num in space_filemarks_fwd\n", dev);
1735#endif
1736                return (-EIO);
1737        }
1738        while (1) {
1739                if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
1740#if DEBUG
1741                        printk(OSST_DEB_MSG "osst%d:D: Couldn't get logical blk num in space_filemarks\n", dev);
1742#endif
1743                        return (-EIO);
1744                }
1745                if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_MARKER)
1746                        cnt++;
1747                if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_EOD) {
1748#if DEBUG
1749                        printk(OSST_DEB_MSG "osst%d:D: space_fwd: EOD reached\n", dev);
1750#endif
1751                        if (STp->first_frame_position > STp->eod_frame_ppos+1) {
1752#if DEBUG
1753                                printk(OSST_DEB_MSG "osst%d:D: EOD position corrected (%d=>%d)\n",
1754                                                dev, STp->eod_frame_ppos, STp->first_frame_position-1);
1755#endif
1756                                STp->eod_frame_ppos = STp->first_frame_position-1;
1757                        }
1758                        return (-EIO);
1759                }
1760                if (cnt == mt_count)
1761                        break;
1762                STp->frame_in_buffer = 0;
1763        }
1764        if (mt_op == MTFSF) {
1765                STp->frame_seq_number++;
1766                STp->frame_in_buffer  = 0;
1767                STp->logical_blk_num += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
1768        }
1769        return 0;
1770}
1771
1772/*
1773 * Fast linux specific version of OnStream FSF
1774 */
1775static int osst_space_over_filemarks_forward_fast(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt,
1776                                                                     int mt_op, int mt_count)
1777{
1778        int     dev = TAPE_NR(STp->devt);
1779        int     cnt = 0,
1780                next_mark_ppos = -1;
1781
1782#if DEBUG
1783        printk(OSST_DEB_MSG "osst%d:D: Reached space_over_filemarks_forward_fast %d %d\n", dev, mt_op, mt_count);
1784#endif
1785        if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
1786#if DEBUG
1787                printk(OSST_DEB_MSG "osst%d:D: Couldn't get logical blk num in space_filemarks_fwd\n", dev);
1788#endif
1789                return (-EIO);
1790        }
1791
1792        if (STp->linux_media_version >= 4) {
1793                /*
1794                 * direct lookup in header filemark list
1795                 */
1796                cnt = ntohl(STp->buffer->aux->filemark_cnt) - 1;
1797                if (STp->header_ok                         && 
1798                    STp->header_cache != NULL              &&
1799                    (cnt + mt_count)   < OS_FM_TAB_MAX     &&
1800                    (cnt + mt_count)   < STp->filemark_cnt &&
1801                    ((cnt == -1 && ntohl(STp->buffer->aux->last_mark_ppos) == -1) ||
1802                     (STp->header_cache->dat_fm_tab.fm_tab_ent[cnt] == STp->buffer->aux->last_mark_ppos)))
1803
1804                        next_mark_ppos = ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[cnt + mt_count]);
1805#if DEBUG
1806                if (STp->header_cache == NULL || (cnt + mt_count) >= OS_FM_TAB_MAX)
1807                        printk(OSST_DEB_MSG "osst%d:D: Filemark lookup fail due to %s\n", dev,
1808                               STp->header_cache == NULL?"lack of header cache":"count out of range");
1809                else
1810                        printk(OSST_DEB_MSG "osst%d:D: Filemark lookup: prev mark %d (%s), skip %d to %d\n",
1811                               dev, cnt,
1812                               ((cnt == -1 && ntohl(STp->buffer->aux->last_mark_ppos) == -1) ||
1813                                (STp->header_cache->dat_fm_tab.fm_tab_ent[cnt] ==
1814                                         STp->buffer->aux->last_mark_ppos))?"match":"error",
1815                               mt_count, next_mark_ppos);
1816#endif
1817                if (next_mark_ppos <= 10 || next_mark_ppos > STp->eod_frame_ppos) {
1818#if DEBUG
1819                        printk(OSST_DEB_MSG "osst%d:D: Reverting to slow filemark space\n", dev);
1820#endif
1821                        return osst_space_over_filemarks_forward_slow(STp, aSRpnt, mt_op, mt_count);
1822                } else {
1823                        osst_position_tape_and_confirm(STp, aSRpnt, next_mark_ppos);
1824                        if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
1825#if DEBUG
1826                                printk(OSST_DEB_MSG "osst%d:D: Couldn't get logical blk num in space_filemarks\n",
1827                                                 dev);
1828#endif
1829                                return (-EIO);
1830                        }
1831                        if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
1832                                printk(KERN_WARNING "osst%d:W: Expected to find marker at ppos %d, not found\n",
1833                                                 dev, next_mark_ppos);
1834                                return (-EIO);
1835                        }
1836                        if (ntohl(STp->buffer->aux->filemark_cnt) != cnt + mt_count) {
1837                                printk(KERN_WARNING "osst%d:W: Expected to find marker %d at ppos %d, not %d\n",
1838                                                 dev, cnt+mt_count, next_mark_ppos,
1839                                                 ntohl(STp->buffer->aux->filemark_cnt));
1840                                return (-EIO);
1841                        }
1842                }
1843        } else {
1844                /*
1845                 * Find nearest (usually previous) marker, then jump from marker to marker
1846                 */
1847                while (1) {
1848                        if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_MARKER)
1849                                break;
1850                        if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_EOD) {
1851#if DEBUG
1852                                printk(OSST_DEB_MSG "osst%d:D: space_fwd: EOD reached\n", dev);
1853#endif
1854                                return (-EIO);
1855                        }
1856                        if (ntohl(STp->buffer->aux->filemark_cnt) == 0) {
1857                                if (STp->first_mark_ppos == -1) {
1858#if DEBUG
1859                                        printk(OSST_DEB_MSG "osst%d:D: Reverting to slow filemark space\n", dev);
1860#endif
1861                                        return osst_space_over_filemarks_forward_slow(STp, aSRpnt, mt_op, mt_count);
1862                                }
1863                                osst_position_tape_and_confirm(STp, aSRpnt, STp->first_mark_ppos);
1864                                if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
1865#if DEBUG
1866                                        printk(OSST_DEB_MSG
1867                                               "osst%d:D: Couldn't get logical blk num in space_filemarks_fwd_fast\n",
1868                                               dev);
1869#endif
1870                                        return (-EIO);
1871                                }
1872                                if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
1873                                        printk(KERN_WARNING "osst%d:W: Expected to find filemark at %d\n",
1874                                                         dev, STp->first_mark_ppos);
1875                                        return (-EIO);
1876                                }
1877                        } else {
1878                                if (osst_space_over_filemarks_backward(STp, aSRpnt, MTBSF, 1) < 0)
1879                                        return (-EIO);
1880                                mt_count++;
1881                        }
1882                }
1883                cnt++;
1884                while (cnt != mt_count) {
1885                        next_mark_ppos = ntohl(STp->buffer->aux->next_mark_ppos);
1886                        if (!next_mark_ppos || next_mark_ppos > STp->eod_frame_ppos) {
1887#if DEBUG
1888                                printk(OSST_DEB_MSG "osst%d:D: Reverting to slow filemark space\n", dev);
1889#endif
1890                                return osst_space_over_filemarks_forward_slow(STp, aSRpnt, mt_op, mt_count - cnt);
1891                        }
1892#if DEBUG
1893                        else printk(OSST_DEB_MSG "osst%d:D: Positioning to next mark at %d\n", dev, next_mark_ppos);
1894#endif
1895                        osst_position_tape_and_confirm(STp, aSRpnt, next_mark_ppos);
1896                        cnt++;
1897                        if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
1898#if DEBUG
1899                                printk(OSST_DEB_MSG "osst%d:D: Couldn't get logical blk num in space_filemarks\n",
1900                                                 dev);
1901#endif
1902                                return (-EIO);
1903                        }
1904                        if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
1905                                printk(KERN_WARNING "osst%d:W: Expected to find marker at ppos %d, not found\n",
1906                                                 dev, next_mark_ppos);
1907                                return (-EIO);
1908                        }
1909                }
1910        }
1911        if (mt_op == MTFSF) {
1912                STp->frame_seq_number++;
1913                STp->frame_in_buffer  = 0;
1914                STp->logical_blk_num += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
1915        }
1916        return 0;
1917}
1918
1919/*
1920 * In debug mode, we want to see as many errors as possible
1921 * to test the error recovery mechanism.
1922 */
1923#if DEBUG
1924static void osst_set_retries(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int retries)
1925{
1926        unsigned char   cmd[MAX_COMMAND_SIZE];
1927        Scsi_Request     * SRpnt  = * aSRpnt;
1928        int             dev  = TAPE_NR(STp->devt);
1929
1930        memset(cmd, 0, MAX_COMMAND_SIZE);
1931        cmd[0] = MODE_SELECT;
1932        cmd[1] = 0x10;
1933        cmd[4] = NUMBER_RETRIES_PAGE_LENGTH + MODE_HEADER_LENGTH;
1934
1935        (STp->buffer)->b_data[0] = cmd[4] - 1;
1936        (STp->buffer)->b_data[1] = 0;                   /* Medium Type - ignoring */
1937        (STp->buffer)->b_data[2] = 0;                   /* Reserved */
1938        (STp->buffer)->b_data[3] = 0;                   /* Block Descriptor Length */
1939        (STp->buffer)->b_data[MODE_HEADER_LENGTH + 0] = NUMBER_RETRIES_PAGE | (1 << 7);
1940        (STp->buffer)->b_data[MODE_HEADER_LENGTH + 1] = 2;
1941        (STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] = 4;
1942        (STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] = retries;
1943
1944        if (debugging)
1945            printk(OSST_DEB_MSG "osst%d:D: Setting number of retries on OnStream tape to %d\n", dev, retries);
1946
1947        SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], SCSI_DATA_WRITE, STp->timeout, 0, TRUE);
1948        *aSRpnt = SRpnt;
1949
1950        if ((STp->buffer)->syscall_result)
1951            printk (KERN_ERR "osst%d:D: Couldn't set retries to %d\n", dev, retries);
1952}
1953#endif
1954
1955
1956static int osst_write_filemark(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt)
1957{
1958        int     result;
1959        int     this_mark_ppos = STp->first_frame_position;
1960        int     this_mark_lbn  = STp->logical_blk_num;
1961#if DEBUG
1962        int     dev = TAPE_NR(STp->devt);
1963#endif
1964
1965        if (STp->raw) return 0;
1966
1967        STp->write_type = OS_WRITE_NEW_MARK;
1968#if DEBUG
1969        printk(OSST_DEB_MSG "osst%d:D: Writing Filemark %i at fppos %d (fseq %d, lblk %d)\n", 
1970               dev, STp->filemark_cnt, this_mark_ppos, STp->frame_seq_number, this_mark_lbn);
1971#endif
1972        STp->dirty = 1;
1973        result  = osst_flush_write_buffer(STp, aSRpnt);
1974        result |= osst_flush_drive_buffer(STp, aSRpnt);
1975        STp->last_mark_ppos = this_mark_ppos;
1976        STp->last_mark_lbn  = this_mark_lbn;
1977        if (STp->header_cache != NULL && STp->filemark_cnt < OS_FM_TAB_MAX)
1978                STp->header_cache->dat_fm_tab.fm_tab_ent[STp->filemark_cnt] = htonl(this_mark_ppos);
1979        if (STp->filemark_cnt++ == 0)
1980                STp->first_mark_ppos = this_mark_ppos;
1981        return result;
1982}
1983
1984static int osst_write_eod(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt)
1985{
1986        int     result;
1987#if DEBUG
1988        int     dev = TAPE_NR(STp->devt);
1989#endif
1990
1991        if (STp->raw) return 0;
1992
1993        STp->write_type = OS_WRITE_EOD;
1994        STp->eod_frame_ppos = STp->first_frame_position;
1995#if DEBUG
1996        printk(OSST_DEB_MSG "osst%d:D: Writing EOD at fppos %d (fseq %d, lblk %d)\n", dev,
1997                        STp->eod_frame_ppos, STp->frame_seq_number, STp->logical_blk_num);
1998#endif
1999        STp->dirty = 1;
2000
2001        result  = osst_flush_write_buffer(STp, aSRpnt); 
2002        result |= osst_flush_drive_buffer(STp, aSRpnt);
2003        STp->eod_frame_lfa = --(STp->frame_seq_number);
2004        return result;
2005}
2006
2007static int osst_write_filler(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int where, int count)
2008{
2009        int     dev = TAPE_NR(STp->devt);
2010
2011#if DEBUG
2012        printk(OSST_DEB_MSG "osst%d:D: Reached onstream write filler group %d\n", dev, where);
2013#endif
2014        osst_wait_ready(STp, aSRpnt, 60 * 5);
2015        osst_set_frame_position(STp, aSRpnt, where, 0);
2016        STp->write_type = OS_WRITE_FILLER;
2017        while (count--) {
2018                memcpy(STp->buffer->b_data, "Filler", 6);
2019                STp->buffer->buffer_bytes = 6;
2020                STp->dirty = 1;
2021                if (osst_flush_write_buffer(STp, aSRpnt)) {
2022                        printk(KERN_INFO "osst%i:I: Couldn't write filler frame\n", dev);
2023                        return (-EIO);
2024                }
2025        }
2026#if DEBUG
2027        printk(OSST_DEB_MSG "osst%d:D: Exiting onstream write filler group\n", dev);
2028#endif
2029        return osst_flush_drive_buffer(STp, aSRpnt);
2030}
2031
2032static int __osst_write_header(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int where, int count)
2033{
2034        int     dev   = TAPE_NR(STp->devt);
2035        int     result;
2036
2037#if DEBUG
2038        printk(OSST_DEB_MSG "osst%d:D: Reached onstream write header group %d\n", dev, where);
2039#endif
2040        osst_wait_ready(STp, aSRpnt, 60 * 5);
2041        osst_set_frame_position(STp, aSRpnt, where, 0);
2042        STp->write_type = OS_WRITE_HEADER;
2043        while (count--) {
2044                osst_copy_to_buffer(STp->buffer, (unsigned char *)STp->header_cache);
2045                STp->buffer->buffer_bytes = sizeof(os_header_t);
2046                STp->dirty = 1;
2047                if (osst_flush_write_buffer(STp, aSRpnt)) {
2048                        printk(KERN_INFO "osst%i:I: Couldn't write header frame\n", dev);
2049                        return (-EIO);
2050                }
2051        }
2052        result = osst_flush_drive_buffer(STp, aSRpnt);
2053#if DEBUG
2054        printk(OSST_DEB_MSG "osst%d:D: Write onstream header group %s\n", dev, result?"failed":"done");
2055#endif
2056        return result;
2057}
2058
2059static int osst_write_header(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int locate_eod)
2060{
2061        os_header_t * header;
2062        int           result;
2063        int           dev   = TAPE_NR(STp->devt);
2064
2065#if DEBUG
2066        printk(OSST_DEB_MSG "osst%d:D: Writing tape header\n", dev);
2067#endif
2068        if (STp->raw) return 0;
2069
2070        if (STp->header_cache == NULL) {
2071                if ((STp->header_cache = (os_header_t *)vmalloc(sizeof(os_header_t))) == NULL) {
2072                        printk(KERN_ERR "osst%i:E: Failed to allocate header cache\n", dev);
2073                        return (-ENOMEM);
2074                }
2075                memset(STp->header_cache, 0, sizeof(os_header_t));
2076#if DEBUG
2077                printk(OSST_DEB_MSG "osst%d:D: Allocated and cleared memory for header cache\n", dev);
2078#endif
2079        }
2080        if (STp->header_ok) STp->update_frame_cntr++;
2081        else                STp->update_frame_cntr = 0;
2082
2083        header = STp->header_cache;
2084        strcpy(header->ident_str, "ADR_SEQ");
2085        header->major_rev      = 1;
2086        header->minor_rev      = 4;
2087        header->ext_trk_tb_off = htons(17192);
2088        header->pt_par_num     = 1;
2089        header->partition[0].partition_num              = OS_DATA_PARTITION;
2090        header->partition[0].par_desc_ver               = OS_PARTITION_VERSION;
2091        header->partition[0].wrt_pass_cntr              = htons(STp->wrt_pass_cntr);
2092        header->partition[0].first_frame_ppos           = htonl(STp->first_data_ppos);
2093        header->partition[0].last_frame_ppos            = htonl(STp->capacity);
2094        header->partition[0].eod_frame_ppos             = htonl(STp->eod_frame_ppos);
2095        header->cfg_col_width                           = htonl(20);
2096        header->dat_col_width                           = htonl(1500);
2097        header->qfa_col_width                           = htonl(0);
2098        header->ext_track_tb.nr_stream_part             = 1;
2099        header->ext_track_tb.et_ent_sz                  = 32;
2100        header->ext_track_tb.dat_ext_trk_ey.et_part_num = 0;
2101        header->ext_track_tb.dat_ext_trk_ey.fmt         = 1;
2102        header->ext_track_tb.dat_ext_trk_ey.fm_tab_off  = htons(17736);
2103        header->ext_track_tb.dat_ext_trk_ey.last_hlb_hi = 0;
2104        header->ext_track_tb.dat_ext_trk_ey.last_hlb    = htonl(STp->eod_frame_lfa);
2105        header->ext_track_tb.dat_ext_trk_ey.last_pp     = htonl(STp->eod_frame_ppos);
2106        header->dat_fm_tab.fm_part_num                  = 0;
2107        header->dat_fm_tab.fm_tab_ent_sz                = 4;
2108        header->dat_fm_tab.fm_tab_ent_cnt               = htons(STp->filemark_cnt<OS_FM_TAB_MAX?
2109                                                                STp->filemark_cnt:OS_FM_TAB_MAX);
2110
2111        result  = __osst_write_header(STp, aSRpnt, 0xbae, 5);
2112        if (STp->update_frame_cntr == 0)
2113                    osst_write_filler(STp, aSRpnt, 0xbb3, 5);
2114        result &= __osst_write_header(STp, aSRpnt,     5, 5);
2115
2116        if (locate_eod) {
2117#if DEBUG
2118                printk(OSST_DEB_MSG "osst%d:D: Locating back to eod frame addr %d\n", dev, STp->eod_frame_ppos);
2119#endif
2120                osst_set_frame_position(STp, aSRpnt, STp->eod_frame_ppos, 0);
2121        }
2122        if (result)
2123                printk(KERN_ERR "osst%i:E: Write header failed\n", dev);
2124        else {
2125                memcpy(STp->application_sig, "LIN4", 4);
2126                STp->linux_media         = 1;
2127                STp->linux_media_version = 4;
2128                STp->header_ok           = 1;
2129        }
2130        return result;
2131}
2132
2133static int osst_reset_header(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt)
2134{
2135        if (STp->header_cache != NULL)
2136                memset(STp->header_cache, 0, sizeof(os_header_t));
2137
2138        STp->logical_blk_num = STp->frame_seq_number = 0;
2139        STp->frame_in_buffer = 0;
2140        STp->eod_frame_ppos = STp->first_data_ppos = 0x0000000A;
2141        STp->filemark_cnt = 0;
2142        STp->first_mark_ppos = STp->last_mark_ppos = STp->last_mark_lbn = -1;
2143        return osst_write_header(STp, aSRpnt, 1);
2144}
2145
2146static int __osst_analyze_headers(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int ppos)
2147{
2148        int           dev = TAPE_NR(STp->devt);
2149        os_header_t * header;
2150        os_aux_t    * aux;
2151        char          id_string[8];
2152        int           linux_media_version,
2153                      update_frame_cntr;
2154
2155        if (STp->raw)
2156                return 1;
2157
2158        if (ppos == 5 || ppos == 0xbae || STp->buffer->syscall_result) {
2159                if (osst_set_frame_position(STp, aSRpnt, ppos, 0))
2160                        printk(KERN_WARNING "osst%i:W: Couldn't position tape\n", dev);
2161                if (osst_initiate_read (STp, aSRpnt)) {
2162                        printk(KERN_WARNING "osst%i:W: Couldn't initiate read\n", dev);
2163                        return 0;
2164                }
2165        }
2166        if (osst_read_frame(STp, aSRpnt, 180)) {
2167#if DEBUG
2168                printk(OSST_DEB_MSG "osst%d:D: Couldn't read header frame\n", dev);
2169#endif
2170                return 0;
2171        }
2172        header = (os_header_t *) STp->buffer->b_data;   /* warning: only first segment addressable */
2173        aux = STp->buffer->aux;
2174        if (aux->frame_type != OS_FRAME_TYPE_HEADER) {
2175#if DEBUG
2176                printk(OSST_DEB_MSG "osst%d:D: Skipping non-header frame (%d)\n", dev, ppos);
2177#endif
2178                return 0;
2179        }
2180        if (ntohl(aux->frame_seq_num)              != 0                   ||
2181            ntohl(aux->logical_blk_num)            != 0                   ||
2182                  aux->partition.partition_num     != OS_CONFIG_PARTITION ||
2183            ntohl(aux->partition.first_frame_ppos) != 0                   ||
2184            ntohl(aux->partition.last_frame_ppos)  != 0xbb7               ) {
2185#if DEBUG
2186                printk(OSST_DEB_MSG "osst%d:D: Invalid header frame (%d,%d,%d,%d,%d)\n", dev,
2187                                ntohl(aux->frame_seq_num), ntohl(aux->logical_blk_num),
2188                                aux->partition.partition_num, ntohl(aux->partition.first_frame_ppos),
2189                                ntohl(aux->partition.last_frame_ppos));
2190#endif
2191                return 0;
2192        }
2193        if (strncmp(header->ident_str, "ADR_SEQ", 7) != 0 &&
2194            strncmp(header->ident_str, "ADR-SEQ", 7) != 0) {
2195                strncpy(id_string, header->ident_str, 7);
2196                id_string[7] = 0;
2197#if DEBUG
2198                printk(OSST_DEB_MSG "osst%d:D: Invalid header identification string %s\n", dev, id_string);
2199#endif
2200                return 0;
2201        }
2202        update_frame_cntr = ntohl(aux->update_frame_cntr);
2203        if (update_frame_cntr < STp->update_frame_cntr) {
2204#if DEBUG
2205                printk(OSST_DEB_MSG "osst%d:D: Skipping frame %d with update_frame_counter %d<%d\n",
2206                                   dev, ppos, update_frame_cntr, STp->update_frame_cntr);
2207#endif
2208                return 0;
2209        }
2210        if (header->major_rev != 1 || header->minor_rev != 4 ) {
2211#if DEBUG
2212                printk(OSST_DEB_MSG "osst%d:D: %s revision %d.%d detected (1.4 supported)\n", 
2213                                 dev, (header->major_rev != 1 || header->minor_rev < 2 || 
2214                                       header->minor_rev  > 4 )? "Invalid" : "Warning:",
2215                                 header->major_rev, header->minor_rev);
2216#endif
2217                if (header->major_rev != 1 || header->minor_rev < 2 || header->minor_rev > 4)
2218                        return 0;
2219        }
2220#if DEBUG
2221        if (header->pt_par_num != 1)
2222                printk(KERN_INFO "osst%i:W: %d partitions defined, only one supported\n", 
2223                                 dev, header->pt_par_num);
2224#endif
2225        memcpy(id_string, aux->application_sig, 4);
2226        id_string[4] = 0;
2227        if (memcmp(id_string, "LIN", 3) == 0) {
2228                STp->linux_media = 1;
2229                linux_media_version = id_string[3] - '0';
2230                if (linux_media_version != 4)
2231                        printk(KERN_INFO "osst%i:I: Linux media version %d detected (current 4)\n",
2232                                         dev, linux_media_version);
2233        } else {
2234                printk(KERN_WARNING "osst%i:W: Non Linux media detected (%s)\n", dev, id_string);
2235                return 0;
2236        }
2237        if (linux_media_version < STp->linux_media_version) {
2238#if DEBUG
2239                printk(OSST_DEB_MSG "osst%d:D: Skipping frame %d with linux_media_version %d\n",
2240                                  dev, ppos, linux_media_version);
2241#endif
2242                return 0;
2243        }
2244        if (linux_media_version > STp->linux_media_version) {
2245#if DEBUG
2246                printk(OSST_DEB_MSG "osst%d:D: Frame %d sets linux_media_version to %d\n",
2247                                   dev, ppos, linux_media_version);
2248#endif
2249                memcpy(STp->application_sig, id_string, 5);
2250                STp->linux_media_version = linux_media_version;
2251                STp->update_frame_cntr = -1;
2252        }
2253        if (update_frame_cntr > STp->update_frame_cntr) {
2254#if DEBUG
2255                printk(OSST_DEB_MSG "osst%d:D: Frame %d sets update_frame_counter to %d\n",
2256                                   dev, ppos, update_frame_cntr);
2257#endif
2258                if (STp->header_cache == NULL) {
2259                        if ((STp->header_cache = (os_header_t *)vmalloc(sizeof(os_header_t))) == NULL) {
2260                                printk(KERN_ERR "osst%i:E: Failed to allocate header cache\n", dev);
2261                                return 0;
2262                        }
2263#if DEBUG
2264                        printk(OSST_DEB_MSG "osst%d:D: Allocated memory for header cache\n", dev);
2265#endif
2266                }
2267                osst_copy_from_buffer(STp->buffer, (unsigned char *)STp->header_cache);
2268                header = STp->header_cache;     /* further accesses from cached (full) copy */
2269
2270                STp->wrt_pass_cntr     = ntohs(header->partition[0].wrt_pass_cntr);
2271                STp->first_data_ppos   = ntohl(header->partition[0].first_frame_ppos);
2272                STp->eod_frame_ppos    = ntohl(header->partition[0].eod_frame_ppos);
2273                STp->eod_frame_lfa     = ntohl(header->ext_track_tb.dat_ext_trk_ey.last_hlb);
2274                STp->filemark_cnt      = ntohl(aux->filemark_cnt);
2275                STp->first_mark_ppos   = ntohl(aux->next_mark_ppos);
2276                STp->last_mark_ppos    = ntohl(aux->last_mark_ppos);
2277                STp->last_mark_lbn     = ntohl(aux->last_mark_lbn);
2278                STp->update_frame_cntr = update_frame_cntr;
2279#if DEBUG
2280        printk(OSST_DEB_MSG "osst%d:D: Detected write pass %d, update frame counter %d, filemark counter %d\n",
2281                          dev, STp->wrt_pass_cntr, STp->update_frame_cntr, STp->filemark_cnt);
2282        printk(OSST_DEB_MSG "osst%d:D: first data frame on tape = %d, last = %d, eod frame = %d\n", dev,
2283                          STp->first_data_ppos,
2284                          ntohl(header->partition[0].last_frame_ppos),
2285                          ntohl(header->partition[0].eod_frame_ppos));
2286        printk(OSST_DEB_MSG "osst%d:D: first mark on tape = %d, last = %d, eod frame = %d\n", 
2287                          dev, STp->first_mark_ppos, STp->last_mark_ppos, STp->eod_frame_ppos);
2288#endif
2289                if (header->minor_rev < 4 && STp->linux_media_version == 4) {
2290#if DEBUG
2291                        printk(OSST_DEB_MSG "osst%i:D: Moving filemark list to ADR 1.4 location\n", dev);
2292#endif
2293                        memcpy((void *)header->dat_fm_tab.fm_tab_ent, 
2294                               (void *)header->old_filemark_list, sizeof(header->dat_fm_tab.fm_tab_ent));
2295                        memset((void *)header->old_filemark_list, 0, sizeof(header->old_filemark_list));
2296                }
2297                if (header->minor_rev == 4   &&
2298                    (header->ext_trk_tb_off                          != htons(17192)               ||
2299                     header->partition[0].partition_num              != OS_DATA_PARTITION          ||
2300                     header->partition[0].par_desc_ver               != OS_PARTITION_VERSION       ||
2301                     header->partition[0].last_frame_ppos            != htonl(STp->capacity)       ||
2302                     header->cfg_col_width                           != htonl(20)                  ||
2303                     header->dat_col_width                           != htonl(1500)                ||
2304                     header->qfa_col_width                           != htonl(0)                   ||
2305                     header->ext_track_tb.nr_stream_part             != 1                          ||
2306                     header->ext_track_tb.et_ent_sz                  != 32                         ||
2307                     header->ext_track_tb.dat_ext_trk_ey.et_part_num != OS_DATA_PARTITION          ||
2308                     header->ext_track_tb.dat_ext_trk_ey.fmt         != 1                          ||
2309                     header->ext_track_tb.dat_ext_trk_ey.fm_tab_off  != htons(17736)               ||
2310                     header->ext_track_tb.dat_ext_trk_ey.last_hlb_hi != 0                          ||
2311                     header->ext_track_tb.dat_ext_trk_ey.last_pp     != htonl(STp->eod_frame_ppos) ||
2312                     header->dat_fm_tab.fm_part_num                  != OS_DATA_PARTITION          ||
2313                     header->dat_fm_tab.fm_tab_ent_sz                != 4                          ||
2314                     header->dat_fm_tab.fm_tab_ent_cnt               !=
2315                             htons(STp->filemark_cnt<OS_FM_TAB_MAX?STp->filemark_cnt:OS_FM_TAB_MAX)))
2316                        printk(KERN_WARNING "osst%i:W: Failed consistency check ADR 1.4 format\n", dev);
2317
2318        }
2319
2320        return 1;
2321}
2322
2323static int osst_analyze_headers(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt)
2324{
2325        int position, ppos;
2326        int     first, last;
2327        int     valid = 0;
2328        int     dev = TAPE_NR(STp->devt);
2329
2330        position = osst_get_frame_position(STp, aSRpnt);
2331
2332        if (STp->raw) {
2333                STp->header_ok = STp->linux_media = 1;
2334                STp->linux_media_version = 0;
2335                return 1;
2336        }
2337        STp->header_ok = STp->linux_media = STp->linux_media_version = 0;
2338        STp->wrt_pass_cntr = STp->update_frame_cntr = -1;
2339        STp->eod_frame_ppos = STp->first_data_ppos = -1;
2340        STp->first_mark_ppos = STp->last_mark_ppos = STp->last_mark_lbn = -1;
2341#if DEBUG
2342        printk(OSST_DEB_MSG "osst%d:D: Reading header\n", dev);
2343#endif
2344
2345        /* optimization for speed - if we are positioned at ppos 10, read second group first  */        
2346        /* TODO try the ADR 1.1 locations for the second group if we have no valid one yet... */
2347
2348        first = position==10?0xbae: 5;
2349        last  = position==10?0xbb3:10;
2350
2351        for (ppos = first; ppos < last; ppos++)
2352                if (__osst_analyze_headers(STp, aSRpnt, ppos))
2353                        valid = 1;
2354
2355        first = position==10? 5:0xbae;
2356        last  = position==10?10:0xbb3;
2357
2358        for (ppos = first; ppos < last; ppos++)
2359                if (__osst_analyze_headers(STp, aSRpnt, ppos))
2360                        valid = 1;
2361
2362        if (!valid) {
2363                printk(KERN_ERR "osst%i:E: Failed to find valid ADRL header, new media?\n", dev);
2364                STp->eod_frame_ppos = STp->first_data_ppos = 0;
2365                osst_set_frame_position(STp, aSRpnt, 10, 0);
2366                return 0;
2367        }
2368        if (position <= STp->first_data_ppos) {
2369                position = STp->first_data_ppos;
2370                STp->ps[0].drv_file = STp->ps[0].drv_block = STp->frame_seq_number = STp->logical_blk_num = 0;
2371        }
2372        osst_set_frame_position(STp, aSRpnt, position, 0);
2373        STp->header_ok = 1;
2374
2375        return 1;
2376}
2377
2378static int osst_verify_position(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt)
2379{
2380        int     frame_position  = STp->first_frame_position;
2381        int frame_seq_numbr = STp->frame_seq_number;
2382        int     logical_blk_num = STp->logical_blk_num;
2383        int halfway_frame   = STp->frame_in_buffer;
2384        int read_pointer    = STp->buffer->read_pointer;
2385        int     prev_mark_ppos  = -1;
2386        int     actual_mark_ppos, i, n;
2387#if DEBUG
2388        int     dev = TAPE_NR(STp->devt);
2389
2390        printk(OSST_DEB_MSG "osst%d:D: Verify that the tape is really the one we think before writing\n", dev);
2391#endif
2392        osst_set_frame_position(STp, aSRpnt, frame_position - 1, 0);
2393        if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
2394#if DEBUG
2395                printk(OSST_DEB_MSG "osst%d:D: Couldn't get logical blk num in verify_position\n", dev);
2396#endif
2397                return (-EIO);
2398        }
2399        if (STp->linux_media_version >= 4) {
2400                for (i=0; i<STp->filemark_cnt; i++)
2401                        if ((n=ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[i])) < frame_position)
2402                                prev_mark_ppos = n;
2403        } else
2404                prev_mark_ppos = frame_position - 1;  /* usually - we don't really know */
2405        actual_mark_ppos = STp->buffer->aux->frame_type == OS_FRAME_TYPE_MARKER ?
2406                                frame_position - 1 : ntohl(STp->buffer->aux->last_mark_ppos);
2407        if (frame_position  != STp->first_frame_position                   ||
2408            frame_seq_numbr != STp->frame_seq_number + (halfway_frame?0:1) ||
2409            prev_mark_ppos  != actual_mark_ppos                            ) {
2410#if DEBUG
2411                printk(OSST_DEB_MSG "osst%d:D: Block mismatch: fppos %d-%d, fseq %d-%d, mark %d-%d\n", dev,
2412                                  STp->first_frame_position, frame_position, 
2413                                  STp->frame_seq_number + (halfway_frame?0:1),
2414                                  frame_seq_numbr, actual_mark_ppos, prev_mark_ppos);
2415#endif
2416                return (-EIO);
2417        }
2418        if (halfway_frame) {
2419                /* prepare buffer for append and rewrite on top of original */
2420                osst_set_frame_position(STp, aSRpnt, frame_position - 1, 0);
2421                STp->buffer->buffer_bytes  = read_pointer;
2422                STp->ps[STp->partition].rw = ST_WRITING;
2423                STp->dirty                 = 1;
2424        }
2425        STp->frame_in_buffer  = halfway_frame;
2426        STp->frame_seq_number = frame_seq_numbr;
2427        STp->logical_blk_num  = logical_blk_num;
2428        return 0;
2429}
2430
2431/* Acc. to OnStream, the vers. numbering is the following:
2432 * X.XX for released versions (X=digit), 
2433 * XXXY for unreleased versions (Y=letter)
2434 * Ordering 1.05 < 106A < 106B < ...  < 106a < ... < 1.06
2435 * This fn makes monoton numbers out of this scheme ...
2436 */
2437static unsigned int osst_parse_firmware_rev (const char * str)
2438{
2439        if (str[1] == '.') {
2440                return (str[0]-'0')*10000
2441                        +(str[2]-'0')*1000
2442                        +(str[3]-'0')*100;
2443        } else {
2444                return (str[0]-'0')*10000
2445                        +(str[1]-'0')*1000
2446                        +(str[2]-'0')*100 - 100
2447                        +(str[3]-'@');
2448        }
2449}
2450
2451/*
2452 * Configure the OnStream SCII tape drive for default operation
2453 */
2454static int osst_configure_onstream(OS_Scsi_Tape *STp, Scsi_Request ** aSRpnt)
2455{
2456        unsigned char                  cmd[MAX_COMMAND_SIZE];
2457        int                            dev   = TAPE_NR(STp->devt);
2458        Scsi_Request                    * SRpnt = * aSRpnt;
2459        osst_mode_parameter_header_t * header;
2460        osst_block_size_page_t       * bs;
2461        osst_capabilities_page_t     * cp;
2462        osst_tape_paramtr_page_t     * prm;
2463        int                            drive_buffer_size;
2464
2465        if (STp->ready != ST_READY) {
2466#if DEBUG
2467            printk(OSST_DEB_MSG "osst%d:D: Not Ready\n", dev);
2468#endif
2469            return (-EIO);
2470        }
2471        
2472        if (STp->os_fw_rev < 10600) {
2473            printk(KERN_INFO "osst%i:I: Old OnStream firmware revision detected (%s),\n", dev, STp->device->rev);
2474            printk(KERN_INFO "osst%d:I: an upgrade to version 1.06 or above is recommended\n", dev);
2475        }
2476
2477        /*
2478         * Configure 32.5KB (data+aux) frame size.
2479         * Get the current frame size from the block size mode page
2480         */
2481        memset(cmd, 0, MAX_COMMAND_SIZE);
2482        cmd[0] = MODE_SENSE;
2483        cmd[1] = 8;
2484        cmd[2] = BLOCK_SIZE_PAGE;
2485        cmd[4] = BLOCK_SIZE_PAGE_LENGTH + MODE_HEADER_LENGTH;
2486
2487        SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], SCSI_DATA_READ, STp->timeout, 0, TRUE);
2488        if (SRpnt == NULL) {
2489#if DEBUG
2490            printk(OSST_DEB_MSG "osst :D: Busy\n");
2491#endif
2492            return (-EBUSY);
2493        }
2494        *aSRpnt = SRpnt;
2495        if ((STp->buffer)->syscall_result != 0) {
2496            printk (KERN_ERR "osst%i:E: Can't get tape block size mode page\n", dev);
2497            return (-EIO);
2498        }
2499
2500        header = (osst_mode_parameter_header_t *) (STp->buffer)->b_data;
2501        bs = (osst_block_size_page_t *) ((STp->buffer)->b_data + sizeof(osst_mode_parameter_header_t) + header->bdl);
2502
2503#if DEBUG
2504        printk(OSST_DEB_MSG "osst%d:D: 32KB play back: %s\n",   dev, bs->play32     ? "Yes" : "No");
2505        printk(OSST_DEB_MSG "osst%d:D: 32.5KB play back: %s\n", dev, bs->play32_5   ? "Yes" : "No");
2506        printk(OSST_DEB_MSG "osst%d:D: 32KB record: %s\n",      dev, bs->record32   ? "Yes" : "No");
2507        printk(OSST_DEB_MSG "osst%d:D: 32.5KB record: %s\n",    dev, bs->record32_5 ? "Yes" : "No");
2508#endif
2509
2510        /*
2511         * Configure default auto columns mode, 32.5KB transfer mode
2512         */ 
2513        bs->one = 1;
2514        bs->play32 = 0;
2515        bs->play32_5 = 1;
2516        bs->record32 = 0;
2517        bs->record32_5 = 1;
2518
2519        memset(cmd, 0, MAX_COMMAND_SIZE);
2520        cmd[0] = MODE_SELECT;
2521        cmd[1] = 0x10;
2522        cmd[4] = BLOCK_SIZE_PAGE_LENGTH + MODE_HEADER_LENGTH;
2523
2524        SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], SCSI_DATA_WRITE, STp->timeout, 0, TRUE);
2525        *aSRpnt = SRpnt;
2526        if ((STp->buffer)->syscall_result != 0) {
2527            printk (KERN_ERR "osst%i:E: Couldn't set tape block size mode page\n", dev);
2528            return (-EIO);
2529        }
2530
2531#if DEBUG
2532        printk(KERN_INFO "osst%d:D: Drive Block Size changed to 32.5K\n", dev);
2533         /*
2534         * In debug mode, we want to see as many errors as possible
2535         * to test the error recovery mechanism.
2536         */
2537        osst_set_retries(STp, aSRpnt, 0);
2538        SRpnt = * aSRpnt;
2539#endif
2540
2541        /*
2542         * Set vendor name to 'LIN4' for "Linux support version 4".
2543         */
2544
2545        memset(cmd, 0, MAX_COMMAND_SIZE);
2546        cmd[0] = MODE_SELECT;
2547        cmd[1] = 0x10;
2548        cmd[4] = VENDOR_IDENT_PAGE_LENGTH + MODE_HEADER_LENGTH;
2549
2550        header->mode_data_length = VENDOR_IDENT_PAGE_LENGTH + MODE_HEADER_LENGTH - 1;
2551        header->medium_type      = 0;   /* Medium Type - ignoring */
2552        header->dsp              = 0;   /* Reserved */
2553        header->bdl              = 0;   /* Block Descriptor Length */
2554        
2555        (STp->buffer)->b_data[MODE_HEADER_LENGTH + 0] = VENDOR_IDENT_PAGE | (1 << 7);
2556        (STp->buffer)->b_data[MODE_HEADER_LENGTH + 1] = 6;
2557        (STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] = 'L';
2558        (STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] = 'I';
2559        (STp->buffer)->b_data[MODE_HEADER_LENGTH + 4] = 'N';
2560        (STp->buffer)->b_data[MODE_HEADER_LENGTH + 5] = '4';
2561        (STp->buffer)->b_data[MODE_HEADER_LENGTH + 6] = 0;
2562        (STp->buffer)->b_data[MODE_HEADER_LENGTH + 7] = 0;
2563
2564        SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], SCSI_DATA_WRITE, STp->timeout, 0, TRUE);
2565        *aSRpnt = SRpnt;
2566
2567        if ((STp->buffer)->syscall_result != 0) {
2568            printk (KERN_ERR "osst%i:E: Couldn't set vendor name to %s\n", dev, 
2569                        (char *) ((STp->buffer)->b_data + MODE_HEADER_LENGTH + 2));
2570            return (-EIO);
2571        }
2572
2573        memset(cmd, 0, MAX_COMMAND_SIZE);
2574        cmd[0] = MODE_SENSE;
2575        cmd[1] = 8;
2576        cmd[2] = CAPABILITIES_PAGE;
2577        cmd[4] = CAPABILITIES_PAGE_LENGTH + MODE_HEADER_LENGTH;
2578
2579        SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], SCSI_DATA_READ, STp->timeout, 0, TRUE);
2580        *aSRpnt = SRpnt;
2581
2582        if ((STp->buffer)->syscall_result != 0) {
2583            printk (KERN_ERR "osst%i:E: Can't get capabilities page\n", dev);
2584            return (-EIO);
2585        }
2586
2587        header = (osst_mode_parameter_header_t *) (STp->buffer)->b_data;
2588        cp     = (osst_capabilities_page_t    *) ((STp->buffer)->b_data +
2589                 sizeof(osst_mode_parameter_header_t) + header->bdl);
2590
2591        drive_buffer_size = ntohs(cp->buffer_size) / 2;
2592
2593        memset(cmd, 0, MAX_COMMAND_SIZE);
2594        cmd[0] = MODE_SENSE;
2595        cmd[1] = 8;
2596        cmd[2] = TAPE_PARAMTR_PAGE;
2597        cmd[4] = TAPE_PARAMTR_PAGE_LENGTH + MODE_HEADER_LENGTH;
2598
2599        SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], SCSI_DATA_READ, STp->timeout, 0, TRUE);
2600        *aSRpnt = SRpnt;
2601
2602        if ((STp->buffer)->syscall_result != 0) {
2603            printk (KERN_ERR "osst%i:E: Can't get tape parameter page\n", dev);
2604            return (-EIO);
2605        }
2606
2607        header = (osst_mode_parameter_header_t *) (STp->buffer)->b_data;
2608        prm    = (osst_tape_paramtr_page_t    *) ((STp->buffer)->b_data +
2609                 sizeof(osst_mode_parameter_header_t) + header->bdl);
2610
2611        STp->density  = prm->density;
2612        STp->capacity = ntohs(prm->segtrk) * ntohs(prm->trks);
2613#if DEBUG
2614        printk(OSST_DEB_MSG "osst%d:D: Density %d, tape length: %dMB, drive buffer size: %dKB\n",
2615                          dev, STp->density, STp->capacity / 32, drive_buffer_size);
2616#endif
2617
2618        return 0;
2619        
2620}
2621
2622
2623/* Step over EOF if it has been inadvertently crossed (ioctl not used because
2624   it messes up the block number). */
2625static int cross_eof(OS_Scsi_Tape *STp, Scsi_Request ** aSRpnt, int forward)
2626{
2627        int     result;
2628        int     dev   = TAPE_NR(STp->devt);
2629
2630#if DEBUG
2631        if (debugging)
2632                printk(OSST_DEB_MSG "osst%d:D: Stepping over filemark %s.\n",
2633                                  dev, forward ? "forward" : "backward");
2634#endif
2635
2636        if (forward) {
2637           /* assumes that the filemark is already read by the drive, so this is low cost */
2638           result = osst_space_over_filemarks_forward_slow(STp, aSRpnt, MTFSF, 1);
2639        }
2640        else
2641           /* assumes this is only called if we just read the filemark! */
2642           result = osst_seek_logical_blk(STp, aSRpnt, STp->logical_blk_num - 1);
2643
2644        if (result < 0)
2645           printk(KERN_WARNING "osst%d:W: Stepping over filemark %s failed.\n",
2646                                dev, forward ? "forward" : "backward");
2647
2648        return result;
2649}
2650
2651
2652/* Get the tape position. */
2653
2654static int osst_get_frame_position(OS_Scsi_Tape *STp, Scsi_Request ** aSRpnt)
2655{
2656        unsigned char   scmd[MAX_COMMAND_SIZE];
2657        Scsi_Request  * SRpnt;
2658        int             result = 0;
2659
2660        /* KG: We want to be able to use it for checking Write Buffer availability
2661         *  and thus don't want to risk to overwrite anything. Exchange buffers ... */
2662        char            mybuf[24];
2663        char          * olddata = STp->buffer->b_data;
2664        int             oldsize = STp->buffer->buffer_size;
2665        int             dev     = TAPE_NR(STp->devt);
2666
2667        if (STp->ready != ST_READY) return (-EIO);
2668
2669        memset (scmd, 0, MAX_COMMAND_SIZE);
2670        scmd[0] = READ_POSITION;
2671
2672        STp->buffer->b_data = mybuf; STp->buffer->buffer_size = 24;
2673        SRpnt = osst_do_scsi(*aSRpnt, STp, scmd, 20, SCSI_DATA_READ,
2674                                      STp->timeout, MAX_READY_RETRIES, TRUE);
2675        if (!SRpnt) {
2676                STp->buffer->b_data = olddata; STp->buffer->buffer_size = oldsize;
2677                return (-EBUSY);
2678        }
2679        *aSRpnt = SRpnt;
2680
2681        if (STp->buffer->syscall_result)
2682                result = ((SRpnt->sr_sense_buffer[2] & 0x0f) == 3) ? -EIO : -EINVAL;
2683
2684        if (result == -EINVAL)
2685                printk(KERN_ERR "osst%d:E: Can't read tape position.\n", dev);
2686        else {
2687
2688                if (result == -EIO) {   /* re-read position */
2689                        unsigned char mysense[16];
2690                        memcpy (mysense, SRpnt->sr_sense_buffer, 16);
2691                        memset (scmd, 0, MAX_COMMAND_SIZE);
2692                        scmd[0] = READ_POSITION;
2693                        STp->buffer->b_data = mybuf; STp->buffer->buffer_size = 24;
2694                        SRpnt = osst_do_scsi(SRpnt, STp, scmd, 20, SCSI_DATA_READ,
2695                                                    STp->timeout, MAX_READY_RETRIES, TRUE);
2696                        if (!STp->buffer->syscall_result)
2697                                memcpy (SRpnt->sr_sense_buffer, mysense, 16);
2698                }
2699                STp->first_frame_position = ((STp->buffer)->b_data[4] << 24)
2700                                          + ((STp->buffer)->b_data[5] << 16)
2701                                          + ((STp->buffer)->b_data[6] << 8)
2702                                          +  (STp->buffer)->b_data[7];
2703                STp->last_frame_position  = ((STp->buffer)->b_data[ 8] << 24)
2704                                          + ((STp->buffer)->b_data[ 9] << 16)
2705                                          + ((STp->buffer)->b_data[10] <<  8)
2706                                          +  (STp->buffer)->b_data[11];
2707                STp->cur_frames           =  (STp->buffer)->b_data[15];
2708#if DEBUG
2709                if (debugging) {
2710                        printk(OSST_DEB_MSG "osst%d:D: Drive Positions: host %d, tape %d%s, buffer %d\n", dev,
2711                                            STp->first_frame_position, STp->last_frame_position,
2712                                            ((STp->buffer)->b_data[0]&0x80)?" (BOP)":
2713                                            ((STp->buffer)->b_data[0]&0x40)?" (EOP)":"",
2714                                            STp->cur_frames);
2715                }
2716#endif
2717                if (STp->cur_frames == 0 && STp->first_frame_position != STp->last_frame_position) {
2718#if DEBUG
2719                        printk(KERN_WARNING "osst%d:D: Correcting read position %d, %d, %d\n", dev,
2720                                        STp->first_frame_position, STp->last_frame_position, STp->cur_frames);
2721#endif
2722                        STp->first_frame_position = STp->last_frame_position;
2723                }
2724        }
2725        STp->buffer->b_data = olddata; STp->buffer->buffer_size = oldsize;
2726
2727        return (result == 0 ? STp->first_frame_position : result);
2728}
2729
2730
2731/* Set the tape block */
2732static int osst_set_frame_position(OS_Scsi_Tape *STp, Scsi_Request ** aSRpnt, int ppos, int skip)
2733{
2734        unsigned char   scmd[MAX_COMMAND_SIZE];
2735        Scsi_Request  * SRpnt;
2736        ST_partstat   * STps;
2737        int             result = 0;
2738        int             pp  = (ppos == 3000 && !skip)? 0 : ppos;
2739        int             dev = TAPE_NR(STp->devt);
2740
2741        if (STp->ready != ST_READY) return (-EIO);
2742
2743        STps = &(STp->ps[STp->partition]);
2744
2745        if (ppos < 0 || ppos > STp->capacity) {
2746                printk(KERN_WARNING "osst%d:W: Reposition request %d out of range\n", dev, ppos);
2747                pp = ppos = ppos < 0 ? 0 : (STp->capacity - 1);
2748                result = (-EINVAL);
2749        }
2750
2751        do {
2752#if DEBUG
2753                if (debugging)
2754                        printk(OSST_DEB_MSG "osst%d:D: Setting ppos to %d.\n", dev, pp);
2755#endif
2756                memset (scmd, 0, MAX_COMMAND_SIZE);
2757                scmd[0] = SEEK_10;
2758                scmd[1] = 1;
2759                scmd[3] = (pp >> 24);
2760                scmd[4] = (pp >> 16);
2761                scmd[5] = (pp >> 8);
2762                scmd[6] =  pp;
2763                if (skip)
2764                        scmd[9] = 0x80;
2765
2766                SRpnt = osst_do_scsi(*aSRpnt, STp, scmd, 0, SCSI_DATA_NONE, STp->long_timeout,
2767                                                                MAX_READY_RETRIES, TRUE);
2768                if (!SRpnt)
2769                        return (-EBUSY);
2770                *aSRpnt  = SRpnt;
2771
2772                if ((STp->buffer)->syscall_result != 0) {
2773#if DEBUG
2774                        printk(OSST_DEB_MSG "osst%d:D: SEEK command from %d to %d failed.\n",
2775                                        dev, STp->first_frame_position, pp);
2776#endif
2777                        result = (-EIO);
2778                }
2779                if (pp != ppos)
2780                        osst_wait_ready(STp, aSRpnt, 5 * 60);
2781        } while ((pp != ppos) && (pp = ppos));
2782        STp->first_frame_position = STp->last_frame_position = ppos;
2783        STps->eof = ST_NOEOF;
2784        STps->at_sm = 0;
2785        STps->rw = ST_IDLE;
2786        STp->frame_in_buffer = 0;
2787        return result;
2788}
2789
2790
2791
2792/* osst versions of st functions - augmented and stripped to suit OnStream only */
2793
2794/* Flush the write buffer (never need to write if variable blocksize). */
2795static int osst_flush_write_buffer(OS_Scsi_Tape *STp, Scsi_Request ** aSRpnt)
2796{
2797        int offset, transfer, blks = 0;
2798        int result = 0;
2799        unsigned char cmd[MAX_COMMAND_SIZE];
2800        Scsi_Request * SRpnt = *aSRpnt;
2801        ST_partstat * STps;
2802        int dev = TAPE_NR(STp->devt);
2803
2804        if ((STp->buffer)->writing) {
2805                if (SRpnt == (STp->buffer)->last_SRpnt)
2806#if DEBUG
2807                        { printk(OSST_DEB_MSG
2808         "osst%d:D: aSRpnt points to Scsi_Request that write_behind_check will release -- cleared\n", dev);
2809#endif
2810                        *aSRpnt = SRpnt = NULL;
2811#if DEBUG
2812                        } else if (SRpnt)
2813                                printk(OSST_DEB_MSG
2814         "osst%d:D: aSRpnt does not point to Scsi_Request that write_behind_check will release -- strange\n", dev);
2815#endif  
2816                osst_write_behind_check(STp);
2817                if ((STp->buffer)->syscall_result) {
2818#if DEBUG
2819                        if (debugging)
2820                                printk(OSST_DEB_MSG "osst%d:D: Async write error (flush) %x.\n",
2821                                       dev, (STp->buffer)->midlevel_result);
2822#endif
2823                        if ((STp->buffer)->midlevel_result == INT_MAX)
2824                                return (-ENOSPC);
2825                        return (-EIO);
2826                }
2827        }
2828
2829        result = 0;
2830        if (STp->dirty == 1) {
2831
2832                STp->write_count++;
2833                STps     = &(STp->ps[STp->partition]);
2834                STps->rw = ST_WRITING;
2835                offset   = STp->buffer->buffer_bytes;
2836                blks     = (offset + STp->block_size - 1) / STp->block_size;
2837                transfer = OS_FRAME_SIZE;
2838                
2839                if (offset < OS_DATA_SIZE)
2840                        osst_zero_buffer_tail(STp->buffer);
2841
2842                /* TODO: Error handling! */
2843                if (STp->poll)
2844                        result = osst_wait_frame (STp, aSRpnt, STp->first_frame_position, -50, 120);
2845
2846                memset(cmd, 0, MAX_COMMAND_SIZE);
2847                cmd[0] = WRITE_6;
2848                cmd[1] = 1;
2849                cmd[4] = 1;
2850
2851                switch  (STp->write_type) {
2852                   case OS_WRITE_DATA:
2853#if DEBUG
2854                        if (debugging)
2855                                printk(OSST_DEB_MSG "osst%d:D: Writing %d blocks to frame %d, lblks %d-%d\n",
2856                                        dev, blks, STp->frame_seq_number, 
2857                                        STp->logical_blk_num - blks, STp->logical_blk_num - 1);
2858#endif
2859                        osst_init_aux(STp, OS_FRAME_TYPE_DATA, STp->frame_seq_number++,
2860                                      STp->logical_blk_num - blks, STp->block_size, blks);
2861                        break;
2862                   case OS_WRITE_EOD:
2863                        osst_init_aux(STp, OS_FRAME_TYPE_EOD, STp->frame_seq_number++,
2864                                      STp->logical_blk_num, 0, 0);
2865                        break;
2866                   case OS_WRITE_NEW_MARK:
2867                        osst_init_aux(STp, OS_FRAME_TYPE_MARKER, STp->frame_seq_number++,
2868                                      STp->logical_blk_num++, 0, blks=1);
2869                        break;
2870                   case OS_WRITE_HEADER:
2871                        osst_init_aux(STp, OS_FRAME_TYPE_HEADER, 0, 0, 0, blks=0);
2872                        break;
2873                default: /* probably FILLER */
2874                        osst_init_aux(STp, OS_FRAME_TYPE_FILL, 0, 0, 0, 0);
2875                }
2876#if DEBUG
2877                if (debugging)
2878                        printk(OSST_DEB_MSG "osst%d:D: Flushing %d bytes, Transfering %d bytes in %d lblocks.\n",
2879                                                 dev, offset, transfer, blks);
2880#endif
2881
2882                SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, transfer, SCSI_DATA_WRITE,
2883                                          STp->timeout, MAX_WRITE_RETRIES, TRUE);
2884                *aSRpnt = SRpnt;
2885                if (!SRpnt)
2886                        return (-EBUSY);
2887
2888                if ((STp->buffer)->syscall_result != 0) {
2889#if DEBUG
2890                        printk(OSST_DEB_MSG
2891                                "osst%d:D: write sense [0]=0x%02x [2]=%02x [12]=%02x [13]=%02x\n",
2892                                dev, SRpnt->sr_sense_buffer[0], SRpnt->sr_sense_buffer[2],
2893                                SRpnt->sr_sense_buffer[12], SRpnt->sr_sense_buffer[13]);
2894#endif
2895                        if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 &&
2896                            (SRpnt->sr_sense_buffer[2] & 0x40) && /* FIXME - SC-30 drive doesn't assert EOM bit */
2897                            (SRpnt->sr_sense_buffer[2] & 0x0f) == NO_SENSE) {
2898                                STp->dirty = 0;
2899                                (STp->buffer)->buffer_bytes = 0;
2900                                result = (-ENOSPC);
2901                        }
2902                        else {
2903                                if (osst_write_error_recovery(STp, aSRpnt, 1)) {
2904                                        printk(KERN_ERR "osst%d:E: Error on flush write.\n", dev);
2905                                        result = (-EIO);
2906                                }
2907                        }
2908                        STps->drv_block = (-1);
2909                }
2910                else {
2911                        STp->first_frame_position++;
2912                        STp->dirty = 0;
2913                        (STp->buffer)->buffer_bytes = 0;
2914                }
2915        }
2916#if DEBUG
2917        printk(OSST_DEB_MSG "osst%d:D: Exit flush write buffer with code %d\n", dev, result);
2918#endif
2919        return result;
2920}
2921
2922
2923/* Flush the tape buffer. The tape will be positioned correctly unless
2924   seek_next is true. */
2925static int osst_flush_buffer(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int seek_next)
2926{
2927        ST_partstat   * STps;
2928        int backspace = 0, result = 0;
2929#if DEBUG
2930        int dev = TAPE_NR(STp->devt);
2931#endif
2932
2933        /*
2934         * If there was a bus reset, block further access
2935         * to this device.
2936         */
2937        if( STp->device->was_reset )
2938                return (-EIO);
2939
2940        if (STp->ready != ST_READY)
2941                return 0;
2942
2943        STps = &(STp->ps[STp->partition]);
2944        if (STps->rw == ST_WRITING)  /* Writing */
2945                return osst_flush_write_buffer(STp, aSRpnt);
2946
2947        if (STp->block_size == 0)
2948                return 0;
2949
2950#if DEBUG
2951        printk(OSST_DEB_MSG "osst%d:D: Reached flush (read) buffer\n", dev);
2952#endif
2953
2954        if (!STp->can_bsr) {
2955                backspace = ((STp->buffer)->buffer_bytes + (STp->buffer)->read_pointer) / STp->block_size -
2956                            ((STp->buffer)->read_pointer + STp->block_size - 1        ) / STp->block_size ;
2957                (STp->buffer)->buffer_bytes = 0;
2958                (STp->buffer)->read_pointer = 0;
2959                STp->frame_in_buffer = 0;               /* FIXME is this relevant w. OSST? */
2960        }
2961
2962        if (!seek_next) {
2963                if (STps->eof == ST_FM_HIT) {
2964                        result = cross_eof(STp, aSRpnt, FALSE); /* Back over the EOF hit */
2965                        if (!result)
2966                                STps->eof = ST_NOEOF;
2967                        else {
2968                                if (STps->drv_file >= 0)
2969                                        STps->drv_file++;
2970                                STps->drv_block = 0;
2971                        }
2972                }
2973                if (!result && backspace > 0)   /* TODO -- design and run a test case for this */
2974                        result = osst_seek_logical_blk(STp, aSRpnt, STp->logical_blk_num - backspace);
2975        }
2976        else if (STps->eof == ST_FM_HIT) {
2977                if (STps->drv_file >= 0)
2978                        STps->drv_file++;
2979                STps->drv_block = 0;
2980                STps->eof = ST_NOEOF;
2981        }
2982
2983        return result;
2984}
2985
2986static int osst_write_frame(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int synchronous)
2987{
2988        unsigned char   cmd[MAX_COMMAND_SIZE];
2989        Scsi_Request     * SRpnt;
2990        int             blks;
2991#if DEBUG
2992        int             dev = TAPE_NR(STp->devt);
2993#endif
2994
2995        if ((!STp-> raw) && (STp->first_frame_position == 0xbae)) { /* _must_ preserve buffer! */
2996#if DEBUG
2997                printk(OSST_DEB_MSG "osst%d:D: Reaching config partition.\n", dev);
2998#endif
2999                if (osst_flush_drive_buffer(STp, aSRpnt) < 0) {
3000                        return (-EIO);
3001                }
3002                /* error recovery may have bumped us past the header partition */
3003                if (osst_get_frame_position(STp, aSRpnt) < 0xbb8) {
3004#if DEBUG
3005                        printk(OSST_DEB_MSG "osst%d:D: Skipping over config partition.\n", dev);
3006#endif
3007                osst_position_tape_and_confirm(STp, aSRpnt, 0xbb8);
3008                }
3009        }
3010
3011        if (STp->poll)
3012                osst_wait_frame (STp, aSRpnt, STp->first_frame_position, -50, 60);
3013        /* TODO: Check for an error ! */
3014
3015//      osst_build_stats(STp, &SRpnt);
3016
3017        STp->ps[STp->partition].rw = ST_WRITING;
3018        STp->write_type            = OS_WRITE_DATA;
3019                        
3020        memset(cmd, 0, MAX_COMMAND_SIZE);
3021        cmd[0]   = WRITE_6;
3022        cmd[1]   = 1;
3023        cmd[4]   = 1;                                           /* one frame at a time... */
3024        blks     = STp->buffer->buffer_bytes / STp->block_size;
3025#if DEBUG
3026        if (debugging)
3027                printk(OSST_DEB_MSG "osst%d:D: Writing %d blocks to frame %d, lblks %d-%d\n", dev, blks, 
3028                        STp->frame_seq_number, STp->logical_blk_num - blks, STp->logical_blk_num - 1);
3029#endif
3030        osst_init_aux(STp, OS_FRAME_TYPE_DATA, STp->frame_seq_number++,
3031                      STp->logical_blk_num - blks, STp->block_size, blks);
3032
3033#if DEBUG
3034        if (!synchronous)
3035                STp->write_pending = 1;
3036#endif
3037        SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, OS_FRAME_SIZE, SCSI_DATA_WRITE, STp->timeout,
3038                                                        MAX_WRITE_RETRIES, synchronous);
3039        if (!SRpnt)
3040                return (-EBUSY);
3041        *aSRpnt = SRpnt;
3042
3043        if (synchronous) {
3044                if (STp->buffer->syscall_result != 0) {
3045#if DEBUG
3046                        if (debugging)
3047                                printk(OSST_DEB_MSG "osst%d:D: Error on write:\n", dev);
3048#endif
3049                        if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 &&
3050                            (SRpnt->sr_sense_buffer[2] & 0x40)) {
3051                                if ((SRpnt->sr_sense_buffer[2] & 0x0f) == VOLUME_OVERFLOW)
3052                                        return (-ENOSPC);
3053                        }
3054                        else {
3055                                if (osst_write_error_recovery(STp, aSRpnt, 1))
3056                                        return (-EIO);
3057                        }
3058                }
3059                else
3060                        STp->first_frame_position++;
3061        }
3062
3063        STp->write_count++;
3064
3065        return 0;
3066}
3067
3068
3069/* Entry points to osst */
3070
3071/* Write command */
3072static ssize_t osst_write(struct file * filp, const char * buf, size_t count, loff_t *ppos)
3073{
3074        struct inode *inode = filp->f_dentry->d_inode;
3075        ssize_t total, retval = 0;
3076        ssize_t i, do_count, blks, transfer;
3077        int write_threshold;
3078        int doing_write = 0;
3079        const char *b_point;
3080        Scsi_Request * SRpnt = NULL;
3081        OS_Scsi_Tape * STp;
3082        ST_mode * STm;
3083        ST_partstat * STps;
3084        int dev = TAPE_NR(inode->i_rdev);
3085
3086        STp = os_scsi_tapes[dev];
3087
3088        if (down_interruptible(&STp->lock))
3089                return (-ERESTARTSYS);
3090
3091        /*
3092         * If we are in the middle of error recovery, don't let anyone
3093         * else try and use this device.  Also, if error recovery fails, it
3094         * may try and take the device offline, in which case all further
3095         * access to the device is prohibited.
3096         */
3097        if( !scsi_block_when_processing_errors(STp->device) ) {
3098                retval = (-ENXIO);
3099                goto out;
3100        }
3101        
3102        if (ppos != &filp->f_pos) {
3103                /* "A request was outside the capabilities of the device." */
3104                retval = (-ENXIO);
3105                goto out;
3106        }
3107
3108        if (STp->ready != ST_READY) {
3109                if (STp->ready == ST_NO_TAPE)
3110                        retval = (-ENOMEDIUM);
3111                else
3112                        retval = (-EIO);
3113                goto out;
3114        }
3115        STm = &(STp->modes[STp->current_mode]);
3116        if (!STm->defined) {
3117                retval = (-ENXIO);
3118                goto out;
3119        }
3120        if (count == 0)
3121                goto out;
3122
3123        /*
3124         * If there was a bus reset, block further access
3125         * to this device.
3126         */
3127        if (STp->device->was_reset) {
3128                retval = (-EIO);
3129                goto out;
3130        }
3131
3132#if DEBUG
3133        if (!STp->in_use) {
3134                printk(OSST_DEB_MSG "osst%d:D: Incorrect device.\n", dev);
3135                retval = (-EIO);
3136                goto out;
3137        }
3138#endif
3139
3140        if (STp->write_prot) {
3141                retval = (-EACCES);
3142                goto out;
3143        }
3144
3145        /* Write must be integral number of blocks */
3146        if (STp->block_size != 0 && (count % STp->block_size) != 0) {
3147                printk(KERN_ERR "osst%d:E: Write (%ld bytes) not multiple of tape block size (%d%c).\n",
3148                                       dev, (unsigned long)count, STp->block_size<1024?
3149                                       STp->block_size:STp->block_size/1024, STp->block_size<1024?'b':'k');
3150                retval = (-EINVAL);
3151                goto out;
3152        }
3153
3154        if (STp->first_frame_position >= STp->capacity - OSST_EOM_RESERVE) {
3155                printk(KERN_ERR "osst%d:E: Write truncated at EOM early warning (frame %d).\n",
3156                                       dev, STp->first_frame_position);
3157                retval = (-ENOSPC);
3158                goto out;
3159        }
3160
3161        STps = &(STp->ps[STp->partition]);
3162
3163        if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED &&
3164            !osst_int_ioctl(STp, &SRpnt, MTLOCK, 0))
3165                STp->door_locked = ST_LOCKED_AUTO;
3166
3167
3168        if (STps->rw == ST_READING) {
3169                retval = osst_flush_buffer(STp, &SRpnt, 0);
3170                if (retval)
3171                        goto out;
3172                STps->rw = ST_IDLE;
3173        }
3174        else if (STps->rw != ST_WRITING) {
3175                /* Are we totally rewriting this tape? */
3176                if (!STp->header_ok ||
3177                    (STp->first_frame_position == STp->first_data_ppos && STps->drv_block < 0) ||
3178                    (STps->drv_file == 0 && STps->drv_block == 0)) {
3179                        STp->wrt_pass_cntr++;
3180#if DEBUG
3181                        printk(OSST_DEB_MSG "osst%d:D: Allocating next write pass counter: %d\n",
3182                                                  dev, STp->wrt_pass_cntr);
3183#endif
3184                        osst_reset_header(STp, &SRpnt);
3185                        STps->drv_file = STps->drv_block = 0;
3186                }
3187                /* Do we know where we'll be writing on the tape? */
3188                else {
3189                        if ((STp->fast_open && osst_verify_position(STp, &SRpnt)) ||
3190                                        STps->drv_file < 0 || STps->drv_block < 0) {
3191                                if (STp->first_frame_position == STp->eod_frame_ppos) { /* at EOD */
3192                                        STps->drv_file = STp->filemark_cnt;
3193                                        STps->drv_block = 0;
3194                                }
3195                                else {
3196                                        /* We have no idea where the tape is positioned - give up */
3197#if DEBUG
3198                                        printk(OSST_DEB_MSG
3199                                                "osst%d:D: Cannot write at indeterminate position.\n", dev);
3200#endif
3201                                        retval = (-EIO);
3202                                        goto out;
3203                                }
3204                        }         
3205                        if ((STps->drv_file + STps->drv_block) > 0 && STps->drv_file < STp->filemark_cnt) {
3206                                STp->filemark_cnt = STps->drv_file;
3207                                STp->last_mark_ppos =
3208                                        ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[STp->filemark_cnt-1]);
3209                                printk(KERN_WARNING
3210                                        "osst%d:W: Overwriting file %d with old write pass counter %d\n",
3211                                                dev, STps->drv_file, STp->wrt_pass_cntr);
3212                                printk(KERN_WARNING
3213                                        "osst%d:W: may lead to stale data being accepted on reading back!\n",
3214                                                dev);
3215#if DEBUG
3216                                printk(OSST_DEB_MSG
3217                                  "osst%d:D: resetting filemark count to %d and last mark ppos,lbn to %d,%d\n",
3218                                        dev, STp->filemark_cnt, STp->last_mark_ppos, STp->last_mark_lbn);
3219#endif
3220                        }
3221                }
3222                STp->fast_open = FALSE;
3223        }
3224        if (!STp->header_ok) {
3225#if DEBUG
3226                printk(OSST_DEB_MSG "osst%d:D: Write cannot proceed without valid headers\n", dev);
3227#endif
3228                retval = (-EIO);
3229                goto out;
3230        }
3231
3232        if ((STp->buffer)->writing) {
3233if (SRpnt) printk(KERN_ERR "osst%d:A: Not supposed to have SRpnt at line %d\n", dev, __LINE__);
3234                osst_write_behind_check(STp);
3235                if ((STp->buffer)->syscall_result) {
3236#if DEBUG
3237                if (debugging)
3238                        printk(OSST_DEB_MSG "osst%d:D: Async write error (write) %x.\n", dev,
3239                                                 (STp->buffer)->midlevel_result);
3240#endif
3241                if ((STp->buffer)->midlevel_result == INT_MAX)
3242                        STps->eof = ST_EOM_OK;
3243                else
3244                        STps->eof = ST_EOM_ERROR;
3245                }
3246        }
3247        if (STps->eof == ST_EOM_OK) {
3248                retval = (-ENOSPC);
3249                goto out;
3250        }
3251        else if (STps->eof == ST_EOM_ERROR) {
3252                retval = (-EIO);
3253                goto out;
3254        }
3255
3256        /* Check the buffer readability in cases where copy_user might catch
3257                 the problems after some tape movement. */
3258        if ((copy_from_user(&i, buf, 1) != 0 ||
3259             copy_from_user(&i, buf + count - 1, 1) != 0)) {
3260                retval = (-EFAULT);
3261                goto out;
3262        }
3263
3264        if (!STm->do_buffer_writes) {
3265                write_threshold = 1;
3266        }
3267        else
3268                write_threshold = (STp->buffer)->buffer_blocks * STp->block_size;
3269        if (!STm->do_async_writes)
3270                write_threshold--;
3271
3272        total = count;
3273#if DEBUG
3274        if (debugging)
3275                printk(OSST_DEB_MSG "osst%d:D: Writing %d bytes to file %d block %d lblk %d fseq %d fppos %d\n",
3276                                dev, count, STps->drv_file, STps->drv_block,
3277                                STp->logical_blk_num, STp->frame_seq_number, STp->first_frame_position);
3278#endif
3279        b_point = buf;
3280        while ((STp->buffer)->buffer_bytes + count > write_threshold)
3281        {
3282                doing_write = 1;
3283                do_count = (STp->buffer)->buffer_blocks * STp->block_size -
3284                           (STp->buffer)->buffer_bytes;
3285                if (do_count > count)
3286                        do_count = count;
3287
3288                i = append_to_buffer(b_point, STp->buffer, do_count);
3289                if (i) {
3290                        retval = i;
3291                        goto out;
3292                }
3293
3294                blks = do_count / STp->block_size;
3295                STp->logical_blk_num += blks;  /* logical_blk_num is incremented as data is moved from user */
3296  
3297                i = osst_write_frame(STp, &SRpnt, TRUE);
3298
3299                if (i == (-ENOSPC)) {
3300                        transfer = STp->buffer->writing;        /* FIXME -- check this logic */
3301                        if (transfer <= do_count) {
3302                                filp->f_pos += do_count - transfer;
3303                                count -= do_count - transfer;
3304                                if (STps->drv_block >= 0) {
3305                                        STps->drv_block += (do_count - transfer) / STp->block_size;
3306                                }
3307                                STps->eof = ST_EOM_OK;
3308                                retval = (-ENOSPC);             /* EOM within current request */
3309#if DEBUG
3310                                if (debugging)
3311                                      printk(OSST_DEB_MSG "osst%d:D: EOM with %d bytes unwritten.\n",
3312                                                             dev, transfer);
3313#endif
3314                        }
3315                        else {
3316                                STps->eof = ST_EOM_ERROR;
3317                                STps->drv_block = (-1);         /* Too cautious? */
3318                                retval = (-EIO);                /* EOM for old data */
3319#if DEBUG
3320                                if (debugging)
3321                                      printk(OSST_DEB_MSG "osst%d:D: EOM with lost data.\n", dev);
3322#endif
3323                        }
3324                }
3325                else
3326                        retval = i;
3327                        
3328                if (retval < 0) {
3329                        if (SRpnt != NULL) {
3330                                scsi_release_request(SRpnt);
3331                                SRpnt = NULL;
3332                        }
3333                        STp->buffer->buffer_bytes = 0;
3334                        STp->dirty = 0;
3335                        if (count < total)
3336                                retval = total - count;
3337                        goto out;
3338                }
3339
3340                filp->f_pos += do_count;
3341                b_point += do_count;
3342                count -= do_count;
3343                if (STps->drv_block >= 0) {
3344                        STps->drv_block += blks;
3345                }
3346                STp->buffer->buffer_bytes = 0;
3347                STp->dirty = 0;
3348        }  /* end while write threshold exceeded */
3349
3350        if (count != 0) {
3351                STp->dirty = 1;
3352                i = append_to_buffer(b_point, STp->buffer, count);
3353                if (i) {
3354                        retval = i;
3355                        goto out;
3356                }
3357                blks = count / STp->block_size;
3358                STp->logical_blk_num += blks;
3359                if (STps->drv_block >= 0) {
3360                        STps->drv_block += blks;
3361                }
3362                filp->f_pos += count;
3363                count = 0;
3364        }
3365
3366        if (doing_write && (STp->buffer)->syscall_result != 0) {
3367                retval = (STp->buffer)->syscall_result;
3368                goto out;
3369        }
3370
3371        if (STm->do_async_writes && ((STp->buffer)->buffer_bytes >= STp->write_threshold)) { 
3372                /* Schedule an asynchronous write */
3373                (STp->buffer)->writing = ((STp->buffer)->buffer_bytes /
3374                                           STp->block_size) * STp->block_size;
3375                STp->dirty = !((STp->buffer)->writing ==
3376                                          (STp->buffer)->buffer_bytes);
3377
3378                i = osst_write_frame(STp, &SRpnt, FALSE);
3379                if (i < 0) {
3380                        retval = (-EIO);
3381                        goto out;
3382                }
3383                SRpnt = NULL;                   /* Prevent releasing this request! */
3384        }
3385        STps->at_sm &= (total == 0);
3386        if (total > 0)
3387                STps->eof = ST_NOEOF;
3388
3389        retval = total;
3390
3391out:
3392        if (SRpnt != NULL) scsi_release_request(SRpnt);
3393
3394        up(&STp->lock);
3395
3396        return retval;
3397}
3398
3399
3400/* Read command */
3401static ssize_t osst_read(struct file * filp, char * buf, size_t count, loff_t *ppos)
3402{
3403        struct inode * inode = filp->f_dentry->d_inode;
3404        ssize_t total, retval = 0;
3405        ssize_t i, transfer;
3406        int special;
3407        OS_Scsi_Tape * STp;
3408        ST_mode * STm;
3409        ST_partstat * STps;
3410        Scsi_Request *SRpnt = NULL;
3411        int dev = TAPE_NR(inode->i_rdev);
3412
3413        STp = os_scsi_tapes[dev];
3414
3415        if (down_interruptible(&STp->lock))
3416                return (-ERESTARTSYS);
3417
3418        /*
3419         * If we are in the middle of error recovery, don't let anyone
3420         * else try and use this device.  Also, if error recovery fails, it
3421         * may try and take the device offline, in which case all further
3422         * access to the device is prohibited.
3423         */
3424        if( !scsi_block_when_processing_errors(STp->device) ) {
3425                retval = (-ENXIO);
3426                goto out;
3427        }
3428        
3429        if (ppos != &filp->f_pos) {
3430                /* "A request was outside the capabilities of the device." */
3431                retval = (-ENXIO);
3432                goto out;
3433        }
3434
3435        if (STp->ready != ST_READY) {
3436                if (STp->ready == ST_NO_TAPE)
3437                        retval = (-ENOMEDIUM);
3438                else
3439                        retval = (-EIO);
3440                goto out;
3441        }
3442        STm = &(STp->modes[STp->current_mode]);
3443        if (!STm->defined) {
3444                retval = (-ENXIO);
3445                goto out;
3446        }
3447#if DEBUG
3448        if (!STp->in_use) {
3449                printk(OSST_DEB_MSG "osst%d:D: Incorrect device.\n", dev);
3450                retval = (-EIO);
3451                goto out;
3452        }
3453#endif
3454        /* Must have initialized medium */
3455        if (!STp->header_ok) {
3456                retval = (-EIO);
3457                goto out;
3458        }
3459
3460        if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED &&
3461        !osst_int_ioctl(STp, &SRpnt, MTLOCK, 0))
3462                STp->door_locked = ST_LOCKED_AUTO;
3463
3464        STps = &(STp->ps[STp->partition]);
3465        if (STps->rw == ST_WRITING) {
3466                retval = osst_flush_buffer(STp, &SRpnt, 0);
3467                if (retval)
3468                        goto out;
3469                STps->rw = ST_IDLE;
3470                /* FIXME -- this may leave the tape without EOD and up2date headers */
3471        }
3472
3473        if ((count % STp->block_size) != 0) {
3474                printk(KERN_WARNING
3475                    "osst%d:W: Read (%Zd bytes) not multiple of tape block size (%d%c).\n", dev, count,
3476                    STp->block_size<1024?STp->block_size:STp->block_size/1024, STp->block_size<1024?'b':'k');
3477        }
3478
3479#if DEBUG
3480        if (debugging && STps->eof != ST_NOEOF)
3481                printk(OSST_DEB_MSG "osst%d:D: EOF/EOM flag up (%d). Bytes %d\n", dev,
3482                                     STps->eof, (STp->buffer)->buffer_bytes);
3483#endif
3484        if ((STp->buffer)->buffer_bytes == 0 &&
3485             STps->eof >= ST_EOD_1) {
3486                if (STps->eof < ST_EOD) {
3487                        STps->eof += 1;
3488                        retval = 0;
3489                        goto out;
3490                }
3491                retval = (-EIO);  /* EOM or Blank Check */
3492                goto out;
3493        }
3494
3495        /* Check the buffer writability before any tape movement. Don't alter
3496                 buffer data. */
3497        if (copy_from_user(&i, buf, 1)             != 0 ||
3498            copy_to_user  (buf, &i, 1)             != 0 ||
3499            copy_from_user(&i, buf + count - 1, 1) != 0 ||
3500            copy_to_user  (buf + count - 1, &i, 1) != 0) {
3501                retval = (-EFAULT);
3502                goto out;
3503        }
3504
3505        /* Loop until enough data in buffer or a special condition found */
3506        for (total = 0, special = 0; total < count - STp->block_size + 1 && !special; ) {
3507
3508                /* Get new data if the buffer is empty */
3509                if ((STp->buffer)->buffer_bytes == 0) {
3510                        if (STps->eof == ST_FM_HIT)
3511                                break;
3512                        special = osst_get_logical_frame(STp, &SRpnt, STp->frame_seq_number, 0);
3513                        if (special < 0) {                      /* No need to continue read */
3514                                STp->frame_in_buffer = 0;
3515                                retval = special;
3516                                goto out;
3517                        }
3518                }
3519
3520                /* Move the data from driver buffer to user buffer */
3521                if ((STp->buffer)->buffer_bytes > 0) {
3522#if DEBUG
3523                        if (debugging && STps->eof != ST_NOEOF)
3524                            printk(OSST_DEB_MSG "osst%d:D: EOF up (%d). Left %d, needed %d.\n", dev,
3525                                                 STps->eof, (STp->buffer)->buffer_bytes, count - total);
3526#endif
3527                        transfer = (((STp->buffer)->buffer_bytes < count - total ?
3528                                     (STp->buffer)->buffer_bytes : count - total)/
3529                                        STp->block_size) * STp->block_size; /* force multiple of block size */
3530                        i = from_buffer(STp->buffer, buf, transfer);
3531                        if (i)  {
3532                                retval = i;
3533                                goto out;
3534                        }
3535                        STp->logical_blk_num += transfer / STp->block_size;
3536                        STps->drv_block      += transfer / STp->block_size;
3537                        filp->f_pos          += transfer;
3538                        buf                  += transfer;
3539                        total                += transfer;
3540                }
3541 
3542                if ((STp->buffer)->buffer_bytes == 0) {
3543#if DEBUG
3544                        if (debugging)
3545                                printk(OSST_DEB_MSG "osst%d:D: Finished with frame %d\n",
3546                                                dev, STp->frame_seq_number);
3547#endif
3548                        STp->frame_in_buffer = 0;
3549                        STp->frame_seq_number++;              /* frame to look for next time */
3550                }
3551        } /* for (total = 0, special = 0; total < count && !special; ) */
3552
3553        /* Change the eof state if no data from tape or buffer */
3554        if (total == 0) {
3555                if (STps->eof == ST_FM_HIT) {
3556                        STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD:ST_FM;
3557                        STps->drv_block = 0;
3558                        if (STps->drv_file >= 0)
3559                                STps->drv_file++;
3560                }
3561                else if (STps->eof == ST_EOD_1) {
3562                        STps->eof = ST_EOD_2;
3563                        if (STps->drv_block > 0 && STps->drv_file >= 0)
3564                                STps->drv_file++;
3565                        STps->drv_block = 0;
3566                }
3567                else if (STps->eof == ST_EOD_2)
3568                        STps->eof = ST_EOD;
3569        }
3570        else if (STps->eof == ST_FM)
3571                STps->eof = ST_NOEOF;
3572
3573        retval = total;
3574
3575out:
3576        if (SRpnt != NULL) scsi_release_request(SRpnt);
3577
3578        up(&STp->lock);
3579
3580        return retval;
3581}
3582
3583
3584/* Set the driver options */
3585static void osst_log_options(OS_Scsi_Tape *STp, ST_mode *STm, int dev)
3586{
3587  printk(KERN_INFO
3588"osst%d:I: Mode %d options: buffer writes: %d, async writes: %d, read ahead: %d\n",
3589         dev, STp->current_mode, STm->do_buffer_writes, STm->do_async_writes,
3590         STm->do_read_ahead);
3591  printk(KERN_INFO
3592"osst%d:I:    can bsr: %d, two FMs: %d, fast mteom: %d, auto lock: %d,\n",
3593         dev, STp->can_bsr, STp->two_fm, STp->fast_mteom, STp->do_auto_lock);
3594  printk(KERN_INFO
3595"osst%d:I:    defs for wr: %d, no block limits: %d, partitions: %d, s2 log: %d\n",
3596         dev, STm->defaults_for_writes, STp->omit_blklims, STp->can_partitions,
3597         STp->scsi2_logical);
3598  printk(KERN_INFO
3599"osst%d:I:    sysv: %d\n", dev, STm->sysv);
3600#if DEBUG
3601  printk(KERN_INFO
3602         "osst%d:D:    debugging: %d\n",
3603         dev, debugging);
3604#endif
3605}
3606
3607
3608static int osst_set_options(OS_Scsi_Tape *STp, long options)
3609{
3610        int value;
3611        long code;
3612        ST_mode *STm;
3613        int dev = TAPE_NR(STp->devt);
3614
3615        STm = &(STp->modes[STp->current_mode]);
3616        if (!STm->defined) {
3617                memcpy(STm, &(STp->modes[0]), sizeof(ST_mode));
3618                modes_defined = TRUE;
3619#if DEBUG
3620                if (debugging)
3621                        printk(OSST_DEB_MSG "osst%d:D: Initialized mode %d definition from mode 0\n",
3622                                             dev, STp->current_mode);
3623#endif
3624        }
3625
3626        code = options & MT_ST_OPTIONS;
3627        if (code == MT_ST_BOOLEANS) {
3628                STm->do_buffer_writes = (options & MT_ST_BUFFER_WRITES) != 0;
3629                STm->do_async_writes  = (options & MT_ST_ASYNC_WRITES) != 0;
3630                STm->defaults_for_writes = (options & MT_ST_DEF_WRITES) != 0;
3631                STm->do_read_ahead    = (options & MT_ST_READ_AHEAD) != 0;
3632                STp->two_fm           = (options & MT_ST_TWO_FM) != 0;
3633                STp->fast_mteom       = (options & MT_ST_FAST_MTEOM) != 0;
3634                STp->do_auto_lock     = (options & MT_ST_AUTO_LOCK) != 0;
3635                STp->can_bsr          = (options & MT_ST_CAN_BSR) != 0;
3636                STp->omit_blklims     = (options & MT_ST_NO_BLKLIMS) != 0;
3637                if ((STp->device)->scsi_level >= SCSI_2)
3638                        STp->can_partitions = (options & MT_ST_CAN_PARTITIONS) != 0;
3639                STp->scsi2_logical    = (options & MT_ST_SCSI2LOGICAL) != 0;
3640                STm->sysv             = (options & MT_ST_SYSV) != 0;
3641#if DEBUG
3642                debugging = (options & MT_ST_DEBUGGING) != 0;
3643#endif
3644                osst_log_options(STp, STm, dev);
3645        }
3646        else if (code == MT_ST_SETBOOLEANS || code == MT_ST_CLEARBOOLEANS) {
3647                value = (code == MT_ST_SETBOOLEANS);
3648                if ((options & MT_ST_BUFFER_WRITES) != 0)
3649                        STm->do_buffer_writes = value;
3650                if ((options & MT_ST_ASYNC_WRITES) != 0)
3651                        STm->do_async_writes = value;
3652                if ((options & MT_ST_DEF_WRITES) != 0)
3653                        STm->defaults_for_writes = value;
3654                if ((options & MT_ST_READ_AHEAD) != 0)
3655                        STm->do_read_ahead = value;
3656                if ((options & MT_ST_TWO_FM) != 0)
3657                        STp->two_fm = value;
3658                if ((options & MT_ST_FAST_MTEOM) != 0)
3659                        STp->fast_mteom = value;
3660                if ((options & MT_ST_AUTO_LOCK) != 0)
3661                        STp->do_auto_lock = value;
3662                if ((options & MT_ST_CAN_BSR) != 0)
3663                        STp->can_bsr = value;
3664                if ((options & MT_ST_NO_BLKLIMS) != 0)
3665                        STp->omit_blklims = value;
3666                if ((STp->device)->scsi_level >= SCSI_2 &&
3667                    (options & MT_ST_CAN_PARTITIONS) != 0)
3668                        STp->can_partitions = value;
3669                if ((options & MT_ST_SCSI2LOGICAL) != 0)
3670                        STp->scsi2_logical = value;
3671                if ((options & MT_ST_SYSV) != 0)
3672                        STm->sysv = value;
3673#if DEBUG
3674                if ((options & MT_ST_DEBUGGING) != 0)
3675                        debugging = value;
3676#endif
3677                osst_log_options(STp, STm, dev);
3678        }
3679        else if (code == MT_ST_WRITE_THRESHOLD) {
3680                value = (options & ~MT_ST_OPTIONS) * ST_KILOBYTE;
3681                if (value < 1 || value > osst_buffer_size) {
3682                        printk(KERN_WARNING "osst%d:W: Write threshold %d too small or too large.\n",
3683                                             dev, value);
3684                        return (-EIO);
3685                }
3686                STp->write_threshold = value;
3687                printk(KERN_INFO "osst%d:I: Write threshold set to %d bytes.\n",
3688                                  dev, value);
3689        }
3690        else if (code == MT_ST_DEF_BLKSIZE) {
3691                value = (options & ~MT_ST_OPTIONS);
3692                if (value == ~MT_ST_OPTIONS) {
3693                        STm->default_blksize = (-1);
3694                        printk(KERN_INFO "osst%d:I: Default block size disabled.\n", dev);
3695                }
3696                else {
3697                        if (value < 512 || value > OS_DATA_SIZE || OS_DATA_SIZE % value) {
3698                                printk(KERN_WARNING "osst%d:W: Default block size cannot be set to %d.\n",
3699                                                         dev, value);
3700                                return (-EINVAL);
3701                        }
3702                        STm->default_blksize = value;
3703                        printk(KERN_INFO "osst%d:I: Default block size set to %d bytes.\n",
3704                                          dev, STm->default_blksize);
3705                }
3706        }
3707        else if (code == MT_ST_TIMEOUTS) {
3708                value = (options & ~MT_ST_OPTIONS);
3709                if ((value & MT_ST_SET_LONG_TIMEOUT) != 0) {
3710                        STp->long_timeout = (value & ~MT_ST_SET_LONG_TIMEOUT) * HZ;
3711                        printk(KERN_INFO "osst%d:I: Long timeout set to %d seconds.\n", dev,
3712                                             (value & ~MT_ST_SET_LONG_TIMEOUT));
3713                }
3714                else {
3715                        STp->timeout = value * HZ;
3716                        printk(KERN_INFO "osst%d:I: Normal timeout set to %d seconds.\n", dev, value);
3717                }
3718        }
3719        else if (code == MT_ST_DEF_OPTIONS) {
3720                code = (options & ~MT_ST_CLEAR_DEFAULT);
3721                value = (options & MT_ST_CLEAR_DEFAULT);
3722                if (code == MT_ST_DEF_DENSITY) {
3723                        if (value == MT_ST_CLEAR_DEFAULT) {
3724                                STm->default_density = (-1);
3725                                printk(KERN_INFO "osst%d:I: Density default disabled.\n", dev);
3726                        }
3727                        else {
3728                                STm->default_density = value & 0xff;
3729                                printk(KERN_INFO "osst%d:I: Density default set to %x\n",
3730                                                  dev, STm->default_density);
3731                        }
3732                }
3733                else if (code == MT_ST_DEF_DRVBUFFER) {
3734                        if (value == MT_ST_CLEAR_DEFAULT) {
3735                                STp->default_drvbuffer = 0xff;
3736                                printk(KERN_INFO "osst%d:I: Drive buffer default disabled.\n", dev);
3737                        }
3738                        else {
3739                                STp->default_drvbuffer = value & 7;
3740                                printk(KERN_INFO "osst%d:I: Drive buffer default set to %x\n",
3741                                                  dev, STp->default_drvbuffer);
3742                        }
3743                }
3744                else if (code == MT_ST_DEF_COMPRESSION) {
3745                        if (value == MT_ST_CLEAR_DEFAULT) {
3746                                STm->default_compression = ST_DONT_TOUCH;
3747                                printk(KERN_INFO "osst%d:I: Compression default disabled.\n", dev);
3748                        }
3749                        else {
3750                                STm->default_compression = (value & 1 ? ST_YES : ST_NO);
3751                                printk(KERN_INFO "osst%d:I: Compression default set to %x\n",
3752                                                  dev, (value & 1));
3753                        }
3754                }
3755        }
3756        else
3757                return (-EIO);
3758
3759        return 0;
3760}
3761
3762
3763/* Internal ioctl function */
3764static int osst_int_ioctl(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, unsigned int cmd_in, unsigned long arg)
3765{
3766        int timeout;
3767        long ltmp;
3768        int i, ioctl_result;
3769        int chg_eof = TRUE;
3770        unsigned char cmd[MAX_COMMAND_SIZE];
3771        Scsi_Request * SRpnt = * aSRpnt;
3772        ST_partstat * STps;
3773        int fileno, blkno, at_sm, frame_seq_numbr, logical_blk_num;
3774        int datalen = 0, direction = SCSI_DATA_NONE;
3775        int dev = TAPE_NR(STp->devt);
3776
3777        if (STp->ready != ST_READY && cmd_in != MTLOAD) {
3778                if (STp->ready == ST_NO_TAPE)
3779                        return (-ENOMEDIUM);
3780                else
3781                        return (-EIO);
3782        }
3783        timeout = STp->long_timeout;
3784        STps = &(STp->ps[STp->partition]);
3785        fileno = STps->drv_file;
3786        blkno = STps->drv_block;
3787        at_sm = STps->at_sm;
3788        frame_seq_numbr = STp->frame_seq_number;
3789        logical_blk_num = STp->logical_blk_num;
3790
3791        memset(cmd, 0, MAX_COMMAND_SIZE);
3792        switch (cmd_in) {
3793         case MTFSFM:
3794                chg_eof = FALSE; /* Changed from the FSF after this */
3795         case MTFSF:
3796                if (STp->raw)
3797                   return (-EIO);
3798                if (STp->linux_media)
3799                   ioctl_result = osst_space_over_filemarks_forward_fast(STp, &SRpnt, cmd_in, arg);
3800                else
3801                   ioctl_result = osst_space_over_filemarks_forward_slow(STp, &SRpnt, cmd_in, arg);
3802                if (fileno >= 0)
3803                   fileno += arg;
3804                blkno = 0;
3805                at_sm &= (arg == 0);
3806                goto os_bypass;
3807
3808         case MTBSF:
3809                chg_eof = FALSE; /* Changed from the FSF after this */
3810         case MTBSFM:
3811                if (STp->raw)
3812                   return (-EIO);
3813                ioctl_result = osst_space_over_filemarks_backward(STp, &SRpnt, cmd_in, arg);
3814                if (fileno >= 0)
3815                   fileno -= arg;
3816                blkno = (-1);  /* We can't know the block number */
3817                at_sm &= (arg == 0);
3818                goto os_bypass;
3819
3820         case MTFSR:
3821         case MTBSR:
3822#if DEBUG
3823                if (debugging)
3824                   printk(OSST_DEB_MSG "osst%d:D: Skipping %lu blocks %s from logical block %d\n",
3825                                dev, arg, cmd_in==MTFSR?"forward":"backward", logical_blk_num);
3826#endif
3827                if (cmd_in == MTFSR) {
3828                   logical_blk_num += arg;
3829                   if (blkno >= 0) blkno += arg;
3830                }
3831                else {
3832                   logical_blk_num -= arg;
3833                   if (blkno >= 0) blkno -= arg;
3834                }
3835                ioctl_result = osst_seek_logical_blk(STp, &SRpnt, logical_blk_num);
3836                fileno = STps->drv_file;
3837                blkno  = STps->drv_block;
3838                at_sm &= (arg == 0);
3839                goto os_bypass;
3840
3841         case MTFSS:
3842                cmd[0] = SPACE;
3843                cmd[1] = 0x04; /* Space Setmarks */   /* FIXME -- OS can't do this? */
3844                cmd[2] = (arg >> 16);
3845                cmd[3] = (arg >> 8);
3846                cmd[4] = arg;
3847#if DEBUG
3848                if (debugging)
3849                        printk(OSST_DEB_MSG "osst%d:D: Spacing tape forward %d setmarks.\n", dev,
3850                cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
3851#endif
3852                if (arg != 0) {
3853                        blkno = fileno = (-1);
3854                        at_sm = 1;
3855                }
3856                break;
3857         case MTBSS:
3858                cmd[0] = SPACE;
3859                cmd[1] = 0x04; /* Space Setmarks */   /* FIXME -- OS can't do this? */
3860                ltmp = (-arg);
3861                cmd[2] = (ltmp >> 16);
3862                cmd[3] = (ltmp >> 8);
3863                cmd[4] = ltmp;
3864#if DEBUG
3865                if (debugging) {
3866                        if (cmd[2] & 0x80)
3867                           ltmp = 0xff000000;
3868                        ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4];
3869                        printk(OSST_DEB_MSG "osst%d:D: Spacing tape backward %ld setmarks.\n",
3870                                                dev, (-ltmp));
3871                 }
3872#endif
3873                 if (arg != 0) {
3874                        blkno = fileno = (-1);
3875                        at_sm = 1;
3876                 }
3877                 break;
3878         case MTWEOF:
3879                 if ( STps->rw == ST_WRITING && !(STp->device)->was_reset)
3880                        ioctl_result = osst_flush_write_buffer(STp, &SRpnt);
3881                 else
3882                        ioctl_result = 0;
3883#if DEBUG
3884                 if (debugging) 
3885                           printk(OSST_DEB_MSG "osst%d:D: Writing %ld filemark(s).\n", dev, arg);
3886#endif
3887                 for (i=0; i<arg; i++)
3888                        ioctl_result |= osst_write_filemark(STp, &SRpnt);
3889                 if (fileno >= 0) fileno += arg;
3890                 if (blkno  >= 0) blkno   = 0;
3891                 goto os_bypass;
3892
3893         case MTWSM:
3894                 if (STp->write_prot)
3895                        return (-EACCES);
3896                 if (!STp->raw)
3897                        return 0;
3898                 cmd[0] = WRITE_FILEMARKS;   /* FIXME -- need OS version */
3899                 if (cmd_in == MTWSM)
3900                         cmd[1] = 2;
3901                 cmd[2] = (arg >> 16);
3902                 cmd[3] = (arg >> 8);
3903                 cmd[4] = arg;
3904                 timeout = STp->timeout;
3905#if DEBUG
3906                 if (debugging) 
3907                           printk(OSST_DEB_MSG "osst%d:D: Writing %d setmark(s).\n", dev,
3908                                  cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
3909#endif
3910                 if (fileno >= 0)
3911                        fileno += arg;
3912                 blkno = 0;
3913                 at_sm = (cmd_in == MTWSM);
3914                 break;
3915         case MTOFFL:
3916         case MTLOAD:
3917         case MTUNLOAD:
3918         case MTRETEN:
3919                 cmd[0] = START_STOP;
3920                 cmd[1] = 1;                    /* Don't wait for completion */
3921                 if (cmd_in == MTLOAD) {
3922                     if (STp->ready == ST_NO_TAPE)
3923                         cmd[4] = 4;            /* open tray */
3924                      else
3925                         cmd[4] = 1;            /* load */
3926                 }
3927                 if (cmd_in == MTRETEN)
3928                         cmd[4] = 3;            /* retension then mount */
3929                 if (cmd_in == MTOFFL)
3930                         cmd[4] = 4;            /* rewind then eject */
3931                 timeout = STp->timeout;
3932#if DEBUG
3933                 if (debugging) {
3934                         switch (cmd_in) {
3935                                 case MTUNLOAD:
3936                                         printk(OSST_DEB_MSG "osst%d:D: Unloading tape.\n", dev);
3937                                         break;
3938                                 case MTLOAD:
3939                                         printk(OSST_DEB_MSG "osst%d:D: Loading tape.\n", dev);
3940                                         break;
3941                                 case MTRETEN:
3942                                         printk(OSST_DEB_MSG "osst%d:D: Retensioning tape.\n", dev);
3943                                         break;
3944                                 case MTOFFL:
3945                                         printk(OSST_DEB_MSG "osst%d:D: Ejecting tape.\n", dev);
3946                                         break;
3947                         }
3948                 }
3949#endif
3950       fileno = blkno = at_sm = frame_seq_numbr = logical_blk_num = 0 ;
3951                 break;
3952         case MTNOP:
3953#if DEBUG
3954                 if (debugging)
3955                         printk(OSST_DEB_MSG "osst%d:D: No-op on tape.\n", dev);
3956#endif
3957                 return 0;  /* Should do something ? */
3958                 break;
3959         case MTEOM:
3960#if DEBUG
3961                if (debugging)
3962                   printk(OSST_DEB_MSG "osst%d:D: Spacing to end of recorded medium.\n", dev);
3963#endif
3964                osst_set_frame_position(STp, &SRpnt, STp->eod_frame_ppos, 0);
3965        if (osst_get_logical_frame(STp, &SRpnt, -1, 0) < 0) {
3966                   ioctl_result = -EIO;
3967                   goto os_bypass;
3968                }
3969                if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_EOD) {
3970#if DEBUG
3971                   printk(OSST_DEB_MSG "osst%d:D: No EOD frame found where expected.\n", dev);
3972#endif
3973                   ioctl_result = -EIO;
3974                   goto os_bypass;
3975                }
3976                ioctl_result = osst_set_frame_position(STp, &SRpnt, STp->eod_frame_ppos, 0);
3977                fileno = STp->filemark_cnt;
3978                blkno  = at_sm = 0;
3979                goto os_bypass;
3980
3981         case MTERASE:
3982                if (STp->write_prot)
3983                   return (-EACCES);
3984                ioctl_result = osst_reset_header(STp, &SRpnt);
3985                i = osst_write_eod(STp, &SRpnt);
3986                if (i < ioctl_result) ioctl_result = i;
3987                i = osst_position_tape_and_confirm(STp, &SRpnt, STp->eod_frame_ppos);
3988                if (i < ioctl_result) ioctl_result = i;
3989                fileno = blkno = at_sm = 0 ;
3990                goto os_bypass;
3991
3992         case MTREW:
3993                cmd[0] = REZERO_UNIT; /* rewind */
3994                cmd[1] = 1;
3995#if DEBUG
3996                if (debugging)
3997                   printk(OSST_DEB_MSG "osst%d:D: Rewinding tape, Immed=%d.\n", dev, cmd[1]);
3998#endif
3999                fileno = blkno = at_sm = frame_seq_numbr = logical_blk_num = 0 ;
4000                break;
4001
4002         case MTLOCK:
4003                chg_eof = FALSE;
4004                cmd[0] = ALLOW_MEDIUM_REMOVAL;
4005                cmd[4] = SCSI_REMOVAL_PREVENT;
4006#if DEBUG
4007                if (debugging)
4008                    printk(OSST_DEB_MSG "osst%d:D: Locking drive door.\n", dev);
4009#endif
4010                break;
4011
4012         case MTUNLOCK:
4013                chg_eof = FALSE;
4014                cmd[0] = ALLOW_MEDIUM_REMOVAL;
4015                cmd[4] = SCSI_REMOVAL_ALLOW;
4016#if DEBUG
4017                if (debugging)
4018                   printk(OSST_DEB_MSG "osst%d:D: Unlocking drive door.\n", dev);
4019#endif
4020        break;
4021
4022         case MTSETBLK:           /* Set block length */
4023         case MTSETDENSITY:       /* Set tape density */
4024         case MTSETDRVBUFFER:     /* Set drive buffering */
4025         case SET_DENS_AND_BLK:   /* Set density and block size */
4026                 chg_eof = FALSE;
4027                 if (STp->dirty || (STp->buffer)->buffer_bytes != 0)
4028                         return (-EIO);       /* Not allowed if data in buffer */
4029                 if ((cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) &&
4030                   (arg & MT_ST_BLKSIZE_MASK) != 0 &&
4031                   ((arg & MT_ST_BLKSIZE_MASK) < STp->min_block ||
4032                    (arg & MT_ST_BLKSIZE_MASK) > STp->max_block ||
4033                    (arg & MT_ST_BLKSIZE_MASK) > osst_buffer_size)) {
4034                         printk(KERN_WARNING "osst%d:W: Illegal block size.\n", dev);
4035                         return (-EINVAL);
4036                 }
4037                 return 0;  /* FIXME silently ignore if block size didn't change */
4038
4039         default:
4040                return (-ENOSYS);
4041        }
4042
4043        SRpnt = osst_do_scsi(SRpnt, STp, cmd, datalen, direction, timeout, MAX_RETRIES, TRUE);
4044
4045        ioctl_result = (STp->buffer)->syscall_result;
4046
4047        if (!SRpnt) {
4048#if DEBUG
4049                printk(OSST_DEB_MSG "osst%d:D: Couldn't exec scsi cmd for IOCTL\n", dev);
4050#endif
4051                return ioctl_result;
4052        }
4053
4054        if (!ioctl_result) {  /* SCSI command successful */
4055                STp->frame_seq_number = frame_seq_numbr;
4056                STp->logical_blk_num  = logical_blk_num;
4057        }
4058
4059os_bypass:
4060#if DEBUG
4061        if (debugging)
4062                printk(OSST_DEB_MSG "osst%d:D: IOCTL (%d) Result=%d\n", dev, cmd_in, ioctl_result);
4063#endif
4064
4065        if (!ioctl_result) {                            /* success */
4066
4067                if (cmd_in == MTFSFM) {
4068                         fileno--;
4069                         blkno--;
4070                }
4071                if (cmd_in == MTBSFM) {
4072                         fileno++;
4073                         blkno++;
4074                }
4075                STps->drv_block = blkno;
4076                STps->drv_file = fileno;
4077                STps->at_sm = at_sm;
4078
4079                if (cmd_in == MTLOCK)
4080                         STp->door_locked = ST_LOCKED_EXPLICIT;
4081                else if (cmd_in == MTUNLOCK)
4082                        STp->door_locked = ST_UNLOCKED;
4083
4084                if (cmd_in == MTEOM)
4085                        STps->eof = ST_EOD;
4086                else if (cmd_in == MTFSF)
4087                        STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD:ST_FM;
4088                else if (chg_eof)
4089                        STps->eof = ST_NOEOF;
4090
4091                if (cmd_in == MTOFFL || cmd_in == MTUNLOAD)
4092                        STp->rew_at_close = 0;
4093                else if (cmd_in == MTLOAD) {
4094/*                      STp->rew_at_close = (MINOR(inode->i_rdev) & 0x80) == 0;  FIXME */
4095                        for (i=0; i < ST_NBR_PARTITIONS; i++) {
4096                            STp->ps[i].rw = ST_IDLE;
4097                            STp->ps[i].last_block_valid = FALSE;/* FIXME - where else is this field maintained? */
4098                        }
4099                        STp->partition = 0;
4100                }
4101
4102                if (cmd_in == MTREW) {
4103                        ioctl_result = osst_position_tape_and_confirm(STp, &SRpnt, STp->first_data_ppos); 
4104                        if (ioctl_result > 0)
4105                                ioctl_result = 0;
4106                }
4107
4108        } else if (cmd_in == MTBSF || cmd_in == MTBSFM ) {
4109                if (osst_position_tape_and_confirm(STp, &SRpnt, STp->first_data_ppos) < 0)
4110                        STps->drv_file = STps->drv_block = -1;
4111                else
4112                        STps->drv_file = STps->drv_block = 0;
4113                STps->eof = ST_NOEOF;
4114        } else if (cmd_in == MTFSF || cmd_in == MTFSFM) {
4115                if (osst_position_tape_and_confirm(STp, &SRpnt, STp->eod_frame_ppos) < 0)
4116                        STps->drv_file = STps->drv_block = -1;
4117                else {
4118                        STps->drv_file  = STp->filemark_cnt;
4119                        STps->drv_block = 0;
4120                }
4121                STps->eof = ST_EOD;
4122        } else if (cmd_in == MTBSR || cmd_in == MTFSR || cmd_in == MTWEOF || cmd_in == MTEOM) {
4123                STps->drv_file = STps->drv_block = (-1);
4124                STps->eof = ST_NOEOF;
4125                STp->header_ok = 0;
4126        } else if (cmd_in == MTERASE) {
4127                STp->header_ok = 0;
4128        } else if (SRpnt) {  /* SCSI command was not completely successful. */
4129                if (SRpnt->sr_sense_buffer[2] & 0x40) {
4130                        STps->eof = ST_EOM_OK;
4131                        STps->drv_block = 0;
4132                }
4133                if (chg_eof)
4134                        STps->eof = ST_NOEOF;
4135
4136                if ((SRpnt->sr_sense_buffer[2] & 0x0f) == BLANK_CHECK)
4137                        STps->eof = ST_EOD;
4138
4139                if (cmd_in == MTLOCK)
4140                        STp->door_locked = ST_LOCK_FAILS;
4141
4142                if (cmd_in == MTLOAD && osst_wait_for_medium(STp, &SRpnt, 60))
4143                        ioctl_result = osst_wait_ready(STp, &SRpnt, 5 * 60);
4144        }
4145        *aSRpnt = SRpnt;
4146
4147        return ioctl_result;
4148}
4149
4150
4151/* Open the device */
4152static int os_scsi_tape_open(struct inode * inode, struct file * filp)
4153{
4154        unsigned short flags;
4155        int i, b_size, need_dma_buffer, new_session = FALSE, retval = 0;
4156        unsigned char cmd[MAX_COMMAND_SIZE];
4157        Scsi_Request * SRpnt;
4158        OS_Scsi_Tape * STp;
4159        ST_mode * STm;
4160        ST_partstat * STps;
4161        int dev = TAPE_NR(inode->i_rdev);
4162        int mode = TAPE_MODE(inode->i_rdev);
4163
4164        if (dev >= osst_template.dev_max || (STp = os_scsi_tapes[dev]) == NULL || !STp->device)
4165                return (-ENXIO);
4166
4167        if( !scsi_block_when_processing_errors(STp->device) ) {
4168                return -ENXIO;
4169        }
4170
4171        if (STp->in_use) {
4172#if DEBUG
4173                printk(OSST_DEB_MSG "osst%d:D: Device already in use.\n", dev);
4174#endif
4175                return (-EBUSY);
4176        }
4177        STp->in_use       = 1;
4178        STp->rew_at_close = (MINOR(inode->i_rdev) & 0x80) == 0;
4179
4180        if (STp->device->host->hostt->module)
4181                 __MOD_INC_USE_COUNT(STp->device->host->hostt->module);
4182        if (osst_template.module)
4183                 __MOD_INC_USE_COUNT(osst_template.module);
4184        STp->device->access_count++;
4185
4186        if (mode != STp->current_mode) {
4187#if DEBUG
4188                if (debugging)
4189                        printk(OSST_DEB_MSG "osst%d:D: Mode change from %d to %d.\n",
4190                                               dev, STp->current_mode, mode);
4191#endif
4192                new_session = TRUE;
4193                STp->current_mode = mode;
4194        }
4195        STm = &(STp->modes[STp->current_mode]);
4196
4197        flags = filp->f_flags;
4198        STp->write_prot = ((flags & O_ACCMODE) == O_RDONLY);
4199
4200        STp->raw = (MINOR(inode->i_rdev) & 0x40) != 0;
4201        if (STp->raw)
4202                STp->header_ok = 0;
4203
4204        /* Allocate a buffer for this user */
4205        need_dma_buffer = STp->restr_dma;
4206        for (i=0; i < osst_nbr_buffers; i++)
4207                if (!osst_buffers[i]->in_use &&
4208                   (!need_dma_buffer || osst_buffers[i]->dma))
4209                        break;
4210        if (i >= osst_nbr_buffers) {
4211                STp->buffer = new_tape_buffer(FALSE, need_dma_buffer);
4212                if (STp->buffer == NULL) {
4213                        printk(KERN_WARNING "osst%d:W: Can't allocate tape buffer.\n", dev);
4214                        retval = (-EBUSY);
4215                        goto err_out;
4216                }
4217        }
4218        else
4219                STp->buffer = osst_buffers[i];
4220        (STp->buffer)->in_use = 1;
4221        (STp->buffer)->writing = 0;
4222        (STp->buffer)->syscall_result = 0;
4223        (STp->buffer)->use_sg = STp->device->host->sg_tablesize;
4224
4225        /* Compute the usable buffer size for this SCSI adapter */
4226        if (!(STp->buffer)->use_sg)
4227        (STp->buffer)->buffer_size = (STp->buffer)->sg[0].length;
4228        else {
4229                for (i=0, (STp->buffer)->buffer_size = 0; i < (STp->buffer)->use_sg &&
4230                     i < (STp->buffer)->sg_segs; i++)
4231                        (STp->buffer)->buffer_size += (STp->buffer)->sg[i].length;
4232        }
4233
4234        STp->dirty = 0;
4235        for (i=0; i < ST_NBR_PARTITIONS; i++) {
4236                STps = &(STp->ps[i]);
4237                STps->rw = ST_IDLE;
4238        }
4239        STp->ready = ST_READY;
4240#if DEBUG
4241        STp->nbr_waits = STp->nbr_finished = 0;
4242#endif
4243
4244        memset (cmd, 0, MAX_COMMAND_SIZE);
4245        cmd[0] = TEST_UNIT_READY;
4246
4247        SRpnt = osst_do_scsi(NULL, STp, cmd, 0, SCSI_DATA_NONE, STp->timeout, MAX_READY_RETRIES, TRUE);
4248        if (!SRpnt) {
4249                retval = (STp->buffer)->syscall_result;
4250                goto err_out;
4251        }
4252        if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70      &&
4253            (SRpnt->sr_sense_buffer[2] & 0x0f) == NOT_READY &&
4254             SRpnt->sr_sense_buffer[12]        == 4         ) {
4255#if DEBUG
4256                printk(OSST_DEB_MSG "osst%d:D: Unit not ready, cause %x\n", dev, SRpnt->sr_sense_buffer[13]);
4257#endif
4258                if (SRpnt->sr_sense_buffer[13] == 2) {  /* initialize command required (LOAD) */
4259                        memset (cmd, 0, MAX_COMMAND_SIZE);
4260                        cmd[0] = START_STOP;
4261                        cmd[1] = 1;
4262                        cmd[4] = 1;
4263                        SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, SCSI_DATA_NONE,
4264                                             STp->timeout, MAX_READY_RETRIES, TRUE);
4265                }
4266                osst_wait_ready(STp, &SRpnt, (SRpnt->sr_sense_buffer[13]==1?15:3) * 60);
4267        }
4268        if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 &&
4269            (SRpnt->sr_sense_buffer[2] & 0x0f) == UNIT_ATTENTION) { /* New media? */
4270#if DEBUG
4271                printk(OSST_DEB_MSG "osst%d:D: Unit wants attention\n", dev);
4272#endif
4273                STp->header_ok = 0;
4274
4275                for (i=0; i < 10; i++) {
4276
4277                        memset (cmd, 0, MAX_COMMAND_SIZE);
4278                        cmd[0] = TEST_UNIT_READY;
4279
4280                        SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, SCSI_DATA_NONE,
4281                                             STp->timeout, MAX_READY_RETRIES, TRUE);
4282                        if ((SRpnt->sr_sense_buffer[0] & 0x70) != 0x70 ||
4283                            (SRpnt->sr_sense_buffer[2] & 0x0f) != UNIT_ATTENTION)
4284                                break;
4285                }
4286
4287                STp->device->was_reset = 0;
4288                STp->partition = STp->new_partition = 0;
4289                if (STp->can_partitions)
4290                        STp->nbr_partitions = 1;  /* This guess will be updated later if necessary */
4291                for (i=0; i < ST_NBR_PARTITIONS; i++) {
4292                        STps = &(STp->ps[i]);
4293                        STps->rw = ST_IDLE;             /* FIXME - seems to be redundant... */
4294                        STps->eof = ST_NOEOF;
4295                        STps->at_sm = 0;
4296                        STps->last_block_valid = FALSE;
4297                        STps->drv_block = 0;
4298                        STps->drv_file = 0 ;
4299                }
4300                new_session = TRUE;
4301                STp->recover_count = 0;
4302        }
4303        /*
4304         * if we have valid headers from before, and the drive/tape seem untouched,
4305         * open without reconfiguring and re-reading the headers
4306         */
4307        if (!STp->buffer->syscall_result && STp->header_ok &&
4308            !SRpnt->sr_result && SRpnt->sr_sense_buffer[0] == 0) {
4309
4310                memset(cmd, 0, MAX_COMMAND_SIZE);
4311                cmd[0] = MODE_SENSE;
4312                cmd[1] = 8;
4313                cmd[2] = VENDOR_IDENT_PAGE;
4314                cmd[4] = VENDOR_IDENT_PAGE_LENGTH + MODE_HEADER_LENGTH;
4315
4316                SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], SCSI_DATA_READ, STp->timeout, 0, TRUE);
4317
4318                if (STp->buffer->syscall_result                     ||
4319                    STp->buffer->b_data[MODE_HEADER_LENGTH + 2] != 'L' ||
4320                    STp->buffer->b_data[MODE_HEADER_LENGTH + 3] != 'I' ||
4321                    STp->buffer->b_data[MODE_HEADER_LENGTH + 4] != 'N' ||
4322                    STp->buffer->b_data[MODE_HEADER_LENGTH + 5] != '4'  ) {
4323#if DEBUG
4324                        printk(OSST_DEB_MSG "osst%d:D: Signature was changed to %c%c%c%c\n", dev,
4325                          STp->buffer->b_data[MODE_HEADER_LENGTH + 2],
4326                          STp->buffer->b_data[MODE_HEADER_LENGTH + 3],
4327                          STp->buffer->b_data[MODE_HEADER_LENGTH + 4],
4328                          STp->buffer->b_data[MODE_HEADER_LENGTH + 5]);
4329#endif
4330                        STp->header_ok = 0;
4331                }
4332                i = STp->first_frame_position;
4333                if (STp->header_ok && i == osst_get_frame_position(STp, &SRpnt)) {
4334                        if (STp->door_locked == ST_UNLOCKED) {
4335                                if (osst_int_ioctl(STp, &SRpnt, MTLOCK, 0))
4336                                        printk(KERN_INFO "osst%d:I: Can't lock drive door\n", dev);
4337                                else
4338                                        STp->door_locked = ST_LOCKED_AUTO;
4339                        }
4340                        if (!STp->frame_in_buffer) {
4341                                STp->block_size = (STm->default_blksize > 0) ?
4342                                                        STm->default_blksize : OS_DATA_SIZE;
4343                                STp->buffer->buffer_bytes = STp->buffer->read_pointer = 0;
4344                        }
4345                        STp->buffer->buffer_blocks = OS_DATA_SIZE / STp->block_size;
4346                        STp->fast_open = TRUE;
4347                        scsi_release_request(SRpnt);
4348                        return 0;
4349                }
4350#if DEBUG
4351                if (i != STp->first_frame_position)
4352                        printk(OSST_DEB_MSG "osst%d:D: Tape position changed from %d to %d\n",
4353                                                dev, i, STp->first_frame_position);
4354#endif
4355                STp->header_ok = 0;
4356        }
4357        STp->fast_open = FALSE;
4358
4359        if ((STp->buffer)->syscall_result != 0 &&   /* in all error conditions except no medium */ 
4360            (SRpnt->sr_sense_buffer[2] != 2 || SRpnt->sr_sense_buffer[12] != 0x3A) ) {
4361
4362                memset(cmd, 0, MAX_COMMAND_SIZE);
4363                cmd[0] = MODE_SELECT;
4364                cmd[1] = 0x10;
4365                cmd[4] = 4 + MODE_HEADER_LENGTH;
4366
4367                (STp->buffer)->b_data[0] = cmd[4] - 1;
4368                (STp->buffer)->b_data[1] = 0;                   /* Medium Type - ignoring */
4369                (STp->buffer)->b_data[2] = 0;                   /* Reserved */
4370                (STp->buffer)->b_data[3] = 0;                   /* Block Descriptor Length */
4371                (STp->buffer)->b_data[MODE_HEADER_LENGTH + 0] = 0x3f;
4372                (STp->buffer)->b_data[MODE_HEADER_LENGTH + 1] = 1;
4373                (STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] = 2;
4374                (STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] = 3;
4375
4376#if DEBUG
4377                printk(OSST_DEB_MSG "osst%d:D: Applying soft reset\n", dev);
4378#endif
4379                SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], SCSI_DATA_WRITE, STp->timeout, 0, TRUE);
4380
4381                STp->header_ok = 0;
4382
4383                for (i=0; i < 10; i++) {
4384
4385                        memset (cmd, 0, MAX_COMMAND_SIZE);
4386                        cmd[0] = TEST_UNIT_READY;
4387
4388                        SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, SCSI_DATA_NONE,
4389                                             STp->timeout, MAX_READY_RETRIES, TRUE);
4390                        if ((SRpnt->sr_sense_buffer[0] & 0x70) != 0x70 ||
4391                            (SRpnt->sr_sense_buffer[2] & 0x0f) == NOT_READY)
4392                        break;
4393
4394                        if ((SRpnt->sr_sense_buffer[2] & 0x0f) == UNIT_ATTENTION) {
4395                                STp->device->was_reset = 0;
4396                                STp->partition = STp->new_partition = 0;
4397                                if (STp->can_partitions)
4398                                        STp->nbr_partitions = 1;  /* This guess will be updated later if necessary */
4399                                for (i=0; i < ST_NBR_PARTITIONS; i++) {
4400                                        STps = &(STp->ps[i]);
4401                                        STps->rw = ST_IDLE;
4402                                        STps->eof = ST_NOEOF;
4403                                        STps->at_sm = 0;
4404                                        STps->last_block_valid = FALSE;
4405                                        STps->drv_block = 0;
4406                                        STps->drv_file = 0 ;
4407                                }
4408                                new_session = TRUE;
4409                        }
4410                }
4411        }
4412
4413        if (osst_wait_ready(STp, &SRpnt, 15 * 60))              /* FIXME - not allowed with NOBLOCK */
4414                 printk(KERN_INFO "osst%i:I: Device did not become Ready in open\n",dev);
4415
4416        if ((STp->buffer)->syscall_result != 0) {
4417                if ((STp->device)->scsi_level >= SCSI_2 &&
4418                    (SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 &&
4419                    (SRpnt->sr_sense_buffer[2] & 0x0f) == NOT_READY &&
4420                     SRpnt->sr_sense_buffer[12] == 0x3a) { /* Check ASC */
4421                        STp->ready = ST_NO_TAPE;
4422                } else
4423                        STp->ready = ST_NOT_READY;
4424                scsi_release_request(SRpnt);
4425                SRpnt = NULL;
4426                STp->density = 0;       /* Clear the erroneous "residue" */
4427                STp->write_prot = 0;
4428                STp->block_size = 0;
4429                STp->ps[0].drv_file = STp->ps[0].drv_block = (-1);
4430                STp->partition = STp->new_partition = 0;
4431                STp->door_locked = ST_UNLOCKED;
4432                return 0;
4433        }
4434
4435        osst_configure_onstream(STp, &SRpnt);
4436
4437/*      STp->drv_write_prot = ((STp->buffer)->b_data[2] & 0x80) != 0; FIXME */
4438
4439        if (OS_FRAME_SIZE > (STp->buffer)->buffer_size &&
4440            !enlarge_buffer(STp->buffer, OS_FRAME_SIZE, STp->restr_dma)) {
4441                printk(KERN_NOTICE "osst%d:A: Framesize %d too large for buffer.\n", dev,
4442                                     OS_FRAME_SIZE);
4443                retval = (-EIO);
4444                goto err_out;
4445        }
4446
4447        if ((STp->buffer)->buffer_size >= OS_FRAME_SIZE) {
4448                for (i = 0, b_size = 0; 
4449                     i < STp->buffer->sg_segs && (b_size + STp->buffer->sg[i].length) <= OS_DATA_SIZE; 
4450                     b_size += STp->buffer->sg[i++].length);
4451                STp->buffer->aux = (os_aux_t *) (STp->buffer->sg[i].address + OS_DATA_SIZE - b_size);
4452#if DEBUG
4453                printk(OSST_DEB_MSG "osst%d:D: b_data points to %p in segment 0 at %p\n", dev,
4454                        STp->buffer->b_data, STp->buffer->sg[0].address);
4455                printk(OSST_DEB_MSG "osst%d:D: AUX points to %p in segment %d at %p\n", dev,
4456                         STp->buffer->aux, i, STp->buffer->sg[i].address);
4457#endif
4458        } else
4459                STp->buffer->aux = NULL; /* this had better never happen! */
4460
4461        STp->block_size = STp->raw ? OS_FRAME_SIZE : (
4462                             (STm->default_blksize > 0) ? STm->default_blksize : OS_DATA_SIZE);
4463        STp->buffer->buffer_blocks = STp->raw ? 1 : OS_DATA_SIZE / STp->block_size;
4464        STp->buffer->buffer_bytes  =
4465        STp->buffer->read_pointer  =
4466        STp->frame_in_buffer       = 0;
4467
4468#if DEBUG
4469        if (debugging)
4470                printk(OSST_DEB_MSG "osst%d:D: Block size: %d, frame size: %d, buffer size: %d (%d blocks).\n",
4471                     dev, STp->block_size, OS_FRAME_SIZE, (STp->buffer)->buffer_size,
4472                     (STp->buffer)->buffer_blocks);
4473#endif
4474
4475        if (STp->drv_write_prot) {
4476                STp->write_prot = 1;
4477#if DEBUG
4478                if (debugging)
4479                        printk(OSST_DEB_MSG "osst%d:D: Write protected\n", dev);
4480#endif
4481                if ((flags & O_ACCMODE) == O_WRONLY || (flags & O_ACCMODE) == O_RDWR) {
4482                        retval = (-EROFS);
4483                        goto err_out;
4484                }
4485        }
4486
4487        if (new_session) {  /* Change the drive parameters for the new mode */
4488#if DEBUG
4489                if (debugging)
4490        printk(OSST_DEB_MSG "osst%d:D: New Session\n", dev);
4491#endif
4492                STp->density_changed = STp->blksize_changed = FALSE;
4493                STp->compression_changed = FALSE;
4494        }
4495
4496        /*
4497         * properly position the tape and check the ADR headers
4498         */
4499        if (STp->door_locked == ST_UNLOCKED) {
4500                 if (osst_int_ioctl(STp, &SRpnt, MTLOCK, 0))
4501                        printk(KERN_INFO "osst%d:I: Can't lock drive door\n", dev);
4502                 else
4503                        STp->door_locked = ST_LOCKED_AUTO;
4504        }
4505
4506        osst_analyze_headers(STp, &SRpnt);
4507
4508        scsi_release_request(SRpnt);
4509        SRpnt = NULL;
4510
4511        return 0;
4512
4513err_out:
4514        if (SRpnt != NULL)
4515                scsi_release_request(SRpnt);
4516        if (STp->buffer != NULL) {
4517                STp->buffer->in_use = 0;
4518                STp->buffer = NULL;
4519        }
4520        STp->in_use = 0;
4521        STp->header_ok = 0;
4522        STp->device->access_count--;
4523
4524        if (STp->device->host->hostt->module)
4525            __MOD_DEC_USE_COUNT(STp->device->host->hostt->module);
4526        if (osst_template.module)
4527            __MOD_DEC_USE_COUNT(osst_template.module);
4528
4529        return retval;
4530}
4531
4532
4533/* Flush the tape buffer before close */
4534static int os_scsi_tape_flush(struct file * filp)
4535{
4536        int result = 0, result2;
4537        OS_Scsi_Tape * STp;
4538        ST_mode * STm;
4539        ST_partstat * STps;
4540        Scsi_Request *SRpnt = NULL;
4541
4542        struct inode *inode = filp->f_dentry->d_inode;
4543        kdev_t devt = inode->i_rdev;
4544        int dev;
4545
4546        if (file_count(filp) > 1)
4547        return 0;
4548
4549        dev = TAPE_NR(devt);
4550        STp = os_scsi_tapes[dev];
4551        STm = &(STp->modes[STp->current_mode]);
4552        STps = &(STp->ps[STp->partition]);
4553
4554        if ( STps->rw == ST_WRITING && !(STp->device)->was_reset) {
4555                result = osst_flush_write_buffer(STp, &SRpnt);
4556                if (result != 0 && result != (-ENOSPC))
4557                        goto out;
4558        }
4559        if ( STps->rw >= ST_WRITING && !(STp->device)->was_reset) {
4560
4561#if DEBUG
4562                if (debugging) {
4563                        printk(OSST_DEB_MSG "osst%d:D: File length %ld bytes.\n",
4564                                               dev, (long)(filp->f_pos));
4565                        printk(OSST_DEB_MSG "osst%d:D: Async write waits %d, finished %d.\n",
4566                                               dev, STp->nbr_waits, STp->nbr_finished);
4567                }
4568#endif
4569                if (STp->write_type != OS_WRITE_NEW_MARK) {
4570                        /* true unless the user wrote the filemark for us */
4571                        result = osst_flush_drive_buffer(STp, &SRpnt);
4572                        if (result < 0) goto out;
4573                        result = osst_write_filemark(STp, &SRpnt);
4574                        if (result < 0) goto out;
4575
4576                        if (STps->drv_file >= 0)
4577                                STps->drv_file++ ;
4578                        STps->drv_block = 0;
4579                }
4580                result = osst_write_eod(STp, &SRpnt);
4581                osst_write_header(STp, &SRpnt, !(STp->rew_at_close));
4582
4583                STps->eof = ST_FM;
4584
4585#if DEBUG
4586                if (debugging)
4587                        printk(OSST_DEB_MSG "osst%d:D: Buffer flushed, %d EOF(s) written\n",
4588                                               dev, 1+STp->two_fm);
4589#endif
4590        }
4591        else if (!STp->rew_at_close) {
4592                STps = &(STp->ps[STp->partition]);
4593                if (!STm->sysv || STps->rw != ST_READING) {
4594                        if (STp->can_bsr)
4595                result = osst_flush_buffer(STp, &SRpnt, 0);     /* this is the default path */
4596                        else if (STps->eof == ST_FM_HIT) {
4597                                result = cross_eof(STp, &SRpnt, FALSE);
4598                                        if (result) {
4599                                                if (STps->drv_file >= 0)
4600                                                        STps->drv_file++;
4601                                                STps->drv_block = 0;
4602                                                STps->eof = ST_FM;
4603                                        }
4604                                        else
4605                                                STps->eof = ST_NOEOF;
4606                        }
4607                }
4608                else if ((STps->eof == ST_NOEOF &&
4609                          !(result = cross_eof(STp, &SRpnt, TRUE))) ||
4610                          STps->eof == ST_FM_HIT) {
4611                        if (STps->drv_file >= 0)
4612                                STps->drv_file++;
4613                        STps->drv_block = 0;
4614                        STps->eof = ST_FM;
4615                }
4616        }
4617
4618out:
4619        if (STp->rew_at_close) {
4620                result2 = osst_position_tape_and_confirm(STp, &SRpnt, STp->first_data_ppos);
4621                STps->drv_file = STps->drv_block = STp->frame_seq_number = STp->logical_blk_num = 0;
4622                if (result == 0 && result2 < 0)
4623                        result = result2;
4624        }
4625        if (SRpnt) scsi_release_request(SRpnt);
4626
4627        if (STp->recover_count) {
4628                printk(KERN_INFO "osst%d:I: %d recovered errors in", dev, STp->recover_count);
4629                if (STp->write_count)
4630                        printk(" %d frames written", STp->write_count);
4631                if (STp->read_count)
4632                        printk(" %d frames read", STp->read_count);
4633                printk("\n");
4634                STp->recover_count = 0;
4635        }
4636        STp->write_count = 0;
4637        STp->read_count  = 0;
4638
4639        return result;
4640}
4641
4642
4643/* Close the device and release it */
4644static int os_scsi_tape_close(struct inode * inode, struct file * filp)
4645{
4646        int result = 0;
4647        OS_Scsi_Tape * STp;
4648        Scsi_Request * SRpnt = NULL;
4649
4650        kdev_t devt = inode->i_rdev;
4651        int dev;
4652
4653        dev = TAPE_NR(devt);
4654        STp = os_scsi_tapes[dev];
4655
4656        if (STp->door_locked == ST_LOCKED_AUTO)
4657                osst_int_ioctl(STp, &SRpnt, MTUNLOCK, 0);
4658        if (SRpnt) scsi_release_request(SRpnt);
4659
4660        if (STp->buffer != NULL)
4661                STp->buffer->in_use = 0;
4662
4663        if (STp->raw)
4664                STp->header_ok = 0;
4665
4666        STp->in_use = 0;
4667        STp->device->access_count--;
4668
4669        if (STp->device->host->hostt->module)
4670                __MOD_DEC_USE_COUNT(STp->device->host->hostt->module);
4671        if(osst_template.module)
4672                __MOD_DEC_USE_COUNT(osst_template.module);
4673
4674        return result;
4675}
4676
4677
4678/* The ioctl command */
4679static int osst_ioctl(struct inode * inode,struct file * file,
4680         unsigned int cmd_in, unsigned long arg)
4681{
4682        int i, cmd_nr, cmd_type, retval = 0;
4683        unsigned int blk;
4684        OS_Scsi_Tape *STp;
4685        ST_mode *STm;
4686        ST_partstat *STps;
4687        Scsi_Request *SRpnt = NULL;
4688        int dev = TAPE_NR(inode->i_rdev);
4689
4690        STp = os_scsi_tapes[dev];
4691
4692        if (down_interruptible(&STp->lock))
4693                return -ERESTARTSYS;
4694
4695#if DEBUG
4696        if (debugging && !STp->in_use) {
4697                printk(OSST_DEB_MSG "osst%d:D: Incorrect device.\n", dev);
4698                retval = (-EIO);
4699                goto out;
4700        }
4701#endif
4702        STm = &(STp->modes[STp->current_mode]);
4703        STps = &(STp->ps[STp->partition]);
4704
4705        /*
4706         * If we are in the middle of error recovery, don't let anyone
4707         * else try and use this device.  Also, if error recovery fails, it
4708         * may try and take the device offline, in which case all further
4709         * access to the device is prohibited.
4710         */
4711        if( !scsi_block_when_processing_errors(STp->device) ) {
4712                retval = (-ENXIO);
4713                goto out;
4714        }
4715
4716        cmd_type = _IOC_TYPE(cmd_in);
4717        cmd_nr   = _IOC_NR(cmd_in);
4718#if DEBUG
4719        printk(OSST_DEB_MSG "osst%d:D: Ioctl %d,%d in %s mode\n", dev,
4720                            cmd_type, cmd_nr, STp->raw?"raw":"normal");
4721#endif
4722        if (cmd_type == _IOC_TYPE(MTIOCTOP) && cmd_nr == _IOC_NR(MTIOCTOP)) {
4723                struct mtop mtc;
4724
4725                if (_IOC_SIZE(cmd_in) != sizeof(mtc)) {
4726                        retval = (-EINVAL);
4727                        goto out;
4728                }
4729
4730                i = copy_from_user((char *) &mtc, (char *)arg, sizeof(struct mtop));
4731                if (i) {
4732                        retval = (-EFAULT);
4733                        goto out;
4734                }
4735
4736                if (mtc.mt_op == MTSETDRVBUFFER && !capable(CAP_SYS_ADMIN)) {
4737                        printk(KERN_WARNING "osst%d:W: MTSETDRVBUFFER only allowed for root.\n", dev);
4738                        retval = (-EPERM);
4739                        goto out;
4740                }
4741
4742                if (!STm->defined && (mtc.mt_op != MTSETDRVBUFFER && (mtc.mt_count & MT_ST_OPTIONS) == 0)) {
4743                        retval = (-ENXIO);
4744                        goto out;
4745                }
4746
4747                if (!(STp->device)->was_reset) {
4748
4749                        if (STps->eof == ST_FM_HIT) {
4750                                if (mtc.mt_op == MTFSF || mtc.mt_op == MTFSFM|| mtc.mt_op == MTEOM) {
4751                                        mtc.mt_count -= 1;
4752                                        if (STps->drv_file >= 0)
4753                                                STps->drv_file += 1;
4754                                }
4755                                else if (mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM) {
4756                                        mtc.mt_count += 1;
4757                                        if (STps->drv_file >= 0)
4758                                                STps->drv_file += 1;
4759                                }
4760                        }
4761
4762                        if (mtc.mt_op == MTSEEK) {
4763                                /* Old position must be restored if partition will be changed */
4764                                i = !STp->can_partitions || (STp->new_partition != STp->partition);
4765                        }
4766                        else {
4767                                i = mtc.mt_op == MTREW   || mtc.mt_op == MTOFFL ||
4768                                    mtc.mt_op == MTRETEN || mtc.mt_op == MTEOM  ||
4769                                    mtc.mt_op == MTLOCK  || mtc.mt_op == MTLOAD ||
4770                                    mtc.mt_op == MTCOMPRESSION;
4771                        }
4772                        i = osst_flush_buffer(STp, &SRpnt, i);
4773                        if (i < 0) {
4774                                retval = i;
4775                                goto out;
4776                        }
4777                }
4778                else {
4779                        /*
4780                         * If there was a bus reset, block further access
4781                         * to this device.  If the user wants to rewind the tape,
4782                         * then reset the flag and allow access again.
4783                         */
4784                        if(mtc.mt_op != MTREW   &&
4785                           mtc.mt_op != MTOFFL  &&
4786                           mtc.mt_op != MTRETEN &&
4787                           mtc.mt_op != MTERASE &&
4788                           mtc.mt_op != MTSEEK  &&
4789                           mtc.mt_op != MTEOM)   {
4790                                retval = (-EIO);
4791                                goto out;
4792                        }
4793                        STp->device->was_reset = 0;
4794                        if (STp->door_locked != ST_UNLOCKED &&
4795                            STp->door_locked != ST_LOCK_FAILS) {
4796                                if (osst_int_ioctl(STp, &SRpnt, MTLOCK, 0)) {
4797                                        printk(KERN_NOTICE "osst%d:I: Could not relock door after bus reset.\n",
4798                                                                  dev);
4799                                        STp->door_locked = ST_UNLOCKED;
4800                                }
4801                        }
4802                }
4803
4804                if (mtc.mt_op != MTNOP && mtc.mt_op != MTWEOF && mtc.mt_op != MTWSM &&
4805                    mtc.mt_op != MTSETDENSITY && mtc.mt_op != MTSETBLK &&
4806                    mtc.mt_op != MTSETDRVBUFFER && mtc.mt_op != MTSETPART)
4807                        STps->rw = ST_IDLE;  /* Prevent automatic WEOF and fsf */
4808
4809                if (mtc.mt_op == MTOFFL && STp->door_locked != ST_UNLOCKED)
4810                        osst_int_ioctl(STp, &SRpnt, MTUNLOCK, 0);  /* Ignore result! */
4811
4812                if (mtc.mt_op == MTSETDRVBUFFER &&
4813                   (mtc.mt_count & MT_ST_OPTIONS) != 0) {
4814                        retval = osst_set_options(STp, mtc.mt_count);
4815                        goto out;
4816                }
4817
4818                if (mtc.mt_op == MTSETPART) {
4819/*     if (!STp->can_partitions ||
4820           mtc.mt_count < 0 || mtc.mt_count >= ST_NBR_PARTITIONS)
4821         return (-EINVAL);
4822                 if (mtc.mt_count >= STp->nbr_partitions &&
4823           (STp->nbr_partitions = nbr_partitions(inode)) < 0)
4824         return (-EIO);*/
4825                        if (mtc.mt_count >= STp->nbr_partitions)
4826                                retval = -EINVAL;
4827                        else {
4828                                STp->new_partition = mtc.mt_count;
4829                                retval = 0;
4830                        }
4831                        goto out;
4832                }
4833
4834                if (mtc.mt_op == MTMKPART) {
4835                        if (!STp->can_partitions) {
4836                                retval = (-EINVAL);
4837                                goto out;
4838                        }
4839                        if ((i = osst_int_ioctl(STp, &SRpnt, MTREW, 0)) < 0 /*||
4840                            (i = partition_tape(inode, mtc.mt_count)) < 0*/) {
4841                                retval = i;
4842                                goto out;
4843                        }
4844                        for (i=0; i < ST_NBR_PARTITIONS; i++) {
4845                                STp->ps[i].rw = ST_IDLE;
4846                                STp->ps[i].at_sm = 0;
4847                                STp->ps[i].last_block_valid = FALSE;
4848                        }
4849                        STp->partition = STp->new_partition = 0;
4850                        STp->nbr_partitions = 1;  /* Bad guess ?-) */
4851                        STps->drv_block = STps->drv_file = 0;
4852                        retval = 0;
4853                        goto out;
4854                }
4855
4856                if (mtc.mt_op == MTSEEK) {
4857                        if (STp->raw)
4858                                i = osst_set_frame_position(STp, &SRpnt, mtc.mt_count, 0);
4859                        else
4860                                i = osst_seek_sector(STp, &SRpnt, mtc.mt_count);
4861                        if (!STp->can_partitions)
4862                                STp->ps[0].rw = ST_IDLE;
4863                        retval = i;
4864                        goto out;
4865                }
4866
4867/*   if (STp->can_partitions && STp->ready == ST_READY &&
4868         (i = update_partition(inode)) < 0)
4869                 {retval=i;goto out;}*/
4870
4871                if (mtc.mt_op == MTCOMPRESSION)
4872                        retval = -EINVAL /*osst_compression(STp, (mtc.mt_count & 1))*/;
4873                else
4874
4875                        retval = osst_int_ioctl(STp, &SRpnt, mtc.mt_op, mtc.mt_count);
4876                goto out;
4877        }
4878
4879        if (!STm->defined) {
4880                retval = (-ENXIO);
4881                goto out;
4882        }
4883
4884        if ((i = osst_flush_buffer(STp, &SRpnt, FALSE)) < 0) {
4885                retval = i;
4886                goto out;
4887        }
4888
4889/* if (STp->can_partitions &&
4890                 (i = update_partition(inode)) < 0)
4891         {retval=i;goto out;}*/
4892
4893        if (cmd_type == _IOC_TYPE(MTIOCGET) && cmd_nr == _IOC_NR(MTIOCGET)) {
4894                struct mtget mt_status;
4895
4896                if (_IOC_SIZE(cmd_in) != sizeof(struct mtget)) {
4897                         retval = (-EINVAL);
4898                         goto out;
4899                }
4900
4901                mt_status.mt_type = MT_ISONSTREAM_SC;
4902                mt_status.mt_erreg = STp->recover_erreg << MT_ST_SOFTERR_SHIFT;
4903                mt_status.mt_dsreg =
4904                        ((STp->block_size << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK) |
4905                        ((STp->density    << MT_ST_DENSITY_SHIFT) & MT_ST_DENSITY_MASK);
4906                mt_status.mt_blkno = STps->drv_block;
4907                mt_status.mt_fileno = STps->drv_file;
4908                if (STp->block_size != 0) {
4909                        if (STps->rw == ST_WRITING)
4910                                mt_status.mt_blkno += (STp->buffer)->buffer_bytes / STp->block_size;
4911                        else if (STps->rw == ST_READING)
4912                                mt_status.mt_blkno -= ((STp->buffer)->buffer_bytes +
4913                                                        STp->block_size - 1) / STp->block_size;
4914                }
4915
4916                mt_status.mt_gstat = 0;
4917                if (STp->drv_write_prot)
4918                        mt_status.mt_gstat |= GMT_WR_PROT(0xffffffff);
4919                if (mt_status.mt_blkno == 0) {
4920                        if (mt_status.mt_fileno == 0)
4921                                mt_status.mt_gstat |= GMT_BOT(0xffffffff);
4922                        else
4923                                mt_status.mt_gstat |= GMT_EOF(0xffffffff);
4924                }
4925                mt_status.mt_resid = STp->partition;
4926                if (STps->eof == ST_EOM_OK || STps->eof == ST_EOM_ERROR)
4927                        mt_status.mt_gstat |= GMT_EOT(0xffffffff);
4928                else if (STps->eof >= ST_EOM_OK)
4929                        mt_status.mt_gstat |= GMT_EOD(0xffffffff);
4930                if (STp->density == 1)
4931                        mt_status.mt_gstat |= GMT_D_800(0xffffffff);
4932                else if (STp->density == 2)
4933                        mt_status.mt_gstat |= GMT_D_1600(0xffffffff);
4934                else if (STp->density == 3)
4935                        mt_status.mt_gstat |= GMT_D_6250(0xffffffff);
4936                if (STp->ready == ST_READY)
4937                        mt_status.mt_gstat |= GMT_ONLINE(0xffffffff);
4938                if (STp->ready == ST_NO_TAPE)
4939                        mt_status.mt_gstat |= GMT_DR_OPEN(0xffffffff);
4940                if (STps->at_sm)
4941                        mt_status.mt_gstat |= GMT_SM(0xffffffff);
4942                if (STm->do_async_writes || (STm->do_buffer_writes && STp->block_size != 0) ||
4943                    STp->drv_buffer != 0)
4944                        mt_status.mt_gstat |= GMT_IM_REP_EN(0xffffffff);
4945
4946                i = copy_to_user((char *)arg, (char *)&mt_status,
4947                      sizeof(struct mtget));
4948                if (i) {
4949                        retval = (-EFAULT);
4950                        goto out;
4951                }
4952
4953                STp->recover_erreg = 0;  /* Clear after read */
4954                retval = 0;
4955                goto out;
4956        } /* End of MTIOCGET */
4957
4958        if (cmd_type == _IOC_TYPE(MTIOCPOS) && cmd_nr == _IOC_NR(MTIOCPOS)) {
4959                struct mtpos mt_pos;
4960
4961                if (_IOC_SIZE(cmd_in) != sizeof(struct mtpos)) {
4962                        retval = (-EINVAL);
4963                        goto out;
4964                }
4965                if (STp->raw)
4966                        blk = osst_get_frame_position(STp, &SRpnt);
4967                else
4968                        blk = osst_get_sector(STp, &SRpnt);
4969                if (blk < 0) {
4970                        retval = blk;
4971                        goto out;
4972                }
4973                mt_pos.mt_blkno = blk;
4974                i = copy_to_user((char *)arg, (char *) (&mt_pos), sizeof(struct mtpos));
4975                if (i)
4976                        retval = -EFAULT;
4977                goto out;
4978        }
4979        if (SRpnt) scsi_release_request(SRpnt);
4980
4981        up(&STp->lock);
4982
4983        return scsi_ioctl(STp->device, cmd_in, (void *) arg);
4984
4985out:
4986        if (SRpnt) scsi_release_request(SRpnt);
4987
4988        up(&STp->lock);
4989
4990        return retval;
4991}
4992
4993
4994/* Memory handling routines */
4995
4996/* Try to allocate a new tape buffer */
4997static OSST_buffer * new_tape_buffer( int from_initialization, int need_dma )
4998{
4999        int i, priority, b_size, order, got = 0, segs = 0;
5000        OSST_buffer *tb;
5001
5002        if (osst_nbr_buffers >= osst_template.dev_max)
5003                return NULL;  /* Should never happen */
5004
5005        if (from_initialization)
5006                priority = GFP_ATOMIC;
5007        else
5008                priority = GFP_KERNEL;
5009
5010        i = sizeof(OSST_buffer) + (osst_max_sg_segs - 1) * sizeof(struct scatterlist);
5011        tb = (OSST_buffer *)kmalloc(i, priority);
5012        if (tb) {
5013//    tb->this_size = i;
5014                if (need_dma)
5015                        priority |= GFP_DMA;
5016
5017                /* Try to allocate the first segment up to OSST_FIRST_ORDER and the
5018                 others big enough to reach the goal */
5019                for (b_size = PAGE_SIZE,          order = 0;
5020                     b_size < osst_buffer_size && order < OSST_FIRST_ORDER;
5021                     b_size *= 2,                 order++ );
5022
5023                for ( ; b_size >= PAGE_SIZE; order--, b_size /= 2) {
5024                        tb->sg[0].address =
5025                            (unsigned char *)__get_free_pages(priority, order);
5026                        if (tb->sg[0].address != NULL) {
5027                            tb->sg[0].page = NULL;
5028                            tb->sg[0].length = b_size;
5029                            break;
5030                        }
5031                }
5032                if (tb->sg[segs].address == NULL) {
5033                        kfree(tb);
5034                        tb = NULL;
5035                }
5036                else {  /* Got something, continue */
5037
5038                        for (b_size = PAGE_SIZE, order = 0;
5039                             osst_buffer_size > tb->sg[0].length + (OSST_FIRST_SG - 1) * b_size;
5040                             b_size *= 2, order++ );
5041
5042                        for (segs=1, got=tb->sg[0].length;
5043                             got < osst_buffer_size && segs < OSST_FIRST_SG; ) {
5044                            tb->sg[segs].address =
5045                                (unsigned char *)__get_free_pages(priority, order);
5046                            if (tb->sg[segs].address == NULL) {
5047                                if (osst_buffer_size - got <=
5048                                    (OSST_FIRST_SG - segs) * b_size / 2) {
5049                                    b_size /= 2; /* Large enough for the rest of the buffers */
5050                                    order--;
5051                                    continue;
5052                                }
5053                                tb->sg_segs = segs;
5054                                tb->orig_sg_segs = 0;
5055#if DEBUG
5056                                tb->buffer_size = got;
5057#endif
5058                                normalize_buffer(tb);
5059                                kfree(tb);
5060                                tb = NULL;
5061                                break;
5062                            }
5063                            tb->sg[segs].page = NULL;
5064                            tb->sg[segs].length = b_size;
5065                            got += b_size;
5066                            segs++;
5067                        }
5068                }
5069        }
5070        if (!tb) {
5071                printk(KERN_NOTICE "osst :I: Can't allocate new tape buffer (nbr %d).\n",
5072                                   osst_nbr_buffers);
5073                return NULL;
5074        }
5075        tb->sg_segs = tb->orig_sg_segs = segs;
5076        tb->b_data = tb->sg[0].address;
5077
5078#if DEBUG
5079        if (debugging) {
5080                printk(OSST_DEB_MSG
5081                        "osst :D: Allocated tape buffer %d (%d bytes, %d segments, dma: %d, a: %p).\n",
5082                           osst_nbr_buffers, got, tb->sg_segs, need_dma, tb->b_data);
5083                printk(OSST_DEB_MSG
5084                        "osst :D: segment sizes: first %d, last %d bytes.\n",
5085                           tb->sg[0].length, tb->sg[segs-1].length);
5086        }
5087#endif
5088        tb->in_use = 0;
5089        tb->dma = need_dma;
5090        tb->buffer_size = got;
5091        tb->writing = 0;
5092        osst_buffers[osst_nbr_buffers++] = tb;
5093
5094        return tb;
5095}
5096
5097
5098/* Try to allocate a temporary enlarged tape buffer */
5099static int enlarge_buffer(OSST_buffer *STbuffer, int new_size, int need_dma)
5100{
5101        int segs, nbr, max_segs, b_size, priority, order, got;
5102
5103        normalize_buffer(STbuffer);
5104
5105        max_segs = STbuffer->use_sg;
5106        if (max_segs > osst_max_sg_segs)
5107                max_segs = osst_max_sg_segs;
5108        nbr = max_segs - STbuffer->sg_segs;
5109        if (nbr <= 0)
5110                return FALSE;
5111
5112        priority = GFP_KERNEL;
5113        if (need_dma)
5114                priority |= GFP_DMA;
5115        for (b_size = PAGE_SIZE, order = 0;
5116                 b_size * nbr < new_size - STbuffer->buffer_size;
5117                 b_size *= 2, order++);
5118
5119        for (segs=STbuffer->sg_segs, got=STbuffer->buffer_size;
5120             segs < max_segs && got < new_size; ) {
5121                STbuffer->sg[segs].address =
5122                          (unsigned char *)__get_free_pages(priority, order);
5123                if (STbuffer->sg[segs].address == NULL) {
5124                        if (new_size - got <= (max_segs - segs) * b_size / 2) {
5125                                b_size /= 2;  /* Large enough for the rest of the buffers */
5126                                order--;
5127                                continue;
5128                        }
5129                        printk(KERN_WARNING "osst :W: Failed to enlarge buffer to %d bytes.\n",
5130                                                new_size);
5131#if DEBUG
5132                        STbuffer->buffer_size = got;
5133#endif
5134                        normalize_buffer(STbuffer);
5135                        return FALSE;
5136                }
5137                STbuffer->sg[segs].page = NULL;
5138                STbuffer->sg[segs].length = b_size;
5139                STbuffer->sg_segs += 1;
5140                got += b_size;
5141                STbuffer->buffer_size = got;
5142                segs++;
5143        }
5144#if DEBUG
5145        if (debugging) {
5146                for (nbr=0; osst_buffers[nbr] != STbuffer && nbr < osst_nbr_buffers; nbr++);
5147                        printk(OSST_DEB_MSG
5148                           "osst :D: Expanded tape buffer %d (%d bytes, %d->%d segments, dma: %d, a: %p).\n",
5149                           nbr, got, STbuffer->orig_sg_segs, STbuffer->sg_segs, need_dma, STbuffer->b_data);
5150                        printk(OSST_DEB_MSG
5151                           "osst :D: segment sizes: first %d, last %d bytes.\n",
5152                           STbuffer->sg[0].length, STbuffer->sg[segs-1].length);
5153        }
5154#endif
5155
5156        return TRUE;
5157}
5158
5159
5160/* Release the extra buffer */
5161static void normalize_buffer(OSST_buffer *STbuffer)
5162{
5163  int i, order, b_size;
5164
5165        for (i=STbuffer->orig_sg_segs; i < STbuffer->sg_segs; i++) {
5166
5167                for (b_size = PAGE_SIZE, order = 0;
5168                     b_size < STbuffer->sg[i].length;
5169                     b_size *= 2, order++);
5170
5171                free_pages((unsigned long)STbuffer->sg[i].address, order);
5172                STbuffer->buffer_size -= STbuffer->sg[i].length;
5173        }
5174#if DEBUG
5175        if (debugging && STbuffer->orig_sg_segs < STbuffer->sg_segs)
5176                printk(OSST_DEB_MSG "osst :D: Buffer at %p normalized to %d bytes (segs %d).\n",
5177                             STbuffer->b_data, STbuffer->buffer_size, STbuffer->sg_segs);
5178#endif
5179        STbuffer->sg_segs = STbuffer->orig_sg_segs;
5180}
5181
5182
5183/* Move data from the user buffer to the tape buffer. Returns zero (success) or
5184   negative error code. */
5185static int append_to_buffer(const char *ubp, OSST_buffer *st_bp, int do_count)
5186{
5187        int i, cnt, res, offset;
5188
5189        for (i=0, offset=st_bp->buffer_bytes;
5190             i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++)
5191        offset -= st_bp->sg[i].length;
5192        if (i == st_bp->sg_segs) {  /* Should never happen */
5193                printk(KERN_WARNING "osst :A: Append_to_buffer offset overflow.\n");
5194                return (-EIO);
5195        }
5196        for ( ; i < st_bp->sg_segs && do_count > 0; i++) {
5197                cnt = st_bp->sg[i].length - offset < do_count ?
5198                      st_bp->sg[i].length - offset : do_count;
5199                res = copy_from_user(st_bp->sg[i].address + offset, ubp, cnt);
5200                if (res)
5201                        return (-EFAULT);
5202                do_count -= cnt;
5203                st_bp->buffer_bytes += cnt;
5204                ubp += cnt;
5205                offset = 0;
5206        }
5207        if (do_count) {  /* Should never happen */
5208                printk(KERN_WARNING "osst :A: Append_to_buffer overflow (left %d).\n",
5209                       do_count);
5210                return (-EIO);
5211        }
5212        return 0;
5213}
5214
5215
5216/* Move data from the tape buffer to the user buffer. Returns zero (success) or
5217   negative error code. */
5218static int from_buffer(OSST_buffer *st_bp, char *ubp, int do_count)
5219{
5220        int i, cnt, res, offset;
5221
5222        for (i=0, offset=st_bp->read_pointer;
5223             i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++)
5224                offset -= st_bp->sg[i].length;
5225        if (i == st_bp->sg_segs) {  /* Should never happen */
5226                printk(KERN_WARNING "osst :A: From_buffer offset overflow.\n");
5227                return (-EIO);
5228        }
5229        for ( ; i < st_bp->sg_segs && do_count > 0; i++) {
5230                cnt = st_bp->sg[i].length - offset < do_count ?
5231                      st_bp->sg[i].length - offset : do_count;
5232                res = copy_to_user(ubp, st_bp->sg[i].address + offset, cnt);
5233                if (res)
5234                        return (-EFAULT);
5235                do_count -= cnt;
5236                st_bp->buffer_bytes -= cnt;
5237                st_bp->read_pointer += cnt;
5238                ubp += cnt;
5239                offset = 0;
5240        }
5241        if (do_count) {  /* Should never happen */
5242                printk(KERN_WARNING "osst :A: From_buffer overflow (left %d).\n", do_count);
5243                return (-EIO);
5244        }
5245        return 0;
5246}
5247
5248/* Sets the tail of the buffer after fill point to zero.
5249   Returns zero (success) or negative error code.        */
5250static int osst_zero_buffer_tail(OSST_buffer *st_bp)
5251{
5252        int     i, offset, do_count, cnt;
5253
5254        for (i = 0, offset = st_bp->buffer_bytes;
5255             i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++)
5256                offset -= st_bp->sg[i].length;
5257        if (i == st_bp->sg_segs) {  /* Should never happen */
5258                printk(KERN_WARNING "osst :A: Zero_buffer offset overflow.\n");
5259                return (-EIO);
5260        }
5261        for (do_count = OS_DATA_SIZE - st_bp->buffer_bytes;
5262             i < st_bp->sg_segs && do_count > 0; i++) {
5263                cnt = st_bp->sg[i].length - offset < do_count ?
5264                      st_bp->sg[i].length - offset : do_count ;
5265                memset(st_bp->sg[i].address + offset, 0, cnt);
5266                do_count -= cnt;
5267                offset = 0;
5268        }
5269        if (do_count) {  /* Should never happen */
5270                printk(KERN_WARNING "osst :A: Zero_buffer overflow (left %d).\n", do_count);
5271                return (-EIO);
5272        }
5273        return 0;
5274}
5275
5276/* Copy a osst 32K chunk of memory into the buffer.
5277   Returns zero (success) or negative error code.  */
5278static int osst_copy_to_buffer(OSST_buffer *st_bp, unsigned char *ptr)
5279{
5280        int     i, cnt, do_count = OS_DATA_SIZE;
5281
5282        for (i = 0; i < st_bp->sg_segs && do_count > 0; i++) {
5283                cnt = st_bp->sg[i].length < do_count ?
5284                      st_bp->sg[i].length : do_count ;
5285                memcpy(st_bp->sg[i].address, ptr, cnt);
5286                do_count -= cnt;
5287                ptr      += cnt;
5288        }
5289        if (do_count || i != st_bp->sg_segs-1) {  /* Should never happen */
5290                printk(KERN_WARNING "osst :A: Copy_to_buffer overflow (left %d at sg %d).\n",
5291                                         do_count, i);
5292                return (-EIO);
5293        }
5294        return 0;
5295}
5296
5297/* Copy a osst 32K chunk of memory from the buffer.
5298   Returns zero (success) or negative error code.  */
5299static int osst_copy_from_buffer(OSST_buffer *st_bp, unsigned char *ptr)
5300{
5301        int     i, cnt, do_count = OS_DATA_SIZE;
5302
5303        for (i = 0; i < st_bp->sg_segs && do_count > 0; i++) {
5304                cnt = st_bp->sg[i].length < do_count ?
5305                      st_bp->sg[i].length : do_count ;
5306                memcpy(ptr, st_bp->sg[i].address, cnt);
5307                do_count -= cnt;
5308                ptr      += cnt;
5309        }
5310        if (do_count || i != st_bp->sg_segs-1) {  /* Should never happen */
5311                printk(KERN_WARNING "osst :A: Copy_from_buffer overflow (left %d at sg %d).\n",
5312                                         do_count, i);
5313                return (-EIO);
5314        }
5315        return 0;
5316}
5317
5318
5319/* Module housekeeping */
5320
5321static void validate_options (void)
5322{
5323  if (buffer_kbs > 0)
5324                osst_buffer_size = buffer_kbs * ST_KILOBYTE;
5325  if (write_threshold_kbs > 0)
5326                osst_write_threshold = write_threshold_kbs * ST_KILOBYTE;
5327  if (osst_write_threshold > osst_buffer_size)
5328                osst_write_threshold = osst_buffer_size;
5329  if (max_buffers > 0)
5330                osst_max_buffers = max_buffers;
5331  if (max_sg_segs >= OSST_FIRST_SG)
5332                osst_max_sg_segs = max_sg_segs;
5333#if DEBUG
5334  printk(OSST_DEB_MSG "osst :D: bufsize %d, wrt %d, max buffers %d, s/g segs %d.\n",
5335         osst_buffer_size, osst_write_threshold, osst_max_buffers, osst_max_sg_segs);
5336//printk(OSST_DEB_MSG "osst :D: sizeof(header) = %d (%s)\n",
5337//              sizeof(os_header_t),sizeof(os_header_t)==OS_DATA_SIZE?"ok":"error");
5338#endif
5339}
5340        
5341#ifndef MODULE
5342/* Set the boot options. Syntax: osst=xxx,yyy,...
5343   where xxx is buffer size in 1024 byte blocks and yyy is write threshold
5344   in 1024 byte blocks. */
5345static int __init osst_setup (char *str)
5346{
5347  int i, ints[5];
5348  char *stp;
5349
5350  stp = get_options(str, ARRAY_SIZE(ints), ints);
5351        
5352  if (ints[0] > 0) {
5353        for (i = 0; i < ints[0] && i < ARRAY_SIZE(parms); i++)
5354                  *parms[i].val = ints[i + 1];
5355  } else {
5356        while (stp != NULL) {
5357                for (i = 0; i < ARRAY_SIZE(parms); i++) {
5358                        int len = strlen(parms[i].name);
5359                        if (!strncmp(stp, parms[i].name, len) &&
5360                            (*(stp + len) == ':' || *(stp + len) == '=')) {
5361                                *parms[i].val =
5362                                        simple_strtoul(stp + len + 1, NULL, 0);
5363                                break;
5364                        }
5365                }
5366                if (i >= sizeof(parms) / sizeof(struct osst_dev_parm))
5367                        printk(KERN_INFO "osst :I: Illegal parameter in '%s'\n",
5368                               stp);
5369                stp = strchr(stp, ',');
5370                if (stp)
5371                        stp++;
5372        }
5373  }
5374
5375  return 1;
5376}
5377
5378__setup("osst=", osst_setup);
5379
5380#endif
5381
5382
5383static struct file_operations osst_fops = {
5384        read:           osst_read,
5385        write:          osst_write,
5386        ioctl:          osst_ioctl,
5387        open:           os_scsi_tape_open,
5388        flush:          os_scsi_tape_flush,
5389        release:        os_scsi_tape_close,
5390};
5391
5392static int osst_supports(Scsi_Device * SDp)
5393{
5394        struct  osst_support_data {
5395                char *vendor;
5396                char *model;
5397                char *rev;
5398                char *driver_hint; /* Name of the correct driver, NULL if unknown */
5399        };
5400
5401static  struct  osst_support_data support_list[] = {
5402                /* {"XXX", "Yy-", "", NULL},  example */
5403                SIGS_FROM_OSST,
5404                {NULL, }};
5405
5406        struct  osst_support_data *rp;
5407
5408        /* We are willing to drive OnStream SC-x0 as well as the
5409         *       * IDE, ParPort, FireWire, USB variants, if accessible by
5410         *               * emulation layer (ide-scsi, usb-storage, ...) */
5411
5412        for (rp=&(support_list[0]); rp->vendor != NULL; rp++)
5413                if (!strncmp(rp->vendor, SDp->vendor, strlen(rp->vendor)) &&
5414                    !strncmp(rp->model, SDp->model, strlen(rp->model)) &&
5415                    !strncmp(rp->rev, SDp->rev, strlen(rp->rev))) 
5416                        return 1;
5417        return 0;
5418}
5419
5420static int osst_attach(Scsi_Device * SDp)
5421{
5422        OS_Scsi_Tape * tpnt;
5423        ST_mode * STm;
5424        ST_partstat * STps;
5425        int i, dev;
5426#ifdef CONFIG_DEVFS_FS
5427        int mode;
5428#endif
5429
5430        if (SDp->type != TYPE_TAPE || !osst_supports(SDp))
5431                 return 1;
5432
5433        if (osst_template.nr_dev >= osst_template.dev_max) {
5434                 SDp->attached--;
5435                 return 1;
5436        }
5437        
5438        /* find a free minor number */
5439        for (i=0; os_scsi_tapes[i] && i<osst_template.dev_max; i++);
5440        if(i >= osst_template.dev_max) panic ("Scsi_devices corrupt (osst)");
5441
5442        /* allocate a OS_Scsi_Tape for this device */
5443        tpnt = (OS_Scsi_Tape *)kmalloc(sizeof(OS_Scsi_Tape), GFP_ATOMIC);
5444        if (tpnt == NULL) {
5445                 SDp->attached--;
5446                 printk(KERN_WARNING "osst :W: Can't allocate device descriptor.\n");
5447                 return 1;
5448        }
5449        memset(tpnt, 0, sizeof(OS_Scsi_Tape));
5450        os_scsi_tapes[i] = tpnt;
5451        dev = i;
5452        tpnt->capacity = 0xfffff;
5453
5454        /* allocate a buffer for this device */
5455        if (!new_tape_buffer(TRUE, TRUE)) 
5456                 printk(KERN_ERR "osst :W: Unable to allocate a tape buffer.\n");
5457
5458#ifdef CONFIG_DEVFS_FS
5459        for (mode = 0; mode < ST_NBR_MODES; ++mode) {
5460                 char name[8];
5461                 static char *formats[ST_NBR_MODES] ={"", "l", "m", "a"};
5462
5463                 /*  Rewind entry  */
5464                 sprintf (name, "mt%s", formats[mode]);
5465# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
5466                 tpnt->de_r[mode] =
5467                        devfs_register (SDp->de, name, DEVFS_FL_DEFAULT,
5468                           MAJOR_NR, i + (mode << 5),
5469                           S_IFCHR | S_IRUGO | S_IWUGO,
5470                           &osst_fops, NULL);
5471# else
5472                 tpnt->de_r[mode] =
5473                        devfs_register (SDp->de, name, 0, DEVFS_FL_DEFAULT,
5474                           MAJOR_NR, i + (mode << 5),
5475                           S_IFCHR | S_IRUGO | S_IWUGO,
5476                           0, 0, &osst_fops, NULL);
5477# endif         
5478                 /*  No-rewind entry  */
5479                 sprintf (name, "mt%sn", formats[mode]);
5480# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
5481                 tpnt->de_n[mode] =
5482                        devfs_register (SDp->de, name, DEVFS_FL_DEFAULT,
5483                           MAJOR_NR, i + (mode << 5) + 128,
5484                           S_IFCHR | S_IRUGO | S_IWUGO,
5485                           &osst_fops, NULL);
5486# else          
5487                 tpnt->de_n[mode] =
5488                        devfs_register (SDp->de, name, 0, DEVFS_FL_DEFAULT,
5489                           MAJOR_NR, i + (mode << 5) + 128,
5490                           S_IFCHR | S_IRUGO | S_IWUGO,
5491                           0, 0, &osst_fops, NULL);
5492# endif
5493        }
5494        devfs_register_tape (tpnt->de_r[0]);
5495#endif
5496
5497        tpnt->device = SDp;
5498        tpnt->devt = MKDEV(MAJOR_NR, i);
5499        tpnt->dirty = 0;
5500        tpnt->in_use = 0;
5501        tpnt->drv_buffer = 1;  /* Try buffering if no mode sense */
5502        tpnt->restr_dma = (SDp->host)->unchecked_isa_dma;
5503        tpnt->density = 0;
5504        tpnt->do_auto_lock = OSST_AUTO_LOCK;
5505        tpnt->can_bsr = OSST_IN_FILE_POS;
5506        tpnt->can_partitions = 0;
5507        tpnt->two_fm = OSST_TWO_FM;
5508        tpnt->fast_mteom = OSST_FAST_MTEOM;
5509        tpnt->scsi2_logical = OSST_SCSI2LOGICAL; /* FIXME */
5510        tpnt->write_threshold = osst_write_threshold;
5511        tpnt->default_drvbuffer = 0xff; /* No forced buffering */
5512        tpnt->partition = 0;
5513        tpnt->new_partition = 0;
5514        tpnt->nbr_partitions = 0;
5515        tpnt->min_block = 512;
5516        tpnt->max_block = OS_DATA_SIZE;
5517        tpnt->timeout = OSST_TIMEOUT;
5518        tpnt->long_timeout = OSST_LONG_TIMEOUT;
5519
5520        /* Recognize OnStream tapes */
5521        /* We don't need to test for OnStream, as this has been done in detect () */
5522        tpnt->os_fw_rev = osst_parse_firmware_rev (SDp->rev);
5523        tpnt->omit_blklims = 1;
5524
5525        tpnt->poll = (strncmp(SDp->model, "DI-", 3) == 0) || OSST_FW_NEED_POLL(tpnt->os_fw_rev,SDp);
5526        tpnt->frame_in_buffer = 0;
5527        tpnt->header_ok = 0;
5528        tpnt->linux_media = 0;
5529        tpnt->header_cache = NULL;
5530
5531        for (i=0; i < ST_NBR_MODES; i++) {
5532                STm = &(tpnt->modes[i]);
5533                STm->defined = FALSE;
5534                STm->sysv = OSST_SYSV;
5535                STm->defaults_for_writes = 0;
5536                STm->do_async_writes = OSST_ASYNC_WRITES;
5537                STm->do_buffer_writes = OSST_BUFFER_WRITES;
5538                STm->do_read_ahead = OSST_READ_AHEAD;
5539                STm->default_compression = ST_DONT_TOUCH;
5540                STm->default_blksize = 512;
5541                STm->default_density = (-1);  /* No forced density */
5542        }
5543
5544        for (i=0; i < ST_NBR_PARTITIONS; i++) {
5545                STps = &(tpnt->ps[i]);
5546                STps->rw = ST_IDLE;
5547                STps->eof = ST_NOEOF;
5548                STps->at_sm = 0;
5549                STps->last_block_valid = FALSE;
5550                STps->drv_block = (-1);
5551                STps->drv_file = (-1);
5552        }
5553
5554        tpnt->current_mode = 0;
5555        tpnt->modes[0].defined = TRUE;
5556        tpnt->modes[2].defined = TRUE;
5557        tpnt->density_changed = tpnt->compression_changed = tpnt->blksize_changed = FALSE;
5558        init_MUTEX(&tpnt->lock);
5559
5560        osst_template.nr_dev++;
5561
5562        printk(KERN_INFO
5563                "osst :I: Attached OnStream %.5s tape at scsi%d, channel %d, id %d, lun %d as osst%d\n",
5564                SDp->model, SDp->host->host_no, SDp->channel, SDp->id, SDp->lun, dev);
5565
5566        return 0;
5567};
5568
5569static int osst_detect(Scsi_Device * SDp)
5570{
5571        if (SDp->type != TYPE_TAPE) return 0;
5572        if ( ! osst_supports(SDp) ) return 0;
5573        
5574        osst_template.dev_noticed++;
5575        return 1;
5576}
5577
5578static int osst_registered = 0;
5579
5580/* Driver initialization (not __initfunc because may be called later) */
5581static int osst_init()
5582{
5583  int i;
5584
5585  if (osst_template.dev_noticed == 0) return 0;
5586
5587  if(!osst_registered) {
5588#ifdef CONFIG_DEVFS_FS
5589        if (devfs_register_chrdev(MAJOR_NR,"osst",&osst_fops)) {
5590#else
5591        if (register_chrdev(MAJOR_NR,"osst",&osst_fops)) {
5592#endif
5593                printk(KERN_ERR "osst :W: Unable to get major %d for OnStream tapes\n",MAJOR_NR);
5594                return 1;
5595        }
5596        osst_registered++;
5597  }
5598  
5599  if (os_scsi_tapes) return 0;
5600  osst_template.dev_max = OSST_MAX_TAPES;
5601  if (osst_template.dev_max > 128 / ST_NBR_MODES)
5602        printk(KERN_INFO "osst :I: Only %d tapes accessible.\n", 128 / ST_NBR_MODES);
5603  os_scsi_tapes =
5604        (OS_Scsi_Tape **)kmalloc(osst_template.dev_max * sizeof(OS_Scsi_Tape *),
5605                                   GFP_ATOMIC);
5606  if (os_scsi_tapes == NULL) {
5607        printk(KERN_ERR "osst :W: Unable to allocate array for OnStream SCSI tapes.\n");
5608#ifdef CONFIG_DEVFS_FS
5609        devfs_unregister_chrdev(MAJOR_NR, "osst");
5610#else
5611        unregister_chrdev(MAJOR_NR, "osst");
5612#endif
5613        return 1;
5614  }
5615
5616  for (i=0; i < osst_template.dev_max; ++i) os_scsi_tapes[i] = NULL;
5617
5618  /* Allocate the buffer pointers */
5619  osst_buffers =
5620        (OSST_buffer **)kmalloc(osst_template.dev_max * sizeof(OSST_buffer *),
5621                                    GFP_ATOMIC);
5622  if (osst_buffers == NULL) {
5623        printk(KERN_ERR "osst :W: Unable to allocate tape buffer pointers.\n");
5624#ifdef CONFIG_DEVFS_FS
5625        devfs_unregister_chrdev(MAJOR_NR, "osst");
5626#else
5627        unregister_chrdev(MAJOR_NR, "osst");
5628#endif
5629        kfree(os_scsi_tapes);
5630        return 1;
5631  }
5632  osst_nbr_buffers = 0;
5633
5634  printk(KERN_INFO "osst :I: Tape driver with OnStream support version %s\nosst :I: %s\n", osst_version, cvsid);
5635
5636#if DEBUG
5637  printk(OSST_DEB_MSG "osst :D: Buffer size %d bytes, write threshold %d bytes.\n",
5638         osst_buffer_size, osst_write_threshold);
5639#endif
5640  return 0;
5641}
5642
5643
5644static void osst_detach(Scsi_Device * SDp)
5645{
5646  OS_Scsi_Tape * tpnt;
5647  int i;
5648#ifdef CONFIG_DEVFS_FS
5649  int mode;
5650#endif
5651
5652  for(i=0; i<osst_template.dev_max; i++) {
5653        tpnt = os_scsi_tapes[i];
5654        if(tpnt != NULL && tpnt->device == SDp) {
5655                tpnt->device = NULL;
5656#ifdef CONFIG_DEVFS_FS
5657                for (mode = 0; mode < ST_NBR_MODES; ++mode) {
5658          devfs_unregister (tpnt->de_r[mode]);
5659          tpnt->de_r[mode] = NULL;
5660          devfs_unregister (tpnt->de_n[mode]);
5661          tpnt->de_n[mode] = NULL;
5662                }
5663#endif
5664                kfree(tpnt);
5665                os_scsi_tapes[i] = NULL;
5666                SDp->attached--;
5667                osst_template.nr_dev--;
5668                osst_template.dev_noticed--;
5669                return;
5670        }
5671  }
5672  return;
5673}
5674
5675static int __init init_osst(void) 
5676{
5677        validate_options();
5678        osst_template.module = THIS_MODULE;
5679        return scsi_register_module(MODULE_SCSI_DEV, &osst_template);
5680}
5681
5682static void __exit exit_osst (void)
5683{
5684  int i;
5685  OS_Scsi_Tape * STp;
5686
5687  scsi_unregister_module(MODULE_SCSI_DEV, &osst_template);
5688#ifdef CONFIG_DEVFS_FS
5689  devfs_unregister_chrdev(MAJOR_NR, "osst");
5690#else
5691  unregister_chrdev(MAJOR_NR, "osst");
5692#endif
5693  osst_registered--;
5694  if(os_scsi_tapes != NULL) {
5695        for (i=0; i < osst_template.dev_max; ++i) {
5696                if ((STp = os_scsi_tapes[i])) {
5697        if (STp->header_cache != NULL) vfree(STp->header_cache);
5698        kfree(STp);
5699                }
5700        }
5701        kfree(os_scsi_tapes);
5702
5703        if (osst_buffers != NULL) {
5704                for (i=0; i < osst_nbr_buffers; i++)
5705        if (osst_buffers[i] != NULL) {
5706          osst_buffers[i]->orig_sg_segs = 0;
5707          normalize_buffer(osst_buffers[i]);
5708          kfree(osst_buffers[i]);
5709        }
5710
5711                kfree(osst_buffers);
5712        }
5713  }
5714  osst_template.dev_max = 0;
5715  printk(KERN_INFO "osst :I: Unloaded.\n");
5716}
5717
5718module_init(init_osst);
5719module_exit(exit_osst);
5720
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.