[S390] tape: deadlock on system work queue

The 34xx and 3590 tape driver uses the system work queue to defer work
from the interrupt function to process context, e.g. a medium sense
after an unsolicited interrupt. The tape commands started by the work
handler need to be asynchronous, otherwise a deadlock on the system
work queue can occur.

Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>

authored by Martin Schwidefsky and committed by Martin Schwidefsky 0c2bd9b2 b652277b

+116 -34
+8
drivers/s390/char/tape.h
··· 280 return rc; 281 } 282 283 extern int tape_oper_handler(int irq, int status); 284 extern void tape_noper_handler(int irq, int status); 285 extern int tape_open(struct tape_device *);
··· 280 return rc; 281 } 282 283 + static inline void 284 + tape_do_io_async_free(struct tape_device *device, struct tape_request *request) 285 + { 286 + request->callback = (void *) tape_free_request; 287 + request->callback_data = NULL; 288 + tape_do_io_async(device, request); 289 + } 290 + 291 extern int tape_oper_handler(int irq, int status); 292 extern void tape_noper_handler(int irq, int status); 293 extern int tape_open(struct tape_device *);
+41 -18
drivers/s390/char/tape_34xx.c
··· 53 * Medium sense for 34xx tapes. There is no 'real' medium sense call. 54 * So we just do a normal sense. 55 */ 56 - static int 57 - tape_34xx_medium_sense(struct tape_device *device) 58 { 59 - struct tape_request *request; 60 - unsigned char *sense; 61 - int rc; 62 63 - request = tape_alloc_request(1, 32); 64 - if (IS_ERR(request)) { 65 - DBF_EXCEPTION(6, "MSEN fail\n"); 66 - return PTR_ERR(request); 67 - } 68 - 69 - request->op = TO_MSEN; 70 - tape_ccw_end(request->cpaddr, SENSE, 32, request->cpdata); 71 - 72 - rc = tape_do_io_interruptible(device, request); 73 if (request->rc == 0) { 74 sense = request->cpdata; 75 ··· 76 device->tape_generic_status |= GMT_WR_PROT(~0); 77 else 78 device->tape_generic_status &= ~GMT_WR_PROT(~0); 79 - } else { 80 DBF_EVENT(4, "tape_34xx: medium sense failed with rc=%d\n", 81 request->rc); 82 - } 83 tape_free_request(request); 84 85 return rc; 86 } 87 88 struct tape_34xx_work { ··· 129 * is inserted but cannot call tape_do_io* from an interrupt context. 130 * Maybe that's useful for other actions we want to start from the 131 * interrupt handler. 132 */ 133 static void 134 tape_34xx_work_handler(struct work_struct *work) ··· 142 143 switch(p->op) { 144 case TO_MSEN: 145 - tape_34xx_medium_sense(device); 146 break; 147 default: 148 DBF_EVENT(3, "T34XX: internal error: unknown work\n");
··· 53 * Medium sense for 34xx tapes. There is no 'real' medium sense call. 54 * So we just do a normal sense. 55 */ 56 + static void __tape_34xx_medium_sense(struct tape_request *request) 57 { 58 + struct tape_device *device = request->device; 59 + unsigned char *sense; 60 61 if (request->rc == 0) { 62 sense = request->cpdata; 63 ··· 88 device->tape_generic_status |= GMT_WR_PROT(~0); 89 else 90 device->tape_generic_status &= ~GMT_WR_PROT(~0); 91 + } else 92 DBF_EVENT(4, "tape_34xx: medium sense failed with rc=%d\n", 93 request->rc); 94 tape_free_request(request); 95 + } 96 97 + static int tape_34xx_medium_sense(struct tape_device *device) 98 + { 99 + struct tape_request *request; 100 + int rc; 101 + 102 + request = tape_alloc_request(1, 32); 103 + if (IS_ERR(request)) { 104 + DBF_EXCEPTION(6, "MSEN fail\n"); 105 + return PTR_ERR(request); 106 + } 107 + 108 + request->op = TO_MSEN; 109 + tape_ccw_end(request->cpaddr, SENSE, 32, request->cpdata); 110 + rc = tape_do_io_interruptible(device, request); 111 + __tape_34xx_medium_sense(request); 112 return rc; 113 + } 114 + 115 + static void tape_34xx_medium_sense_async(struct tape_device *device) 116 + { 117 + struct tape_request *request; 118 + 119 + request = tape_alloc_request(1, 32); 120 + if (IS_ERR(request)) { 121 + DBF_EXCEPTION(6, "MSEN fail\n"); 122 + return; 123 + } 124 + 125 + request->op = TO_MSEN; 126 + tape_ccw_end(request->cpaddr, SENSE, 32, request->cpdata); 127 + request->callback = (void *) __tape_34xx_medium_sense; 128 + request->callback_data = NULL; 129 + tape_do_io_async(device, request); 130 } 131 132 struct tape_34xx_work { ··· 109 * is inserted but cannot call tape_do_io* from an interrupt context. 110 * Maybe that's useful for other actions we want to start from the 111 * interrupt handler. 112 + * Note: the work handler is called by the system work queue. The tape 113 + * commands started by the handler need to be asynchrounous, otherwise 114 + * a deadlock can occur e.g. in case of a deferred cc=1 (see __tape_do_irq). 115 */ 116 static void 117 tape_34xx_work_handler(struct work_struct *work) ··· 119 120 switch(p->op) { 121 case TO_MSEN: 122 + tape_34xx_medium_sense_async(device); 123 break; 124 default: 125 DBF_EVENT(3, "T34XX: internal error: unknown work\n");
+67 -16
drivers/s390/char/tape_3590.c
··· 329 /* 330 * Enable encryption 331 */ 332 - static int tape_3592_enable_crypt(struct tape_device *device) 333 { 334 struct tape_request *request; 335 char *data; 336 337 DBF_EVENT(6, "tape_3592_enable_crypt\n"); 338 if (!crypt_supported(device)) 339 - return -ENOSYS; 340 request = tape_alloc_request(2, 72); 341 if (IS_ERR(request)) 342 - return PTR_ERR(request); 343 data = request->cpdata; 344 memset(data,0,72); 345 ··· 354 request->op = TO_CRYPT_ON; 355 tape_ccw_cc(request->cpaddr, MODE_SET_CB, 36, data); 356 tape_ccw_end(request->cpaddr + 1, MODE_SET_CB, 36, data + 36); 357 return tape_do_io_free(device, request); 358 } 359 360 /* 361 * Disable encryption 362 */ 363 - static int tape_3592_disable_crypt(struct tape_device *device) 364 { 365 struct tape_request *request; 366 char *data; 367 368 DBF_EVENT(6, "tape_3592_disable_crypt\n"); 369 if (!crypt_supported(device)) 370 - return -ENOSYS; 371 request = tape_alloc_request(2, 72); 372 if (IS_ERR(request)) 373 - return PTR_ERR(request); 374 data = request->cpdata; 375 memset(data,0,72); 376 ··· 402 tape_ccw_cc(request->cpaddr, MODE_SET_CB, 36, data); 403 tape_ccw_end(request->cpaddr + 1, MODE_SET_CB, 36, data + 36); 404 405 return tape_do_io_free(device, request); 406 } 407 408 /* ··· 495 /* 496 * SENSE Medium: Get Sense data about medium state 497 */ 498 - static int 499 - tape_3590_sense_medium(struct tape_device *device) 500 { 501 struct tape_request *request; 502 ··· 505 request->op = TO_MSEN; 506 tape_ccw_end(request->cpaddr, MEDIUM_SENSE, 128, request->cpdata); 507 return tape_do_io_free(device, request); 508 } 509 510 /* ··· 595 * 2. The attention msg is written to the "read subsystem data" buffer. 596 * In this case we probably should print it to the console. 597 */ 598 - static int 599 - tape_3590_read_attmsg(struct tape_device *device) 600 { 601 struct tape_request *request; 602 char *buf; 603 604 request = tape_alloc_request(3, 4096); 605 if (IS_ERR(request)) 606 - return PTR_ERR(request); 607 request->op = TO_READ_ATTMSG; 608 buf = request->cpdata; 609 buf[0] = PREP_RD_SS_DATA; ··· 610 tape_ccw_cc(request->cpaddr, PERFORM_SS_FUNC, 12, buf); 611 tape_ccw_cc(request->cpaddr + 1, READ_SS_DATA, 4096 - 12, buf + 12); 612 tape_ccw_end(request->cpaddr + 2, NOP, 0, NULL); 613 - return tape_do_io_free(device, request); 614 } 615 616 /* 617 * These functions are used to schedule follow-up actions from within an 618 * interrupt context (like unsolicited interrupts). 619 */ 620 struct work_handler_data { 621 struct tape_device *device; ··· 634 635 switch (p->op) { 636 case TO_MSEN: 637 - tape_3590_sense_medium(p->device); 638 break; 639 case TO_READ_ATTMSG: 640 - tape_3590_read_attmsg(p->device); 641 break; 642 case TO_CRYPT_ON: 643 - tape_3592_enable_crypt(p->device); 644 break; 645 case TO_CRYPT_OFF: 646 - tape_3592_disable_crypt(p->device); 647 break; 648 default: 649 DBF_EVENT(3, "T3590: work handler undefined for "
··· 329 /* 330 * Enable encryption 331 */ 332 + static struct tape_request *__tape_3592_enable_crypt(struct tape_device *device) 333 { 334 struct tape_request *request; 335 char *data; 336 337 DBF_EVENT(6, "tape_3592_enable_crypt\n"); 338 if (!crypt_supported(device)) 339 + return ERR_PTR(-ENOSYS); 340 request = tape_alloc_request(2, 72); 341 if (IS_ERR(request)) 342 + return request; 343 data = request->cpdata; 344 memset(data,0,72); 345 ··· 354 request->op = TO_CRYPT_ON; 355 tape_ccw_cc(request->cpaddr, MODE_SET_CB, 36, data); 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); 367 return tape_do_io_free(device, request); 368 + } 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 379 /* 380 * Disable encryption 381 */ 382 + static struct tape_request *__tape_3592_disable_crypt(struct tape_device *device) 383 { 384 struct tape_request *request; 385 char *data; 386 387 DBF_EVENT(6, "tape_3592_disable_crypt\n"); 388 if (!crypt_supported(device)) 389 + return ERR_PTR(-ENOSYS); 390 request = tape_alloc_request(2, 72); 391 if (IS_ERR(request)) 392 + return request; 393 data = request->cpdata; 394 memset(data,0,72); 395 ··· 383 tape_ccw_cc(request->cpaddr, MODE_SET_CB, 36, data); 384 tape_ccw_end(request->cpaddr + 1, MODE_SET_CB, 36, data + 36); 385 386 + return request; 387 + } 388 + 389 + static int tape_3592_disable_crypt(struct tape_device *device) 390 + { 391 + struct tape_request *request; 392 + 393 + request = __tape_3592_disable_crypt(device); 394 + if (IS_ERR(request)) 395 + return PTR_ERR(request); 396 return tape_do_io_free(device, request); 397 + } 398 + 399 + static void tape_3592_disable_crypt_async(struct tape_device *device) 400 + { 401 + struct tape_request *request; 402 + 403 + request = __tape_3592_disable_crypt(device); 404 + if (!IS_ERR(request)) 405 + tape_do_io_async_free(device, request); 406 } 407 408 /* ··· 457 /* 458 * SENSE Medium: Get Sense data about medium state 459 */ 460 + static int tape_3590_sense_medium(struct tape_device *device) 461 { 462 struct tape_request *request; 463 ··· 468 request->op = TO_MSEN; 469 tape_ccw_end(request->cpaddr, MEDIUM_SENSE, 128, request->cpdata); 470 return tape_do_io_free(device, request); 471 + } 472 + 473 + static void tape_3590_sense_medium_async(struct tape_device *device) 474 + { 475 + struct tape_request *request; 476 + 477 + request = tape_alloc_request(1, 128); 478 + if (IS_ERR(request)) 479 + return; 480 + request->op = TO_MSEN; 481 + tape_ccw_end(request->cpaddr, MEDIUM_SENSE, 128, request->cpdata); 482 + tape_do_io_async_free(device, request); 483 } 484 485 /* ··· 546 * 2. The attention msg is written to the "read subsystem data" buffer. 547 * In this case we probably should print it to the console. 548 */ 549 + static void tape_3590_read_attmsg_async(struct tape_device *device) 550 { 551 struct tape_request *request; 552 char *buf; 553 554 request = tape_alloc_request(3, 4096); 555 if (IS_ERR(request)) 556 + return; 557 request->op = TO_READ_ATTMSG; 558 buf = request->cpdata; 559 buf[0] = PREP_RD_SS_DATA; ··· 562 tape_ccw_cc(request->cpaddr, PERFORM_SS_FUNC, 12, buf); 563 tape_ccw_cc(request->cpaddr + 1, READ_SS_DATA, 4096 - 12, buf + 12); 564 tape_ccw_end(request->cpaddr + 2, NOP, 0, NULL); 565 + tape_do_io_async_free(device, request); 566 } 567 568 /* 569 * These functions are used to schedule follow-up actions from within an 570 * interrupt context (like unsolicited interrupts). 571 + * Note: the work handler is called by the system work queue. The tape 572 + * commands started by the handler need to be asynchrounous, otherwise 573 + * a deadlock can occur e.g. in case of a deferred cc=1 (see __tape_do_irq). 574 */ 575 struct work_handler_data { 576 struct tape_device *device; ··· 583 584 switch (p->op) { 585 case TO_MSEN: 586 + tape_3590_sense_medium_async(p->device); 587 break; 588 case TO_READ_ATTMSG: 589 + tape_3590_read_attmsg_async(p->device); 590 break; 591 case TO_CRYPT_ON: 592 + tape_3592_enable_crypt_async(p->device); 593 break; 594 case TO_CRYPT_OFF: 595 + tape_3592_disable_crypt_async(p->device); 596 break; 597 default: 598 DBF_EVENT(3, "T3590: work handler undefined for "