diff options
Diffstat (limited to 'drivers/scsi/scsi_lib.c')
-rw-r--r-- | drivers/scsi/scsi_lib.c | 83 |
1 files changed, 62 insertions, 21 deletions
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index e5a9526d2037..f5d3b96890dc 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c | |||
@@ -529,6 +529,14 @@ static void scsi_single_lun_run(struct scsi_device *current_sdev) | |||
529 | spin_unlock_irqrestore(shost->host_lock, flags); | 529 | spin_unlock_irqrestore(shost->host_lock, flags); |
530 | } | 530 | } |
531 | 531 | ||
532 | static inline int scsi_device_is_busy(struct scsi_device *sdev) | ||
533 | { | ||
534 | if (sdev->device_busy >= sdev->queue_depth || sdev->device_blocked) | ||
535 | return 1; | ||
536 | |||
537 | return 0; | ||
538 | } | ||
539 | |||
532 | static inline int scsi_target_is_busy(struct scsi_target *starget) | 540 | static inline int scsi_target_is_busy(struct scsi_target *starget) |
533 | { | 541 | { |
534 | return ((starget->can_queue > 0 && | 542 | return ((starget->can_queue > 0 && |
@@ -536,6 +544,15 @@ static inline int scsi_target_is_busy(struct scsi_target *starget) | |||
536 | starget->target_blocked); | 544 | starget->target_blocked); |
537 | } | 545 | } |
538 | 546 | ||
547 | static inline int scsi_host_is_busy(struct Scsi_Host *shost) | ||
548 | { | ||
549 | if ((shost->can_queue > 0 && shost->host_busy >= shost->can_queue) || | ||
550 | shost->host_blocked || shost->host_self_blocked) | ||
551 | return 1; | ||
552 | |||
553 | return 0; | ||
554 | } | ||
555 | |||
539 | /* | 556 | /* |
540 | * Function: scsi_run_queue() | 557 | * Function: scsi_run_queue() |
541 | * | 558 | * |
@@ -558,11 +575,7 @@ static void scsi_run_queue(struct request_queue *q) | |||
558 | scsi_single_lun_run(sdev); | 575 | scsi_single_lun_run(sdev); |
559 | 576 | ||
560 | spin_lock_irqsave(shost->host_lock, flags); | 577 | spin_lock_irqsave(shost->host_lock, flags); |
561 | while (!list_empty(&shost->starved_list) && | 578 | while (!list_empty(&shost->starved_list) && !scsi_host_is_busy(shost)) { |
562 | !shost->host_blocked && !shost->host_self_blocked && | ||
563 | !((shost->can_queue > 0) && | ||
564 | (shost->host_busy >= shost->can_queue))) { | ||
565 | |||
566 | int flagset; | 579 | int flagset; |
567 | 580 | ||
568 | /* | 581 | /* |
@@ -1348,8 +1361,6 @@ int scsi_prep_fn(struct request_queue *q, struct request *req) | |||
1348 | static inline int scsi_dev_queue_ready(struct request_queue *q, | 1361 | static inline int scsi_dev_queue_ready(struct request_queue *q, |
1349 | struct scsi_device *sdev) | 1362 | struct scsi_device *sdev) |
1350 | { | 1363 | { |
1351 | if (sdev->device_busy >= sdev->queue_depth) | ||
1352 | return 0; | ||
1353 | if (sdev->device_busy == 0 && sdev->device_blocked) { | 1364 | if (sdev->device_busy == 0 && sdev->device_blocked) { |
1354 | /* | 1365 | /* |
1355 | * unblock after device_blocked iterates to zero | 1366 | * unblock after device_blocked iterates to zero |
@@ -1363,7 +1374,7 @@ static inline int scsi_dev_queue_ready(struct request_queue *q, | |||
1363 | return 0; | 1374 | return 0; |
1364 | } | 1375 | } |
1365 | } | 1376 | } |
1366 | if (sdev->device_blocked) | 1377 | if (scsi_device_is_busy(sdev)) |
1367 | return 0; | 1378 | return 0; |
1368 | 1379 | ||
1369 | return 1; | 1380 | return 1; |
@@ -1440,8 +1451,7 @@ static inline int scsi_host_queue_ready(struct request_queue *q, | |||
1440 | return 0; | 1451 | return 0; |
1441 | } | 1452 | } |
1442 | } | 1453 | } |
1443 | if ((shost->can_queue > 0 && shost->host_busy >= shost->can_queue) || | 1454 | if (scsi_host_is_busy(shost)) { |
1444 | shost->host_blocked || shost->host_self_blocked) { | ||
1445 | if (list_empty(&sdev->starved_entry)) | 1455 | if (list_empty(&sdev->starved_entry)) |
1446 | list_add_tail(&sdev->starved_entry, &shost->starved_list); | 1456 | list_add_tail(&sdev->starved_entry, &shost->starved_list); |
1447 | return 0; | 1457 | return 0; |
@@ -1455,6 +1465,37 @@ static inline int scsi_host_queue_ready(struct request_queue *q, | |||
1455 | } | 1465 | } |
1456 | 1466 | ||
1457 | /* | 1467 | /* |
1468 | * Busy state exporting function for request stacking drivers. | ||
1469 | * | ||
1470 | * For efficiency, no lock is taken to check the busy state of | ||
1471 | * shost/starget/sdev, since the returned value is not guaranteed and | ||
1472 | * may be changed after request stacking drivers call the function, | ||
1473 | * regardless of taking lock or not. | ||
1474 | * | ||
1475 | * When scsi can't dispatch I/Os anymore and needs to kill I/Os | ||
1476 | * (e.g. !sdev), scsi needs to return 'not busy'. | ||
1477 | * Otherwise, request stacking drivers may hold requests forever. | ||
1478 | */ | ||
1479 | static int scsi_lld_busy(struct request_queue *q) | ||
1480 | { | ||
1481 | struct scsi_device *sdev = q->queuedata; | ||
1482 | struct Scsi_Host *shost; | ||
1483 | struct scsi_target *starget; | ||
1484 | |||
1485 | if (!sdev) | ||
1486 | return 0; | ||
1487 | |||
1488 | shost = sdev->host; | ||
1489 | starget = scsi_target(sdev); | ||
1490 | |||
1491 | if (scsi_host_in_recovery(shost) || scsi_host_is_busy(shost) || | ||
1492 | scsi_target_is_busy(starget) || scsi_device_is_busy(sdev)) | ||
1493 | return 1; | ||
1494 | |||
1495 | return 0; | ||
1496 | } | ||
1497 | |||
1498 | /* | ||
1458 | * Kill a request for a dead device | 1499 | * Kill a request for a dead device |
1459 | */ | 1500 | */ |
1460 | static void scsi_kill_request(struct request *req, struct request_queue *q) | 1501 | static void scsi_kill_request(struct request *req, struct request_queue *q) |
@@ -1757,6 +1798,7 @@ struct request_queue *scsi_alloc_queue(struct scsi_device *sdev) | |||
1757 | blk_queue_prep_rq(q, scsi_prep_fn); | 1798 | blk_queue_prep_rq(q, scsi_prep_fn); |
1758 | blk_queue_softirq_done(q, scsi_softirq_done); | 1799 | blk_queue_softirq_done(q, scsi_softirq_done); |
1759 | blk_queue_rq_timed_out(q, scsi_times_out); | 1800 | blk_queue_rq_timed_out(q, scsi_times_out); |
1801 | blk_queue_lld_busy(q, scsi_lld_busy); | ||
1760 | return q; | 1802 | return q; |
1761 | } | 1803 | } |
1762 | 1804 | ||
@@ -2105,22 +2147,21 @@ scsi_test_unit_ready(struct scsi_device *sdev, int timeout, int retries, | |||
2105 | do { | 2147 | do { |
2106 | result = scsi_execute_req(sdev, cmd, DMA_NONE, NULL, 0, sshdr, | 2148 | result = scsi_execute_req(sdev, cmd, DMA_NONE, NULL, 0, sshdr, |
2107 | timeout, retries); | 2149 | timeout, retries); |
2108 | } while ((driver_byte(result) & DRIVER_SENSE) && | 2150 | if (sdev->removable && scsi_sense_valid(sshdr) && |
2109 | sshdr && sshdr->sense_key == UNIT_ATTENTION && | 2151 | sshdr->sense_key == UNIT_ATTENTION) |
2110 | --retries); | 2152 | sdev->changed = 1; |
2153 | } while (scsi_sense_valid(sshdr) && | ||
2154 | sshdr->sense_key == UNIT_ATTENTION && --retries); | ||
2111 | 2155 | ||
2112 | if (!sshdr) | 2156 | if (!sshdr) |
2113 | /* could not allocate sense buffer, so can't process it */ | 2157 | /* could not allocate sense buffer, so can't process it */ |
2114 | return result; | 2158 | return result; |
2115 | 2159 | ||
2116 | if ((driver_byte(result) & DRIVER_SENSE) && sdev->removable) { | 2160 | if (sdev->removable && scsi_sense_valid(sshdr) && |
2117 | 2161 | (sshdr->sense_key == UNIT_ATTENTION || | |
2118 | if ((scsi_sense_valid(sshdr)) && | 2162 | sshdr->sense_key == NOT_READY)) { |
2119 | ((sshdr->sense_key == UNIT_ATTENTION) || | 2163 | sdev->changed = 1; |
2120 | (sshdr->sense_key == NOT_READY))) { | 2164 | result = 0; |
2121 | sdev->changed = 1; | ||
2122 | result = 0; | ||
2123 | } | ||
2124 | } | 2165 | } |
2125 | if (!sshdr_external) | 2166 | if (!sshdr_external) |
2126 | kfree(sshdr); | 2167 | kfree(sshdr); |