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