aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/libsas/sas_init.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/libsas/sas_init.c')
-rw-r--r--drivers/scsi/libsas/sas_init.c90
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
181int sas_unregister_ha(struct sas_ha_struct *sas_ha) 181static 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
194int 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
388void 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}
404EXPORT_SYMBOL(sas_prep_resume_ha);
405
406static 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
420void 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}
451EXPORT_SYMBOL(sas_resume_ha);
452
453void 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}
470EXPORT_SYMBOL(sas_suspend_ha);
471
384static void sas_phy_release(struct sas_phy *phy) 472static void sas_phy_release(struct sas_phy *phy)
385{ 473{
386 kfree(phy->hostdata); 474 kfree(phy->hostdata);