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