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