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 tape_request *request;
57
58 request = tape_alloc_request(cplength: 2, datasize: 11);
59 if (IS_ERR(ptr: request))
60 return PTR_ERR(ptr: request);
61
62 request->op = TO_ASSIGN;
63 tape_ccw_cc(ccw: request->cpaddr, ASSIGN, memsize: 11, cda: request->cpdata);
64 tape_ccw_end(ccw: request->cpaddr + 1, NOP, memsize: 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 timer_setup(&request->timer, tape_std_assign_timeout, 0);
72 mod_timer(timer: &request->timer, expires: jiffies + msecs_to_jiffies(m: 2000));
73
74 rc = tape_do_io_interruptible(device, request);
75
76 del_timer_sync(timer: &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_unassign
90 */
91int
92tape_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(cplength: 2, datasize: 11);
104 if (IS_ERR(ptr: request))
105 return PTR_ERR(ptr: request);
106
107 request->op = TO_UNASSIGN;
108 tape_ccw_cc(ccw: request->cpaddr, UNASSIGN, memsize: 11, cda: request->cpdata);
109 tape_ccw_end(ccw: request->cpaddr + 1, NOP, memsize: 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 */
123int
124tape_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(cplength: 2, datasize: 17);
130 if (IS_ERR(ptr: request)) {
131 DBF_EVENT(3, "TAPE: load display failed\n");
132 return PTR_ERR(ptr: 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(ccw: request->cpaddr, LOAD_DISPLAY, memsize: 17, cda: request->cpdata);
143 tape_ccw_end(ccw: request->cpaddr + 1, NOP, memsize: 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 */
153int
154tape_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(cplength: 3, datasize: 8);
160 if (IS_ERR(ptr: request))
161 return PTR_ERR(ptr: request);
162 request->op = TO_RBI;
163 /* setup ccws */
164 tape_ccw_cc(ccw: request->cpaddr, MODE_SET_DB, memsize: 1, cda: device->modeset_byte);
165 tape_ccw_cc(ccw: request->cpaddr + 1, READ_BLOCK_ID, memsize: 8, cda: request->cpdata);
166 tape_ccw_end(ccw: request->cpaddr + 2, NOP, memsize: 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
176int
177tape_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 changes
198 * to MS_LOADED.
199 */
200int
201tape_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 */
210int
211tape_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_write
219 * will realloc the idal buffer if a bigger one than the
220 * 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(ptr: 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 */
253int
254tape_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 positioned
263 * at the EOT (End of Tape) side of the file mark.
264 */
265int
266tape_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(cplength: mt_count + 2, datasize: 0);
272 if (IS_ERR(ptr: request))
273 return PTR_ERR(ptr: request);
274 request->op = TO_FSF;
275 /* setup ccws */
276 ccw = tape_ccw_cc(ccw: request->cpaddr, MODE_SET_DB, memsize: 1,
277 cda: device->modeset_byte);
278 ccw = tape_ccw_repeat(ccw, FORSPACEFILE, count: mt_count);
279 ccw = tape_ccw_end(ccw, NOP, memsize: 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 set
287 * via MTSETBLK.
288 */
289int
290tape_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(cplength: mt_count + 2, datasize: 0);
297 if (IS_ERR(ptr: request))
298 return PTR_ERR(ptr: request);
299 request->op = TO_FSB;
300 /* setup ccws */
301 ccw = tape_ccw_cc(ccw: request->cpaddr, MODE_SET_DB, memsize: 1,
302 cda: device->modeset_byte);
303 ccw = tape_ccw_repeat(ccw, FORSPACEBLOCK, count: mt_count);
304 ccw = tape_ccw_end(ccw, NOP, memsize: 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 */
321int
322tape_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(cplength: mt_count + 2, datasize: 0);
329 if (IS_ERR(ptr: request))
330 return PTR_ERR(ptr: request);
331 request->op = TO_BSB;
332 /* setup ccws */
333 ccw = tape_ccw_cc(ccw: request->cpaddr, MODE_SET_DB, memsize: 1,
334 cda: device->modeset_byte);
335 ccw = tape_ccw_repeat(ccw, BACKSPACEBLOCK, count: mt_count);
336 ccw = tape_ccw_end(ccw, NOP, memsize: 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 */
352int
353tape_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(cplength: mt_count + 2, datasize: 0);
359 if (IS_ERR(ptr: request))
360 return PTR_ERR(ptr: request);
361 request->op = TO_WTM;
362 /* setup ccws */
363 ccw = tape_ccw_cc(ccw: request->cpaddr, MODE_SET_DB, memsize: 1,
364 cda: device->modeset_byte);
365 ccw = tape_ccw_repeat(ccw, WRITETAPEMARK, count: mt_count);
366 ccw = tape_ccw_end(ccw, NOP, memsize: 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 the
375 * last skipped file mark.
376 */
377int
378tape_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(cplength: mt_count + 2, datasize: 0);
384 if (IS_ERR(ptr: request))
385 return PTR_ERR(ptr: request);
386 request->op = TO_BSF;
387 /* setup ccws */
388 ccw = tape_ccw_cc(ccw: request->cpaddr, MODE_SET_DB, memsize: 1,
389 cda: device->modeset_byte);
390 ccw = tape_ccw_repeat(ccw, BACKSPACEFILE, count: mt_count);
391 ccw = tape_ccw_end(ccw, NOP, memsize: 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 at
399 * the EOT (End of Tape) side of the last skipped file mark.
400 */
401int
402tape_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(cplength: mt_count + 2, datasize: 0);
409 if (IS_ERR(ptr: request))
410 return PTR_ERR(ptr: request);
411 request->op = TO_BSF;
412 /* setup ccws */
413 ccw = tape_ccw_cc(ccw: request->cpaddr, MODE_SET_DB, memsize: 1,
414 cda: device->modeset_byte);
415 ccw = tape_ccw_repeat(ccw, BACKSPACEFILE, count: mt_count);
416 ccw = tape_ccw_end(ccw, NOP, memsize: 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) side
430 * of the last skipped file mark.
431 */
432int
433tape_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(cplength: mt_count + 2, datasize: 0);
440 if (IS_ERR(ptr: request))
441 return PTR_ERR(ptr: request);
442 request->op = TO_FSF;
443 /* setup ccws */
444 ccw = tape_ccw_cc(ccw: request->cpaddr, MODE_SET_DB, memsize: 1,
445 cda: device->modeset_byte);
446 ccw = tape_ccw_repeat(ccw, FORSPACEFILE, count: mt_count);
447 ccw = tape_ccw_end(ccw, NOP, memsize: 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 */
462int
463tape_std_mtrew(struct tape_device *device, int mt_count)
464{
465 struct tape_request *request;
466
467 request = tape_alloc_request(cplength: 3, datasize: 0);
468 if (IS_ERR(ptr: request))
469 return PTR_ERR(ptr: request);
470 request->op = TO_REW;
471 /* setup ccws */
472 tape_ccw_cc(ccw: request->cpaddr, MODE_SET_DB, memsize: 1,
473 cda: device->modeset_byte);
474 tape_ccw_cc(ccw: request->cpaddr + 1, REWIND, memsize: 0, NULL);
475 tape_ccw_end(ccw: request->cpaddr + 2, NOP, memsize: 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 */
485int
486tape_std_mtoffl(struct tape_device *device, int mt_count)
487{
488 struct tape_request *request;
489
490 request = tape_alloc_request(cplength: 3, datasize: 0);
491 if (IS_ERR(ptr: request))
492 return PTR_ERR(ptr: request);
493 request->op = TO_RUN;
494 /* setup ccws */
495 tape_ccw_cc(ccw: request->cpaddr, MODE_SET_DB, memsize: 1, cda: device->modeset_byte);
496 tape_ccw_cc(ccw: request->cpaddr + 1, REWIND_UNLOAD, memsize: 0, NULL);
497 tape_ccw_end(ccw: request->cpaddr + 2, NOP, memsize: 0, NULL);
498
499 /* execute it */
500 return tape_do_io_free(device, request);
501}
502
503/*
504 * MTNOP: 'No operation'.
505 */
506int
507tape_std_mtnop(struct tape_device *device, int mt_count)
508{
509 struct tape_request *request;
510
511 request = tape_alloc_request(cplength: 2, datasize: 0);
512 if (IS_ERR(ptr: request))
513 return PTR_ERR(ptr: request);
514 request->op = TO_NOP;
515 /* setup ccws */
516 tape_ccw_cc(ccw: request->cpaddr, MODE_SET_DB, memsize: 1, cda: device->modeset_byte);
517 tape_ccw_end(ccw: request->cpaddr + 1, NOP, memsize: 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 used
524 * for recordind data. MTEOM positions after the last file mark, ready for
525 * appending another file.
526 */
527int
528tape_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 was
542 * 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 */
557int
558tape_std_mtreten(struct tape_device *device, int mt_count)
559{
560 struct tape_request *request;
561
562 request = tape_alloc_request(cplength: 4, datasize: 0);
563 if (IS_ERR(ptr: request))
564 return PTR_ERR(ptr: request);
565 request->op = TO_FSF;
566 /* setup ccws */
567 tape_ccw_cc(ccw: request->cpaddr, MODE_SET_DB, memsize: 1, cda: device->modeset_byte);
568 tape_ccw_cc(ccw: request->cpaddr + 1,FORSPACEFILE, memsize: 0, NULL);
569 tape_ccw_cc(ccw: request->cpaddr + 2, NOP, memsize: 0, NULL);
570 tape_ccw_end(ccw: request->cpaddr + 3, cmd_code: CCW_CMD_TIC, memsize: 0, cda: 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 */
580int
581tape_std_mterase(struct tape_device *device, int mt_count)
582{
583 struct tape_request *request;
584
585 request = tape_alloc_request(cplength: 6, datasize: 0);
586 if (IS_ERR(ptr: request))
587 return PTR_ERR(ptr: request);
588 request->op = TO_DSE;
589 /* setup ccws */
590 tape_ccw_cc(ccw: request->cpaddr, MODE_SET_DB, memsize: 1, cda: device->modeset_byte);
591 tape_ccw_cc(ccw: request->cpaddr + 1, REWIND, memsize: 0, NULL);
592 tape_ccw_cc(ccw: request->cpaddr + 2, ERASE_GAP, memsize: 0, NULL);
593 tape_ccw_cc(ccw: request->cpaddr + 3, DATA_SEC_ERASE, memsize: 0, NULL);
594 tape_ccw_cc(ccw: request->cpaddr + 4, REWIND, memsize: 0, NULL);
595 tape_ccw_end(ccw: request->cpaddr + 5, NOP, memsize: 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 */
604int
605tape_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 */
614int
615tape_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(cplength: 2, datasize: 0);
624 if (IS_ERR(ptr: request))
625 return PTR_ERR(ptr: request);
626 request->op = TO_NOP;
627 /* setup ccws */
628 if (mt_count == 0)
629 *device->modeset_byte &= ~0x08;
630 else
631 *device->modeset_byte |= 0x08;
632 tape_ccw_cc(ccw: request->cpaddr, MODE_SET_DB, memsize: 1, cda: device->modeset_byte);
633 tape_ccw_end(ccw: request->cpaddr + 1, NOP, memsize: 0, NULL);
634 /* execute it */
635 return tape_do_io_free(device, request);
636}
637
638/*
639 * Read Block
640 */
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 request
648 * into a read backward request in error case.
649 */
650 request = tape_alloc_request(cplength: 4, datasize: 0);
651 if (IS_ERR(ptr: request)) {
652 DBF_EXCEPTION(6, "xrbl fail");
653 return request;
654 }
655 request->op = TO_RFO;
656 tape_ccw_cc(ccw: request->cpaddr, MODE_SET_DB, memsize: 1, cda: device->modeset_byte);
657 tape_ccw_end_idal(ccw: request->cpaddr + 1, READ_FORWARD,
658 idal: 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 */
666void
667tape_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 now
671 * transform the request to a read backward, followed by a
672 * forward space block.
673 */
674 request->op = TO_RBA;
675 tape_ccw_cc(ccw: request->cpaddr, MODE_SET_DB, memsize: 1, cda: device->modeset_byte);
676 tape_ccw_cc_idal(ccw: request->cpaddr + 1, READ_BACKWARD,
677 idal: device->char_data.idal_buf);
678 tape_ccw_cc(ccw: request->cpaddr + 2, FORSPACEBLOCK, memsize: 0, NULL);
679 tape_ccw_end(ccw: request->cpaddr + 3, NOP, memsize: 0, NULL);
680 DBF_EVENT(6, "xrop ccwg");}
681
682/*
683 * Write Block
684 */
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(cplength: 2, datasize: 0);
691 if (IS_ERR(ptr: request)) {
692 DBF_EXCEPTION(6, "xwbl fail\n");
693 return request;
694 }
695 request->op = TO_WRI;
696 tape_ccw_cc(ccw: request->cpaddr, MODE_SET_DB, memsize: 1, cda: device->modeset_byte);
697 tape_ccw_end_idal(ccw: request->cpaddr + 1, WRITE_CMD,
698 idal: 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 write
705 */
706void
707tape_std_process_eov(struct tape_device *device)
708{
709 /*
710 * End of volume: We have to backspace the last written record, then
711 * we TRY to write a tapemark and then backspace over the written TM
712 */
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

source code of linux/drivers/s390/char/tape_std.c