[SCSI] mpt2sas: Added raid transport support
authorKashyap, Desai <kashyap.desai@lsi.com>
Wed, 16 Dec 2009 13:24:42 +0000 (18:54 +0530)
committerJames Bottomley <James.Bottomley@suse.de>
Tue, 9 Feb 2010 00:19:41 +0000 (18:19 -0600)
Adding support for raid transport layer.  This will provide sysfs attributes
containing raid level, state, and resync rate.

MPT2SAS module will select RAID_ATTRS.

Signed-off-by: Kashyap Desai <kashyap.desai@lsi.com>
Reviewed-by: Eric Moore <eric.moore@lsi.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
drivers/scsi/mpt2sas/Kconfig
drivers/scsi/mpt2sas/mpt2sas_base.h
drivers/scsi/mpt2sas/mpt2sas_scsih.c
include/linux/raid_class.h

index 70c4c24..ba8e128 100644 (file)
@@ -44,6 +44,7 @@ config SCSI_MPT2SAS
        tristate "LSI MPT Fusion SAS 2.0 Device Driver"
        depends on PCI && SCSI
        select SCSI_SAS_ATTRS
+       select RAID_ATTRS
        ---help---
        This driver supports PCI-Express SAS 6Gb/s Host Adapters.
 
index 12fa18b..014318f 100644 (file)
@@ -323,6 +323,7 @@ struct _sas_device {
  * @device_info: bitfield provides detailed info about the hidden components
  * @num_pds: number of hidden raid components
  * @responding: used in _scsih_raid_device_mark_responding
+ * @percent_complete: resync percent complete
  */
 struct _raid_device {
        struct list_head list;
@@ -336,6 +337,7 @@ struct _raid_device {
        u32     device_info;
        u8      num_pds;
        u8      responding;
+       u8      percent_complete;
 };
 
 /**
index cd55176..ca984cb 100644 (file)
@@ -52,6 +52,7 @@
 #include <linux/delay.h>
 #include <linux/pci.h>
 #include <linux/interrupt.h>
+#include <linux/raid_class.h>
 
 #include "mpt2sas_base.h"
 
@@ -133,6 +134,9 @@ struct fw_event_work {
        void                    *event_data;
 };
 
+/* raid transport support */
+static struct raid_template *mpt2sas_raid_template;
+
 /**
  * struct _scsi_io_transfer - scsi io transfer
  * @handle: sas device handle (assigned by firmware)
@@ -1418,6 +1422,140 @@ _scsih_display_sata_capabilities(struct MPT2SAS_ADAPTER *ioc,
            (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_SW_PRESERVE) ? "y" : "n");
 }
 
+/**
+ * _scsih_is_raid - return boolean indicating device is raid volume
+ * @dev the device struct object
+ */
+static int
+_scsih_is_raid(struct device *dev)
+{
+       struct scsi_device *sdev = to_scsi_device(dev);
+
+       return (sdev->channel == RAID_CHANNEL) ? 1 : 0;
+}
+
+/**
+ * _scsih_get_resync - get raid volume resync percent complete
+ * @dev the device struct object
+ */
+static void
+_scsih_get_resync(struct device *dev)
+{
+       struct scsi_device *sdev = to_scsi_device(dev);
+       struct MPT2SAS_ADAPTER *ioc = shost_priv(sdev->host);
+       static struct _raid_device *raid_device;
+       unsigned long flags;
+       Mpi2RaidVolPage0_t vol_pg0;
+       Mpi2ConfigReply_t mpi_reply;
+       u32 volume_status_flags;
+       u8 percent_complete = 0;
+
+       spin_lock_irqsave(&ioc->raid_device_lock, flags);
+       raid_device = _scsih_raid_device_find_by_id(ioc, sdev->id,
+           sdev->channel);
+       spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
+
+       if (!raid_device)
+               goto out;
+
+       if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, &vol_pg0,
+            MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle,
+            sizeof(Mpi2RaidVolPage0_t))) {
+               printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+                   ioc->name, __FILE__, __LINE__, __func__);
+               goto out;
+       }
+
+       volume_status_flags = le32_to_cpu(vol_pg0.VolumeStatusFlags);
+       if (volume_status_flags & MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS)
+               percent_complete = raid_device->percent_complete;
+ out:
+       raid_set_resync(mpt2sas_raid_template, dev, percent_complete);
+}
+
+/**
+ * _scsih_get_state - get raid volume level
+ * @dev the device struct object
+ */
+static void
+_scsih_get_state(struct device *dev)
+{
+       struct scsi_device *sdev = to_scsi_device(dev);
+       struct MPT2SAS_ADAPTER *ioc = shost_priv(sdev->host);
+       static struct _raid_device *raid_device;
+       unsigned long flags;
+       Mpi2RaidVolPage0_t vol_pg0;
+       Mpi2ConfigReply_t mpi_reply;
+       u32 volstate;
+       enum raid_state state = RAID_STATE_UNKNOWN;
+
+       spin_lock_irqsave(&ioc->raid_device_lock, flags);
+       raid_device = _scsih_raid_device_find_by_id(ioc, sdev->id,
+           sdev->channel);
+       spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
+
+       if (!raid_device)
+               goto out;
+
+       if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, &vol_pg0,
+            MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle,
+            sizeof(Mpi2RaidVolPage0_t))) {
+               printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+                   ioc->name, __FILE__, __LINE__, __func__);
+               goto out;
+       }
+
+       volstate = le32_to_cpu(vol_pg0.VolumeStatusFlags);
+       if (volstate & MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS) {
+               state = RAID_STATE_RESYNCING;
+               goto out;
+       }
+
+       switch (vol_pg0.VolumeState) {
+       case MPI2_RAID_VOL_STATE_OPTIMAL:
+       case MPI2_RAID_VOL_STATE_ONLINE:
+               state = RAID_STATE_ACTIVE;
+               break;
+       case  MPI2_RAID_VOL_STATE_DEGRADED:
+               state = RAID_STATE_DEGRADED;
+               break;
+       case MPI2_RAID_VOL_STATE_FAILED:
+       case MPI2_RAID_VOL_STATE_MISSING:
+               state = RAID_STATE_OFFLINE;
+               break;
+       }
+ out:
+       raid_set_state(mpt2sas_raid_template, dev, state);
+}
+
+/**
+ * _scsih_set_level - set raid level
+ * @sdev: scsi device struct
+ * @raid_device: raid_device object
+ */
+static void
+_scsih_set_level(struct scsi_device *sdev, struct _raid_device *raid_device)
+{
+       enum raid_level level = RAID_LEVEL_UNKNOWN;
+
+       switch (raid_device->volume_type) {
+       case MPI2_RAID_VOL_TYPE_RAID0:
+               level = RAID_LEVEL_0;
+               break;
+       case MPI2_RAID_VOL_TYPE_RAID10:
+               level = RAID_LEVEL_10;
+               break;
+       case MPI2_RAID_VOL_TYPE_RAID1E:
+               level = RAID_LEVEL_1E;
+               break;
+       case MPI2_RAID_VOL_TYPE_RAID1:
+               level = RAID_LEVEL_1;
+               break;
+       }
+
+       raid_set_level(mpt2sas_raid_template, &sdev->sdev_gendev, level);
+}
+
 /**
  * _scsih_get_volume_capabilities - volume capabilities
  * @ioc: per adapter object
@@ -1574,6 +1712,8 @@ _scsih_slave_configure(struct scsi_device *sdev)
                    (unsigned long long)raid_device->wwid,
                    raid_device->num_pds, ds);
                _scsih_change_queue_depth(sdev, qdepth, SCSI_QDEPTH_DEFAULT);
+               /* raid transport support */
+               _scsih_set_level(sdev, raid_device);
                return 0;
        }
 
@@ -5170,11 +5310,33 @@ static void
 _scsih_sas_ir_operation_status_event(struct MPT2SAS_ADAPTER *ioc,
     struct fw_event_work *fw_event)
 {
+       Mpi2EventDataIrOperationStatus_t *event_data = fw_event->event_data;
+       static struct _raid_device *raid_device;
+       unsigned long flags;
+       u16 handle;
+
 #ifdef CONFIG_SCSI_MPT2SAS_LOGGING
        if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
                _scsih_sas_ir_operation_status_event_debug(ioc,
-                    fw_event->event_data);
+                    event_data);
 #endif
+
+       /* code added for raid transport support */
+       if (event_data->RAIDOperation == MPI2_EVENT_IR_RAIDOP_RESYNC) {
+
+               handle = le16_to_cpu(event_data->VolDevHandle);
+
+               spin_lock_irqsave(&ioc->raid_device_lock, flags);
+               raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
+               spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
+
+               if (!raid_device)
+                       return;
+
+               if (event_data->RAIDOperation == MPI2_EVENT_IR_RAIDOP_RESYNC)
+                       raid_device->percent_complete =
+                           event_data->PercentComplete;
+       }
 }
 
 /**
@@ -6390,6 +6552,13 @@ static struct pci_driver scsih_driver = {
 #endif
 };
 
+/* raid transport support */
+static struct raid_function_template mpt2sas_raid_functions = {
+       .cookie         = &scsih_driver_template,
+       .is_raid        = _scsih_is_raid,
+       .get_resync     = _scsih_get_resync,
+       .get_state      = _scsih_get_state,
+};
 
 /**
  * _scsih_init - main entry point for this driver.
@@ -6409,6 +6578,12 @@ _scsih_init(void)
            sas_attach_transport(&mpt2sas_transport_functions);
        if (!mpt2sas_transport_template)
                return -ENODEV;
+       /* raid transport support */
+       mpt2sas_raid_template = raid_class_attach(&mpt2sas_raid_functions);
+       if (!mpt2sas_raid_template) {
+               sas_release_transport(mpt2sas_transport_template);
+               return -ENODEV;
+       }
 
        mpt2sas_base_initialize_callback_handler();
 
@@ -6443,8 +6618,11 @@ _scsih_init(void)
        mpt2sas_ctl_init();
 
        error = pci_register_driver(&scsih_driver);
-       if (error)
+       if (error) {
+               /* raid transport support */
+               raid_class_release(mpt2sas_raid_template);
                sas_release_transport(mpt2sas_transport_template);
+       }
 
        return error;
 }
@@ -6462,7 +6640,8 @@ _scsih_exit(void)
 
        pci_unregister_driver(&scsih_driver);
 
-       sas_release_transport(mpt2sas_transport_template);
+       mpt2sas_ctl_exit();
+
        mpt2sas_base_release_callback_handler(scsi_io_cb_idx);
        mpt2sas_base_release_callback_handler(tm_cb_idx);
        mpt2sas_base_release_callback_handler(base_cb_idx);
@@ -6474,7 +6653,10 @@ _scsih_exit(void)
        mpt2sas_base_release_callback_handler(tm_tr_cb_idx);
        mpt2sas_base_release_callback_handler(tm_sas_control_cb_idx);
 
-       mpt2sas_ctl_exit();
+       /* raid transport support */
+       raid_class_release(mpt2sas_raid_template);
+       sas_release_transport(mpt2sas_transport_template);
+
 }
 
 module_init(_scsih_init);
index 6b537f1..31e1ff6 100644 (file)
@@ -32,6 +32,7 @@ enum raid_level {
        RAID_LEVEL_0,
        RAID_LEVEL_1,
        RAID_LEVEL_10,
+       RAID_LEVEL_1E,
        RAID_LEVEL_3,
        RAID_LEVEL_4,
        RAID_LEVEL_5,