xref: /openbmc/linux/drivers/s390/char/tape_std.c (revision f68f2ff9)
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 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 	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_unassign
90  */
91 int
92 tape_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  */
123 int
124 tape_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  */
153 int
154 tape_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 
176 int
177 tape_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  */
200 int
201 tape_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  */
210 int
211 tape_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(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  */
253 int
254 tape_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  */
265 int
266 tape_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 set
287  * via MTSETBLK.
288  */
289 int
290 tape_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  */
321 int
322 tape_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  */
352 int
353 tape_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 the
375  * last skipped file mark.
376  */
377 int
378 tape_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 at
399  * the EOT (End of Tape) side of the last skipped file mark.
400  */
401 int
402 tape_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) side
430  * of the last skipped file mark.
431  */
432 int
433 tape_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  */
462 int
463 tape_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  */
485 int
486 tape_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  */
506 int
507 tape_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 used
524  * for recordind data. MTEOM positions after the last file mark, ready for
525  * appending another file.
526  */
527 int
528 tape_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  */
557 int
558 tape_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  */
580 int
581 tape_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  */
604 int
605 tape_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  */
614 int
615 tape_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 	else
631 		*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 Block
640  */
641 struct tape_request *
642 tape_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(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  */
666 void
667 tape_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(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 Block
684  */
685 struct tape_request *
686 tape_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 write
705  */
706 void
707 tape_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 
719 EXPORT_SYMBOL(tape_std_assign);
720 EXPORT_SYMBOL(tape_std_unassign);
721 EXPORT_SYMBOL(tape_std_display);
722 EXPORT_SYMBOL(tape_std_read_block_id);
723 EXPORT_SYMBOL(tape_std_mtload);
724 EXPORT_SYMBOL(tape_std_mtsetblk);
725 EXPORT_SYMBOL(tape_std_mtreset);
726 EXPORT_SYMBOL(tape_std_mtfsf);
727 EXPORT_SYMBOL(tape_std_mtfsr);
728 EXPORT_SYMBOL(tape_std_mtbsr);
729 EXPORT_SYMBOL(tape_std_mtweof);
730 EXPORT_SYMBOL(tape_std_mtbsfm);
731 EXPORT_SYMBOL(tape_std_mtbsf);
732 EXPORT_SYMBOL(tape_std_mtfsfm);
733 EXPORT_SYMBOL(tape_std_mtrew);
734 EXPORT_SYMBOL(tape_std_mtoffl);
735 EXPORT_SYMBOL(tape_std_mtnop);
736 EXPORT_SYMBOL(tape_std_mteom);
737 EXPORT_SYMBOL(tape_std_mtreten);
738 EXPORT_SYMBOL(tape_std_mterase);
739 EXPORT_SYMBOL(tape_std_mtunload);
740 EXPORT_SYMBOL(tape_std_mtcompression);
741 EXPORT_SYMBOL(tape_std_read_block);
742 EXPORT_SYMBOL(tape_std_read_backward);
743 EXPORT_SYMBOL(tape_std_write_block);
744 EXPORT_SYMBOL(tape_std_process_eov);
745