Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f7c95ef0 authored by Kashyap, Desai's avatar Kashyap, Desai Committed by James Bottomley
Browse files

[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: default avatarKashyap Desai <kashyap.desai@lsi.com>
Reviewed-by: default avatarEric Moore <eric.moore@lsi.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@suse.de>
parent 22c88425
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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.

+2 −0
Original line number Diff line number Diff line
@@ -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;
};

/**
+186 −4
Original line number Diff line number Diff line
@@ -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);
+1 −0
Original line number Diff line number Diff line
@@ -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,