linux/drivers/s390/char/tape_std.c
<<
>>
Prefs
   1/*
   2 *  drivers/s390/char/tape_std.c
   3 *    standard tape device functions for ibm tapes.
   4 *
   5 *  S390 and zSeries version
   6 *    Copyright (C) 2001,2002 IBM Deutschland Entwicklung GmbH, IBM Corporation
   7 *    Author(s): Carsten Otte <cotte@de.ibm.com>
   8 *               Michael Holzheu <holzheu@de.ibm.com>
   9 *               Tuan Ngo-Anh <ngoanh@de.ibm.com>
  10 *               Martin Schwidefsky <schwidefsky@de.ibm.com>
  11 *               Stefan Bader <shbader@de.ibm.com>
  12 */
  13
  14#include <linux/stddef.h>
  15#include <linux/kernel.h>
  16#include <linux/bio.h>
  17#include <linux/timer.h>
  18
  19#include <asm/types.h>
  20#include <asm/idals.h>
  21#include <asm/ebcdic.h>
  22#include <asm/tape390.h>
  23
  24#define TAPE_DBF_AREA   tape_core_dbf
  25
  26#include "tape.h"
  27#include "tape_std.h"
  28
  29#define PRINTK_HEADER "TAPE_STD: "
  30
  31/*
  32 * tape_std_assign
  33 */
  34static void
  35tape_std_assign_timeout(unsigned long data)
  36{
  37        struct tape_request *   request;
  38        struct tape_device *    device;
  39        int rc;
  40
  41        request = (struct tape_request *) data;
  42        if ((device = request->device) == NULL)
  43                BUG();
  44
  45        DBF_EVENT(3, "%08x: Assignment timeout. Device busy.\n",
  46                        device->cdev_id);
  47        rc = tape_cancel_io(device, request);
  48        if(rc)
  49                PRINT_ERR("(%s): Assign timeout: Cancel failed with rc = %i\n",
  50                        dev_name(&device->cdev->dev), rc);
  51
  52}
  53
  54int
  55tape_std_assign(struct tape_device *device)
  56{
  57        int                  rc;
  58        struct timer_list    timeout;
  59        struct tape_request *request;
  60
  61        request = tape_alloc_request(2, 11);
  62        if (IS_ERR(request))
  63                return PTR_ERR(request);
  64
  65        request->op = TO_ASSIGN;
  66        tape_ccw_cc(request->cpaddr, ASSIGN, 11, request->cpdata);
  67        tape_ccw_end(request->cpaddr + 1, NOP, 0, NULL);
  68
  69        /*
  70         * The assign command sometimes blocks if the device is assigned
  71         * to another host (actually this shouldn't happen but it does).
  72         * So we set up a timeout for this call.
  73         */
  74        init_timer(&timeout);
  75        timeout.function = tape_std_assign_timeout;
  76        timeout.data     = (unsigned long) request;
  77        timeout.expires  = jiffies + 2 * HZ;
  78        add_timer(&timeout);
  79
  80        rc = tape_do_io_interruptible(device, request);
  81
  82        del_timer(&timeout);
  83
  84        if (rc != 0) {
  85                PRINT_WARN("%s: assign failed - device might be busy\n",
  86                        dev_name(&device->cdev->dev));
  87                DBF_EVENT(3, "%08x: assign failed - device might be busy\n",
  88                        device->cdev_id);
  89        } else {
  90                DBF_EVENT(3, "%08x: Tape assigned\n", device->cdev_id);
  91        }
  92        tape_free_request(request);
  93        return rc;
  94}
  95
  96/*
  97 * tape_std_unassign
  98 */
  99int
 100tape_std_unassign (struct tape_device *device)
 101{
 102        int                  rc;
 103        struct tape_request *request;
 104
 105        if (device->tape_state == TS_NOT_OPER) {
 106                DBF_EVENT(3, "(%08x): Can't unassign device\n",
 107                        device->cdev_id);
 108                PRINT_WARN("(%s): Can't unassign device - device gone\n",
 109                        dev_name(&device->cdev->dev));
 110                return -EIO;
 111        }
 112
 113        request = tape_alloc_request(2, 11);
 114        if (IS_ERR(request))
 115                return PTR_ERR(request);
 116
 117        request->op = TO_UNASSIGN;
 118        tape_ccw_cc(request->cpaddr, UNASSIGN, 11, request->cpdata);
 119        tape_ccw_end(request->cpaddr + 1, NOP, 0, NULL);
 120
 121        if ((rc = tape_do_io(device, request)) != 0) {
 122                DBF_EVENT(3, "%08x: Unassign failed\n", device->cdev_id);
 123                PRINT_WARN("%s: Unassign failed\n",
 124                           dev_name(&device->cdev->dev));
 125        } else {
 126                DBF_EVENT(3, "%08x: Tape unassigned\n", device->cdev_id);
 127        }
 128        tape_free_request(request);
 129        return rc;
 130}
 131
 132/*
 133 * TAPE390_DISPLAY: Show a string on the tape display.
 134 */
 135int
 136tape_std_display(struct tape_device *device, struct display_struct *disp)
 137{
 138        struct tape_request *request;
 139        int rc;
 140
 141        request = tape_alloc_request(2, 17);
 142        if (IS_ERR(request)) {
 143                DBF_EVENT(3, "TAPE: load display failed\n");
 144                return PTR_ERR(request);
 145        }
 146        request->op = TO_DIS;
 147
 148        *(unsigned char *) request->cpdata = disp->cntrl;
 149        DBF_EVENT(5, "TAPE: display cntrl=%04x\n", disp->cntrl);
 150        memcpy(((unsigned char *) request->cpdata) + 1, disp->message1, 8);
 151        memcpy(((unsigned char *) request->cpdata) + 9, disp->message2, 8);
 152        ASCEBC(((unsigned char*) request->cpdata) + 1, 16);
 153
 154        tape_ccw_cc(request->cpaddr, LOAD_DISPLAY, 17, request->cpdata);
 155        tape_ccw_end(request->cpaddr + 1, NOP, 0, NULL);
 156
 157        rc = tape_do_io_interruptible(device, request);
 158        tape_free_request(request);
 159        return rc;
 160}
 161
 162/*
 163 * Read block id.
 164 */
 165int
 166tape_std_read_block_id(struct tape_device *device, __u64 *id)
 167{
 168        struct tape_request *request;
 169        int rc;
 170
 171        request = tape_alloc_request(3, 8);
 172        if (IS_ERR(request))
 173                return PTR_ERR(request);
 174        request->op = TO_RBI;
 175        /* setup ccws */
 176        tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1, device->modeset_byte);
 177        tape_ccw_cc(request->cpaddr + 1, READ_BLOCK_ID, 8, request->cpdata);
 178        tape_ccw_end(request->cpaddr + 2, NOP, 0, NULL);
 179        /* execute it */
 180        rc = tape_do_io(device, request);
 181        if (rc == 0)
 182                /* Get result from read buffer. */
 183                *id = *(__u64 *) request->cpdata;
 184        tape_free_request(request);
 185        return rc;
 186}
 187
 188int
 189tape_std_terminate_write(struct tape_device *device)
 190{
 191        int rc;
 192
 193        if(device->required_tapemarks == 0)
 194                return 0;
 195
 196        DBF_LH(5, "tape%d: terminate write %dxEOF\n", device->first_minor,
 197                device->required_tapemarks);
 198
 199        rc = tape_mtop(device, MTWEOF, device->required_tapemarks);
 200        if (rc)
 201                return rc;
 202
 203        device->required_tapemarks = 0;
 204        return tape_mtop(device, MTBSR, 1);
 205}
 206
 207/*
 208 * MTLOAD: Loads the tape.
 209 * The default implementation just wait until the tape medium state changes
 210 * to MS_LOADED.
 211 */
 212int
 213tape_std_mtload(struct tape_device *device, int count)
 214{
 215        return wait_event_interruptible(device->state_change_wq,
 216                (device->medium_state == MS_LOADED));
 217}
 218
 219/*
 220 * MTSETBLK: Set block size.
 221 */
 222int
 223tape_std_mtsetblk(struct tape_device *device, int count)
 224{
 225        struct idal_buffer *new;
 226
 227        DBF_LH(6, "tape_std_mtsetblk(%d)\n", count);
 228        if (count <= 0) {
 229                /*
 230                 * Just set block_size to 0. tapechar_read/tapechar_write
 231                 * will realloc the idal buffer if a bigger one than the
 232                 * current is needed.
 233                 */
 234                device->char_data.block_size = 0;
 235                return 0;
 236        }
 237        if (device->char_data.idal_buf != NULL &&
 238            device->char_data.idal_buf->size == count)
 239                /* We already have a idal buffer of that size. */
 240                return 0;
 241
 242        if (count > MAX_BLOCKSIZE) {
 243                DBF_EVENT(3, "Invalid block size (%d > %d) given.\n",
 244                        count, MAX_BLOCKSIZE);
 245                PRINT_ERR("Invalid block size (%d > %d) given.\n",
 246                        count, MAX_BLOCKSIZE);
 247                return -EINVAL;
 248        }
 249
 250        /* Allocate a new idal buffer. */
 251        new = idal_buffer_alloc(count, 0);
 252        if (IS_ERR(new))
 253                return -ENOMEM;
 254        if (device->char_data.idal_buf != NULL)
 255                idal_buffer_free(device->char_data.idal_buf);
 256        device->char_data.idal_buf = new;
 257        device->char_data.block_size = count;
 258
 259        DBF_LH(6, "new blocksize is %d\n", device->char_data.block_size);
 260
 261        return 0;
 262}
 263
 264/*
 265 * MTRESET: Set block size to 0.
 266 */
 267int
 268tape_std_mtreset(struct tape_device *device, int count)
 269{
 270        DBF_EVENT(6, "TCHAR:devreset:\n");
 271        device->char_data.block_size = 0;
 272        return 0;
 273}
 274
 275/*
 276 * MTFSF: Forward space over 'count' file marks. The tape is positioned
 277 * at the EOT (End of Tape) side of the file mark.
 278 */
 279int
 280tape_std_mtfsf(struct tape_device *device, int mt_count)
 281{
 282        struct tape_request *request;
 283        struct ccw1 *ccw;
 284
 285        request = tape_alloc_request(mt_count + 2, 0);
 286        if (IS_ERR(request))
 287                return PTR_ERR(request);
 288        request->op = TO_FSF;
 289        /* setup ccws */
 290        ccw = tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1,
 291                          device->modeset_byte);
 292        ccw = tape_ccw_repeat(ccw, FORSPACEFILE, mt_count);
 293        ccw = tape_ccw_end(ccw, NOP, 0, NULL);
 294
 295        /* execute it */
 296        return tape_do_io_free(device, request);
 297}
 298
 299/*
 300 * MTFSR: Forward space over 'count' tape blocks (blocksize is set
 301 * via MTSETBLK.
 302 */
 303int
 304tape_std_mtfsr(struct tape_device *device, int mt_count)
 305{
 306        struct tape_request *request;
 307        struct ccw1 *ccw;
 308        int rc;
 309
 310        request = tape_alloc_request(mt_count + 2, 0);
 311        if (IS_ERR(request))
 312                return PTR_ERR(request);
 313        request->op = TO_FSB;
 314        /* setup ccws */
 315        ccw = tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1,
 316                          device->modeset_byte);
 317        ccw = tape_ccw_repeat(ccw, FORSPACEBLOCK, mt_count);
 318        ccw = tape_ccw_end(ccw, NOP, 0, NULL);
 319
 320        /* execute it */
 321        rc = tape_do_io(device, request);
 322        if (rc == 0 && request->rescnt > 0) {
 323                DBF_LH(3, "FSR over tapemark\n");
 324                rc = 1;
 325        }
 326        tape_free_request(request);
 327
 328        return rc;
 329}
 330
 331/*
 332 * MTBSR: Backward space over 'count' tape blocks.
 333 * (blocksize is set via MTSETBLK.
 334 */
 335int
 336tape_std_mtbsr(struct tape_device *device, int mt_count)
 337{
 338        struct tape_request *request;
 339        struct ccw1 *ccw;
 340        int rc;
 341
 342        request = tape_alloc_request(mt_count + 2, 0);
 343        if (IS_ERR(request))
 344                return PTR_ERR(request);
 345        request->op = TO_BSB;
 346        /* setup ccws */
 347        ccw = tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1,
 348                          device->modeset_byte);
 349        ccw = tape_ccw_repeat(ccw, BACKSPACEBLOCK, mt_count);
 350        ccw = tape_ccw_end(ccw, NOP, 0, NULL);
 351
 352        /* execute it */
 353        rc = tape_do_io(device, request);
 354        if (rc == 0 && request->rescnt > 0) {
 355                DBF_LH(3, "BSR over tapemark\n");
 356                rc = 1;
 357        }
 358        tape_free_request(request);
 359
 360        return rc;
 361}
 362
 363/*
 364 * MTWEOF: Write 'count' file marks at the current position.
 365 */
 366int
 367tape_std_mtweof(struct tape_device *device, int mt_count)
 368{
 369        struct tape_request *request;
 370        struct ccw1 *ccw;
 371
 372        request = tape_alloc_request(mt_count + 2, 0);
 373        if (IS_ERR(request))
 374                return PTR_ERR(request);
 375        request->op = TO_WTM;
 376        /* setup ccws */
 377        ccw = tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1,
 378                          device->modeset_byte);
 379        ccw = tape_ccw_repeat(ccw, WRITETAPEMARK, mt_count);
 380        ccw = tape_ccw_end(ccw, NOP, 0, NULL);
 381
 382        /* execute it */
 383        return tape_do_io_free(device, request);
 384}
 385
 386/*
 387 * MTBSFM: Backward space over 'count' file marks.
 388 * The tape is positioned at the BOT (Begin Of Tape) side of the
 389 * last skipped file mark.
 390 */
 391int
 392tape_std_mtbsfm(struct tape_device *device, int mt_count)
 393{
 394        struct tape_request *request;
 395        struct ccw1 *ccw;
 396
 397        request = tape_alloc_request(mt_count + 2, 0);
 398        if (IS_ERR(request))
 399                return PTR_ERR(request);
 400        request->op = TO_BSF;
 401        /* setup ccws */
 402        ccw = tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1,
 403                          device->modeset_byte);
 404        ccw = tape_ccw_repeat(ccw, BACKSPACEFILE, mt_count);
 405        ccw = tape_ccw_end(ccw, NOP, 0, NULL);
 406
 407        /* execute it */
 408        return tape_do_io_free(device, request);
 409}
 410
 411/*
 412 * MTBSF: Backward space over 'count' file marks. The tape is positioned at
 413 * the EOT (End of Tape) side of the last skipped file mark.
 414 */
 415int
 416tape_std_mtbsf(struct tape_device *device, int mt_count)
 417{
 418        struct tape_request *request;
 419        struct ccw1 *ccw;
 420        int rc;
 421
 422        request = tape_alloc_request(mt_count + 2, 0);
 423        if (IS_ERR(request))
 424                return PTR_ERR(request);
 425        request->op = TO_BSF;
 426        /* setup ccws */
 427        ccw = tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1,
 428                          device->modeset_byte);
 429        ccw = tape_ccw_repeat(ccw, BACKSPACEFILE, mt_count);
 430        ccw = tape_ccw_end(ccw, NOP, 0, NULL);
 431        /* execute it */
 432        rc = tape_do_io_free(device, request);
 433        if (rc == 0) {
 434                rc = tape_mtop(device, MTFSR, 1);
 435                if (rc > 0)
 436                        rc = 0;
 437        }
 438        return rc;
 439}
 440
 441/*
 442 * MTFSFM: Forward space over 'count' file marks.
 443 * The tape is positioned at the BOT (Begin Of Tape) side
 444 * of the last skipped file mark.
 445 */
 446int
 447tape_std_mtfsfm(struct tape_device *device, int mt_count)
 448{
 449        struct tape_request *request;
 450        struct ccw1 *ccw;
 451        int rc;
 452
 453        request = tape_alloc_request(mt_count + 2, 0);
 454        if (IS_ERR(request))
 455                return PTR_ERR(request);
 456        request->op = TO_FSF;
 457        /* setup ccws */
 458        ccw = tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1,
 459                          device->modeset_byte);
 460        ccw = tape_ccw_repeat(ccw, FORSPACEFILE, mt_count);
 461        ccw = tape_ccw_end(ccw, NOP, 0, NULL);
 462        /* execute it */
 463        rc = tape_do_io_free(device, request);
 464        if (rc == 0) {
 465                rc = tape_mtop(device, MTBSR, 1);
 466                if (rc > 0)
 467                        rc = 0;
 468        }
 469
 470        return rc;
 471}
 472
 473/*
 474 * MTREW: Rewind the tape.
 475 */
 476int
 477tape_std_mtrew(struct tape_device *device, int mt_count)
 478{
 479        struct tape_request *request;
 480
 481        request = tape_alloc_request(3, 0);
 482        if (IS_ERR(request))
 483                return PTR_ERR(request);
 484        request->op = TO_REW;
 485        /* setup ccws */
 486        tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1,
 487                    device->modeset_byte);
 488        tape_ccw_cc(request->cpaddr + 1, REWIND, 0, NULL);
 489        tape_ccw_end(request->cpaddr + 2, NOP, 0, NULL);
 490
 491        /* execute it */
 492        return tape_do_io_free(device, request);
 493}
 494
 495/*
 496 * MTOFFL: Rewind the tape and put the drive off-line.
 497 * Implement 'rewind unload'
 498 */
 499int
 500tape_std_mtoffl(struct tape_device *device, int mt_count)
 501{
 502        struct tape_request *request;
 503
 504        request = tape_alloc_request(3, 0);
 505        if (IS_ERR(request))
 506                return PTR_ERR(request);
 507        request->op = TO_RUN;
 508        /* setup ccws */
 509        tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1, device->modeset_byte);
 510        tape_ccw_cc(request->cpaddr + 1, REWIND_UNLOAD, 0, NULL);
 511        tape_ccw_end(request->cpaddr + 2, NOP, 0, NULL);
 512
 513        /* execute it */
 514        return tape_do_io_free(device, request);
 515}
 516
 517/*
 518 * MTNOP: 'No operation'.
 519 */
 520int
 521tape_std_mtnop(struct tape_device *device, int mt_count)
 522{
 523        struct tape_request *request;
 524
 525        request = tape_alloc_request(2, 0);
 526        if (IS_ERR(request))
 527                return PTR_ERR(request);
 528        request->op = TO_NOP;
 529        /* setup ccws */
 530        tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1, device->modeset_byte);
 531        tape_ccw_end(request->cpaddr + 1, NOP, 0, NULL);
 532        /* execute it */
 533        return tape_do_io_free(device, request);
 534}
 535
 536/*
 537 * MTEOM: positions at the end of the portion of the tape already used
 538 * for recordind data. MTEOM positions after the last file mark, ready for
 539 * appending another file.
 540 */
 541int
 542tape_std_mteom(struct tape_device *device, int mt_count)
 543{
 544        int rc;
 545
 546        /*
 547         * Seek from the beginning of tape (rewind).
 548         */
 549        if ((rc = tape_mtop(device, MTREW, 1)) < 0)
 550                return rc;
 551
 552        /*
 553         * The logical end of volume is given by two sewuential tapemarks.
 554         * Look for this by skipping to the next file (over one tapemark)
 555         * and then test for another one (fsr returns 1 if a tapemark was
 556         * encountered).
 557         */
 558        do {
 559                if ((rc = tape_mtop(device, MTFSF, 1)) < 0)
 560                        return rc;
 561                if ((rc = tape_mtop(device, MTFSR, 1)) < 0)
 562                        return rc;
 563        } while (rc == 0);
 564
 565        return tape_mtop(device, MTBSR, 1);
 566}
 567
 568/*
 569 * MTRETEN: Retension the tape, i.e. forward space to end of tape and rewind.
 570 */
 571int
 572tape_std_mtreten(struct tape_device *device, int mt_count)
 573{
 574        struct tape_request *request;
 575        int rc;
 576
 577        request = tape_alloc_request(4, 0);
 578        if (IS_ERR(request))
 579                return PTR_ERR(request);
 580        request->op = TO_FSF;
 581        /* setup ccws */
 582        tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1, device->modeset_byte);
 583        tape_ccw_cc(request->cpaddr + 1,FORSPACEFILE, 0, NULL);
 584        tape_ccw_cc(request->cpaddr + 2, NOP, 0, NULL);
 585        tape_ccw_end(request->cpaddr + 3, CCW_CMD_TIC, 0, request->cpaddr);
 586        /* execute it, MTRETEN rc gets ignored */
 587        rc = tape_do_io_interruptible(device, request);
 588        tape_free_request(request);
 589        return tape_mtop(device, MTREW, 1);
 590}
 591
 592/*
 593 * MTERASE: erases the tape.
 594 */
 595int
 596tape_std_mterase(struct tape_device *device, int mt_count)
 597{
 598        struct tape_request *request;
 599
 600        request = tape_alloc_request(6, 0);
 601        if (IS_ERR(request))
 602                return PTR_ERR(request);
 603        request->op = TO_DSE;
 604        /* setup ccws */
 605        tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1, device->modeset_byte);
 606        tape_ccw_cc(request->cpaddr + 1, REWIND, 0, NULL);
 607        tape_ccw_cc(request->cpaddr + 2, ERASE_GAP, 0, NULL);
 608        tape_ccw_cc(request->cpaddr + 3, DATA_SEC_ERASE, 0, NULL);
 609        tape_ccw_cc(request->cpaddr + 4, REWIND, 0, NULL);
 610        tape_ccw_end(request->cpaddr + 5, NOP, 0, NULL);
 611
 612        /* execute it */
 613        return tape_do_io_free(device, request);
 614}
 615
 616/*
 617 * MTUNLOAD: Rewind the tape and unload it.
 618 */
 619int
 620tape_std_mtunload(struct tape_device *device, int mt_count)
 621{
 622        return tape_mtop(device, MTOFFL, mt_count);
 623}
 624
 625/*
 626 * MTCOMPRESSION: used to enable compression.
 627 * Sets the IDRC on/off.
 628 */
 629int
 630tape_std_mtcompression(struct tape_device *device, int mt_count)
 631{
 632        struct tape_request *request;
 633
 634        if (mt_count < 0 || mt_count > 1) {
 635                DBF_EXCEPTION(6, "xcom parm\n");
 636                if (*device->modeset_byte & 0x08)
 637                        PRINT_INFO("(%s) Compression is currently on\n",
 638                                   dev_name(&device->cdev->dev));
 639                else
 640                        PRINT_INFO("(%s) Compression is currently off\n",
 641                                   dev_name(&device->cdev->dev));
 642                PRINT_INFO("Use 1 to switch compression on, 0 to "
 643                           "switch it off\n");
 644                return -EINVAL;
 645        }
 646        request = tape_alloc_request(2, 0);
 647        if (IS_ERR(request))
 648                return PTR_ERR(request);
 649        request->op = TO_NOP;
 650        /* setup ccws */
 651        if (mt_count == 0)
 652                *device->modeset_byte &= ~0x08;
 653        else
 654                *device->modeset_byte |= 0x08;
 655        tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1, device->modeset_byte);
 656        tape_ccw_end(request->cpaddr + 1, NOP, 0, NULL);
 657        /* execute it */
 658        return tape_do_io_free(device, request);
 659}
 660
 661/*
 662 * Read Block
 663 */
 664struct tape_request *
 665tape_std_read_block(struct tape_device *device, size_t count)
 666{
 667        struct tape_request *request;
 668
 669        /*
 670         * We have to alloc 4 ccws in order to be able to transform request
 671         * into a read backward request in error case.
 672         */
 673        request = tape_alloc_request(4, 0);
 674        if (IS_ERR(request)) {
 675                DBF_EXCEPTION(6, "xrbl fail");
 676                return request;
 677        }
 678        request->op = TO_RFO;
 679        tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1, device->modeset_byte);
 680        tape_ccw_end_idal(request->cpaddr + 1, READ_FORWARD,
 681                          device->char_data.idal_buf);
 682        DBF_EVENT(6, "xrbl ccwg\n");
 683        return request;
 684}
 685
 686/*
 687 * Read Block backward transformation function.
 688 */
 689void
 690tape_std_read_backward(struct tape_device *device, struct tape_request *request)
 691{
 692        /*
 693         * We have allocated 4 ccws in tape_std_read, so we can now
 694         * transform the request to a read backward, followed by a
 695         * forward space block.
 696         */
 697        request->op = TO_RBA;
 698        tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1, device->modeset_byte);
 699        tape_ccw_cc_idal(request->cpaddr + 1, READ_BACKWARD,
 700                         device->char_data.idal_buf);
 701        tape_ccw_cc(request->cpaddr + 2, FORSPACEBLOCK, 0, NULL);
 702        tape_ccw_end(request->cpaddr + 3, NOP, 0, NULL);
 703        DBF_EVENT(6, "xrop ccwg");}
 704
 705/*
 706 * Write Block
 707 */
 708struct tape_request *
 709tape_std_write_block(struct tape_device *device, size_t count)
 710{
 711        struct tape_request *request;
 712
 713        request = tape_alloc_request(2, 0);
 714        if (IS_ERR(request)) {
 715                DBF_EXCEPTION(6, "xwbl fail\n");
 716                return request;
 717        }
 718        request->op = TO_WRI;
 719        tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1, device->modeset_byte);
 720        tape_ccw_end_idal(request->cpaddr + 1, WRITE_CMD,
 721                          device->char_data.idal_buf);
 722        DBF_EVENT(6, "xwbl ccwg\n");
 723        return request;
 724}
 725
 726/*
 727 * This routine is called by frontend after an ENOSP on write
 728 */
 729void
 730tape_std_process_eov(struct tape_device *device)
 731{
 732        /*
 733         * End of volume: We have to backspace the last written record, then
 734         * we TRY to write a tapemark and then backspace over the written TM
 735         */
 736        if (tape_mtop(device, MTBSR, 1) == 0 &&
 737            tape_mtop(device, MTWEOF, 1) == 0) {
 738                tape_mtop(device, MTBSR, 1);
 739        }
 740}
 741
 742EXPORT_SYMBOL(tape_std_assign);
 743EXPORT_SYMBOL(tape_std_unassign);
 744EXPORT_SYMBOL(tape_std_display);
 745EXPORT_SYMBOL(tape_std_read_block_id);
 746EXPORT_SYMBOL(tape_std_mtload);
 747EXPORT_SYMBOL(tape_std_mtsetblk);
 748EXPORT_SYMBOL(tape_std_mtreset);
 749EXPORT_SYMBOL(tape_std_mtfsf);
 750EXPORT_SYMBOL(tape_std_mtfsr);
 751EXPORT_SYMBOL(tape_std_mtbsr);
 752EXPORT_SYMBOL(tape_std_mtweof);
 753EXPORT_SYMBOL(tape_std_mtbsfm);
 754EXPORT_SYMBOL(tape_std_mtbsf);
 755EXPORT_SYMBOL(tape_std_mtfsfm);
 756EXPORT_SYMBOL(tape_std_mtrew);
 757EXPORT_SYMBOL(tape_std_mtoffl);
 758EXPORT_SYMBOL(tape_std_mtnop);
 759EXPORT_SYMBOL(tape_std_mteom);
 760EXPORT_SYMBOL(tape_std_mtreten);
 761EXPORT_SYMBOL(tape_std_mterase);
 762EXPORT_SYMBOL(tape_std_mtunload);
 763EXPORT_SYMBOL(tape_std_mtcompression);
 764EXPORT_SYMBOL(tape_std_read_block);
 765EXPORT_SYMBOL(tape_std_read_backward);
 766EXPORT_SYMBOL(tape_std_write_block);
 767EXPORT_SYMBOL(tape_std_process_eov);
 768
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.