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