diff options
Diffstat (limited to 'drivers/scsi/scsi_transport_srp.c')
-rw-r--r-- | drivers/scsi/scsi_transport_srp.c | 106 |
1 files changed, 99 insertions, 7 deletions
diff --git a/drivers/scsi/scsi_transport_srp.c b/drivers/scsi/scsi_transport_srp.c index 2696e26b3423..2700a5a09bd4 100644 --- a/drivers/scsi/scsi_transport_srp.c +++ b/drivers/scsi/scsi_transport_srp.c | |||
@@ -41,7 +41,7 @@ struct srp_host_attrs { | |||
41 | #define to_srp_host_attrs(host) ((struct srp_host_attrs *)(host)->shost_data) | 41 | #define to_srp_host_attrs(host) ((struct srp_host_attrs *)(host)->shost_data) |
42 | 42 | ||
43 | #define SRP_HOST_ATTRS 0 | 43 | #define SRP_HOST_ATTRS 0 |
44 | #define SRP_RPORT_ATTRS 6 | 44 | #define SRP_RPORT_ATTRS 8 |
45 | 45 | ||
46 | struct srp_internal { | 46 | struct srp_internal { |
47 | struct scsi_transport_template t; | 47 | struct scsi_transport_template t; |
@@ -69,11 +69,13 @@ static inline struct Scsi_Host *rport_to_shost(struct srp_rport *r) | |||
69 | * are finished in a reasonable time. Hence do not allow the fast I/O fail | 69 | * are finished in a reasonable time. Hence do not allow the fast I/O fail |
70 | * timeout to exceed SCSI_DEVICE_BLOCK_MAX_TIMEOUT. Furthermore, these | 70 | * timeout to exceed SCSI_DEVICE_BLOCK_MAX_TIMEOUT. Furthermore, these |
71 | * parameters must be such that multipath can detect failed paths timely. | 71 | * parameters must be such that multipath can detect failed paths timely. |
72 | * Hence do not allow both parameters to be disabled simultaneously. | 72 | * Hence do not allow all three parameters to be disabled simultaneously. |
73 | */ | 73 | */ |
74 | int srp_tmo_valid(int fast_io_fail_tmo, int dev_loss_tmo) | 74 | int srp_tmo_valid(int reconnect_delay, int fast_io_fail_tmo, int dev_loss_tmo) |
75 | { | 75 | { |
76 | if (fast_io_fail_tmo < 0 && dev_loss_tmo < 0) | 76 | if (reconnect_delay < 0 && fast_io_fail_tmo < 0 && dev_loss_tmo < 0) |
77 | return -EINVAL; | ||
78 | if (reconnect_delay == 0) | ||
77 | return -EINVAL; | 79 | return -EINVAL; |
78 | if (fast_io_fail_tmo > SCSI_DEVICE_BLOCK_MAX_TIMEOUT) | 80 | if (fast_io_fail_tmo > SCSI_DEVICE_BLOCK_MAX_TIMEOUT) |
79 | return -EINVAL; | 81 | return -EINVAL; |
@@ -202,6 +204,56 @@ static int srp_parse_tmo(int *tmo, const char *buf) | |||
202 | return res; | 204 | return res; |
203 | } | 205 | } |
204 | 206 | ||
207 | static ssize_t show_reconnect_delay(struct device *dev, | ||
208 | struct device_attribute *attr, char *buf) | ||
209 | { | ||
210 | struct srp_rport *rport = transport_class_to_srp_rport(dev); | ||
211 | |||
212 | return srp_show_tmo(buf, rport->reconnect_delay); | ||
213 | } | ||
214 | |||
215 | static ssize_t store_reconnect_delay(struct device *dev, | ||
216 | struct device_attribute *attr, | ||
217 | const char *buf, const size_t count) | ||
218 | { | ||
219 | struct srp_rport *rport = transport_class_to_srp_rport(dev); | ||
220 | int res, delay; | ||
221 | |||
222 | res = srp_parse_tmo(&delay, buf); | ||
223 | if (res) | ||
224 | goto out; | ||
225 | res = srp_tmo_valid(delay, rport->fast_io_fail_tmo, | ||
226 | rport->dev_loss_tmo); | ||
227 | if (res) | ||
228 | goto out; | ||
229 | |||
230 | if (rport->reconnect_delay <= 0 && delay > 0 && | ||
231 | rport->state != SRP_RPORT_RUNNING) { | ||
232 | queue_delayed_work(system_long_wq, &rport->reconnect_work, | ||
233 | delay * HZ); | ||
234 | } else if (delay <= 0) { | ||
235 | cancel_delayed_work(&rport->reconnect_work); | ||
236 | } | ||
237 | rport->reconnect_delay = delay; | ||
238 | res = count; | ||
239 | |||
240 | out: | ||
241 | return res; | ||
242 | } | ||
243 | |||
244 | static DEVICE_ATTR(reconnect_delay, S_IRUGO | S_IWUSR, show_reconnect_delay, | ||
245 | store_reconnect_delay); | ||
246 | |||
247 | static ssize_t show_failed_reconnects(struct device *dev, | ||
248 | struct device_attribute *attr, char *buf) | ||
249 | { | ||
250 | struct srp_rport *rport = transport_class_to_srp_rport(dev); | ||
251 | |||
252 | return sprintf(buf, "%d\n", rport->failed_reconnects); | ||
253 | } | ||
254 | |||
255 | static DEVICE_ATTR(failed_reconnects, S_IRUGO, show_failed_reconnects, NULL); | ||
256 | |||
205 | static ssize_t show_srp_rport_fast_io_fail_tmo(struct device *dev, | 257 | static ssize_t show_srp_rport_fast_io_fail_tmo(struct device *dev, |
206 | struct device_attribute *attr, | 258 | struct device_attribute *attr, |
207 | char *buf) | 259 | char *buf) |
@@ -222,7 +274,8 @@ static ssize_t store_srp_rport_fast_io_fail_tmo(struct device *dev, | |||
222 | res = srp_parse_tmo(&fast_io_fail_tmo, buf); | 274 | res = srp_parse_tmo(&fast_io_fail_tmo, buf); |
223 | if (res) | 275 | if (res) |
224 | goto out; | 276 | goto out; |
225 | res = srp_tmo_valid(fast_io_fail_tmo, rport->dev_loss_tmo); | 277 | res = srp_tmo_valid(rport->reconnect_delay, fast_io_fail_tmo, |
278 | rport->dev_loss_tmo); | ||
226 | if (res) | 279 | if (res) |
227 | goto out; | 280 | goto out; |
228 | rport->fast_io_fail_tmo = fast_io_fail_tmo; | 281 | rport->fast_io_fail_tmo = fast_io_fail_tmo; |
@@ -256,7 +309,8 @@ static ssize_t store_srp_rport_dev_loss_tmo(struct device *dev, | |||
256 | res = srp_parse_tmo(&dev_loss_tmo, buf); | 309 | res = srp_parse_tmo(&dev_loss_tmo, buf); |
257 | if (res) | 310 | if (res) |
258 | goto out; | 311 | goto out; |
259 | res = srp_tmo_valid(rport->fast_io_fail_tmo, dev_loss_tmo); | 312 | res = srp_tmo_valid(rport->reconnect_delay, rport->fast_io_fail_tmo, |
313 | dev_loss_tmo); | ||
260 | if (res) | 314 | if (res) |
261 | goto out; | 315 | goto out; |
262 | rport->dev_loss_tmo = dev_loss_tmo; | 316 | rport->dev_loss_tmo = dev_loss_tmo; |
@@ -312,6 +366,29 @@ invalid: | |||
312 | return -EINVAL; | 366 | return -EINVAL; |
313 | } | 367 | } |
314 | 368 | ||
369 | /** | ||
370 | * srp_reconnect_work() - reconnect and schedule a new attempt if necessary | ||
371 | */ | ||
372 | static void srp_reconnect_work(struct work_struct *work) | ||
373 | { | ||
374 | struct srp_rport *rport = container_of(to_delayed_work(work), | ||
375 | struct srp_rport, reconnect_work); | ||
376 | struct Scsi_Host *shost = rport_to_shost(rport); | ||
377 | int delay, res; | ||
378 | |||
379 | res = srp_reconnect_rport(rport); | ||
380 | if (res != 0) { | ||
381 | shost_printk(KERN_ERR, shost, | ||
382 | "reconnect attempt %d failed (%d)\n", | ||
383 | ++rport->failed_reconnects, res); | ||
384 | delay = rport->reconnect_delay * | ||
385 | min(100, max(1, rport->failed_reconnects - 10)); | ||
386 | if (delay > 0) | ||
387 | queue_delayed_work(system_long_wq, | ||
388 | &rport->reconnect_work, delay * HZ); | ||
389 | } | ||
390 | } | ||
391 | |||
315 | static void __rport_fail_io_fast(struct srp_rport *rport) | 392 | static void __rport_fail_io_fast(struct srp_rport *rport) |
316 | { | 393 | { |
317 | struct Scsi_Host *shost = rport_to_shost(rport); | 394 | struct Scsi_Host *shost = rport_to_shost(rport); |
@@ -371,16 +448,21 @@ static void rport_dev_loss_timedout(struct work_struct *work) | |||
371 | static void __srp_start_tl_fail_timers(struct srp_rport *rport) | 448 | static void __srp_start_tl_fail_timers(struct srp_rport *rport) |
372 | { | 449 | { |
373 | struct Scsi_Host *shost = rport_to_shost(rport); | 450 | struct Scsi_Host *shost = rport_to_shost(rport); |
374 | int fast_io_fail_tmo, dev_loss_tmo; | 451 | int delay, fast_io_fail_tmo, dev_loss_tmo; |
375 | 452 | ||
376 | lockdep_assert_held(&rport->mutex); | 453 | lockdep_assert_held(&rport->mutex); |
377 | 454 | ||
378 | if (!rport->deleted) { | 455 | if (!rport->deleted) { |
456 | delay = rport->reconnect_delay; | ||
379 | fast_io_fail_tmo = rport->fast_io_fail_tmo; | 457 | fast_io_fail_tmo = rport->fast_io_fail_tmo; |
380 | dev_loss_tmo = rport->dev_loss_tmo; | 458 | dev_loss_tmo = rport->dev_loss_tmo; |
381 | pr_debug("%s current state: %d\n", | 459 | pr_debug("%s current state: %d\n", |
382 | dev_name(&shost->shost_gendev), rport->state); | 460 | dev_name(&shost->shost_gendev), rport->state); |
383 | 461 | ||
462 | if (delay > 0) | ||
463 | queue_delayed_work(system_long_wq, | ||
464 | &rport->reconnect_work, | ||
465 | 1UL * delay * HZ); | ||
384 | if (fast_io_fail_tmo >= 0 && | 466 | if (fast_io_fail_tmo >= 0 && |
385 | srp_rport_set_state(rport, SRP_RPORT_BLOCKED) == 0) { | 467 | srp_rport_set_state(rport, SRP_RPORT_BLOCKED) == 0) { |
386 | pr_debug("%s new state: %d\n", | 468 | pr_debug("%s new state: %d\n", |
@@ -481,6 +563,7 @@ int srp_reconnect_rport(struct srp_rport *rport) | |||
481 | cancel_delayed_work(&rport->fast_io_fail_work); | 563 | cancel_delayed_work(&rport->fast_io_fail_work); |
482 | cancel_delayed_work(&rport->dev_loss_work); | 564 | cancel_delayed_work(&rport->dev_loss_work); |
483 | 565 | ||
566 | rport->failed_reconnects = 0; | ||
484 | srp_rport_set_state(rport, SRP_RPORT_RUNNING); | 567 | srp_rport_set_state(rport, SRP_RPORT_RUNNING); |
485 | scsi_target_unblock(&shost->shost_gendev, SDEV_RUNNING); | 568 | scsi_target_unblock(&shost->shost_gendev, SDEV_RUNNING); |
486 | /* | 569 | /* |
@@ -539,6 +622,7 @@ static void srp_rport_release(struct device *dev) | |||
539 | { | 622 | { |
540 | struct srp_rport *rport = dev_to_rport(dev); | 623 | struct srp_rport *rport = dev_to_rport(dev); |
541 | 624 | ||
625 | cancel_delayed_work_sync(&rport->reconnect_work); | ||
542 | cancel_delayed_work_sync(&rport->fast_io_fail_work); | 626 | cancel_delayed_work_sync(&rport->fast_io_fail_work); |
543 | cancel_delayed_work_sync(&rport->dev_loss_work); | 627 | cancel_delayed_work_sync(&rport->dev_loss_work); |
544 | 628 | ||
@@ -635,6 +719,10 @@ struct srp_rport *srp_rport_add(struct Scsi_Host *shost, | |||
635 | memcpy(rport->port_id, ids->port_id, sizeof(rport->port_id)); | 719 | memcpy(rport->port_id, ids->port_id, sizeof(rport->port_id)); |
636 | rport->roles = ids->roles; | 720 | rport->roles = ids->roles; |
637 | 721 | ||
722 | if (i->f->reconnect) | ||
723 | rport->reconnect_delay = i->f->reconnect_delay ? | ||
724 | *i->f->reconnect_delay : 10; | ||
725 | INIT_DELAYED_WORK(&rport->reconnect_work, srp_reconnect_work); | ||
638 | rport->fast_io_fail_tmo = i->f->fast_io_fail_tmo ? | 726 | rport->fast_io_fail_tmo = i->f->fast_io_fail_tmo ? |
639 | *i->f->fast_io_fail_tmo : 15; | 727 | *i->f->fast_io_fail_tmo : 15; |
640 | rport->dev_loss_tmo = i->f->dev_loss_tmo ? *i->f->dev_loss_tmo : 60; | 728 | rport->dev_loss_tmo = i->f->dev_loss_tmo ? *i->f->dev_loss_tmo : 60; |
@@ -773,6 +861,10 @@ srp_attach_transport(struct srp_function_template *ft) | |||
773 | i->rport_attrs[count++] = &dev_attr_fast_io_fail_tmo; | 861 | i->rport_attrs[count++] = &dev_attr_fast_io_fail_tmo; |
774 | i->rport_attrs[count++] = &dev_attr_dev_loss_tmo; | 862 | i->rport_attrs[count++] = &dev_attr_dev_loss_tmo; |
775 | } | 863 | } |
864 | if (ft->reconnect) { | ||
865 | i->rport_attrs[count++] = &dev_attr_reconnect_delay; | ||
866 | i->rport_attrs[count++] = &dev_attr_failed_reconnects; | ||
867 | } | ||
776 | if (ft->rport_delete) | 868 | if (ft->rport_delete) |
777 | i->rport_attrs[count++] = &dev_attr_delete; | 869 | i->rport_attrs[count++] = &dev_attr_delete; |
778 | i->rport_attrs[count++] = NULL; | 870 | i->rport_attrs[count++] = NULL; |