diff options
Diffstat (limited to 'drivers/scsi/scsi_transport_srp.c')
-rw-r--r-- | drivers/scsi/scsi_transport_srp.c | 70 |
1 files changed, 44 insertions, 26 deletions
diff --git a/drivers/scsi/scsi_transport_srp.c b/drivers/scsi/scsi_transport_srp.c index ae45bd99baed..e3cd3ece4412 100644 --- a/drivers/scsi/scsi_transport_srp.c +++ b/drivers/scsi/scsi_transport_srp.c | |||
@@ -61,6 +61,11 @@ static inline struct Scsi_Host *rport_to_shost(struct srp_rport *r) | |||
61 | return dev_to_shost(r->dev.parent); | 61 | return dev_to_shost(r->dev.parent); |
62 | } | 62 | } |
63 | 63 | ||
64 | static inline struct srp_rport *shost_to_rport(struct Scsi_Host *shost) | ||
65 | { | ||
66 | return transport_class_to_srp_rport(&shost->shost_gendev); | ||
67 | } | ||
68 | |||
64 | /** | 69 | /** |
65 | * srp_tmo_valid() - check timeout combination validity | 70 | * srp_tmo_valid() - check timeout combination validity |
66 | * @reconnect_delay: Reconnect delay in seconds. | 71 | * @reconnect_delay: Reconnect delay in seconds. |
@@ -198,7 +203,7 @@ static ssize_t srp_show_tmo(char *buf, int tmo) | |||
198 | return tmo >= 0 ? sprintf(buf, "%d\n", tmo) : sprintf(buf, "off\n"); | 203 | return tmo >= 0 ? sprintf(buf, "%d\n", tmo) : sprintf(buf, "off\n"); |
199 | } | 204 | } |
200 | 205 | ||
201 | static int srp_parse_tmo(int *tmo, const char *buf) | 206 | int srp_parse_tmo(int *tmo, const char *buf) |
202 | { | 207 | { |
203 | int res = 0; | 208 | int res = 0; |
204 | 209 | ||
@@ -209,6 +214,7 @@ static int srp_parse_tmo(int *tmo, const char *buf) | |||
209 | 214 | ||
210 | return res; | 215 | return res; |
211 | } | 216 | } |
217 | EXPORT_SYMBOL(srp_parse_tmo); | ||
212 | 218 | ||
213 | static ssize_t show_reconnect_delay(struct device *dev, | 219 | static ssize_t show_reconnect_delay(struct device *dev, |
214 | struct device_attribute *attr, char *buf) | 220 | struct device_attribute *attr, char *buf) |
@@ -396,6 +402,36 @@ static void srp_reconnect_work(struct work_struct *work) | |||
396 | } | 402 | } |
397 | } | 403 | } |
398 | 404 | ||
405 | /** | ||
406 | * scsi_request_fn_active() - number of kernel threads inside scsi_request_fn() | ||
407 | * @shost: SCSI host for which to count the number of scsi_request_fn() callers. | ||
408 | * | ||
409 | * To do: add support for scsi-mq in this function. | ||
410 | */ | ||
411 | static int scsi_request_fn_active(struct Scsi_Host *shost) | ||
412 | { | ||
413 | struct scsi_device *sdev; | ||
414 | struct request_queue *q; | ||
415 | int request_fn_active = 0; | ||
416 | |||
417 | shost_for_each_device(sdev, shost) { | ||
418 | q = sdev->request_queue; | ||
419 | |||
420 | spin_lock_irq(q->queue_lock); | ||
421 | request_fn_active += q->request_fn_active; | ||
422 | spin_unlock_irq(q->queue_lock); | ||
423 | } | ||
424 | |||
425 | return request_fn_active; | ||
426 | } | ||
427 | |||
428 | /* Wait until ongoing shost->hostt->queuecommand() calls have finished. */ | ||
429 | static void srp_wait_for_queuecommand(struct Scsi_Host *shost) | ||
430 | { | ||
431 | while (scsi_request_fn_active(shost)) | ||
432 | msleep(20); | ||
433 | } | ||
434 | |||
399 | static void __rport_fail_io_fast(struct srp_rport *rport) | 435 | static void __rport_fail_io_fast(struct srp_rport *rport) |
400 | { | 436 | { |
401 | struct Scsi_Host *shost = rport_to_shost(rport); | 437 | struct Scsi_Host *shost = rport_to_shost(rport); |
@@ -409,8 +445,10 @@ static void __rport_fail_io_fast(struct srp_rport *rport) | |||
409 | 445 | ||
410 | /* Involve the LLD if possible to terminate all I/O on the rport. */ | 446 | /* Involve the LLD if possible to terminate all I/O on the rport. */ |
411 | i = to_srp_internal(shost->transportt); | 447 | i = to_srp_internal(shost->transportt); |
412 | if (i->f->terminate_rport_io) | 448 | if (i->f->terminate_rport_io) { |
449 | srp_wait_for_queuecommand(shost); | ||
413 | i->f->terminate_rport_io(rport); | 450 | i->f->terminate_rport_io(rport); |
451 | } | ||
414 | } | 452 | } |
415 | 453 | ||
416 | /** | 454 | /** |
@@ -504,27 +542,6 @@ void srp_start_tl_fail_timers(struct srp_rport *rport) | |||
504 | EXPORT_SYMBOL(srp_start_tl_fail_timers); | 542 | EXPORT_SYMBOL(srp_start_tl_fail_timers); |
505 | 543 | ||
506 | /** | 544 | /** |
507 | * scsi_request_fn_active() - number of kernel threads inside scsi_request_fn() | ||
508 | * @shost: SCSI host for which to count the number of scsi_request_fn() callers. | ||
509 | */ | ||
510 | static int scsi_request_fn_active(struct Scsi_Host *shost) | ||
511 | { | ||
512 | struct scsi_device *sdev; | ||
513 | struct request_queue *q; | ||
514 | int request_fn_active = 0; | ||
515 | |||
516 | shost_for_each_device(sdev, shost) { | ||
517 | q = sdev->request_queue; | ||
518 | |||
519 | spin_lock_irq(q->queue_lock); | ||
520 | request_fn_active += q->request_fn_active; | ||
521 | spin_unlock_irq(q->queue_lock); | ||
522 | } | ||
523 | |||
524 | return request_fn_active; | ||
525 | } | ||
526 | |||
527 | /** | ||
528 | * srp_reconnect_rport() - reconnect to an SRP target port | 545 | * srp_reconnect_rport() - reconnect to an SRP target port |
529 | * @rport: SRP target port. | 546 | * @rport: SRP target port. |
530 | * | 547 | * |
@@ -559,8 +576,7 @@ int srp_reconnect_rport(struct srp_rport *rport) | |||
559 | if (res) | 576 | if (res) |
560 | goto out; | 577 | goto out; |
561 | scsi_target_block(&shost->shost_gendev); | 578 | scsi_target_block(&shost->shost_gendev); |
562 | while (scsi_request_fn_active(shost)) | 579 | srp_wait_for_queuecommand(shost); |
563 | msleep(20); | ||
564 | res = rport->state != SRP_RPORT_LOST ? i->f->reconnect(rport) : -ENODEV; | 580 | res = rport->state != SRP_RPORT_LOST ? i->f->reconnect(rport) : -ENODEV; |
565 | pr_debug("%s (state %d): transport.reconnect() returned %d\n", | 581 | pr_debug("%s (state %d): transport.reconnect() returned %d\n", |
566 | dev_name(&shost->shost_gendev), rport->state, res); | 582 | dev_name(&shost->shost_gendev), rport->state, res); |
@@ -618,9 +634,11 @@ static enum blk_eh_timer_return srp_timed_out(struct scsi_cmnd *scmd) | |||
618 | struct scsi_device *sdev = scmd->device; | 634 | struct scsi_device *sdev = scmd->device; |
619 | struct Scsi_Host *shost = sdev->host; | 635 | struct Scsi_Host *shost = sdev->host; |
620 | struct srp_internal *i = to_srp_internal(shost->transportt); | 636 | struct srp_internal *i = to_srp_internal(shost->transportt); |
637 | struct srp_rport *rport = shost_to_rport(shost); | ||
621 | 638 | ||
622 | pr_debug("timeout for sdev %s\n", dev_name(&sdev->sdev_gendev)); | 639 | pr_debug("timeout for sdev %s\n", dev_name(&sdev->sdev_gendev)); |
623 | return i->f->reset_timer_if_blocked && scsi_device_blocked(sdev) ? | 640 | return rport->fast_io_fail_tmo < 0 && rport->dev_loss_tmo < 0 && |
641 | i->f->reset_timer_if_blocked && scsi_device_blocked(sdev) ? | ||
624 | BLK_EH_RESET_TIMER : BLK_EH_NOT_HANDLED; | 642 | BLK_EH_RESET_TIMER : BLK_EH_NOT_HANDLED; |
625 | } | 643 | } |
626 | 644 | ||