⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 megaraid_sas.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * *		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.02.00-rc4 * * Authors: * 	Sreenivas Bagalkote	<Sreenivas.Bagalkote@lsil.com> * 	Sumant Patro		<Sumant.Patro@lsil.com> * * 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 <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("sreenivas.bagalkote@lsil.com");MODULE_DESCRIPTION("LSI Logic MegaRAID SAS Driver");/* * PCI ID table for all supported controllers */static struct pci_device_id megasas_pci_table[] = {	{	 PCI_VENDOR_ID_LSI_LOGIC,	 PCI_DEVICE_ID_LSI_SAS1064R,	 PCI_ANY_ID,	 PCI_ANY_ID,	 },	{	 PCI_VENDOR_ID_DELL,	 PCI_DEVICE_ID_DELL_PERC5,	 PCI_ANY_ID,	 PCI_ANY_ID,	 },	{0}			/* Terminating entry */};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 DECLARE_MUTEX(megasas_async_queue_mutex);/** * megasas_get_cmd -	Get a command from the free pool * @instance:		Adapter soft state * * Returns a free command from the pool */static inline 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);}/** * megasas_enable_intr -	Enables interrupts * @regs:			MFI register set */static inline voidmegasas_enable_intr(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 -	Disables interrupts * @regs:			MFI register set */static inline voidmegasas_disable_intr(struct megasas_register_set __iomem * regs){	u32 mask = readl(&regs->outbound_intr_mask) & (~0x00000001);	writel(mask, &regs->outbound_intr_mask);	/* Dummy readl to force pci flush */	readl(&regs->outbound_intr_mask);}/** * 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	 */	writel(cmd->frame_phys_addr >> 3,	       &instance->reg_set->inbound_queue_port);	/*	 * 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. * Used to issue ioctl commands. */static intmegasas_issue_blocked_cmd(struct megasas_instance *instance,			  struct megasas_cmd *cmd){	cmd->cmd_status = ENODATA;	writel(cmd->frame_phys_addr >> 3,	       &instance->reg_set->inbound_queue_port);	wait_event(instance->int_cmd_wait_q, (cmd->cmd_status != ENODATA));	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 blocks till it is completed. */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;	writel(cmd->frame_phys_addr >> 3,	       &instance->reg_set->inbound_queue_port);	/*	 * Wait for this cmd to complete	 */	wait_event(instance->abort_cmd_wait_q, (cmd->cmd_status != 0xFF));	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 inline 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;	/*	 * Return 0 if there is no data transfer	 */	if (!scp->request_buffer || !scp->request_bufflen)		return 0;	if (!scp->use_sg) {		mfi_sgl->sge32[0].phys_addr = pci_map_single(instance->pdev,							     scp->							     request_buffer,							     scp->							     request_bufflen,							     scp->							     sc_data_direction);		mfi_sgl->sge32[0].length = scp->request_bufflen;		return 1;	}	os_sgl = (struct scatterlist *)scp->request_buffer;	sge_count = pci_map_sg(instance->pdev, os_sgl, scp->use_sg,			       scp->sc_data_direction);	for (i = 0; i < sge_count; i++, os_sgl++) {		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 inline 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;	/*	 * Return 0 if there is no data transfer	 */	if (!scp->request_buffer || !scp->request_bufflen)		return 0;	if (!scp->use_sg) {		mfi_sgl->sge64[0].phys_addr = pci_map_single(instance->pdev,							     scp->							     request_buffer,							     scp->							     request_bufflen,							     scp->							     sc_data_direction);		mfi_sgl->sge64[0].length = scp->request_bufflen;		return 1;	}	os_sgl = (struct scatterlist *)scp->request_buffer;	sge_count = pci_map_sg(instance->pdev, os_sgl, scp->use_sg,			       scp->sc_data_direction);	for (i = 0; i < sge_count; i++, os_sgl++) {		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_build_dcdb -	Prepares a direct cdb (DCDB) command * @instance:		Adapter soft state * @scp:		SCSI command * @cmd:		Command to be prepared in * * This function prepares CDB commands. These are typcially pass-through * commands to the devices. */static inline intmegasas_build_dcdb(struct megasas_instance *instance, struct scsi_cmnd *scp,		   struct megasas_cmd *cmd){	u32 sge_sz;	int sge_bytes;	u32 is_logical;	u32 device_id;	u16 flags = 0;	struct megasas_pthru_frame *pthru;	is_logical = MEGASAS_IS_LOGICAL(scp);	device_id = MEGASAS_DEV_INDEX(instance, scp);	pthru = (struct megasas_pthru_frame *)cmd->frame;	if (scp->sc_data_direction == PCI_DMA_TODEVICE)		flags = MFI_FRAME_DIR_WRITE;	else if (scp->sc_data_direction == PCI_DMA_FROMDEVICE)		flags = MFI_FRAME_DIR_READ;	else if (scp->sc_data_direction == PCI_DMA_NONE)		flags = MFI_FRAME_DIR_NONE;	/*	 * Prepare the DCDB frame	 */	pthru->cmd = (is_logical) ? MFI_CMD_LD_SCSI_IO : MFI_CMD_PD_SCSI_IO;	pthru->cmd_status = 0x0;	pthru->scsi_status = 0x0;	pthru->target_id = device_id;	pthru->lun = scp->device->lun;	pthru->cdb_len = scp->cmd_len;	pthru->timeout = 0;	pthru->flags = flags;	pthru->data_xfer_len = scp->request_bufflen;	memcpy(pthru->cdb, scp->cmnd, scp->cmd_len);	/*	 * Construct SGL	 */	sge_sz = (IS_DMA64) ? sizeof(struct megasas_sge64) :	    sizeof(struct megasas_sge32);	if (IS_DMA64) {		pthru->flags |= MFI_FRAME_SGL64;		pthru->sge_count = megasas_make_sgl64(instance, scp,						      &pthru->sgl);	} else		pthru->sge_count = megasas_make_sgl32(instance, scp,						      &pthru->sgl);	/*	 * Sense info specific	 */	pthru->sense_len = SCSI_SENSE_BUFFERSIZE;	pthru->sense_buf_phys_addr_hi = 0;	pthru->sense_buf_phys_addr_lo = cmd->sense_phys_addr;	sge_bytes = sge_sz * pthru->sge_count;	/*	 * Compute the total number of frames this command consumes. FW uses	 * this number to pull sufficient number of frames from host memory.	 */	cmd->frame_count = (sge_bytes / MEGAMFI_FRAME_SIZE) +	    ((sge_bytes % MEGAMFI_FRAME_SIZE) ? 1 : 0) + 1;	if (cmd->frame_count > 7)		cmd->frame_count = 8;	return cmd->frame_count;}/** * megasas_build_ldio -	Prepares IOs to logical devices * @instance:		Adapter soft state * @scp:		SCSI command * @cmd:		Command to to be prepared * * Frames (and accompanying SGLs) for regular SCSI IOs use this function. */static inline intmegasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp,		   struct megasas_cmd *cmd){	u32 sge_sz;	int sge_bytes;	u32 device_id;	u8 sc = scp->cmnd[0];	u16 flags = 0;	struct megasas_io_frame *ldio;	device_id = MEGASAS_DEV_INDEX(instance, scp);	ldio = (struct megasas_io_frame *)cmd->frame;	if (scp->sc_data_direction == PCI_DMA_TODEVICE)		flags = MFI_FRAME_DIR_WRITE;	else if (scp->sc_data_direction == PCI_DMA_FROMDEVICE)		flags = MFI_FRAME_DIR_READ;	/*	 * Preare the Logical IO frame: 2nd bit is zero for all read cmds	 */	ldio->cmd = (sc & 0x02) ? MFI_CMD_LD_WRITE : MFI_CMD_LD_READ;	ldio->cmd_status = 0x0;	ldio->scsi_status = 0x0;	ldio->target_id = device_id;	ldio->timeout = 0;	ldio->reserved_0 = 0;	ldio->pad_0 = 0;	ldio->flags = flags;	ldio->start_lba_hi = 0;	ldio->access_byte = (scp->cmd_len != 6) ? scp->cmnd[1] : 0;	/*	 * 6-byte READ(0x08) or WRITE(0x0A) cdb	 */	if (scp->cmd_len == 6) {		ldio->lba_count = (u32) scp->cmnd[4];		ldio->start_lba_lo = ((u32) scp->cmnd[1] << 16) |		    ((u32) scp->cmnd[2] << 8) | (u32) scp->cmnd[3];		ldio->start_lba_lo &= 0x1FFFFF;	}	/*	 * 10-byte READ(0x28) or WRITE(0x2A) cdb	 */	else if (scp->cmd_len == 10) {		ldio->lba_count = (u32) scp->cmnd[8] |		    ((u32) scp->cmnd[7] << 8);		ldio->start_lba_lo = ((u32) scp->cmnd[2] << 24) |		    ((u32) scp->cmnd[3] << 16) |		    ((u32) scp->cmnd[4] << 8) | (u32) scp->cmnd[5];	}	/*	 * 12-byte READ(0xA8) or WRITE(0xAA) cdb	 */	else if (scp->cmd_len == 12) {		ldio->lba_count = ((u32) scp->cmnd[6] << 24) |		    ((u32) scp->cmnd[7] << 16) |		    ((u32) scp->cmnd[8] << 8) | (u32) scp->cmnd[9];		ldio->start_lba_lo = ((u32) scp->cmnd[2] << 24) |		    ((u32) scp->cmnd[3] << 16) |		    ((u32) scp->cmnd[4] << 8) | (u32) scp->cmnd[5];	}	/*	 * 16-byte READ(0x88) or WRITE(0x8A) cdb	 */	else if (scp->cmd_len == 16) {		ldio->lba_count = ((u32) scp->cmnd[10] << 24) |		    ((u32) scp->cmnd[11] << 16) |		    ((u32) scp->cmnd[12] << 8) | (u32) scp->cmnd[13];		ldio->start_lba_lo = ((u32) scp->cmnd[6] << 24) |		    ((u32) scp->cmnd[7] << 16) |		    ((u32) scp->cmnd[8] << 8) | (u32) scp->cmnd[9];		ldio->start_lba_hi = ((u32) scp->cmnd[2] << 24) |		    ((u32) scp->cmnd[3] << 16) |		    ((u32) scp->cmnd[4] << 8) | (u32) scp->cmnd[5];	}	/*	 * Construct SGL	 */

⌨️ 快捷键说明

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