scsi_dh_rdac: update 'access_state' field
authorHannes Reinecke <hare@suse.de>
Thu, 3 Mar 2016 06:54:10 +0000 (07:54 +0100)
committerMartin K. Petersen <martin.petersen@oracle.com>
Sat, 5 Mar 2016 22:18:28 +0000 (17:18 -0500)
Track attached SCSI devices and update the 'access_state' whenever the
path state of the device changes.

Signed-off-by: Hannes Reinecke <hare@suse.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>
drivers/scsi/device_handler/scsi_dh_rdac.c

index 93880ed..06fbd0b 100644 (file)
@@ -165,6 +165,7 @@ struct rdac_controller {
        struct work_struct      ms_work;
        struct scsi_device      *ms_sdev;
        struct list_head        ms_head;
+       struct list_head        dh_list;
 };
 
 struct c2_inquiry {
@@ -181,7 +182,9 @@ struct c2_inquiry {
 };
 
 struct rdac_dh_data {
+       struct list_head        node;
        struct rdac_controller  *ctlr;
+       struct scsi_device      *sdev;
 #define UNINITIALIZED_LUN      (1 << 8)
        unsigned                lun;
 
@@ -392,6 +395,7 @@ static struct rdac_controller *get_controller(int index, char *array_name,
        INIT_WORK(&ctlr->ms_work, send_mode_select);
        INIT_LIST_HEAD(&ctlr->ms_head);
        list_add(&ctlr->node, &ctlr_list);
+       INIT_LIST_HEAD(&ctlr->dh_list);
 
        return ctlr;
 }
@@ -455,7 +459,8 @@ static int get_lun_info(struct scsi_device *sdev, struct rdac_dh_data *h,
 
 static int check_ownership(struct scsi_device *sdev, struct rdac_dh_data *h)
 {
-       int err;
+       int err, access_state;
+       struct rdac_dh_data *tmp;
        struct c9_inquiry *inqp;
 
        h->state = RDAC_STATE_ACTIVE;
@@ -471,19 +476,31 @@ static int check_ownership(struct scsi_device *sdev, struct rdac_dh_data *h)
                        h->mode = RDAC_MODE; /* LUN in RDAC mode */
 
                /* Update ownership */
-               if (inqp->avte_cvp & 0x1)
+               if (inqp->avte_cvp & 0x1) {
                        h->lun_state = RDAC_LUN_OWNED;
-               else {
+                       access_state = SCSI_ACCESS_STATE_OPTIMAL;
+               } else {
                        h->lun_state = RDAC_LUN_UNOWNED;
-                       if (h->mode == RDAC_MODE)
+                       if (h->mode == RDAC_MODE) {
                                h->state = RDAC_STATE_PASSIVE;
+                               access_state = SCSI_ACCESS_STATE_STANDBY;
+                       } else
+                               access_state = SCSI_ACCESS_STATE_ACTIVE;
                }
 
                /* Update path prio*/
-               if (inqp->path_prio & 0x1)
+               if (inqp->path_prio & 0x1) {
                        h->preferred = RDAC_PREFERRED;
-               else
+                       access_state |= SCSI_ACCESS_STATE_PREFERRED;
+               } else
                        h->preferred = RDAC_NON_PREFERRED;
+               rcu_read_lock();
+               list_for_each_entry_rcu(tmp, &h->ctlr->dh_list, node) {
+                       /* h->sdev should always be valid */
+                       BUG_ON(!tmp->sdev);
+                       tmp->sdev->access_state = access_state;
+               }
+               rcu_read_unlock();
        }
 
        return err;
@@ -508,6 +525,10 @@ static int initialize_controller(struct scsi_device *sdev,
                h->ctlr = get_controller(index, array_name, array_id, sdev);
                if (!h->ctlr)
                        err = SCSI_DH_RES_TEMP_UNAVAIL;
+               else {
+                       list_add_rcu(&h->node, &h->ctlr->dh_list);
+                       h->sdev = sdev;
+               }
                spin_unlock(&list_lock);
        }
        return err;
@@ -829,8 +850,11 @@ static void rdac_bus_detach( struct scsi_device *sdev )
                flush_workqueue(kmpath_rdacd);
 
        spin_lock(&list_lock);
-       if (h->ctlr)
+       if (h->ctlr) {
+               list_del_rcu(&h->node);
+               h->sdev = NULL;
                kref_put(&h->ctlr->kref, release_controller);
+       }
        spin_unlock(&list_lock);
        sdev->handler_data = NULL;
        kfree(h);