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

📄 aic94xx_init.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Aic94xx SAS/SATA driver initialization. * * Copyright (C) 2005 Adaptec, Inc.  All rights reserved. * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> * * This file is licensed under GPLv2. * * This file is part of the aic94xx driver. * * The aic94xx driver 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; version 2 of the * License. * * The aic94xx driver 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. * * You should have received a copy of the GNU General Public License * along with the aic94xx driver; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA * */#include <linux/module.h>#include <linux/init.h>#include <linux/kernel.h>#include <linux/pci.h>#include <linux/delay.h>#include <scsi/scsi_host.h>#include "aic94xx.h"#include "aic94xx_reg.h"#include "aic94xx_hwi.h"#include "aic94xx_seq.h"/* The format is "version.release.patchlevel" */#define ASD_DRIVER_VERSION "1.0.3"static int use_msi = 0;module_param_named(use_msi, use_msi, int, S_IRUGO);MODULE_PARM_DESC(use_msi, "\n"	"\tEnable(1) or disable(0) using PCI MSI.\n"	"\tDefault: 0");static int lldd_max_execute_num = 0;module_param_named(collector, lldd_max_execute_num, int, S_IRUGO);MODULE_PARM_DESC(collector, "\n"	"\tIf greater than one, tells the SAS Layer to run in Task Collector\n"	"\tMode.  If 1 or 0, tells the SAS Layer to run in Direct Mode.\n"	"\tThe aic94xx SAS LLDD supports both modes.\n"	"\tDefault: 0 (Direct Mode).\n");char sas_addr_str[2*SAS_ADDR_SIZE + 1] = "";static struct scsi_transport_template *aic94xx_transport_template;static int asd_scan_finished(struct Scsi_Host *, unsigned long);static void asd_scan_start(struct Scsi_Host *);static struct scsi_host_template aic94xx_sht = {	.module			= THIS_MODULE,	/* .name is initialized */	.name			= "aic94xx",	.queuecommand		= sas_queuecommand,	.target_alloc		= sas_target_alloc,	.slave_configure	= sas_slave_configure,	.slave_destroy		= sas_slave_destroy,	.scan_finished		= asd_scan_finished,	.scan_start		= asd_scan_start,	.change_queue_depth	= sas_change_queue_depth,	.change_queue_type	= sas_change_queue_type,	.bios_param		= sas_bios_param,	.can_queue		= 1,	.cmd_per_lun		= 1,	.this_id		= -1,	.sg_tablesize		= SG_ALL,	.max_sectors		= SCSI_DEFAULT_MAX_SECTORS,	.use_clustering		= ENABLE_CLUSTERING,	.eh_device_reset_handler	= sas_eh_device_reset_handler,	.eh_bus_reset_handler	= sas_eh_bus_reset_handler,	.slave_alloc		= sas_slave_alloc,	.target_destroy		= sas_target_destroy,	.ioctl			= sas_ioctl,};static int __devinit asd_map_memio(struct asd_ha_struct *asd_ha){	int err, i;	struct asd_ha_addrspace *io_handle;	asd_ha->iospace = 0;	for (i = 0; i < 3; i += 2) {		io_handle = &asd_ha->io_handle[i==0?0:1];		io_handle->start = pci_resource_start(asd_ha->pcidev, i);		io_handle->len   = pci_resource_len(asd_ha->pcidev, i);		io_handle->flags = pci_resource_flags(asd_ha->pcidev, i);		err = -ENODEV;		if (!io_handle->start || !io_handle->len) {			asd_printk("MBAR%d start or length for %s is 0.\n",				   i==0?0:1, pci_name(asd_ha->pcidev));			goto Err;		}		err = pci_request_region(asd_ha->pcidev, i, ASD_DRIVER_NAME);		if (err) {			asd_printk("couldn't reserve memory region for %s\n",				   pci_name(asd_ha->pcidev));			goto Err;		}		if (io_handle->flags & IORESOURCE_CACHEABLE)			io_handle->addr = ioremap(io_handle->start,						  io_handle->len);		else			io_handle->addr = ioremap_nocache(io_handle->start,							  io_handle->len);		if (!io_handle->addr) {			asd_printk("couldn't map MBAR%d of %s\n", i==0?0:1,				   pci_name(asd_ha->pcidev));			goto Err_unreq;		}	}	return 0;Err_unreq:	pci_release_region(asd_ha->pcidev, i);Err:	if (i > 0) {		io_handle = &asd_ha->io_handle[0];		iounmap(io_handle->addr);		pci_release_region(asd_ha->pcidev, 0);	}	return err;}static void __devexit asd_unmap_memio(struct asd_ha_struct *asd_ha){	struct asd_ha_addrspace *io_handle;	io_handle = &asd_ha->io_handle[1];	iounmap(io_handle->addr);	pci_release_region(asd_ha->pcidev, 2);	io_handle = &asd_ha->io_handle[0];	iounmap(io_handle->addr);	pci_release_region(asd_ha->pcidev, 0);}static int __devinit asd_map_ioport(struct asd_ha_struct *asd_ha){	int i = PCI_IOBAR_OFFSET, err;	struct asd_ha_addrspace *io_handle = &asd_ha->io_handle[0];	asd_ha->iospace = 1;	io_handle->start = pci_resource_start(asd_ha->pcidev, i);	io_handle->len   = pci_resource_len(asd_ha->pcidev, i);	io_handle->flags = pci_resource_flags(asd_ha->pcidev, i);	io_handle->addr  = (void __iomem *) io_handle->start;	if (!io_handle->start || !io_handle->len) {		asd_printk("couldn't get IO ports for %s\n",			   pci_name(asd_ha->pcidev));		return -ENODEV;	}	err = pci_request_region(asd_ha->pcidev, i, ASD_DRIVER_NAME);	if (err) {		asd_printk("couldn't reserve io space for %s\n",			   pci_name(asd_ha->pcidev));	}	return err;}static void __devexit asd_unmap_ioport(struct asd_ha_struct *asd_ha){	pci_release_region(asd_ha->pcidev, PCI_IOBAR_OFFSET);}static int __devinit asd_map_ha(struct asd_ha_struct *asd_ha){	int err;	u16 cmd_reg;	err = pci_read_config_word(asd_ha->pcidev, PCI_COMMAND, &cmd_reg);	if (err) {		asd_printk("couldn't read command register of %s\n",			   pci_name(asd_ha->pcidev));		goto Err;	}	err = -ENODEV;	if (cmd_reg & PCI_COMMAND_MEMORY) {		if ((err = asd_map_memio(asd_ha)))			goto Err;	} else if (cmd_reg & PCI_COMMAND_IO) {		if ((err = asd_map_ioport(asd_ha)))			goto Err;		asd_printk("%s ioport mapped -- upgrade your hardware\n",			   pci_name(asd_ha->pcidev));	} else {		asd_printk("no proper device access to %s\n",			   pci_name(asd_ha->pcidev));		goto Err;	}	return 0;Err:	return err;}static void __devexit asd_unmap_ha(struct asd_ha_struct *asd_ha){	if (asd_ha->iospace)		asd_unmap_ioport(asd_ha);	else		asd_unmap_memio(asd_ha);}static const char *asd_dev_rev[30] = {	[0] = "A0",	[1] = "A1",	[8] = "B0",};static int __devinit asd_common_setup(struct asd_ha_struct *asd_ha){	int err, i;	asd_ha->revision_id = asd_ha->pcidev->revision;	err = -ENODEV;	if (asd_ha->revision_id < AIC9410_DEV_REV_B0) {		asd_printk("%s is revision %s (%X), which is not supported\n",			   pci_name(asd_ha->pcidev),			   asd_dev_rev[asd_ha->revision_id],			   asd_ha->revision_id);		goto Err;	}	/* Provide some sane default values. */	asd_ha->hw_prof.max_scbs = 512;	asd_ha->hw_prof.max_ddbs = ASD_MAX_DDBS;	asd_ha->hw_prof.num_phys = ASD_MAX_PHYS;	/* All phys are enabled, by default. */	asd_ha->hw_prof.enabled_phys = 0xFF;	for (i = 0; i < ASD_MAX_PHYS; i++) {		asd_ha->hw_prof.phy_desc[i].max_sas_lrate =			SAS_LINK_RATE_3_0_GBPS;		asd_ha->hw_prof.phy_desc[i].min_sas_lrate =			SAS_LINK_RATE_1_5_GBPS;		asd_ha->hw_prof.phy_desc[i].max_sata_lrate =			SAS_LINK_RATE_1_5_GBPS;		asd_ha->hw_prof.phy_desc[i].min_sata_lrate =			SAS_LINK_RATE_1_5_GBPS;	}	return 0;Err:	return err;}static int __devinit asd_aic9410_setup(struct asd_ha_struct *asd_ha){	int err = asd_common_setup(asd_ha);	if (err)		return err;	asd_ha->hw_prof.addr_range = 8;	asd_ha->hw_prof.port_name_base = 0;	asd_ha->hw_prof.dev_name_base = 8;	asd_ha->hw_prof.sata_name_base = 16;	return 0;}static int __devinit asd_aic9405_setup(struct asd_ha_struct *asd_ha){	int err = asd_common_setup(asd_ha);	if (err)		return err;	asd_ha->hw_prof.addr_range = 4;	asd_ha->hw_prof.port_name_base = 0;	asd_ha->hw_prof.dev_name_base = 4;	asd_ha->hw_prof.sata_name_base = 8;	return 0;}static ssize_t asd_show_dev_rev(struct device *dev,				struct device_attribute *attr, char *buf){	struct asd_ha_struct *asd_ha = dev_to_asd_ha(dev);	return snprintf(buf, PAGE_SIZE, "%s\n",			asd_dev_rev[asd_ha->revision_id]);}static DEVICE_ATTR(revision, S_IRUGO, asd_show_dev_rev, NULL);static ssize_t asd_show_dev_bios_build(struct device *dev,				       struct device_attribute *attr,char *buf){	struct asd_ha_struct *asd_ha = dev_to_asd_ha(dev);	return snprintf(buf, PAGE_SIZE, "%d\n", asd_ha->hw_prof.bios.bld);}static DEVICE_ATTR(bios_build, S_IRUGO, asd_show_dev_bios_build, NULL);static ssize_t asd_show_dev_pcba_sn(struct device *dev,				    struct device_attribute *attr, char *buf){	struct asd_ha_struct *asd_ha = dev_to_asd_ha(dev);	return snprintf(buf, PAGE_SIZE, "%s\n", asd_ha->hw_prof.pcba_sn);}static DEVICE_ATTR(pcba_sn, S_IRUGO, asd_show_dev_pcba_sn, NULL);static int asd_create_dev_attrs(struct asd_ha_struct *asd_ha){	int err;	err = device_create_file(&asd_ha->pcidev->dev, &dev_attr_revision);	if (err)		return err;	err = device_create_file(&asd_ha->pcidev->dev, &dev_attr_bios_build);	if (err)		goto err_rev;	err = device_create_file(&asd_ha->pcidev->dev, &dev_attr_pcba_sn);	if (err)		goto err_biosb;	return 0;err_biosb:	device_remove_file(&asd_ha->pcidev->dev, &dev_attr_bios_build);err_rev:	device_remove_file(&asd_ha->pcidev->dev, &dev_attr_revision);	return err;}static void asd_remove_dev_attrs(struct asd_ha_struct *asd_ha){	device_remove_file(&asd_ha->pcidev->dev, &dev_attr_revision);	device_remove_file(&asd_ha->pcidev->dev, &dev_attr_bios_build);	device_remove_file(&asd_ha->pcidev->dev, &dev_attr_pcba_sn);}/* The first entry, 0, is used for dynamic ids, the rest for devices * we know about. */static struct asd_pcidev_struct {	const char * name;	int (*setup)(struct asd_ha_struct *asd_ha);} asd_pcidev_data[] = {	/* Id 0 is used for dynamic ids. */	{ .name  = "Adaptec AIC-94xx SAS/SATA Host Adapter",	  .setup = asd_aic9410_setup	},	{ .name  = "Adaptec AIC-9410W SAS/SATA Host Adapter",	  .setup = asd_aic9410_setup	},	{ .name  = "Adaptec AIC-9405W SAS/SATA Host Adapter",	  .setup = asd_aic9405_setup	},};static inline int asd_create_ha_caches(struct asd_ha_struct *asd_ha){	asd_ha->scb_pool = dma_pool_create(ASD_DRIVER_NAME "_scb_pool",					   &asd_ha->pcidev->dev,					   sizeof(struct scb),					   8, 0);	if (!asd_ha->scb_pool) {		asd_printk("couldn't create scb pool\n");		return -ENOMEM;	}	return 0;}/** * asd_free_edbs -- free empty data buffers * asd_ha: pointer to host adapter structure */static inline void asd_free_edbs(struct asd_ha_struct *asd_ha){	struct asd_seq_data *seq = &asd_ha->seq;	int i;	for (i = 0; i < seq->num_edbs; i++)		asd_free_coherent(asd_ha, seq->edb_arr[i]);	kfree(seq->edb_arr);	seq->edb_arr = NULL;}static inline void asd_free_escbs(struct asd_ha_struct *asd_ha){	struct asd_seq_data *seq = &asd_ha->seq;	int i;	for (i = 0; i < seq->num_escbs; i++) {		if (!list_empty(&seq->escb_arr[i]->list))			list_del_init(&seq->escb_arr[i]->list);		asd_ascb_free(seq->escb_arr[i]);	}	kfree(seq->escb_arr);	seq->escb_arr = NULL;}static inline void asd_destroy_ha_caches(struct asd_ha_struct *asd_ha){	int i;	if (asd_ha->hw_prof.ddb_ext)		asd_free_coherent(asd_ha, asd_ha->hw_prof.ddb_ext);	if (asd_ha->hw_prof.scb_ext)		asd_free_coherent(asd_ha, asd_ha->hw_prof.scb_ext);	if (asd_ha->hw_prof.ddb_bitmap)		kfree(asd_ha->hw_prof.ddb_bitmap);	asd_ha->hw_prof.ddb_bitmap = NULL;	for (i = 0; i < ASD_MAX_PHYS; i++) {		struct asd_phy *phy = &asd_ha->phys[i];		asd_free_coherent(asd_ha, phy->id_frm_tok);	}	if (asd_ha->seq.escb_arr)		asd_free_escbs(asd_ha);	if (asd_ha->seq.edb_arr)		asd_free_edbs(asd_ha);	if (asd_ha->hw_prof.ue.area) {		kfree(asd_ha->hw_prof.ue.area);		asd_ha->hw_prof.ue.area = NULL;	}	if (asd_ha->seq.tc_index_array) {		kfree(asd_ha->seq.tc_index_array);		kfree(asd_ha->seq.tc_index_bitmap);		asd_ha->seq.tc_index_array = NULL;		asd_ha->seq.tc_index_bitmap = NULL;	}	if (asd_ha->seq.actual_dl) {			asd_free_coherent(asd_ha, asd_ha->seq.actual_dl);			asd_ha->seq.actual_dl = NULL;			asd_ha->seq.dl = NULL;	}	if (asd_ha->seq.next_scb.vaddr) {		dma_pool_free(asd_ha->scb_pool, asd_ha->seq.next_scb.vaddr,			      asd_ha->seq.next_scb.dma_handle);		asd_ha->seq.next_scb.vaddr = NULL;	}	dma_pool_destroy(asd_ha->scb_pool);	asd_ha->scb_pool = NULL;}

⌨️ 快捷键说明

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