[SCSI] mpt2sas: Added raid transport support

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>
This commit is contained in:
Kashyap, Desai 2009-12-16 18:54:42 +05:30 committed by James Bottomley
parent 22c88425e0
commit f7c95ef02b
4 changed files with 190 additions and 4 deletions

View 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.

View 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;
};
/**

View 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);

View 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,