megaraid_sas.c

来自「linux 内核源代码」· C语言 代码 · 共 2,561 行 · 第 1/5 页

C
2,561
字号
/* * *		Linux MegaRAID driver for SAS based RAID controllers * * Copyright (c) 2003-2005  LSI Logic Corporation. * *	   This program is free software; you can redistribute it and/or *	   modify it under the terms of the GNU General Public License *	   as published by the Free Software Foundation; either version *	   2 of the License, or (at your option) any later version. * * FILE		: megaraid_sas.c * Version	: v00.00.03.10-rc5 * * Authors: *	(email-id : megaraidlinux@lsi.com) * 	Sreenivas Bagalkote * 	Sumant Patro *	Bo Yang * * List of supported controllers * * OEM	Product Name			VID	DID	SSVID	SSID * ---	------------			---	---	----	---- */#include <linux/kernel.h>#include <linux/types.h>#include <linux/pci.h>#include <linux/list.h>#include <linux/moduleparam.h>#include <linux/module.h>#include <linux/spinlock.h>#include <linux/interrupt.h>#include <linux/delay.h>#include <linux/uio.h>#include <asm/uaccess.h>#include <linux/fs.h>#include <linux/compat.h>#include <linux/blkdev.h>#include <linux/mutex.h>#include <scsi/scsi.h>#include <scsi/scsi_cmnd.h>#include <scsi/scsi_device.h>#include <scsi/scsi_host.h>#include "megaraid_sas.h"MODULE_LICENSE("GPL");MODULE_VERSION(MEGASAS_VERSION);MODULE_AUTHOR("megaraidlinux@lsi.com");MODULE_DESCRIPTION("LSI Logic MegaRAID SAS Driver");/* * PCI ID table for all supported controllers */static struct pci_device_id megasas_pci_table[] = {	{PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1064R)},	/* xscale IOP */	{PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1078R)},	/* ppc IOP */	{PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_VERDE_ZCR)},	/* xscale IOP, vega */	{PCI_DEVICE(PCI_VENDOR_ID_DELL, PCI_DEVICE_ID_DELL_PERC5)},	/* xscale IOP */	{}};MODULE_DEVICE_TABLE(pci, megasas_pci_table);static int megasas_mgmt_majorno;static struct megasas_mgmt_info megasas_mgmt_info;static struct fasync_struct *megasas_async_queue;static DEFINE_MUTEX(megasas_async_queue_mutex);static u32 megasas_dbg_lvl;/** * megasas_get_cmd -	Get a command from the free pool * @instance:		Adapter soft state * * Returns a free command from the pool */static struct megasas_cmd *megasas_get_cmd(struct megasas_instance						  *instance){	unsigned long flags;	struct megasas_cmd *cmd = NULL;	spin_lock_irqsave(&instance->cmd_pool_lock, flags);	if (!list_empty(&instance->cmd_pool)) {		cmd = list_entry((&instance->cmd_pool)->next,				 struct megasas_cmd, list);		list_del_init(&cmd->list);	} else {		printk(KERN_ERR "megasas: Command pool empty!\n");	}	spin_unlock_irqrestore(&instance->cmd_pool_lock, flags);	return cmd;}/** * megasas_return_cmd -	Return a cmd to free command pool * @instance:		Adapter soft state * @cmd:		Command packet to be returned to free command pool */static inline voidmegasas_return_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd){	unsigned long flags;	spin_lock_irqsave(&instance->cmd_pool_lock, flags);	cmd->scmd = NULL;	list_add_tail(&cmd->list, &instance->cmd_pool);	spin_unlock_irqrestore(&instance->cmd_pool_lock, flags);}/***	The following functions are defined for xscale *	(deviceid : 1064R, PERC5) controllers*//** * megasas_enable_intr_xscale -	Enables interrupts * @regs:			MFI register set */static inline voidmegasas_enable_intr_xscale(struct megasas_register_set __iomem * regs){	writel(1, &(regs)->outbound_intr_mask);	/* Dummy readl to force pci flush */	readl(&regs->outbound_intr_mask);}/** * megasas_disable_intr_xscale -Disables interrupt * @regs:			MFI register set */static inline voidmegasas_disable_intr_xscale(struct megasas_register_set __iomem * regs){	u32 mask = 0x1f;	writel(mask, &regs->outbound_intr_mask);	/* Dummy readl to force pci flush */	readl(&regs->outbound_intr_mask);}/** * megasas_read_fw_status_reg_xscale - returns the current FW status value * @regs:			MFI register set */static u32megasas_read_fw_status_reg_xscale(struct megasas_register_set __iomem * regs){	return readl(&(regs)->outbound_msg_0);}/** * megasas_clear_interrupt_xscale -	Check & clear interrupt * @regs:				MFI register set */static int megasas_clear_intr_xscale(struct megasas_register_set __iomem * regs){	u32 status;	/*	 * Check if it is our interrupt	 */	status = readl(&regs->outbound_intr_status);	if (!(status & MFI_OB_INTR_STATUS_MASK)) {		return 1;	}	/*	 * Clear the interrupt by writing back the same value	 */	writel(status, &regs->outbound_intr_status);	return 0;}/** * megasas_fire_cmd_xscale -	Sends command to the FW * @frame_phys_addr :		Physical address of cmd * @frame_count :		Number of frames for the command * @regs :			MFI register set */static inline void megasas_fire_cmd_xscale(dma_addr_t frame_phys_addr,u32 frame_count, struct megasas_register_set __iomem *regs){	writel((frame_phys_addr >> 3)|(frame_count),	       &(regs)->inbound_queue_port);}static struct megasas_instance_template megasas_instance_template_xscale = {	.fire_cmd = megasas_fire_cmd_xscale,	.enable_intr = megasas_enable_intr_xscale,	.disable_intr = megasas_disable_intr_xscale,	.clear_intr = megasas_clear_intr_xscale,	.read_fw_status_reg = megasas_read_fw_status_reg_xscale,};/***	This is the end of set of functions & definitions specific *	to xscale (deviceid : 1064R, PERC5) controllers*//***	The following functions are defined for ppc (deviceid : 0x60) * 	controllers*//** * megasas_enable_intr_ppc -	Enables interrupts * @regs:			MFI register set */static inline voidmegasas_enable_intr_ppc(struct megasas_register_set __iomem * regs){	writel(0xFFFFFFFF, &(regs)->outbound_doorbell_clear);    	writel(~0x80000004, &(regs)->outbound_intr_mask);	/* Dummy readl to force pci flush */	readl(&regs->outbound_intr_mask);}/** * megasas_disable_intr_ppc -	Disable interrupt * @regs:			MFI register set */static inline voidmegasas_disable_intr_ppc(struct megasas_register_set __iomem * regs){	u32 mask = 0xFFFFFFFF;	writel(mask, &regs->outbound_intr_mask);	/* Dummy readl to force pci flush */	readl(&regs->outbound_intr_mask);}/** * megasas_read_fw_status_reg_ppc - returns the current FW status value * @regs:			MFI register set */static u32megasas_read_fw_status_reg_ppc(struct megasas_register_set __iomem * regs){	return readl(&(regs)->outbound_scratch_pad);}/** * megasas_clear_interrupt_ppc -	Check & clear interrupt * @regs:				MFI register set */static int megasas_clear_intr_ppc(struct megasas_register_set __iomem * regs){	u32 status;	/*	 * Check if it is our interrupt	 */	status = readl(&regs->outbound_intr_status);	if (!(status & MFI_REPLY_1078_MESSAGE_INTERRUPT)) {		return 1;	}	/*	 * Clear the interrupt by writing back the same value	 */	writel(status, &regs->outbound_doorbell_clear);	return 0;}/** * megasas_fire_cmd_ppc -	Sends command to the FW * @frame_phys_addr :		Physical address of cmd * @frame_count :		Number of frames for the command * @regs :			MFI register set */static inline void megasas_fire_cmd_ppc(dma_addr_t frame_phys_addr, u32 frame_count, struct megasas_register_set __iomem *regs){	writel((frame_phys_addr | (frame_count<<1))|1, 			&(regs)->inbound_queue_port);}static struct megasas_instance_template megasas_instance_template_ppc = {		.fire_cmd = megasas_fire_cmd_ppc,	.enable_intr = megasas_enable_intr_ppc,	.disable_intr = megasas_disable_intr_ppc,	.clear_intr = megasas_clear_intr_ppc,	.read_fw_status_reg = megasas_read_fw_status_reg_ppc,};/***	This is the end of set of functions & definitions* 	specific to ppc (deviceid : 0x60) controllers*//** * megasas_issue_polled -	Issues a polling command * @instance:			Adapter soft state * @cmd:			Command packet to be issued  * * For polling, MFI requires the cmd_status to be set to 0xFF before posting. */static intmegasas_issue_polled(struct megasas_instance *instance, struct megasas_cmd *cmd){	int i;	u32 msecs = MFI_POLL_TIMEOUT_SECS * 1000;	struct megasas_header *frame_hdr = &cmd->frame->hdr;	frame_hdr->cmd_status = 0xFF;	frame_hdr->flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE;	/*	 * Issue the frame using inbound queue port	 */	instance->instancet->fire_cmd(cmd->frame_phys_addr ,0,instance->reg_set);	/*	 * Wait for cmd_status to change	 */	for (i = 0; (i < msecs) && (frame_hdr->cmd_status == 0xff); i++) {		rmb();		msleep(1);	}	if (frame_hdr->cmd_status == 0xff)		return -ETIME;	return 0;}/** * megasas_issue_blocked_cmd -	Synchronous wrapper around regular FW cmds * @instance:			Adapter soft state * @cmd:			Command to be issued * * This function waits on an event for the command to be returned from ISR. * Max wait time is MEGASAS_INTERNAL_CMD_WAIT_TIME secs * Used to issue ioctl commands. */static intmegasas_issue_blocked_cmd(struct megasas_instance *instance,			  struct megasas_cmd *cmd){	cmd->cmd_status = ENODATA;	instance->instancet->fire_cmd(cmd->frame_phys_addr ,0,instance->reg_set);	wait_event_timeout(instance->int_cmd_wait_q, (cmd->cmd_status != ENODATA),		MEGASAS_INTERNAL_CMD_WAIT_TIME*HZ);	return 0;}/** * megasas_issue_blocked_abort_cmd -	Aborts previously issued cmd * @instance:				Adapter soft state * @cmd_to_abort:			Previously issued cmd to be aborted * * MFI firmware can abort previously issued AEN comamnd (automatic event * notification). The megasas_issue_blocked_abort_cmd() issues such abort * cmd and waits for return status. * Max wait time is MEGASAS_INTERNAL_CMD_WAIT_TIME secs */static intmegasas_issue_blocked_abort_cmd(struct megasas_instance *instance,				struct megasas_cmd *cmd_to_abort){	struct megasas_cmd *cmd;	struct megasas_abort_frame *abort_fr;	cmd = megasas_get_cmd(instance);	if (!cmd)		return -1;	abort_fr = &cmd->frame->abort;	/*	 * Prepare and issue the abort frame	 */	abort_fr->cmd = MFI_CMD_ABORT;	abort_fr->cmd_status = 0xFF;	abort_fr->flags = 0;	abort_fr->abort_context = cmd_to_abort->index;	abort_fr->abort_mfi_phys_addr_lo = cmd_to_abort->frame_phys_addr;	abort_fr->abort_mfi_phys_addr_hi = 0;	cmd->sync_cmd = 1;	cmd->cmd_status = 0xFF;	instance->instancet->fire_cmd(cmd->frame_phys_addr ,0,instance->reg_set);	/*	 * Wait for this cmd to complete	 */	wait_event_timeout(instance->abort_cmd_wait_q, (cmd->cmd_status != 0xFF),		MEGASAS_INTERNAL_CMD_WAIT_TIME*HZ);	megasas_return_cmd(instance, cmd);	return 0;}/** * megasas_make_sgl32 -	Prepares 32-bit SGL * @instance:		Adapter soft state * @scp:		SCSI command from the mid-layer * @mfi_sgl:		SGL to be filled in * * If successful, this function returns the number of SG elements. Otherwise, * it returnes -1. */static intmegasas_make_sgl32(struct megasas_instance *instance, struct scsi_cmnd *scp,		   union megasas_sgl *mfi_sgl){	int i;	int sge_count;	struct scatterlist *os_sgl;	sge_count = scsi_dma_map(scp);	BUG_ON(sge_count < 0);	if (sge_count) {		scsi_for_each_sg(scp, os_sgl, sge_count, i) {			mfi_sgl->sge32[i].length = sg_dma_len(os_sgl);			mfi_sgl->sge32[i].phys_addr = sg_dma_address(os_sgl);		}	}	return sge_count;}/** * megasas_make_sgl64 -	Prepares 64-bit SGL * @instance:		Adapter soft state * @scp:		SCSI command from the mid-layer * @mfi_sgl:		SGL to be filled in * * If successful, this function returns the number of SG elements. Otherwise, * it returnes -1. */static intmegasas_make_sgl64(struct megasas_instance *instance, struct scsi_cmnd *scp,		   union megasas_sgl *mfi_sgl){	int i;	int sge_count;	struct scatterlist *os_sgl;	sge_count = scsi_dma_map(scp);	BUG_ON(sge_count < 0);	if (sge_count) {		scsi_for_each_sg(scp, os_sgl, sge_count, i) {			mfi_sgl->sge64[i].length = sg_dma_len(os_sgl);			mfi_sgl->sge64[i].phys_addr = sg_dma_address(os_sgl);		}	}	return sge_count;} /** * megasas_get_frame_count - Computes the number of frames * @sge_count		: number of sg elements * * Returns the number of frames required for numnber of sge's (sge_count) */static u32 megasas_get_frame_count(u8 sge_count){	int num_cnt;	int sge_bytes;	u32 sge_sz;	u32 frame_count=0;	sge_sz = (IS_DMA64) ? sizeof(struct megasas_sge64) :	    sizeof(struct megasas_sge32);	/*	* Main frame can contain 2 SGEs for 64-bit SGLs and	* 3 SGEs for 32-bit SGLs	*/	if (IS_DMA64)		num_cnt = sge_count - 2;	else		num_cnt = sge_count - 3;	if(num_cnt>0){		sge_bytes = sge_sz * num_cnt;		frame_count = (sge_bytes / MEGAMFI_FRAME_SIZE) +		    ((sge_bytes % MEGAMFI_FRAME_SIZE) ? 1 : 0) ;	}	/* Main frame */	frame_count +=1;	if (frame_count > 7)		frame_count = 8;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?