diff options
Diffstat (limited to 'drivers/s390/char/tape_3590.c')
-rw-r--r-- | drivers/s390/char/tape_3590.c | 124 |
1 files changed, 88 insertions, 36 deletions
diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c index fc993acf99b6..a7d570728882 100644 --- a/drivers/s390/char/tape_3590.c +++ b/drivers/s390/char/tape_3590.c | |||
@@ -24,6 +24,8 @@ | |||
24 | #include "tape_std.h" | 24 | #include "tape_std.h" |
25 | #include "tape_3590.h" | 25 | #include "tape_3590.h" |
26 | 26 | ||
27 | static struct workqueue_struct *tape_3590_wq; | ||
28 | |||
27 | /* | 29 | /* |
28 | * Pointer to debug area. | 30 | * Pointer to debug area. |
29 | */ | 31 | */ |
@@ -31,7 +33,7 @@ debug_info_t *TAPE_DBF_AREA = NULL; | |||
31 | EXPORT_SYMBOL(TAPE_DBF_AREA); | 33 | EXPORT_SYMBOL(TAPE_DBF_AREA); |
32 | 34 | ||
33 | /******************************************************************* | 35 | /******************************************************************* |
34 | * Error Recovery fuctions: | 36 | * Error Recovery functions: |
35 | * - Read Opposite: implemented | 37 | * - Read Opposite: implemented |
36 | * - Read Device (buffered) log: BRA | 38 | * - Read Device (buffered) log: BRA |
37 | * - Read Library log: BRA | 39 | * - Read Library log: BRA |
@@ -327,17 +329,17 @@ out: | |||
327 | /* | 329 | /* |
328 | * Enable encryption | 330 | * Enable encryption |
329 | */ | 331 | */ |
330 | static int tape_3592_enable_crypt(struct tape_device *device) | 332 | static struct tape_request *__tape_3592_enable_crypt(struct tape_device *device) |
331 | { | 333 | { |
332 | struct tape_request *request; | 334 | struct tape_request *request; |
333 | char *data; | 335 | char *data; |
334 | 336 | ||
335 | DBF_EVENT(6, "tape_3592_enable_crypt\n"); | 337 | DBF_EVENT(6, "tape_3592_enable_crypt\n"); |
336 | if (!crypt_supported(device)) | 338 | if (!crypt_supported(device)) |
337 | return -ENOSYS; | 339 | return ERR_PTR(-ENOSYS); |
338 | request = tape_alloc_request(2, 72); | 340 | request = tape_alloc_request(2, 72); |
339 | if (IS_ERR(request)) | 341 | if (IS_ERR(request)) |
340 | return PTR_ERR(request); | 342 | return request; |
341 | data = request->cpdata; | 343 | data = request->cpdata; |
342 | memset(data,0,72); | 344 | memset(data,0,72); |
343 | 345 | ||
@@ -352,23 +354,42 @@ static int tape_3592_enable_crypt(struct tape_device *device) | |||
352 | request->op = TO_CRYPT_ON; | 354 | request->op = TO_CRYPT_ON; |
353 | tape_ccw_cc(request->cpaddr, MODE_SET_CB, 36, data); | 355 | tape_ccw_cc(request->cpaddr, MODE_SET_CB, 36, data); |
354 | tape_ccw_end(request->cpaddr + 1, MODE_SET_CB, 36, data + 36); | 356 | tape_ccw_end(request->cpaddr + 1, MODE_SET_CB, 36, data + 36); |
357 | return request; | ||
358 | } | ||
359 | |||
360 | static int tape_3592_enable_crypt(struct tape_device *device) | ||
361 | { | ||
362 | struct tape_request *request; | ||
363 | |||
364 | request = __tape_3592_enable_crypt(device); | ||
365 | if (IS_ERR(request)) | ||
366 | return PTR_ERR(request); | ||
355 | return tape_do_io_free(device, request); | 367 | return tape_do_io_free(device, request); |
356 | } | 368 | } |
357 | 369 | ||
370 | static void tape_3592_enable_crypt_async(struct tape_device *device) | ||
371 | { | ||
372 | struct tape_request *request; | ||
373 | |||
374 | request = __tape_3592_enable_crypt(device); | ||
375 | if (!IS_ERR(request)) | ||
376 | tape_do_io_async_free(device, request); | ||
377 | } | ||
378 | |||
358 | /* | 379 | /* |
359 | * Disable encryption | 380 | * Disable encryption |
360 | */ | 381 | */ |
361 | static int tape_3592_disable_crypt(struct tape_device *device) | 382 | static struct tape_request *__tape_3592_disable_crypt(struct tape_device *device) |
362 | { | 383 | { |
363 | struct tape_request *request; | 384 | struct tape_request *request; |
364 | char *data; | 385 | char *data; |
365 | 386 | ||
366 | DBF_EVENT(6, "tape_3592_disable_crypt\n"); | 387 | DBF_EVENT(6, "tape_3592_disable_crypt\n"); |
367 | if (!crypt_supported(device)) | 388 | if (!crypt_supported(device)) |
368 | return -ENOSYS; | 389 | return ERR_PTR(-ENOSYS); |
369 | request = tape_alloc_request(2, 72); | 390 | request = tape_alloc_request(2, 72); |
370 | if (IS_ERR(request)) | 391 | if (IS_ERR(request)) |
371 | return PTR_ERR(request); | 392 | return request; |
372 | data = request->cpdata; | 393 | data = request->cpdata; |
373 | memset(data,0,72); | 394 | memset(data,0,72); |
374 | 395 | ||
@@ -381,9 +402,28 @@ static int tape_3592_disable_crypt(struct tape_device *device) | |||
381 | tape_ccw_cc(request->cpaddr, MODE_SET_CB, 36, data); | 402 | tape_ccw_cc(request->cpaddr, MODE_SET_CB, 36, data); |
382 | tape_ccw_end(request->cpaddr + 1, MODE_SET_CB, 36, data + 36); | 403 | tape_ccw_end(request->cpaddr + 1, MODE_SET_CB, 36, data + 36); |
383 | 404 | ||
405 | return request; | ||
406 | } | ||
407 | |||
408 | static int tape_3592_disable_crypt(struct tape_device *device) | ||
409 | { | ||
410 | struct tape_request *request; | ||
411 | |||
412 | request = __tape_3592_disable_crypt(device); | ||
413 | if (IS_ERR(request)) | ||
414 | return PTR_ERR(request); | ||
384 | return tape_do_io_free(device, request); | 415 | return tape_do_io_free(device, request); |
385 | } | 416 | } |
386 | 417 | ||
418 | static void tape_3592_disable_crypt_async(struct tape_device *device) | ||
419 | { | ||
420 | struct tape_request *request; | ||
421 | |||
422 | request = __tape_3592_disable_crypt(device); | ||
423 | if (!IS_ERR(request)) | ||
424 | tape_do_io_async_free(device, request); | ||
425 | } | ||
426 | |||
387 | /* | 427 | /* |
388 | * IOCTL: Set encryption status | 428 | * IOCTL: Set encryption status |
389 | */ | 429 | */ |
@@ -455,8 +495,7 @@ tape_3590_ioctl(struct tape_device *device, unsigned int cmd, unsigned long arg) | |||
455 | /* | 495 | /* |
456 | * SENSE Medium: Get Sense data about medium state | 496 | * SENSE Medium: Get Sense data about medium state |
457 | */ | 497 | */ |
458 | static int | 498 | static int tape_3590_sense_medium(struct tape_device *device) |
459 | tape_3590_sense_medium(struct tape_device *device) | ||
460 | { | 499 | { |
461 | struct tape_request *request; | 500 | struct tape_request *request; |
462 | 501 | ||
@@ -468,6 +507,18 @@ tape_3590_sense_medium(struct tape_device *device) | |||
468 | return tape_do_io_free(device, request); | 507 | return tape_do_io_free(device, request); |
469 | } | 508 | } |
470 | 509 | ||
510 | static void tape_3590_sense_medium_async(struct tape_device *device) | ||
511 | { | ||
512 | struct tape_request *request; | ||
513 | |||
514 | request = tape_alloc_request(1, 128); | ||
515 | if (IS_ERR(request)) | ||
516 | return; | ||
517 | request->op = TO_MSEN; | ||
518 | tape_ccw_end(request->cpaddr, MEDIUM_SENSE, 128, request->cpdata); | ||
519 | tape_do_io_async_free(device, request); | ||
520 | } | ||
521 | |||
471 | /* | 522 | /* |
472 | * MTTELL: Tell block. Return the number of block relative to current file. | 523 | * MTTELL: Tell block. Return the number of block relative to current file. |
473 | */ | 524 | */ |
@@ -544,15 +595,14 @@ tape_3590_read_opposite(struct tape_device *device, | |||
544 | * 2. The attention msg is written to the "read subsystem data" buffer. | 595 | * 2. The attention msg is written to the "read subsystem data" buffer. |
545 | * In this case we probably should print it to the console. | 596 | * In this case we probably should print it to the console. |
546 | */ | 597 | */ |
547 | static int | 598 | static void tape_3590_read_attmsg_async(struct tape_device *device) |
548 | tape_3590_read_attmsg(struct tape_device *device) | ||
549 | { | 599 | { |
550 | struct tape_request *request; | 600 | struct tape_request *request; |
551 | char *buf; | 601 | char *buf; |
552 | 602 | ||
553 | request = tape_alloc_request(3, 4096); | 603 | request = tape_alloc_request(3, 4096); |
554 | if (IS_ERR(request)) | 604 | if (IS_ERR(request)) |
555 | return PTR_ERR(request); | 605 | return; |
556 | request->op = TO_READ_ATTMSG; | 606 | request->op = TO_READ_ATTMSG; |
557 | buf = request->cpdata; | 607 | buf = request->cpdata; |
558 | buf[0] = PREP_RD_SS_DATA; | 608 | buf[0] = PREP_RD_SS_DATA; |
@@ -560,12 +610,15 @@ tape_3590_read_attmsg(struct tape_device *device) | |||
560 | tape_ccw_cc(request->cpaddr, PERFORM_SS_FUNC, 12, buf); | 610 | tape_ccw_cc(request->cpaddr, PERFORM_SS_FUNC, 12, buf); |
561 | tape_ccw_cc(request->cpaddr + 1, READ_SS_DATA, 4096 - 12, buf + 12); | 611 | tape_ccw_cc(request->cpaddr + 1, READ_SS_DATA, 4096 - 12, buf + 12); |
562 | tape_ccw_end(request->cpaddr + 2, NOP, 0, NULL); | 612 | tape_ccw_end(request->cpaddr + 2, NOP, 0, NULL); |
563 | return tape_do_io_free(device, request); | 613 | tape_do_io_async_free(device, request); |
564 | } | 614 | } |
565 | 615 | ||
566 | /* | 616 | /* |
567 | * These functions are used to schedule follow-up actions from within an | 617 | * These functions are used to schedule follow-up actions from within an |
568 | * interrupt context (like unsolicited interrupts). | 618 | * interrupt context (like unsolicited interrupts). |
619 | * Note: the work handler is called by the system work queue. The tape | ||
620 | * commands started by the handler need to be asynchrounous, otherwise | ||
621 | * a deadlock can occur e.g. in case of a deferred cc=1 (see __tape_do_irq). | ||
569 | */ | 622 | */ |
570 | struct work_handler_data { | 623 | struct work_handler_data { |
571 | struct tape_device *device; | 624 | struct tape_device *device; |
@@ -581,16 +634,16 @@ tape_3590_work_handler(struct work_struct *work) | |||
581 | 634 | ||
582 | switch (p->op) { | 635 | switch (p->op) { |
583 | case TO_MSEN: | 636 | case TO_MSEN: |
584 | tape_3590_sense_medium(p->device); | 637 | tape_3590_sense_medium_async(p->device); |
585 | break; | 638 | break; |
586 | case TO_READ_ATTMSG: | 639 | case TO_READ_ATTMSG: |
587 | tape_3590_read_attmsg(p->device); | 640 | tape_3590_read_attmsg_async(p->device); |
588 | break; | 641 | break; |
589 | case TO_CRYPT_ON: | 642 | case TO_CRYPT_ON: |
590 | tape_3592_enable_crypt(p->device); | 643 | tape_3592_enable_crypt_async(p->device); |
591 | break; | 644 | break; |
592 | case TO_CRYPT_OFF: | 645 | case TO_CRYPT_OFF: |
593 | tape_3592_disable_crypt(p->device); | 646 | tape_3592_disable_crypt_async(p->device); |
594 | break; | 647 | break; |
595 | default: | 648 | default: |
596 | DBF_EVENT(3, "T3590: work handler undefined for " | 649 | DBF_EVENT(3, "T3590: work handler undefined for " |
@@ -613,7 +666,7 @@ tape_3590_schedule_work(struct tape_device *device, enum tape_op op) | |||
613 | p->device = tape_get_device(device); | 666 | p->device = tape_get_device(device); |
614 | p->op = op; | 667 | p->op = op; |
615 | 668 | ||
616 | schedule_work(&p->work); | 669 | queue_work(tape_3590_wq, &p->work); |
617 | return 0; | 670 | return 0; |
618 | } | 671 | } |
619 | 672 | ||
@@ -743,10 +796,8 @@ static void tape_3590_med_state_set(struct tape_device *device, | |||
743 | static int | 796 | static int |
744 | tape_3590_done(struct tape_device *device, struct tape_request *request) | 797 | tape_3590_done(struct tape_device *device, struct tape_request *request) |
745 | { | 798 | { |
746 | struct tape_3590_disc_data *disc_data; | ||
747 | 799 | ||
748 | DBF_EVENT(6, "%s done\n", tape_op_verbose[request->op]); | 800 | DBF_EVENT(6, "%s done\n", tape_op_verbose[request->op]); |
749 | disc_data = device->discdata; | ||
750 | 801 | ||
751 | switch (request->op) { | 802 | switch (request->op) { |
752 | case TO_BSB: | 803 | case TO_BSB: |
@@ -798,7 +849,7 @@ tape_3590_done(struct tape_device *device, struct tape_request *request) | |||
798 | } | 849 | } |
799 | 850 | ||
800 | /* | 851 | /* |
801 | * This fuction is called, when error recovery was successfull | 852 | * This function is called, when error recovery was successful |
802 | */ | 853 | */ |
803 | static inline int | 854 | static inline int |
804 | tape_3590_erp_succeded(struct tape_device *device, struct tape_request *request) | 855 | tape_3590_erp_succeded(struct tape_device *device, struct tape_request *request) |
@@ -809,7 +860,7 @@ tape_3590_erp_succeded(struct tape_device *device, struct tape_request *request) | |||
809 | } | 860 | } |
810 | 861 | ||
811 | /* | 862 | /* |
812 | * This fuction is called, when error recovery was not successfull | 863 | * This function is called, when error recovery was not successful |
813 | */ | 864 | */ |
814 | static inline int | 865 | static inline int |
815 | tape_3590_erp_failed(struct tape_device *device, struct tape_request *request, | 866 | tape_3590_erp_failed(struct tape_device *device, struct tape_request *request, |
@@ -1341,17 +1392,12 @@ tape_3590_print_era_msg(struct tape_device *device, struct irb *irb) | |||
1341 | static int tape_3590_crypt_error(struct tape_device *device, | 1392 | static int tape_3590_crypt_error(struct tape_device *device, |
1342 | struct tape_request *request, struct irb *irb) | 1393 | struct tape_request *request, struct irb *irb) |
1343 | { | 1394 | { |
1344 | u8 cu_rc, ekm_rc1; | 1395 | u8 cu_rc; |
1345 | u16 ekm_rc2; | 1396 | u16 ekm_rc2; |
1346 | u32 drv_rc; | ||
1347 | const char *bus_id; | ||
1348 | char *sense; | 1397 | char *sense; |
1349 | 1398 | ||
1350 | sense = ((struct tape_3590_sense *) irb->ecw)->fmt.data; | 1399 | sense = ((struct tape_3590_sense *) irb->ecw)->fmt.data; |
1351 | bus_id = dev_name(&device->cdev->dev); | ||
1352 | cu_rc = sense[0]; | 1400 | cu_rc = sense[0]; |
1353 | drv_rc = *((u32*) &sense[5]) & 0xffffff; | ||
1354 | ekm_rc1 = sense[9]; | ||
1355 | ekm_rc2 = *((u16*) &sense[10]); | 1401 | ekm_rc2 = *((u16*) &sense[10]); |
1356 | if ((cu_rc == 0) && (ekm_rc2 == 0xee31)) | 1402 | if ((cu_rc == 0) && (ekm_rc2 == 0xee31)) |
1357 | /* key not defined on EKM */ | 1403 | /* key not defined on EKM */ |
@@ -1376,7 +1422,6 @@ tape_3590_unit_check(struct tape_device *device, struct tape_request *request, | |||
1376 | struct irb *irb) | 1422 | struct irb *irb) |
1377 | { | 1423 | { |
1378 | struct tape_3590_sense *sense; | 1424 | struct tape_3590_sense *sense; |
1379 | int rc; | ||
1380 | 1425 | ||
1381 | #ifdef CONFIG_S390_TAPE_BLOCK | 1426 | #ifdef CONFIG_S390_TAPE_BLOCK |
1382 | if (request->op == TO_BLOCK) { | 1427 | if (request->op == TO_BLOCK) { |
@@ -1401,7 +1446,6 @@ tape_3590_unit_check(struct tape_device *device, struct tape_request *request, | |||
1401 | * - "break": basic error recovery is done | 1446 | * - "break": basic error recovery is done |
1402 | * - "goto out:": just print error message if available | 1447 | * - "goto out:": just print error message if available |
1403 | */ | 1448 | */ |
1404 | rc = -EIO; | ||
1405 | switch (sense->rc_rqc) { | 1449 | switch (sense->rc_rqc) { |
1406 | 1450 | ||
1407 | case 0x1110: | 1451 | case 0x1110: |
@@ -1629,7 +1673,7 @@ fail_kmalloc: | |||
1629 | static void | 1673 | static void |
1630 | tape_3590_cleanup_device(struct tape_device *device) | 1674 | tape_3590_cleanup_device(struct tape_device *device) |
1631 | { | 1675 | { |
1632 | flush_scheduled_work(); | 1676 | flush_workqueue(tape_3590_wq); |
1633 | tape_std_unassign(device); | 1677 | tape_std_unassign(device); |
1634 | 1678 | ||
1635 | kfree(device->discdata); | 1679 | kfree(device->discdata); |
@@ -1708,8 +1752,10 @@ tape_3590_online(struct ccw_device *cdev) | |||
1708 | } | 1752 | } |
1709 | 1753 | ||
1710 | static struct ccw_driver tape_3590_driver = { | 1754 | static struct ccw_driver tape_3590_driver = { |
1711 | .name = "tape_3590", | 1755 | .driver = { |
1712 | .owner = THIS_MODULE, | 1756 | .name = "tape_3590", |
1757 | .owner = THIS_MODULE, | ||
1758 | }, | ||
1713 | .ids = tape_3590_ids, | 1759 | .ids = tape_3590_ids, |
1714 | .probe = tape_generic_probe, | 1760 | .probe = tape_generic_probe, |
1715 | .remove = tape_generic_remove, | 1761 | .remove = tape_generic_remove, |
@@ -1733,11 +1779,17 @@ tape_3590_init(void) | |||
1733 | #endif | 1779 | #endif |
1734 | 1780 | ||
1735 | DBF_EVENT(3, "3590 init\n"); | 1781 | DBF_EVENT(3, "3590 init\n"); |
1782 | |||
1783 | tape_3590_wq = alloc_workqueue("tape_3590", 0, 0); | ||
1784 | if (!tape_3590_wq) | ||
1785 | return -ENOMEM; | ||
1786 | |||
1736 | /* Register driver for 3590 tapes. */ | 1787 | /* Register driver for 3590 tapes. */ |
1737 | rc = ccw_driver_register(&tape_3590_driver); | 1788 | rc = ccw_driver_register(&tape_3590_driver); |
1738 | if (rc) | 1789 | if (rc) { |
1790 | destroy_workqueue(tape_3590_wq); | ||
1739 | DBF_EVENT(3, "3590 init failed\n"); | 1791 | DBF_EVENT(3, "3590 init failed\n"); |
1740 | else | 1792 | } else |
1741 | DBF_EVENT(3, "3590 registered\n"); | 1793 | DBF_EVENT(3, "3590 registered\n"); |
1742 | return rc; | 1794 | return rc; |
1743 | } | 1795 | } |
@@ -1746,7 +1798,7 @@ static void | |||
1746 | tape_3590_exit(void) | 1798 | tape_3590_exit(void) |
1747 | { | 1799 | { |
1748 | ccw_driver_unregister(&tape_3590_driver); | 1800 | ccw_driver_unregister(&tape_3590_driver); |
1749 | 1801 | destroy_workqueue(tape_3590_wq); | |
1750 | debug_unregister(TAPE_DBF_AREA); | 1802 | debug_unregister(TAPE_DBF_AREA); |
1751 | } | 1803 | } |
1752 | 1804 | ||