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

📄 megaraid.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * *			Linux MegaRAID device driver * * Copyright (c) 2002  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. * * Copyright (c) 2002  Red Hat, Inc. All rights reserved. *	  - fixes *	  - speed-ups (list handling fixes, issued_list, optimizations.) *	  - lots of cleanups. * * Copyright (c) 2003  Christoph Hellwig  <hch@lst.de> *	  - new-style, hotplug-aware pci probing and scsi registration * * Version : v2.00.4 Mon Nov 14 14:02:43 EST 2005 - Seokmann Ju * 						<Seokmann.Ju@lsil.com> * * Description: Linux device driver for LSI Logic MegaRAID controller * * Supported controllers: MegaRAID 418, 428, 438, 466, 762, 467, 471, 490, 493 *					518, 520, 531, 532 * * This driver is supported by LSI Logic, with assistance from Red Hat, Dell, * and others. Please send updates to the mailing list * linux-scsi@vger.kernel.org . * */#include <linux/mm.h>#include <linux/fs.h>#include <linux/blkdev.h>#include <asm/uaccess.h>#include <asm/io.h>#include <linux/completion.h>#include <linux/delay.h>#include <linux/proc_fs.h>#include <linux/reboot.h>#include <linux/module.h>#include <linux/list.h>#include <linux/interrupt.h>#include <linux/pci.h>#include <linux/init.h>#include <linux/dma-mapping.h>#include <scsi/scsicam.h>#include "scsi.h"#include <scsi/scsi_host.h>#include "megaraid.h"#define MEGARAID_MODULE_VERSION "2.00.4"MODULE_AUTHOR ("sju@lsil.com");MODULE_DESCRIPTION ("LSI Logic MegaRAID legacy driver");MODULE_LICENSE ("GPL");MODULE_VERSION(MEGARAID_MODULE_VERSION);static unsigned int max_cmd_per_lun = DEF_CMD_PER_LUN;module_param(max_cmd_per_lun, uint, 0);MODULE_PARM_DESC(max_cmd_per_lun, "Maximum number of commands which can be issued to a single LUN (default=DEF_CMD_PER_LUN=63)");static unsigned short int max_sectors_per_io = MAX_SECTORS_PER_IO;module_param(max_sectors_per_io, ushort, 0);MODULE_PARM_DESC(max_sectors_per_io, "Maximum number of sectors per I/O request (default=MAX_SECTORS_PER_IO=128)");static unsigned short int max_mbox_busy_wait = MBOX_BUSY_WAIT;module_param(max_mbox_busy_wait, ushort, 0);MODULE_PARM_DESC(max_mbox_busy_wait, "Maximum wait for mailbox in microseconds if busy (default=MBOX_BUSY_WAIT=10)");#define RDINDOOR(adapter)	readl((adapter)->mmio_base + 0x20)#define RDOUTDOOR(adapter)	readl((adapter)->mmio_base + 0x2C)#define WRINDOOR(adapter,value)	 writel(value, (adapter)->mmio_base + 0x20)#define WROUTDOOR(adapter,value) writel(value, (adapter)->mmio_base + 0x2C)/* * Global variables */static int hba_count;static adapter_t *hba_soft_state[MAX_CONTROLLERS];static struct proc_dir_entry *mega_proc_dir_entry;/* For controller re-ordering */static struct mega_hbas mega_hbas[MAX_CONTROLLERS];/* * The File Operations structure for the serial/ioctl interface of the driver */static const struct file_operations megadev_fops = {	.owner		= THIS_MODULE,	.ioctl		= megadev_ioctl,	.open		= megadev_open,};/* * Array to structures for storing the information about the controllers. This * information is sent to the user level applications, when they do an ioctl * for this information. */static struct mcontroller mcontroller[MAX_CONTROLLERS];/* The current driver version */static u32 driver_ver = 0x02000000;/* major number used by the device for character interface */static int major;#define IS_RAID_CH(hba, ch)	(((hba)->mega_ch_class >> (ch)) & 0x01)/* * Debug variable to print some diagnostic messages */static int trace_level;/** * mega_setup_mailbox() * @adapter - pointer to our soft state * * Allocates a 8 byte aligned memory for the handshake mailbox. */static intmega_setup_mailbox(adapter_t *adapter){	unsigned long	align;	adapter->una_mbox64 = pci_alloc_consistent(adapter->dev,			sizeof(mbox64_t), &adapter->una_mbox64_dma);	if( !adapter->una_mbox64 ) return -1;			adapter->mbox = &adapter->una_mbox64->mbox;	adapter->mbox = (mbox_t *)((((unsigned long) adapter->mbox) + 15) &			(~0UL ^ 0xFUL));	adapter->mbox64 = (mbox64_t *)(((unsigned long)adapter->mbox) - 8);	align = ((void *)adapter->mbox) - ((void *)&adapter->una_mbox64->mbox);	adapter->mbox_dma = adapter->una_mbox64_dma + 8 + align;	/*	 * Register the mailbox if the controller is an io-mapped controller	 */	if( adapter->flag & BOARD_IOMAP ) {		outb_p(adapter->mbox_dma & 0xFF,				adapter->host->io_port + MBOX_PORT0);		outb_p((adapter->mbox_dma >> 8) & 0xFF,				adapter->host->io_port + MBOX_PORT1);		outb_p((adapter->mbox_dma >> 16) & 0xFF,				adapter->host->io_port + MBOX_PORT2);		outb_p((adapter->mbox_dma >> 24) & 0xFF,				adapter->host->io_port + MBOX_PORT3);		outb_p(ENABLE_MBOX_BYTE,				adapter->host->io_port + ENABLE_MBOX_REGION);		irq_ack(adapter);		irq_enable(adapter);	}	return 0;}/* * mega_query_adapter() * @adapter - pointer to our soft state * * Issue the adapter inquiry commands to the controller and find out * information and parameter about the devices attached */static intmega_query_adapter(adapter_t *adapter){	dma_addr_t	prod_info_dma_handle;	mega_inquiry3	*inquiry3;	u8	raw_mbox[sizeof(struct mbox_out)];	mbox_t	*mbox;	int	retval;	/* Initialize adapter inquiry mailbox */	mbox = (mbox_t *)raw_mbox;	memset((void *)adapter->mega_buffer, 0, MEGA_BUFFER_SIZE);	memset(&mbox->m_out, 0, sizeof(raw_mbox));	/*	 * Try to issue Inquiry3 command	 * if not succeeded, then issue MEGA_MBOXCMD_ADAPTERINQ command and	 * update enquiry3 structure	 */	mbox->m_out.xferaddr = (u32)adapter->buf_dma_handle;	inquiry3 = (mega_inquiry3 *)adapter->mega_buffer;	raw_mbox[0] = FC_NEW_CONFIG;		/* i.e. mbox->cmd=0xA1 */	raw_mbox[2] = NC_SUBOP_ENQUIRY3;	/* i.e. 0x0F */	raw_mbox[3] = ENQ3_GET_SOLICITED_FULL;	/* i.e. 0x02 */	/* Issue a blocking command to the card */	if ((retval = issue_scb_block(adapter, raw_mbox))) {		/* the adapter does not support 40ld */		mraid_ext_inquiry	*ext_inq;		mraid_inquiry		*inq;		dma_addr_t		dma_handle;		ext_inq = pci_alloc_consistent(adapter->dev,				sizeof(mraid_ext_inquiry), &dma_handle);		if( ext_inq == NULL ) return -1;		inq = &ext_inq->raid_inq;		mbox->m_out.xferaddr = (u32)dma_handle;		/*issue old 0x04 command to adapter */		mbox->m_out.cmd = MEGA_MBOXCMD_ADPEXTINQ;		issue_scb_block(adapter, raw_mbox);		/*		 * update Enquiry3 and ProductInfo structures with		 * mraid_inquiry structure		 */		mega_8_to_40ld(inq, inquiry3,				(mega_product_info *)&adapter->product_info);		pci_free_consistent(adapter->dev, sizeof(mraid_ext_inquiry),				ext_inq, dma_handle);	} else {		/*adapter supports 40ld */		adapter->flag |= BOARD_40LD;		/*		 * get product_info, which is static information and will be		 * unchanged		 */		prod_info_dma_handle = pci_map_single(adapter->dev, (void *)				&adapter->product_info,				sizeof(mega_product_info), PCI_DMA_FROMDEVICE);		mbox->m_out.xferaddr = prod_info_dma_handle;		raw_mbox[0] = FC_NEW_CONFIG;	/* i.e. mbox->cmd=0xA1 */		raw_mbox[2] = NC_SUBOP_PRODUCT_INFO;	/* i.e. 0x0E */		if ((retval = issue_scb_block(adapter, raw_mbox)))			printk(KERN_WARNING			"megaraid: Product_info cmd failed with error: %d\n",				retval);		pci_unmap_single(adapter->dev, prod_info_dma_handle,				sizeof(mega_product_info), PCI_DMA_FROMDEVICE);	}	/*	 * kernel scans the channels from 0 to <= max_channel	 */	adapter->host->max_channel =		adapter->product_info.nchannels + NVIRT_CHAN -1;	adapter->host->max_id = 16;	/* max targets per channel */	adapter->host->max_lun = 7;	/* Upto 7 luns for non disk devices */	adapter->host->cmd_per_lun = max_cmd_per_lun;	adapter->numldrv = inquiry3->num_ldrv;	adapter->max_cmds = adapter->product_info.max_commands;	if(adapter->max_cmds > MAX_COMMANDS)		adapter->max_cmds = MAX_COMMANDS;	adapter->host->can_queue = adapter->max_cmds - 1;	/*	 * Get the maximum number of scatter-gather elements supported by this	 * firmware	 */	mega_get_max_sgl(adapter);	adapter->host->sg_tablesize = adapter->sglen;	/* use HP firmware and bios version encoding */	if (adapter->product_info.subsysvid == HP_SUBSYS_VID) {		sprintf (adapter->fw_version, "%c%d%d.%d%d",			 adapter->product_info.fw_version[2],			 adapter->product_info.fw_version[1] >> 8,			 adapter->product_info.fw_version[1] & 0x0f,			 adapter->product_info.fw_version[0] >> 8,			 adapter->product_info.fw_version[0] & 0x0f);		sprintf (adapter->bios_version, "%c%d%d.%d%d",			 adapter->product_info.bios_version[2],			 adapter->product_info.bios_version[1] >> 8,			 adapter->product_info.bios_version[1] & 0x0f,			 adapter->product_info.bios_version[0] >> 8,			 adapter->product_info.bios_version[0] & 0x0f);	} else {		memcpy(adapter->fw_version,				(char *)adapter->product_info.fw_version, 4);		adapter->fw_version[4] = 0;		memcpy(adapter->bios_version,				(char *)adapter->product_info.bios_version, 4);		adapter->bios_version[4] = 0;	}	printk(KERN_NOTICE "megaraid: [%s:%s] detected %d logical drives.\n",		adapter->fw_version, adapter->bios_version, adapter->numldrv);	/*	 * Do we support extended (>10 bytes) cdbs	 */	adapter->support_ext_cdb = mega_support_ext_cdb(adapter);	if (adapter->support_ext_cdb)		printk(KERN_NOTICE "megaraid: supports extended CDBs.\n");	return 0;}/** * mega_runpendq() * @adapter - pointer to our soft state * * Runs through the list of pending requests. */static inline voidmega_runpendq(adapter_t *adapter){	if(!list_empty(&adapter->pending_list))		__mega_runpendq(adapter);}/* * megaraid_queue() * @scmd - Issue this scsi command * @done - the callback hook into the scsi mid-layer * * The command queuing entry point for the mid-layer. */static intmegaraid_queue(Scsi_Cmnd *scmd, void (*done)(Scsi_Cmnd *)){	adapter_t	*adapter;	scb_t	*scb;	int	busy=0;	unsigned long flags;	adapter = (adapter_t *)scmd->device->host->hostdata;	scmd->scsi_done = done;	/*	 * Allocate and build a SCB request	 * busy flag will be set if mega_build_cmd() command could not	 * allocate scb. We will return non-zero status in that case.	 * NOTE: scb can be null even though certain commands completed	 * successfully, e.g., MODE_SENSE and TEST_UNIT_READY, we would	 * return 0 in that case.	 */	spin_lock_irqsave(&adapter->lock, flags);	scb = mega_build_cmd(adapter, scmd, &busy);	if (!scb)		goto out;	scb->state |= SCB_PENDQ;	list_add_tail(&scb->list, &adapter->pending_list);	/*	 * Check if the HBA is in quiescent state, e.g., during a	 * delete logical drive opertion. If it is, don't run	 * the pending_list.	 */	if (atomic_read(&adapter->quiescent) == 0)		mega_runpendq(adapter);	busy = 0; out:	spin_unlock_irqrestore(&adapter->lock, flags);	return busy;}/** * mega_allocate_scb() * @adapter - pointer to our soft state * @cmd - scsi command from the mid-layer * * Allocate a SCB structure. This is the central structure for controller * commands. */static inline scb_t *mega_allocate_scb(adapter_t *adapter, Scsi_Cmnd *cmd){	struct list_head *head = &adapter->free_list;	scb_t	*scb;	/* Unlink command from Free List */	if( !list_empty(head) ) {		scb = list_entry(head->next, scb_t, list);		list_del_init(head->next);		scb->state = SCB_ACTIVE;		scb->cmd = cmd;		scb->dma_type = MEGA_DMA_TYPE_NONE;		return scb;	}	return NULL;}/** * mega_get_ldrv_num() * @adapter - pointer to our soft state * @cmd - scsi mid layer command * @channel - channel on the controller * * Calculate the logical drive number based on the information in scsi command * and the channel number. */static inline intmega_get_ldrv_num(adapter_t *adapter, Scsi_Cmnd *cmd, int channel){	int		tgt;	int		ldrv_num;	tgt = cmd->device->id;		if ( tgt > adapter->this_id )		tgt--;	/* we do not get inquires for initiator id */	ldrv_num = (channel * 15) + tgt;	/*	 * If we have a logical drive with boot enabled, project it first	 */	if( adapter->boot_ldrv_enabled ) {		if( ldrv_num == 0 ) {			ldrv_num = adapter->boot_ldrv;		}		else {			if( ldrv_num <= adapter->boot_ldrv ) {				ldrv_num--;			}		}	}	/*	 * If "delete logical drive" feature is enabled on this controller.	 * Do only if at least one delete logical drive operation was done.	 *	 * Also, after logical drive deletion, instead of logical drive number,	 * the value returned should be 0x80+logical drive id.	 *	 * These is valid only for IO commands.	 */	if (adapter->support_random_del && adapter->read_ldidmap )		switch (cmd->cmnd[0]) {		case READ_6:	/* fall through */		case WRITE_6:	/* fall through */		case READ_10:	/* fall through */		case WRITE_10:			ldrv_num += 0x80;		}	return ldrv_num;}/** * mega_build_cmd() * @adapter - pointer to our soft state * @cmd - Prepare using this scsi command * @busy - busy flag if no resources * * Prepares a command and scatter gather list for the controller. This routine * also finds out if the commands is intended for a logical drive or a * physical device and prepares the controller command accordingly. * * We also re-order the logical drives and physical devices based on their * boot settings. */static scb_t *mega_build_cmd(adapter_t *adapter, Scsi_Cmnd *cmd, int *busy){	mega_ext_passthru	*epthru;	mega_passthru	*pthru;	scb_t	*scb;	mbox_t	*mbox;	long	seg;	char	islogical;	int	max_ldrv_num;	int	channel = 0;	int	target = 0;	int	ldrv_num = 0;   /* logical drive number */	/*	 * filter the internal and ioctl commands	 */	if((cmd->cmnd[0] == MEGA_INTERNAL_CMD))		return (scb_t *)cmd->host_scribble;	/*	 * We know what channels our logical drives are on - mega_find_card()	 */	islogical = adapter->logdrv_chan[cmd->device->channel];	/*	 * The theory: If physical drive is chosen for boot, all the physical	 * devices are exported before the logical drives, otherwise physical	 * devices are pushed after logical drives, in which case - Kernel sees	 * the physical devices on virtual channel which is obviously converted	 * to actual channel on the HBA.	 */	if( adapter->boot_pdrv_enabled ) {		if( islogical ) {			/* logical channel */			channel = cmd->device->channel -				adapter->product_info.nchannels;		}		else {			/* this is physical channel */			channel = cmd->device->channel; 			target = cmd->device->id;			/*			 * boot from a physical disk, that disk needs to be			 * exposed first IF both the channels are SCSI, then			 * booting from the second channel is not allowed.			 */			if( target == 0 ) {				target = adapter->boot_pdrv_tgt;			}			else if( target == adapter->boot_pdrv_tgt ) {

⌨️ 快捷键说明

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