xref: /openbmc/linux/drivers/s390/char/tape_std.c (revision f32e5616)
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  */
35 static void
36 tape_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 
52 int
53 tape_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  */
92 int
93 tape_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  */
124 int
125 tape_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  */
154 int
155 tape_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 
177 int
178 tape_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  */
201 int
202 tape_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  */
211 int
212 tape_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  */
254 int
255 tape_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  */
266 int
267 tape_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  */
290 int
291 tape_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  */
322 int
323 tape_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  */
353 int
354 tape_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  */
378 int
379 tape_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  */
402 int
403 tape_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  */
433 int
434 tape_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  */
463 int
464 tape_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  */
486 int
487 tape_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  */
507 int
508 tape_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  */
528 int
529 tape_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  */
558 int
559 tape_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  */
581 int
582 tape_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  */
605 int
606 tape_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  */
615 int
616 tape_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  */
642 struct tape_request *
643 tape_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  */
667 void
668 tape_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  */
686 struct tape_request *
687 tape_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  */
707 void
708 tape_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 
720 EXPORT_SYMBOL(tape_std_assign);
721 EXPORT_SYMBOL(tape_std_unassign);
722 EXPORT_SYMBOL(tape_std_display);
723 EXPORT_SYMBOL(tape_std_read_block_id);
724 EXPORT_SYMBOL(tape_std_mtload);
725 EXPORT_SYMBOL(tape_std_mtsetblk);
726 EXPORT_SYMBOL(tape_std_mtreset);
727 EXPORT_SYMBOL(tape_std_mtfsf);
728 EXPORT_SYMBOL(tape_std_mtfsr);
729 EXPORT_SYMBOL(tape_std_mtbsr);
730 EXPORT_SYMBOL(tape_std_mtweof);
731 EXPORT_SYMBOL(tape_std_mtbsfm);
732 EXPORT_SYMBOL(tape_std_mtbsf);
733 EXPORT_SYMBOL(tape_std_mtfsfm);
734 EXPORT_SYMBOL(tape_std_mtrew);
735 EXPORT_SYMBOL(tape_std_mtoffl);
736 EXPORT_SYMBOL(tape_std_mtnop);
737 EXPORT_SYMBOL(tape_std_mteom);
738 EXPORT_SYMBOL(tape_std_mtreten);
739 EXPORT_SYMBOL(tape_std_mterase);
740 EXPORT_SYMBOL(tape_std_mtunload);
741 EXPORT_SYMBOL(tape_std_mtcompression);
742 EXPORT_SYMBOL(tape_std_read_block);
743 EXPORT_SYMBOL(tape_std_read_backward);
744 EXPORT_SYMBOL(tape_std_write_block);
745 EXPORT_SYMBOL(tape_std_process_eov);
746