aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/device_handler
diff options
context:
space:
mode:
authorHannes Reinecke <hare@suse.de>2016-03-03 01:54:09 -0500
committerMartin K. Petersen <martin.petersen@oracle.com>2016-03-05 17:17:34 -0500
commitcb0a168cb6b8f77097d69872349278a17383c38e (patch)
tree8767a3cdad4c95b8737fd98f712d181eb5e5edd4 /drivers/scsi/device_handler
parent5115fc7e2e6be8e082a9ff996cb9f343b0e850fe (diff)
scsi_dh_alua: update 'access_state' field
Track attached SCSI devices and update the 'access_state' field whenever an ALUA state change has been detected. Signed-off-by: Hannes Reinecke <hare@suse.de> Reviewed-by: Bart Van Assche <bart.vanassche@sandisk.com> Reviewed-by: Ewan Milne <emilne@redhat.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Diffstat (limited to 'drivers/scsi/device_handler')
-rw-r--r--drivers/scsi/device_handler/scsi_dh_alua.c48
1 files changed, 46 insertions, 2 deletions
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index 19f653930f7c..5bcdf8dd6fb0 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -24,6 +24,7 @@
24#include <linux/module.h> 24#include <linux/module.h>
25#include <asm/unaligned.h> 25#include <asm/unaligned.h>
26#include <scsi/scsi.h> 26#include <scsi/scsi.h>
27#include <scsi/scsi_proto.h>
27#include <scsi/scsi_dbg.h> 28#include <scsi/scsi_dbg.h>
28#include <scsi/scsi_eh.h> 29#include <scsi/scsi_eh.h>
29#include <scsi/scsi_dh.h> 30#include <scsi/scsi_dh.h>
@@ -75,6 +76,7 @@ struct alua_port_group {
75 struct kref kref; 76 struct kref kref;
76 struct rcu_head rcu; 77 struct rcu_head rcu;
77 struct list_head node; 78 struct list_head node;
79 struct list_head dh_list;
78 unsigned char device_id_str[256]; 80 unsigned char device_id_str[256];
79 int device_id_len; 81 int device_id_len;
80 int group_id; 82 int group_id;
@@ -92,6 +94,7 @@ struct alua_port_group {
92}; 94};
93 95
94struct alua_dh_data { 96struct alua_dh_data {
97 struct list_head node;
95 struct alua_port_group *pg; 98 struct alua_port_group *pg;
96 int group_id; 99 int group_id;
97 spinlock_t pg_lock; 100 spinlock_t pg_lock;
@@ -247,6 +250,7 @@ struct alua_port_group *alua_alloc_pg(struct scsi_device *sdev,
247 INIT_DELAYED_WORK(&pg->rtpg_work, alua_rtpg_work); 250 INIT_DELAYED_WORK(&pg->rtpg_work, alua_rtpg_work);
248 INIT_LIST_HEAD(&pg->rtpg_list); 251 INIT_LIST_HEAD(&pg->rtpg_list);
249 INIT_LIST_HEAD(&pg->node); 252 INIT_LIST_HEAD(&pg->node);
253 INIT_LIST_HEAD(&pg->dh_list);
250 spin_lock_init(&pg->lock); 254 spin_lock_init(&pg->lock);
251 255
252 spin_lock(&port_group_lock); 256 spin_lock(&port_group_lock);
@@ -328,6 +332,8 @@ static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h,
328{ 332{
329 int rel_port = -1, group_id; 333 int rel_port = -1, group_id;
330 struct alua_port_group *pg, *old_pg = NULL; 334 struct alua_port_group *pg, *old_pg = NULL;
335 bool pg_updated;
336 unsigned long flags;
331 337
332 group_id = scsi_vpd_tpg_id(sdev, &rel_port); 338 group_id = scsi_vpd_tpg_id(sdev, &rel_port);
333 if (group_id < 0) { 339 if (group_id < 0) {
@@ -357,10 +363,22 @@ static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h,
357 old_pg = h->pg; 363 old_pg = h->pg;
358 if (old_pg != pg) { 364 if (old_pg != pg) {
359 /* port group has changed. Update to new port group */ 365 /* port group has changed. Update to new port group */
366 if (h->pg) {
367 spin_lock_irqsave(&old_pg->lock, flags);
368 list_del_rcu(&h->node);
369 spin_unlock_irqrestore(&old_pg->lock, flags);
370 }
360 rcu_assign_pointer(h->pg, pg); 371 rcu_assign_pointer(h->pg, pg);
372 pg_updated = true;
361 } 373 }
374
375 spin_lock_irqsave(&pg->lock, flags);
362 if (sdev->synchronous_alua) 376 if (sdev->synchronous_alua)
363 pg->flags |= ALUA_SYNC_STPG; 377 pg->flags |= ALUA_SYNC_STPG;
378 if (pg_updated)
379 list_add_rcu(&h->node, &pg->dh_list);
380 spin_unlock_irqrestore(&pg->lock, flags);
381
364 alua_rtpg_queue(h->pg, sdev, NULL, true); 382 alua_rtpg_queue(h->pg, sdev, NULL, true);
365 spin_unlock(&h->pg_lock); 383 spin_unlock(&h->pg_lock);
366 384
@@ -613,8 +631,18 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg)
613 if (spin_trylock_irqsave(&tmp_pg->lock, flags)) { 631 if (spin_trylock_irqsave(&tmp_pg->lock, flags)) {
614 if ((tmp_pg == pg) || 632 if ((tmp_pg == pg) ||
615 !(tmp_pg->flags & ALUA_PG_RUNNING)) { 633 !(tmp_pg->flags & ALUA_PG_RUNNING)) {
634 struct alua_dh_data *h;
635
616 tmp_pg->state = desc[0] & 0x0f; 636 tmp_pg->state = desc[0] & 0x0f;
617 tmp_pg->pref = desc[0] >> 7; 637 tmp_pg->pref = desc[0] >> 7;
638 rcu_read_lock();
639 list_for_each_entry_rcu(h,
640 &tmp_pg->dh_list, node) {
641 /* h->sdev should always be valid */
642 BUG_ON(!h->sdev);
643 h->sdev->access_state = desc[0];
644 }
645 rcu_read_unlock();
618 } 646 }
619 if (tmp_pg == pg) 647 if (tmp_pg == pg)
620 valid_states = desc[1]; 648 valid_states = desc[1];
@@ -645,10 +673,22 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg)
645 pg->interval = 2; 673 pg->interval = 2;
646 err = SCSI_DH_RETRY; 674 err = SCSI_DH_RETRY;
647 } else { 675 } else {
676 struct alua_dh_data *h;
677
648 /* Transitioning time exceeded, set port to standby */ 678 /* Transitioning time exceeded, set port to standby */
649 err = SCSI_DH_IO; 679 err = SCSI_DH_IO;
650 pg->state = SCSI_ACCESS_STATE_STANDBY; 680 pg->state = SCSI_ACCESS_STATE_STANDBY;
651 pg->expiry = 0; 681 pg->expiry = 0;
682 rcu_read_lock();
683 list_for_each_entry_rcu(h, &pg->dh_list, node) {
684 BUG_ON(!h->sdev);
685 h->sdev->access_state =
686 (pg->state & SCSI_ACCESS_STATE_MASK);
687 if (pg->pref)
688 h->sdev->access_state |=
689 SCSI_ACCESS_STATE_PREFERRED;
690 }
691 rcu_read_unlock();
652 } 692 }
653 break; 693 break;
654 case SCSI_ACCESS_STATE_OFFLINE: 694 case SCSI_ACCESS_STATE_OFFLINE:
@@ -1041,6 +1081,7 @@ static int alua_bus_attach(struct scsi_device *sdev)
1041 rcu_assign_pointer(h->pg, NULL); 1081 rcu_assign_pointer(h->pg, NULL);
1042 h->init_error = SCSI_DH_OK; 1082 h->init_error = SCSI_DH_OK;
1043 h->sdev = sdev; 1083 h->sdev = sdev;
1084 INIT_LIST_HEAD(&h->node);
1044 1085
1045 mutex_init(&h->init_mutex); 1086 mutex_init(&h->init_mutex);
1046 err = alua_initialize(sdev, h); 1087 err = alua_initialize(sdev, h);
@@ -1070,9 +1111,12 @@ static void alua_bus_detach(struct scsi_device *sdev)
1070 rcu_assign_pointer(h->pg, NULL); 1111 rcu_assign_pointer(h->pg, NULL);
1071 h->sdev = NULL; 1112 h->sdev = NULL;
1072 spin_unlock(&h->pg_lock); 1113 spin_unlock(&h->pg_lock);
1073 if (pg) 1114 if (pg) {
1115 spin_lock(&pg->lock);
1116 list_del_rcu(&h->node);
1117 spin_unlock(&pg->lock);
1074 kref_put(&pg->kref, release_port_group); 1118 kref_put(&pg->kref, release_port_group);
1075 1119 }
1076 sdev->handler_data = NULL; 1120 sdev->handler_data = NULL;
1077 kfree(h); 1121 kfree(h);
1078} 1122}