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