1
2
3
4
5
6
7
8
9
10
11
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
33
34static void
35tape_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 dev_name(&device->cdev->dev), rc);
51
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
71
72
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 dev_name(&device->cdev->dev));
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
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",
109 dev_name(&device->cdev->dev));
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",
124 dev_name(&device->cdev->dev));
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
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
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
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
180 rc = tape_do_io(device, request);
181 if (rc == 0)
182
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
209
210
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
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
231
232
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
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
251 new = idal_buffer_alloc(count, 0);
252 if (IS_ERR(new))
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
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
277
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
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
296 return tape_do_io_free(device, request);
297}
298
299
300
301
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
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
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
333
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
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
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
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
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
383 return tape_do_io_free(device, request);
384}
385
386
387
388
389
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
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
408 return tape_do_io_free(device, request);
409}
410
411
412
413
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
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
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
443
444
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
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
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
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
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
492 return tape_do_io_free(device, request);
493}
494
495
496
497
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
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
514 return tape_do_io_free(device, request);
515}
516
517
518
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
530 tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1, device->modeset_byte);
531 tape_ccw_end(request->cpaddr + 1, NOP, 0, NULL);
532
533 return tape_do_io_free(device, request);
534}
535
536
537
538
539
540
541int
542tape_std_mteom(struct tape_device *device, int mt_count)
543{
544 int rc;
545
546
547
548
549 if ((rc = tape_mtop(device, MTREW, 1)) < 0)
550 return rc;
551
552
553
554
555
556
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
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
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
587 rc = tape_do_io_interruptible(device, request);
588 tape_free_request(request);
589 return tape_mtop(device, MTREW, 1);
590}
591
592
593
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
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
613 return tape_do_io_free(device, request);
614}
615
616
617
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
627
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",
638 dev_name(&device->cdev->dev));
639 else
640 PRINT_INFO("(%s) Compression is currently off\n",
641 dev_name(&device->cdev->dev));
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
651 if (mt_count == 0)
652 *device->modeset_byte &= ~0x08;
653 else
654 *device->modeset_byte |= 0x08;
655 tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1, device->modeset_byte);
656 tape_ccw_end(request->cpaddr + 1, NOP, 0, NULL);
657
658 return tape_do_io_free(device, request);
659}
660
661
662
663
664struct tape_request *
665tape_std_read_block(struct tape_device *device, size_t count)
666{
667 struct tape_request *request;
668
669
670
671
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
688
689void
690tape_std_read_backward(struct tape_device *device, struct tape_request *request)
691{
692
693
694
695
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
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
728
729void
730tape_std_process_eov(struct tape_device *device)
731{
732
733
734
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);
768