aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2005-10-31 12:49:52 -0500
committerJames Bottomley <jejb@mulgrave.(none)>2005-11-06 13:49:36 -0500
commit7dfdc9a52b4219fba8240750e36de5db860ddd5f (patch)
treeb7be4c6a706aad1ce4e07ac22dea6c2afb050868
parent262eef663b579f9b495c7392ac7d2d3f34ecc9fe (diff)
[SCSI] use a completion in scsi_send_eh_cmnd
scsi_send_eh_cmnd currently uses a semaphore and an overload of eh_timer to either get a completion for a command for a timeout. Switch to using a completion and wait_for_completion_timeout to simply the code and not having to deal with the races ourselves. Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
-rw-r--r--drivers/scsi/scsi_error.c107
-rw-r--r--drivers/scsi/scsi_priv.h1
-rw-r--r--include/scsi/scsi_host.h5
3 files changed, 32 insertions, 81 deletions
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 5a30485d503..18c5d252301 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -417,43 +417,15 @@ static int scsi_eh_completed_normally(struct scsi_cmnd *scmd)
417} 417}
418 418
419/** 419/**
420 * scsi_eh_times_out - timeout function for error handling.
421 * @scmd: Cmd that is timing out.
422 *
423 * Notes:
424 * During error handling, the kernel thread will be sleeping waiting
425 * for some action to complete on the device. our only job is to
426 * record that it timed out, and to wake up the thread.
427 **/
428static void scsi_eh_times_out(struct scsi_cmnd *scmd)
429{
430 scmd->eh_eflags |= SCSI_EH_REC_TIMEOUT;
431 SCSI_LOG_ERROR_RECOVERY(3, printk("%s: scmd:%p\n", __FUNCTION__,
432 scmd));
433
434 up(scmd->device->host->eh_action);
435}
436
437/**
438 * scsi_eh_done - Completion function for error handling. 420 * scsi_eh_done - Completion function for error handling.
439 * @scmd: Cmd that is done. 421 * @scmd: Cmd that is done.
440 **/ 422 **/
441static void scsi_eh_done(struct scsi_cmnd *scmd) 423static void scsi_eh_done(struct scsi_cmnd *scmd)
442{ 424{
443 /* 425 SCSI_LOG_ERROR_RECOVERY(3,
444 * if the timeout handler is already running, then just set the 426 printk("%s scmd: %p result: %x\n",
445 * flag which says we finished late, and return. we have no 427 __FUNCTION__, scmd, scmd->result));
446 * way of stopping the timeout handler from running, so we must 428 complete(scmd->device->host->eh_action);
447 * always defer to it.
448 */
449 if (del_timer(&scmd->eh_timeout)) {
450 scmd->request->rq_status = RQ_SCSI_DONE;
451
452 SCSI_LOG_ERROR_RECOVERY(3, printk("%s scmd: %p result: %x\n",
453 __FUNCTION__, scmd, scmd->result));
454
455 up(scmd->device->host->eh_action);
456 }
457} 429}
458 430
459/** 431/**
@@ -461,10 +433,6 @@ static void scsi_eh_done(struct scsi_cmnd *scmd)
461 * @scmd: SCSI Cmd to send. 433 * @scmd: SCSI Cmd to send.
462 * @timeout: Timeout for cmd. 434 * @timeout: Timeout for cmd.
463 * 435 *
464 * Notes:
465 * The initialization of the structures is quite a bit different in
466 * this case, and furthermore, there is a different completion handler
467 * vs scsi_dispatch_cmd.
468 * Return value: 436 * Return value:
469 * SUCCESS or FAILED or NEEDS_RETRY 437 * SUCCESS or FAILED or NEEDS_RETRY
470 **/ 438 **/
@@ -472,24 +440,16 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, int timeout)
472{ 440{
473 struct scsi_device *sdev = scmd->device; 441 struct scsi_device *sdev = scmd->device;
474 struct Scsi_Host *shost = sdev->host; 442 struct Scsi_Host *shost = sdev->host;
475 DECLARE_MUTEX_LOCKED(sem); 443 DECLARE_COMPLETION(done);
444 unsigned long timeleft;
476 unsigned long flags; 445 unsigned long flags;
477 int rtn = SUCCESS; 446 int rtn;
478 447
479 /*
480 * we will use a queued command if possible, otherwise we will
481 * emulate the queuing and calling of completion function ourselves.
482 */
483 if (sdev->scsi_level <= SCSI_2) 448 if (sdev->scsi_level <= SCSI_2)
484 scmd->cmnd[1] = (scmd->cmnd[1] & 0x1f) | 449 scmd->cmnd[1] = (scmd->cmnd[1] & 0x1f) |
485 (sdev->lun << 5 & 0xe0); 450 (sdev->lun << 5 & 0xe0);
486 451
487 scsi_add_timer(scmd, timeout, scsi_eh_times_out); 452 shost->eh_action = &done;
488
489 /*
490 * set up the semaphore so we wait for the command to complete.
491 */
492 shost->eh_action = &sem;
493 scmd->request->rq_status = RQ_SCSI_BUSY; 453 scmd->request->rq_status = RQ_SCSI_BUSY;
494 454
495 spin_lock_irqsave(shost->host_lock, flags); 455 spin_lock_irqsave(shost->host_lock, flags);
@@ -497,47 +457,29 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, int timeout)
497 shost->hostt->queuecommand(scmd, scsi_eh_done); 457 shost->hostt->queuecommand(scmd, scsi_eh_done);
498 spin_unlock_irqrestore(shost->host_lock, flags); 458 spin_unlock_irqrestore(shost->host_lock, flags);
499 459
500 down(&sem); 460 timeleft = wait_for_completion_timeout(&done, timeout);
501 scsi_log_completion(scmd, SUCCESS);
502 461
462 scmd->request->rq_status = RQ_SCSI_DONE;
503 shost->eh_action = NULL; 463 shost->eh_action = NULL;
504 464
505 /* 465 scsi_log_completion(scmd, SUCCESS);
506 * see if timeout. if so, tell the host to forget about it.
507 * in other words, we don't want a callback any more.
508 */
509 if (scmd->eh_eflags & SCSI_EH_REC_TIMEOUT) {
510 scmd->eh_eflags &= ~SCSI_EH_REC_TIMEOUT;
511
512 /*
513 * as far as the low level driver is
514 * concerned, this command is still active, so
515 * we must give the low level driver a chance
516 * to abort it. (db)
517 *
518 * FIXME(eric) - we are not tracking whether we could
519 * abort a timed out command or not. not sure how
520 * we should treat them differently anyways.
521 */
522 if (shost->hostt->eh_abort_handler)
523 shost->hostt->eh_abort_handler(scmd);
524
525 scmd->request->rq_status = RQ_SCSI_DONE;
526 rtn = FAILED;
527 }
528 466
529 SCSI_LOG_ERROR_RECOVERY(3, printk("%s: scmd: %p, rtn:%x\n", 467 SCSI_LOG_ERROR_RECOVERY(3,
530 __FUNCTION__, scmd, rtn)); 468 printk("%s: scmd: %p, timeleft: %ld\n",
469 __FUNCTION__, scmd, timeleft));
531 470
532 /* 471 /*
533 * now examine the actual status codes to see whether the command 472 * If there is time left scsi_eh_done got called, and we will
534 * actually did complete normally. 473 * examine the actual status codes to see whether the command
474 * actually did complete normally, else tell the host to forget
475 * about this command.
535 */ 476 */
536 if (rtn == SUCCESS) { 477 if (timeleft) {
537 rtn = scsi_eh_completed_normally(scmd); 478 rtn = scsi_eh_completed_normally(scmd);
538 SCSI_LOG_ERROR_RECOVERY(3, 479 SCSI_LOG_ERROR_RECOVERY(3,
539 printk("%s: scsi_eh_completed_normally %x\n", 480 printk("%s: scsi_eh_completed_normally %x\n",
540 __FUNCTION__, rtn)); 481 __FUNCTION__, rtn));
482
541 switch (rtn) { 483 switch (rtn) {
542 case SUCCESS: 484 case SUCCESS:
543 case NEEDS_RETRY: 485 case NEEDS_RETRY:
@@ -547,6 +489,15 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, int timeout)
547 rtn = FAILED; 489 rtn = FAILED;
548 break; 490 break;
549 } 491 }
492 } else {
493 /*
494 * FIXME(eric) - we are not tracking whether we could
495 * abort a timed out command or not. not sure how
496 * we should treat them differently anyways.
497 */
498 if (shost->hostt->eh_abort_handler)
499 shost->hostt->eh_abort_handler(scmd);
500 rtn = FAILED;
550 } 501 }
551 502
552 return rtn; 503 return rtn;
diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h
index d05f778d31a..d632d9e1493 100644
--- a/drivers/scsi/scsi_priv.h
+++ b/drivers/scsi/scsi_priv.h
@@ -22,7 +22,6 @@ struct Scsi_Host;
22 * Scsi Error Handler Flags 22 * Scsi Error Handler Flags
23 */ 23 */
24#define SCSI_EH_CANCEL_CMD 0x0001 /* Cancel this cmd */ 24#define SCSI_EH_CANCEL_CMD 0x0001 /* Cancel this cmd */
25#define SCSI_EH_REC_TIMEOUT 0x0002 /* EH retry timed out */
26 25
27#define SCSI_SENSE_VALID(scmd) \ 26#define SCSI_SENSE_VALID(scmd) \
28 (((scmd)->sense_buffer[0] & 0x70) == 0x70) 27 (((scmd)->sense_buffer[0] & 0x70) == 0x70)
diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
index 9984d3fbb1f..6cbb1982ed0 100644
--- a/include/scsi/scsi_host.h
+++ b/include/scsi/scsi_host.h
@@ -7,6 +7,7 @@
7#include <linux/workqueue.h> 7#include <linux/workqueue.h>
8 8
9struct block_device; 9struct block_device;
10struct completion;
10struct module; 11struct module;
11struct scsi_cmnd; 12struct scsi_cmnd;
12struct scsi_device; 13struct scsi_device;
@@ -467,8 +468,8 @@ struct Scsi_Host {
467 468
468 struct list_head eh_cmd_q; 469 struct list_head eh_cmd_q;
469 struct task_struct * ehandler; /* Error recovery thread. */ 470 struct task_struct * ehandler; /* Error recovery thread. */
470 struct semaphore * eh_action; /* Wait for specific actions on the 471 struct completion * eh_action; /* Wait for specific actions on the
471 host. */ 472 host. */
472 wait_queue_head_t host_wait; 473 wait_queue_head_t host_wait;
473 struct scsi_host_template *hostt; 474 struct scsi_host_template *hostt;
474 struct scsi_transport_template *transportt; 475 struct scsi_transport_template *transportt;