arcmsr_hba.c

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

C
2,271
字号
/**********************************************************************************        O.S   : Linux**   FILE NAME  : arcmsr_hba.c**        BY    : Erich Chen**   Description: SCSI RAID Device Driver for**                ARECA RAID Host adapter********************************************************************************* Copyright (C) 2002 - 2005, Areca Technology Corporation All rights reserved****     Web site: www.areca.com.tw**       E-mail: support@areca.com.tw**** This program is free software; you can redistribute it and/or modify** it under the terms of the GNU General Public License version 2 as** published by the Free Software Foundation.** This program is distributed in the hope that it will be useful,** but WITHOUT ANY WARRANTY; without even the implied warranty of** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the** GNU General Public License for more details.********************************************************************************* Redistribution and use in source and binary forms, with or without** modification, are permitted provided that the following conditions** are met:** 1. Redistributions of source code must retain the above copyright**    notice, this list of conditions and the following disclaimer.** 2. Redistributions in binary form must reproduce the above copyright**    notice, this list of conditions and the following disclaimer in the**    documentation and/or other materials provided with the distribution.** 3. The name of the author may not be used to endorse or promote products**    derived from this software without specific prior written permission.**** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES(INCLUDING,BUT** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,** DATA, OR PROFITS; OR BUSINESS INTERRUPTION)HOWEVER CAUSED AND ON ANY** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT** (INCLUDING NEGLIGENCE OR OTHERWISE)ARISING IN ANY WAY OUT OF THE USE OF** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.********************************************************************************* For history of changes, see Documentation/scsi/ChangeLog.arcmsr**     Firmware Specification, see Documentation/scsi/arcmsr_spec.txt********************************************************************************/#include <linux/module.h>#include <linux/reboot.h>#include <linux/spinlock.h>#include <linux/pci_ids.h>#include <linux/interrupt.h>#include <linux/moduleparam.h>#include <linux/errno.h>#include <linux/types.h>#include <linux/delay.h>#include <linux/dma-mapping.h>#include <linux/timer.h>#include <linux/pci.h>#include <linux/aer.h>#include <asm/dma.h>#include <asm/io.h>#include <asm/system.h>#include <asm/uaccess.h>#include <scsi/scsi_host.h>#include <scsi/scsi.h>#include <scsi/scsi_cmnd.h>#include <scsi/scsi_tcq.h>#include <scsi/scsi_device.h>#include <scsi/scsi_transport.h>#include <scsi/scsicam.h>#include "arcmsr.h"MODULE_AUTHOR("Erich Chen <support@areca.com.tw>");MODULE_DESCRIPTION("ARECA (ARC11xx/12xx/13xx/16xx) SATA/SAS RAID HOST Adapter");MODULE_LICENSE("Dual BSD/GPL");MODULE_VERSION(ARCMSR_DRIVER_VERSION);static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb,					struct scsi_cmnd *cmd);static int arcmsr_iop_confirm(struct AdapterControlBlock *acb);static int arcmsr_abort(struct scsi_cmnd *);static int arcmsr_bus_reset(struct scsi_cmnd *);static int arcmsr_bios_param(struct scsi_device *sdev,		struct block_device *bdev, sector_t capacity, int *info);static int arcmsr_queue_command(struct scsi_cmnd *cmd,					void (*done) (struct scsi_cmnd *));static int arcmsr_probe(struct pci_dev *pdev,				const struct pci_device_id *id);static void arcmsr_remove(struct pci_dev *pdev);static void arcmsr_shutdown(struct pci_dev *pdev);static void arcmsr_iop_init(struct AdapterControlBlock *acb);static void arcmsr_free_ccb_pool(struct AdapterControlBlock *acb);static u32 arcmsr_disable_outbound_ints(struct AdapterControlBlock *acb);static void arcmsr_stop_adapter_bgrb(struct AdapterControlBlock *acb);static void arcmsr_flush_hba_cache(struct AdapterControlBlock *acb);static void arcmsr_flush_hbb_cache(struct AdapterControlBlock *acb);static const char *arcmsr_info(struct Scsi_Host *);static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb);static int arcmsr_adjust_disk_queue_depth(struct scsi_device *sdev,								int queue_depth){	if (queue_depth > ARCMSR_MAX_CMD_PERLUN)		queue_depth = ARCMSR_MAX_CMD_PERLUN;	scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth);	return queue_depth;}static struct scsi_host_template arcmsr_scsi_host_template = {	.module			= THIS_MODULE,	.name			= "ARCMSR ARECA SATA/SAS RAID HOST Adapter"							ARCMSR_DRIVER_VERSION,	.info			= arcmsr_info,	.queuecommand		= arcmsr_queue_command,	.eh_abort_handler	= arcmsr_abort,	.eh_bus_reset_handler	= arcmsr_bus_reset,	.bios_param		= arcmsr_bios_param,	.change_queue_depth	= arcmsr_adjust_disk_queue_depth,	.can_queue		= ARCMSR_MAX_OUTSTANDING_CMD,	.this_id		= ARCMSR_SCSI_INITIATOR_ID,	.sg_tablesize		= ARCMSR_MAX_SG_ENTRIES,	.max_sectors    	= ARCMSR_MAX_XFER_SECTORS,	.cmd_per_lun		= ARCMSR_MAX_CMD_PERLUN,	.use_clustering		= ENABLE_CLUSTERING,	.use_sg_chaining	= ENABLE_SG_CHAINING,	.shost_attrs		= arcmsr_host_attrs,};#ifdef CONFIG_SCSI_ARCMSR_AERstatic pci_ers_result_t arcmsr_pci_slot_reset(struct pci_dev *pdev);static pci_ers_result_t arcmsr_pci_error_detected(struct pci_dev *pdev,						pci_channel_state_t state);static struct pci_error_handlers arcmsr_pci_error_handlers = {	.error_detected		= arcmsr_pci_error_detected,	.slot_reset		= arcmsr_pci_slot_reset,};#endifstatic struct pci_device_id arcmsr_device_id_table[] = {	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1110)},	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1120)},	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1130)},	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1160)},	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1170)},	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1200)},	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1201)},	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1202)},	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1210)},	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1220)},	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1230)},	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1260)},	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1270)},	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1280)},	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1380)},	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1381)},	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1680)},	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1681)},	{0, 0}, /* Terminating entry */};MODULE_DEVICE_TABLE(pci, arcmsr_device_id_table);static struct pci_driver arcmsr_pci_driver = {	.name			= "arcmsr",	.id_table		= arcmsr_device_id_table,	.probe			= arcmsr_probe,	.remove			= arcmsr_remove,	.shutdown		= arcmsr_shutdown,	#ifdef CONFIG_SCSI_ARCMSR_AER	.err_handler		= &arcmsr_pci_error_handlers,	#endif};static irqreturn_t arcmsr_do_interrupt(int irq, void *dev_id){	irqreturn_t handle_state;	struct AdapterControlBlock *acb = dev_id;	spin_lock(acb->host->host_lock);	handle_state = arcmsr_interrupt(acb);	spin_unlock(acb->host->host_lock);	return handle_state;}static int arcmsr_bios_param(struct scsi_device *sdev,		struct block_device *bdev, sector_t capacity, int *geom){	int ret, heads, sectors, cylinders, total_capacity;	unsigned char *buffer;/* return copy of block device's partition table */	buffer = scsi_bios_ptable(bdev);	if (buffer) {		ret = scsi_partsize(buffer, capacity, &geom[2], &geom[0], &geom[1]);		kfree(buffer);		if (ret != -1)			return ret;	}	total_capacity = capacity;	heads = 64;	sectors = 32;	cylinders = total_capacity / (heads * sectors);	if (cylinders > 1024) {		heads = 255;		sectors = 63;		cylinders = total_capacity / (heads * sectors);	}	geom[0] = heads;	geom[1] = sectors;	geom[2] = cylinders;	return 0;}static void arcmsr_define_adapter_type(struct AdapterControlBlock *acb){	struct pci_dev *pdev = acb->pdev;	u16 dev_id;	pci_read_config_word(pdev, PCI_DEVICE_ID, &dev_id);	switch (dev_id) {	case 0x1201 : {		acb->adapter_type = ACB_ADAPTER_TYPE_B;		}		break;	default : acb->adapter_type = ACB_ADAPTER_TYPE_A;	}}static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb){	switch (acb->adapter_type) {	case ACB_ADAPTER_TYPE_A: {		struct pci_dev *pdev = acb->pdev;		void *dma_coherent;		dma_addr_t dma_coherent_handle, dma_addr;		struct CommandControlBlock *ccb_tmp;		uint32_t intmask_org;		int i, j;		acb->pmuA = ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));		if (!acb->pmuA) {			printk(KERN_NOTICE "arcmsr%d: memory mapping region fail \n",							acb->host->host_no);			return -ENOMEM;		}		dma_coherent = dma_alloc_coherent(&pdev->dev,			ARCMSR_MAX_FREECCB_NUM *			sizeof (struct CommandControlBlock) + 0x20,			&dma_coherent_handle, GFP_KERNEL);		if (!dma_coherent) {			iounmap(acb->pmuA);			return -ENOMEM;		}		acb->dma_coherent = dma_coherent;		acb->dma_coherent_handle = dma_coherent_handle;		if (((unsigned long)dma_coherent & 0x1F)) {			dma_coherent = dma_coherent +				(0x20 - ((unsigned long)dma_coherent & 0x1F));			dma_coherent_handle = dma_coherent_handle +				(0x20 - ((unsigned long)dma_coherent_handle & 0x1F));		}		dma_addr = dma_coherent_handle;		ccb_tmp = (struct CommandControlBlock *)dma_coherent;		for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {			ccb_tmp->cdb_shifted_phyaddr = dma_addr >> 5;			ccb_tmp->acb = acb;			acb->pccb_pool[i] = ccb_tmp;			list_add_tail(&ccb_tmp->list, &acb->ccb_free_list);			dma_addr = dma_addr + sizeof(struct CommandControlBlock);			ccb_tmp++;		}		acb->vir2phy_offset = (unsigned long)ccb_tmp -(unsigned long)dma_addr;		for (i = 0; i < ARCMSR_MAX_TARGETID; i++)			for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++)				acb->devstate[i][j] = ARECA_RAID_GONE;		/*		** here we need to tell iop 331 our ccb_tmp.HighPart		** if ccb_tmp.HighPart is not zero		*/		intmask_org = arcmsr_disable_outbound_ints(acb);		}		break;	case ACB_ADAPTER_TYPE_B: {		struct pci_dev *pdev = acb->pdev;		struct MessageUnit_B *reg;		void __iomem *mem_base0, *mem_base1;		void *dma_coherent;		dma_addr_t dma_coherent_handle, dma_addr;		uint32_t intmask_org;		struct CommandControlBlock *ccb_tmp;		int i, j;		dma_coherent = dma_alloc_coherent(&pdev->dev,			((ARCMSR_MAX_FREECCB_NUM *			sizeof(struct CommandControlBlock) + 0x20) +			sizeof(struct MessageUnit_B)),			&dma_coherent_handle, GFP_KERNEL);		if (!dma_coherent)			return -ENOMEM;		acb->dma_coherent = dma_coherent;		acb->dma_coherent_handle = dma_coherent_handle;		if (((unsigned long)dma_coherent & 0x1F)) {			dma_coherent = dma_coherent +				(0x20 - ((unsigned long)dma_coherent & 0x1F));			dma_coherent_handle = dma_coherent_handle +				(0x20 - ((unsigned long)dma_coherent_handle & 0x1F));		}		reg = (struct MessageUnit_B *)(dma_coherent +		ARCMSR_MAX_FREECCB_NUM * sizeof(struct CommandControlBlock));		dma_addr = dma_coherent_handle;		ccb_tmp = (struct CommandControlBlock *)dma_coherent;		for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {			ccb_tmp->cdb_shifted_phyaddr = dma_addr >> 5;			ccb_tmp->acb = acb;			acb->pccb_pool[i] = ccb_tmp;			list_add_tail(&ccb_tmp->list, &acb->ccb_free_list);			dma_addr = dma_addr + sizeof(struct CommandControlBlock);			ccb_tmp++;		}		reg = (struct MessageUnit_B *)(dma_coherent +		ARCMSR_MAX_FREECCB_NUM * sizeof(struct CommandControlBlock));		acb->pmuB = reg;		mem_base0 = ioremap(pci_resource_start(pdev, 0),					pci_resource_len(pdev, 0));		if (!mem_base0)			goto out;		mem_base1 = ioremap(pci_resource_start(pdev, 2),					pci_resource_len(pdev, 2));		if (!mem_base1) {			iounmap(mem_base0);			goto out;		}		reg->drv2iop_doorbell_reg = mem_base0 + ARCMSR_DRV2IOP_DOORBELL;		reg->drv2iop_doorbell_mask_reg = mem_base0 +						ARCMSR_DRV2IOP_DOORBELL_MASK;		reg->iop2drv_doorbell_reg = mem_base0 + ARCMSR_IOP2DRV_DOORBELL;		reg->iop2drv_doorbell_mask_reg = mem_base0 +						ARCMSR_IOP2DRV_DOORBELL_MASK;		reg->ioctl_wbuffer_reg = mem_base1 + ARCMSR_IOCTL_WBUFFER;		reg->ioctl_rbuffer_reg = mem_base1 + ARCMSR_IOCTL_RBUFFER;		reg->msgcode_rwbuffer_reg = mem_base1 + ARCMSR_MSGCODE_RWBUFFER;		acb->vir2phy_offset = (unsigned long)ccb_tmp -(unsigned long)dma_addr;		for (i = 0; i < ARCMSR_MAX_TARGETID; i++)			for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++)				acb->devstate[i][j] = ARECA_RAID_GOOD;		/*		** here we need to tell iop 331 our ccb_tmp.HighPart		** if ccb_tmp.HighPart is not zero		*/		intmask_org = arcmsr_disable_outbound_ints(acb);		}		break;	}	return 0;out:	dma_free_coherent(&acb->pdev->dev,		ARCMSR_MAX_FREECCB_NUM * sizeof(struct CommandControlBlock) + 0x20,		acb->dma_coherent, acb->dma_coherent_handle);	return -ENOMEM;}static int arcmsr_probe(struct pci_dev *pdev,	const struct pci_device_id *id){	struct Scsi_Host *host;	struct AdapterControlBlock *acb;	uint8_t bus, dev_fun;	int error;	error = pci_enable_device(pdev);	if (error)		goto out;	pci_set_master(pdev);	host = scsi_host_alloc(&arcmsr_scsi_host_template,			sizeof(struct AdapterControlBlock));	if (!host) {		error = -ENOMEM;		goto out_disable_device;	}	acb = (struct AdapterControlBlock *)host->hostdata;	memset(acb, 0, sizeof (struct AdapterControlBlock));	error = pci_set_dma_mask(pdev, DMA_64BIT_MASK);	if (error) {		error = pci_set_dma_mask(pdev, DMA_32BIT_MASK);		if (error) {			printk(KERN_WARNING			       "scsi%d: No suitable DMA mask available\n",			       host->host_no);			goto out_host_put;		}	}	bus = pdev->bus->number;	dev_fun = pdev->devfn;	acb->host = host;	acb->pdev = pdev;	host->max_sectors = ARCMSR_MAX_XFER_SECTORS;	host->max_lun = ARCMSR_MAX_TARGETLUN;	host->max_id = ARCMSR_MAX_TARGETID;/*16:8*/	host->max_cmd_len = 16;    /*this is issue of 64bit LBA, over 2T byte*/	host->sg_tablesize = ARCMSR_MAX_SG_ENTRIES;	host->can_queue = ARCMSR_MAX_FREECCB_NUM; /* max simultaneous cmds */	host->cmd_per_lun = ARCMSR_MAX_CMD_PERLUN;	host->this_id = ARCMSR_SCSI_INITIATOR_ID;	host->unique_id = (bus << 8) | dev_fun;	host->irq = pdev->irq;	error = pci_request_regions(pdev, "arcmsr");	if (error) {		goto out_host_put;	}	arcmsr_define_adapter_type(acb);	acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED |			   ACB_F_MESSAGE_RQBUFFER_CLEARED |			   ACB_F_MESSAGE_WQBUFFER_READED);	acb->acb_flags &= ~ACB_F_SCSISTOPADAPTER;	INIT_LIST_HEAD(&acb->ccb_free_list);	error = arcmsr_alloc_ccb_pool(acb);	if (error)		goto out_release_regions;	error = request_irq(pdev->irq, arcmsr_do_interrupt,			    IRQF_SHARED, "arcmsr", acb);	if (error)		goto out_free_ccb_pool;	arcmsr_iop_init(acb);	pci_set_drvdata(pdev, host);	if (strncmp(acb->firm_version, "V1.42", 5) >= 0)		host->max_sectors= ARCMSR_MAX_XFER_SECTORS_B;	error = scsi_add_host(host, &pdev->dev);	if (error)		goto out_free_irq;

⌨️ 快捷键说明

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