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

Commit 36807e67 authored by Adam Radford's avatar Adam Radford Committed by James Bottomley
Browse files

[SCSI] megaraid_sas: Add support for MegaRAID 9360/9380 12GB/s controllers

parent 3f0e58bc
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -48,6 +48,7 @@
#define	PCI_DEVICE_ID_LSI_SAS0073SKINNY		0x0073
#define	PCI_DEVICE_ID_LSI_SAS0071SKINNY		0x0071
#define	PCI_DEVICE_ID_LSI_FUSION		0x005b
#define PCI_DEVICE_ID_LSI_INVADER		0x005d

/*
 * =====================================
@@ -221,6 +222,7 @@ enum MFI_STAT {
	MFI_STAT_RESERVATION_IN_PROGRESS = 0x36,
	MFI_STAT_I2C_ERRORS_DETECTED = 0x37,
	MFI_STAT_PCI_ERRORS_DETECTED = 0x38,
	MFI_STAT_CONFIG_SEQ_MISMATCH = 0x67,

	MFI_STAT_INVALID_STATUS = 0xFF
};
+29 −10
Original line number Diff line number Diff line
@@ -114,6 +114,8 @@ static struct pci_device_id megasas_pci_table[] = {
	/* xscale IOP */
	{PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FUSION)},
	/* Fusion */
	{PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_INVADER)},
	/* Invader */
	{}
};

@@ -1583,7 +1585,8 @@ void megaraid_sas_kill_hba(struct megasas_instance *instance)
{
	if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
	    (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY) ||
	    (instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION)) {
	    (instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) ||
	    (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER)) {
		writel(MFI_STOP_ADP, &instance->reg_set->doorbell);
	} else {
		writel(MFI_STOP_ADP, &instance->reg_set->inbound_doorbell);
@@ -1957,7 +1960,8 @@ static int megasas_reset_bus_host(struct scsi_cmnd *scmd)
	/*
	 * First wait for all commands to complete
	 */
	if (instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION)
	if ((instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) ||
	    (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER))
		ret = megasas_reset_fusion(scmd->device->host);
	else
		ret = megasas_generic_reset(scmd);
@@ -2656,7 +2660,9 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr)
				(instance->pdev->device ==
				 PCI_DEVICE_ID_LSI_SAS0071SKINNY) ||
				(instance->pdev->device ==
				 PCI_DEVICE_ID_LSI_FUSION)) {
				 PCI_DEVICE_ID_LSI_FUSION) ||
				(instance->pdev->device ==
				PCI_DEVICE_ID_LSI_INVADER)) {
				writel(
				  MFI_INIT_CLEAR_HANDSHAKE|MFI_INIT_HOTPLUG,
				  &instance->reg_set->doorbell);
@@ -2676,7 +2682,9 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr)
				(instance->pdev->device ==
				 PCI_DEVICE_ID_LSI_SAS0071SKINNY) ||
			    (instance->pdev->device ==
			     PCI_DEVICE_ID_LSI_FUSION)) {
			     PCI_DEVICE_ID_LSI_FUSION) ||
			    (instance->pdev->device ==
			     PCI_DEVICE_ID_LSI_INVADER)) {
				writel(MFI_INIT_HOTPLUG,
				       &instance->reg_set->doorbell);
			} else
@@ -2697,11 +2705,15 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr)
				(instance->pdev->device ==
				PCI_DEVICE_ID_LSI_SAS0071SKINNY)  ||
				(instance->pdev->device
					== PCI_DEVICE_ID_LSI_FUSION)) {
					== PCI_DEVICE_ID_LSI_FUSION) ||
				(instance->pdev->device
					== PCI_DEVICE_ID_LSI_INVADER)) {
				writel(MFI_RESET_FLAGS,
					&instance->reg_set->doorbell);
				if (instance->pdev->device ==
				    PCI_DEVICE_ID_LSI_FUSION) {
				if ((instance->pdev->device ==
				    PCI_DEVICE_ID_LSI_FUSION) ||
				    (instance->pdev->device ==
				     PCI_DEVICE_ID_LSI_INVADER)) {
					for (i = 0; i < (10 * 1000); i += 20) {
						if (readl(
							    &instance->
@@ -3498,6 +3510,7 @@ static int megasas_init_fw(struct megasas_instance *instance)

	switch (instance->pdev->device) {
	case PCI_DEVICE_ID_LSI_FUSION:
	case PCI_DEVICE_ID_LSI_INVADER:
		instance->instancet = &megasas_instance_template_fusion;
		break;
	case PCI_DEVICE_ID_LSI_SAS1078R:
@@ -3894,7 +3907,8 @@ static int megasas_io_attach(struct megasas_instance *instance)
	host->max_cmd_len = 16;

	/* Fusion only supports host reset */
	if (instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) {
	if ((instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) ||
	    (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER)) {
		host->hostt->eh_device_reset_handler = NULL;
		host->hostt->eh_bus_reset_handler = NULL;
	}
@@ -4004,6 +4018,7 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)

	switch (instance->pdev->device) {
	case PCI_DEVICE_ID_LSI_FUSION:
	case PCI_DEVICE_ID_LSI_INVADER:
	{
		struct fusion_context *fusion;

@@ -4096,7 +4111,8 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
	instance->last_time = 0;
	instance->disableOnlineCtrlReset = 1;

	if (instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION)
	if ((instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) ||
	    (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER))
		INIT_WORK(&instance->work_init, megasas_fusion_ocr_wq);
	else
		INIT_WORK(&instance->work_init, process_fw_state_change_wq);
@@ -4161,7 +4177,8 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
	free_irq(instance->msi_flag ? instance->msixentry.vector :
		 instance->pdev->irq, instance);
fail_irq:
	if (instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION)
	if ((instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) ||
	    (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER))
		megasas_release_fusion(instance);
	else
		megasas_release_mfi(instance);
@@ -4368,6 +4385,7 @@ megasas_resume(struct pci_dev *pdev)

	switch (instance->pdev->device) {
	case PCI_DEVICE_ID_LSI_FUSION:
	case PCI_DEVICE_ID_LSI_INVADER:
	{
		megasas_reset_reply_desc(instance);
		if (megasas_ioc_init_fusion(instance)) {
@@ -4501,6 +4519,7 @@ static void __devexit megasas_detach_one(struct pci_dev *pdev)

	switch (instance->pdev->device) {
	case PCI_DEVICE_ID_LSI_FUSION:
	case PCI_DEVICE_ID_LSI_INVADER:
		megasas_release_fusion(instance);
		for (i = 0; i < 2 ; i++)
			if (fusion->ld_map[i])
+18 −8
Original line number Diff line number Diff line
@@ -52,6 +52,7 @@
#include <scsi/scsi_host.h>

#include "megaraid_sas_fusion.h"
#include "megaraid_sas.h"
#include <asm/div64.h>

#define ABS_DIFF(a, b)   (((a) > (b)) ? ((a) - (b)) : ((b) - (a)))
@@ -226,8 +227,9 @@ u32 MR_GetSpanBlock(u32 ld, u64 row, u64 *span_blk,
*    span          - Span number
*    block         - Absolute Block number in the physical disk
*/
u8 MR_GetPhyParams(u32 ld, u64 stripRow, u16 stripRef, u64 *pdBlock,
		   u16 *pDevHandle, struct RAID_CONTEXT *pRAID_Context,
u8 MR_GetPhyParams(struct megasas_instance *instance, u32 ld, u64 stripRow,
		   u16 stripRef, u64 *pdBlock, u16 *pDevHandle,
		   struct RAID_CONTEXT *pRAID_Context,
		   struct MR_FW_RAID_MAP_ALL *map)
{
	struct MR_LD_RAID  *raid = MR_LdRaidGet(ld, map);
@@ -279,7 +281,8 @@ u8 MR_GetPhyParams(u32 ld, u64 stripRow, u16 stripRef, u64 *pdBlock,
		*pDevHandle = MR_PdDevHandleGet(pd, map);
	else {
		*pDevHandle = MR_PD_INVALID; /* set dev handle as invalid. */
		if (raid->level >= 5)
		if ((raid->level >= 5) &&
		    (instance->pdev->device != PCI_DEVICE_ID_LSI_INVADER))
			pRAID_Context->regLockFlags = REGION_TYPE_EXCLUSIVE;
		else if (raid->level == 1) {
			/* Get alternate Pd. */
@@ -306,7 +309,8 @@ u8 MR_GetPhyParams(u32 ld, u64 stripRow, u16 stripRef, u64 *pdBlock,
* This function will return 0 if region lock was acquired OR return num strips
*/
u8
MR_BuildRaidContext(struct IO_REQUEST_INFO *io_info,
MR_BuildRaidContext(struct megasas_instance *instance,
		    struct IO_REQUEST_INFO *io_info,
		    struct RAID_CONTEXT *pRAID_Context,
		    struct MR_FW_RAID_MAP_ALL *map)
{
@@ -394,8 +398,12 @@ MR_BuildRaidContext(struct IO_REQUEST_INFO *io_info,
	}

	pRAID_Context->timeoutValue     = map->raidMap.fpPdIoTimeoutSec;
	pRAID_Context->regLockFlags     = (isRead) ? REGION_TYPE_SHARED_READ :
		raid->regTypeReqOnWrite;
	if (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER)
		pRAID_Context->regLockFlags = (isRead) ?
			raid->regTypeReqOnRead : raid->regTypeReqOnWrite;
	else
		pRAID_Context->regLockFlags = (isRead) ?
			REGION_TYPE_SHARED_READ : raid->regTypeReqOnWrite;
	pRAID_Context->VirtualDiskTgtId = raid->targetId;
	pRAID_Context->regLockRowLBA    = regStart;
	pRAID_Context->regLockLength    = regSize;
@@ -404,7 +412,8 @@ MR_BuildRaidContext(struct IO_REQUEST_INFO *io_info,
	/*Get Phy Params only if FP capable, or else leave it to MR firmware
	  to do the calculation.*/
	if (io_info->fpOkForIo) {
		retval = MR_GetPhyParams(ld, start_strip, ref_in_start_stripe,
		retval = MR_GetPhyParams(instance, ld, start_strip,
					 ref_in_start_stripe,
					 &io_info->pdBlock,
					 &io_info->devHandle, pRAID_Context,
					 map);
@@ -415,7 +424,8 @@ MR_BuildRaidContext(struct IO_REQUEST_INFO *io_info,
	} else if (isRead) {
		uint stripIdx;
		for (stripIdx = 0; stripIdx < num_strips; stripIdx++) {
			if (!MR_GetPhyParams(ld, start_strip + stripIdx,
			if (!MR_GetPhyParams(instance, ld,
					     start_strip + stripIdx,
					     ref_in_start_stripe,
					     &io_info->pdBlock,
					     &io_info->devHandle,
+77 −19
Original line number Diff line number Diff line
@@ -74,7 +74,8 @@ megasas_issue_polled(struct megasas_instance *instance,
		     struct megasas_cmd *cmd);

u8
MR_BuildRaidContext(struct IO_REQUEST_INFO *io_info,
MR_BuildRaidContext(struct megasas_instance *instance,
		    struct IO_REQUEST_INFO *io_info,
		    struct RAID_CONTEXT *pRAID_Context,
		    struct MR_FW_RAID_MAP_ALL *map);
u16 MR_TargetIdToLdGet(u32 ldTgtId, struct MR_FW_RAID_MAP_ALL *map);
@@ -1038,7 +1039,9 @@ map_cmd_status(struct megasas_cmd_fusion *cmd, u8 status, u8 ext_status)
	case MFI_STAT_DEVICE_NOT_FOUND:
		cmd->scmd->result = DID_BAD_TARGET << 16;
		break;

	case MFI_STAT_CONFIG_SEQ_MISMATCH:
		cmd->scmd->result = DID_IMM_RETRY << 16;
		break;
	default:
		printk(KERN_DEBUG "megasas: FW status %#x\n", status);
		cmd->scmd->result = DID_ERROR << 16;
@@ -1061,14 +1064,17 @@ megasas_make_sgl_fusion(struct megasas_instance *instance,
			struct MPI25_IEEE_SGE_CHAIN64 *sgl_ptr,
			struct megasas_cmd_fusion *cmd)
{
	int i, sg_processed;
	int sge_count, sge_idx;
	int i, sg_processed, sge_count;
	struct scatterlist *os_sgl;
	struct fusion_context *fusion;

	fusion = instance->ctrl_context;

	cmd->io_request->ChainOffset = 0;
	if (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) {
		struct MPI25_IEEE_SGE_CHAIN64 *sgl_ptr_end = sgl_ptr;
		sgl_ptr_end += fusion->max_sge_in_main_msg - 1;
		sgl_ptr_end->Flags = 0;
	}

	sge_count = scsi_dma_map(scp);

@@ -1077,16 +1083,14 @@ megasas_make_sgl_fusion(struct megasas_instance *instance,
	if (sge_count > instance->max_num_sge || !sge_count)
		return sge_count;

	if (sge_count > fusion->max_sge_in_main_msg) {
		/* One element to store the chain info */
		sge_idx = fusion->max_sge_in_main_msg - 1;
	} else
		sge_idx = sge_count;

	scsi_for_each_sg(scp, os_sgl, sge_count, i) {
		sgl_ptr->Length = sg_dma_len(os_sgl);
		sgl_ptr->Address = sg_dma_address(os_sgl);
		sgl_ptr->Flags = 0;
		if (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) {
			if (i == sge_count - 1)
				sgl_ptr->Flags = IEEE_SGE_FLAGS_END_OF_LIST;
		}
		sgl_ptr++;

		sg_processed = i + 1;
@@ -1095,12 +1099,29 @@ megasas_make_sgl_fusion(struct megasas_instance *instance,
		    (sge_count > fusion->max_sge_in_main_msg)) {

			struct MPI25_IEEE_SGE_CHAIN64 *sg_chain;
			if (instance->pdev->device ==
			    PCI_DEVICE_ID_LSI_INVADER) {
				if ((cmd->io_request->IoFlags &
				MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH) !=
				MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH)
					cmd->io_request->ChainOffset =
						fusion->
						chain_offset_io_request;
				else
					cmd->io_request->ChainOffset = 0;
			} else
				cmd->io_request->ChainOffset =
					fusion->chain_offset_io_request;

			sg_chain = sgl_ptr;
			/* Prepare chain element */
			sg_chain->NextChainOffset = 0;
			sg_chain->Flags = (IEEE_SGE_FLAGS_CHAIN_ELEMENT |
			if (instance->pdev->device ==
			    PCI_DEVICE_ID_LSI_INVADER)
				sg_chain->Flags = IEEE_SGE_FLAGS_CHAIN_ELEMENT;
			else
				sg_chain->Flags =
					(IEEE_SGE_FLAGS_CHAIN_ELEMENT |
					 MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR);
			sg_chain->Length =  (sizeof(union MPI2_SGE_IO_UNION)
					     *(sge_count - sg_processed));
@@ -1394,7 +1415,8 @@ megasas_build_ldio_fusion(struct megasas_instance *instance,
		io_request->RaidContext.regLockFlags  = 0;
		fp_possible = 0;
	} else {
		if (MR_BuildRaidContext(&io_info, &io_request->RaidContext,
		if (MR_BuildRaidContext(instance, &io_info,
					&io_request->RaidContext,
					local_map_ptr))
			fp_possible = io_info.fpOkForIo;
	}
@@ -1407,6 +1429,20 @@ megasas_build_ldio_fusion(struct megasas_instance *instance,
		cmd->request_desc->SCSIIO.RequestFlags =
			(MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY
			 << MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
		if (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) {
			if (io_request->RaidContext.regLockFlags ==
			    REGION_TYPE_UNUSED)
				cmd->request_desc->SCSIIO.RequestFlags =
					(MEGASAS_REQ_DESCRIPT_FLAGS_NO_LOCK <<
					MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
			io_request->RaidContext.Type = MPI2_TYPE_CUDA;
			io_request->RaidContext.nseg = 0x1;
			io_request->IoFlags |=
			  MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH;
			io_request->RaidContext.regLockFlags |=
			  (MR_RL_FLAGS_GRANT_DESTINATION_CUDA |
			   MR_RL_FLAGS_SEQ_NUM_ENABLE);
		}
		if ((fusion->load_balance_info[device_id].loadBalanceFlag) &&
		    (io_info.isRead)) {
			io_info.devHandle =
@@ -1421,11 +1457,23 @@ megasas_build_ldio_fusion(struct megasas_instance *instance,
	} else {
		io_request->RaidContext.timeoutValue =
			local_map_ptr->raidMap.fpPdIoTimeoutSec;
		io_request->Function = MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST;
		io_request->DevHandle = device_id;
		cmd->request_desc->SCSIIO.RequestFlags =
			(MEGASAS_REQ_DESCRIPT_FLAGS_LD_IO
			 << MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
		if (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) {
			if (io_request->RaidContext.regLockFlags ==
			    REGION_TYPE_UNUSED)
				cmd->request_desc->SCSIIO.RequestFlags =
					(MEGASAS_REQ_DESCRIPT_FLAGS_NO_LOCK <<
					MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
			io_request->RaidContext.Type = MPI2_TYPE_CUDA;
			io_request->RaidContext.regLockFlags |=
				(MR_RL_FLAGS_GRANT_DESTINATION_CPU0 |
				 MR_RL_FLAGS_SEQ_NUM_ENABLE);
			io_request->RaidContext.nseg = 0x1;
		}
		io_request->Function = MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST;
		io_request->DevHandle = device_id;
	} /* Not FP */
}

@@ -1508,8 +1556,10 @@ megasas_build_io_fusion(struct megasas_instance *instance,
	io_request->EEDPFlags = 0;
	io_request->Control = 0;
	io_request->EEDPBlockSize = 0;
	io_request->IoFlags = 0;
	io_request->ChainOffset = 0;
	io_request->RaidContext.RAIDFlags = 0;
	io_request->RaidContext.Type = 0;
	io_request->RaidContext.nseg = 0;

	memcpy(io_request->CDB.CDB32, scp->cmnd, scp->cmd_len);
	/*
@@ -1863,6 +1913,14 @@ build_mpt_mfi_pass_thru(struct megasas_instance *instance,

	fusion = instance->ctrl_context;
	io_req = cmd->io_request;

	if (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) {
		struct MPI25_IEEE_SGE_CHAIN64 *sgl_ptr_end =
			(struct MPI25_IEEE_SGE_CHAIN64 *)&io_req->SGL;
		sgl_ptr_end += fusion->max_sge_in_main_msg - 1;
		sgl_ptr_end->Flags = 0;
	}

	mpi25_ieee_chain =
	  (struct MPI25_IEEE_SGE_CHAIN64 *)&io_req->SGL.IeeeChain;

+13 −3
Original line number Diff line number Diff line
@@ -44,6 +44,14 @@
#define HOST_DIAG_RESET_ADAPTER			    0x4
#define MEGASAS_FUSION_MAX_RESET_TRIES		    3

/* Invader defines */
#define MPI2_TYPE_CUDA				    0x2
#define MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH   0x4000
#define	MR_RL_FLAGS_GRANT_DESTINATION_CPU0	    0x00
#define	MR_RL_FLAGS_GRANT_DESTINATION_CPU1	    0x10
#define	MR_RL_FLAGS_GRANT_DESTINATION_CUDA	    0x80
#define MR_RL_FLAGS_SEQ_NUM_ENABLE		    0x8

/* T10 PI defines */
#define MR_PROT_INFO_TYPE_CONTROLLER                0x8
#define MEGASAS_SCSI_VARIABLE_LENGTH_CMD            0x7f
@@ -70,7 +78,7 @@ enum MR_RAID_FLAGS_IO_SUB_TYPE {
 */
#define MEGASAS_REQ_DESCRIPT_FLAGS_LD_IO           0x7
#define MEGASAS_REQ_DESCRIPT_FLAGS_MFA             0x1

#define MEGASAS_REQ_DESCRIPT_FLAGS_NO_LOCK	   0x2
#define MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT      1

#define MEGASAS_FP_CMD_LEN	16
@@ -82,7 +90,9 @@ enum MR_RAID_FLAGS_IO_SUB_TYPE {
 */

struct RAID_CONTEXT {
	u16     resvd0;
	u8	Type:4;
	u8	nseg:4;
	u8	resvd0;
	u16     timeoutValue;
	u8      regLockFlags;
	u8      resvd1;
@@ -527,7 +537,7 @@ struct MR_LD_RAID {
	u8      ldState;
	u8      regTypeReqOnWrite;
	u8      modFactor;
	u8      reserved2[1];
	u8	regTypeReqOnRead;
	u16     seqNum;

	struct {