diff options
Diffstat (limited to 'drivers/scsi/libsas/sas_init.c')
-rw-r--r-- | drivers/scsi/libsas/sas_init.c | 90 |
1 files changed, 89 insertions, 1 deletions
diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c index 014297c05880..dbc8a793fd86 100644 --- a/drivers/scsi/libsas/sas_init.c +++ b/drivers/scsi/libsas/sas_init.c | |||
@@ -178,7 +178,7 @@ Undo_phys: | |||
178 | return error; | 178 | return error; |
179 | } | 179 | } |
180 | 180 | ||
181 | int sas_unregister_ha(struct sas_ha_struct *sas_ha) | 181 | static void sas_disable_events(struct sas_ha_struct *sas_ha) |
182 | { | 182 | { |
183 | /* Set the state to unregistered to avoid further unchained | 183 | /* Set the state to unregistered to avoid further unchained |
184 | * events to be queued, and flush any in-progress drainers | 184 | * events to be queued, and flush any in-progress drainers |
@@ -189,7 +189,11 @@ int sas_unregister_ha(struct sas_ha_struct *sas_ha) | |||
189 | spin_unlock_irq(&sas_ha->lock); | 189 | spin_unlock_irq(&sas_ha->lock); |
190 | __sas_drain_work(sas_ha); | 190 | __sas_drain_work(sas_ha); |
191 | mutex_unlock(&sas_ha->drain_mutex); | 191 | mutex_unlock(&sas_ha->drain_mutex); |
192 | } | ||
192 | 193 | ||
194 | int sas_unregister_ha(struct sas_ha_struct *sas_ha) | ||
195 | { | ||
196 | sas_disable_events(sas_ha); | ||
193 | sas_unregister_ports(sas_ha); | 197 | sas_unregister_ports(sas_ha); |
194 | 198 | ||
195 | /* flush unregistration work */ | 199 | /* flush unregistration work */ |
@@ -381,6 +385,90 @@ int sas_set_phy_speed(struct sas_phy *phy, | |||
381 | return ret; | 385 | return ret; |
382 | } | 386 | } |
383 | 387 | ||
388 | void sas_prep_resume_ha(struct sas_ha_struct *ha) | ||
389 | { | ||
390 | int i; | ||
391 | |||
392 | set_bit(SAS_HA_REGISTERED, &ha->state); | ||
393 | |||
394 | /* clear out any stale link events/data from the suspension path */ | ||
395 | for (i = 0; i < ha->num_phys; i++) { | ||
396 | struct asd_sas_phy *phy = ha->sas_phy[i]; | ||
397 | |||
398 | memset(phy->attached_sas_addr, 0, SAS_ADDR_SIZE); | ||
399 | phy->port_events_pending = 0; | ||
400 | phy->phy_events_pending = 0; | ||
401 | phy->frame_rcvd_size = 0; | ||
402 | } | ||
403 | } | ||
404 | EXPORT_SYMBOL(sas_prep_resume_ha); | ||
405 | |||
406 | static int phys_suspended(struct sas_ha_struct *ha) | ||
407 | { | ||
408 | int i, rc = 0; | ||
409 | |||
410 | for (i = 0; i < ha->num_phys; i++) { | ||
411 | struct asd_sas_phy *phy = ha->sas_phy[i]; | ||
412 | |||
413 | if (phy->suspended) | ||
414 | rc++; | ||
415 | } | ||
416 | |||
417 | return rc; | ||
418 | } | ||
419 | |||
420 | void sas_resume_ha(struct sas_ha_struct *ha) | ||
421 | { | ||
422 | const unsigned long tmo = msecs_to_jiffies(25000); | ||
423 | int i; | ||
424 | |||
425 | /* deform ports on phys that did not resume | ||
426 | * at this point we may be racing the phy coming back (as posted | ||
427 | * by the lldd). So we post the event and once we are in the | ||
428 | * libsas context check that the phy remains suspended before | ||
429 | * tearing it down. | ||
430 | */ | ||
431 | i = phys_suspended(ha); | ||
432 | if (i) | ||
433 | dev_info(ha->dev, "waiting up to 25 seconds for %d phy%s to resume\n", | ||
434 | i, i > 1 ? "s" : ""); | ||
435 | wait_event_timeout(ha->eh_wait_q, phys_suspended(ha) == 0, tmo); | ||
436 | for (i = 0; i < ha->num_phys; i++) { | ||
437 | struct asd_sas_phy *phy = ha->sas_phy[i]; | ||
438 | |||
439 | if (phy->suspended) { | ||
440 | dev_warn(&phy->phy->dev, "resume timeout\n"); | ||
441 | sas_notify_phy_event(phy, PHYE_RESUME_TIMEOUT); | ||
442 | } | ||
443 | } | ||
444 | |||
445 | /* all phys are back up or timed out, turn on i/o so we can | ||
446 | * flush out disks that did not return | ||
447 | */ | ||
448 | scsi_unblock_requests(ha->core.shost); | ||
449 | sas_drain_work(ha); | ||
450 | } | ||
451 | EXPORT_SYMBOL(sas_resume_ha); | ||
452 | |||
453 | void sas_suspend_ha(struct sas_ha_struct *ha) | ||
454 | { | ||
455 | int i; | ||
456 | |||
457 | sas_disable_events(ha); | ||
458 | scsi_block_requests(ha->core.shost); | ||
459 | for (i = 0; i < ha->num_phys; i++) { | ||
460 | struct asd_sas_port *port = ha->sas_port[i]; | ||
461 | |||
462 | sas_discover_event(port, DISCE_SUSPEND); | ||
463 | } | ||
464 | |||
465 | /* flush suspend events while unregistered */ | ||
466 | mutex_lock(&ha->drain_mutex); | ||
467 | __sas_drain_work(ha); | ||
468 | mutex_unlock(&ha->drain_mutex); | ||
469 | } | ||
470 | EXPORT_SYMBOL(sas_suspend_ha); | ||
471 | |||
384 | static void sas_phy_release(struct sas_phy *phy) | 472 | static void sas_phy_release(struct sas_phy *phy) |
385 | { | 473 | { |
386 | kfree(phy->hostdata); | 474 | kfree(phy->hostdata); |