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