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

📄 sym_glue.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 4 页
字号:
	instance->max_channel	= 0;	instance->this_id	= np->myaddr;	instance->max_id	= np->maxwide ? 16 : 8;	instance->max_lun	= SYM_CONF_MAX_LUN;	instance->unique_id	= pci_resource_start(pdev, 0);	instance->cmd_per_lun	= SYM_CONF_MAX_TAG;	instance->can_queue	= (SYM_CONF_MAX_START-2);	instance->sg_tablesize	= SYM_CONF_MAX_SG;	instance->max_cmd_len	= 16;	BUG_ON(sym2_transport_template == NULL);	instance->transportt	= sym2_transport_template;	spin_unlock_irqrestore(instance->host_lock, flags);	return instance; reset_failed:	printf_err("%s: FATAL ERROR: CHECK SCSI BUS - CABLES, "		   "TERMINATION, DEVICE POWER etc.!\n", sym_name(np));	spin_unlock_irqrestore(instance->host_lock, flags); attach_failed:	if (!instance)		return NULL;	printf_info("%s: giving up ...\n", sym_name(np));	if (np)		sym_free_resources(np, pdev);	scsi_host_put(instance);	return NULL; }/* *    Detect and try to read SYMBIOS and TEKRAM NVRAM. */#if SYM_CONF_NVRAM_SUPPORTstatic void __devinit sym_get_nvram(struct sym_device *devp, struct sym_nvram *nvp){	devp->nvram = nvp;	devp->device_id = devp->chip.device_id;	nvp->type = 0;	sym_read_nvram(devp, nvp);}#elsestatic inline void sym_get_nvram(struct sym_device *devp, struct sym_nvram *nvp){}#endif	/* SYM_CONF_NVRAM_SUPPORT */static int __devinit sym_check_supported(struct sym_device *device){	struct sym_chip *chip;	struct pci_dev *pdev = device->pdev;	u_char revision;	unsigned long io_port = pci_resource_start(pdev, 0);	int i;	/*	 *  If user excluded this chip, do not initialize it.	 *  I hate this code so much.  Must kill it.	 */	if (io_port) {		for (i = 0 ; i < 8 ; i++) {			if (sym_driver_setup.excludes[i] == io_port)				return -ENODEV;		}	}	/*	 * Check if the chip is supported.  Then copy the chip description	 * to our device structure so we can make it match the actual device	 * and options.	 */	pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);	chip = sym_lookup_chip_table(pdev->device, revision);	if (!chip) {		dev_info(&pdev->dev, "device not supported\n");		return -ENODEV;	}	memcpy(&device->chip, chip, sizeof(device->chip));	device->chip.revision_id = revision;	return 0;}/* * Ignore Symbios chips controlled by various RAID controllers. * These controllers set value 0x52414944 at RAM end - 16. */static int __devinit sym_check_raid(struct sym_device *device){	unsigned int ram_size, ram_val;	if (!device->s.ramaddr)		return 0;	if (device->chip.features & FE_RAM8K)		ram_size = 8192;	else		ram_size = 4096;	ram_val = readl(device->s.ramaddr + ram_size - 16);	if (ram_val != 0x52414944)		return 0;	dev_info(&device->pdev->dev,			"not initializing, driven by RAID controller.\n");	return -ENODEV;}static int __devinit sym_set_workarounds(struct sym_device *device){	struct sym_chip *chip = &device->chip;	struct pci_dev *pdev = device->pdev;	u_short status_reg;	/*	 *  (ITEM 12 of a DEL about the 896 I haven't yet).	 *  We must ensure the chip will use WRITE AND INVALIDATE.	 *  The revision number limit is for now arbitrary.	 */	if (pdev->device == PCI_DEVICE_ID_NCR_53C896 && chip->revision_id < 0x4) {		chip->features	|= (FE_WRIE | FE_CLSE);	}	/* If the chip can do Memory Write Invalidate, enable it */	if (chip->features & FE_WRIE) {		if (pci_set_mwi(pdev))			return -ENODEV;	}	/*	 *  Work around for errant bit in 895A. The 66Mhz	 *  capable bit is set erroneously. Clear this bit.	 *  (Item 1 DEL 533)	 *	 *  Make sure Config space and Features agree.	 *	 *  Recall: writes are not normal to status register -	 *  write a 1 to clear and a 0 to leave unchanged.	 *  Can only reset bits.	 */	pci_read_config_word(pdev, PCI_STATUS, &status_reg);	if (chip->features & FE_66MHZ) {		if (!(status_reg & PCI_STATUS_66MHZ))			chip->features &= ~FE_66MHZ;	} else {		if (status_reg & PCI_STATUS_66MHZ) {			status_reg = PCI_STATUS_66MHZ;			pci_write_config_word(pdev, PCI_STATUS, status_reg);			pci_read_config_word(pdev, PCI_STATUS, &status_reg);		}	}	return 0;}/* *  Read and check the PCI configuration for any detected NCR  *  boards and save data for attaching after all boards have  *  been detected. */static void __devinitsym_init_device(struct pci_dev *pdev, struct sym_device *device){	int i;	device->host_id = SYM_SETUP_HOST_ID;	device->pdev = pdev;	i = pci_get_base_address(pdev, 1, &device->mmio_base);	pci_get_base_address(pdev, i, &device->ram_base);#ifndef CONFIG_SCSI_SYM53C8XX_IOMAPPED	if (device->mmio_base)		device->s.ioaddr = pci_iomap(pdev, 1,						pci_resource_len(pdev, 1));#endif	if (!device->s.ioaddr)		device->s.ioaddr = pci_iomap(pdev, 0,						pci_resource_len(pdev, 0));	if (device->ram_base)		device->s.ramaddr = pci_iomap(pdev, i,						pci_resource_len(pdev, i));}/* * The NCR PQS and PDS cards are constructed as a DEC bridge * behind which sits a proprietary NCR memory controller and * either four or two 53c875s as separate devices.  We can tell * if an 875 is part of a PQS/PDS or not since if it is, it will * be on the same bus as the memory controller.  In its usual * mode of operation, the 875s are slaved to the memory * controller for all transfers.  To operate with the Linux * driver, the memory controller is disabled and the 875s * freed to function independently.  The only wrinkle is that * the preset SCSI ID (which may be zero) must be read in from * a special configuration space register of the 875. */static void sym_config_pqs(struct pci_dev *pdev, struct sym_device *sym_dev){	int slot;	u8 tmp;	for (slot = 0; slot < 256; slot++) {		struct pci_dev *memc = pci_get_slot(pdev->bus, slot);		if (!memc || memc->vendor != 0x101a || memc->device == 0x0009) {			pci_dev_put(memc);			continue;		}		/* bit 1: allow individual 875 configuration */		pci_read_config_byte(memc, 0x44, &tmp);		if ((tmp & 0x2) == 0) {			tmp |= 0x2;			pci_write_config_byte(memc, 0x44, tmp);		}		/* bit 2: drive individual 875 interrupts to the bus */		pci_read_config_byte(memc, 0x45, &tmp);		if ((tmp & 0x4) == 0) {			tmp |= 0x4;			pci_write_config_byte(memc, 0x45, tmp);		}		pci_dev_put(memc);		break;	}	pci_read_config_byte(pdev, 0x84, &tmp);	sym_dev->host_id = tmp;}/* *  Called before unloading the module. *  Detach the host. *  We have to free resources and halt the NCR chip. */static int sym_detach(struct sym_hcb *np, struct pci_dev *pdev){	printk("%s: detaching ...\n", sym_name(np));	del_timer_sync(&np->s.timer);	/*	 * Reset NCR chip.	 * We should use sym_soft_reset(), but we don't want to do 	 * so, since we may not be safe if interrupts occur.	 */	printk("%s: resetting chip\n", sym_name(np));	OUTB(np, nc_istat, SRST);	INB(np, nc_mbox1);	udelay(10);	OUTB(np, nc_istat, 0);	sym_free_resources(np, pdev);	return 1;}/* * Driver host template. */static struct scsi_host_template sym2_template = {	.module			= THIS_MODULE,	.name			= "sym53c8xx",	.info			= sym53c8xx_info, 	.queuecommand		= sym53c8xx_queue_command,	.slave_alloc		= sym53c8xx_slave_alloc,	.slave_configure	= sym53c8xx_slave_configure,	.eh_abort_handler	= sym53c8xx_eh_abort_handler,	.eh_device_reset_handler = sym53c8xx_eh_device_reset_handler,	.eh_bus_reset_handler	= sym53c8xx_eh_bus_reset_handler,	.eh_host_reset_handler	= sym53c8xx_eh_host_reset_handler,	.this_id		= 7,	.use_clustering		= DISABLE_CLUSTERING,#ifdef SYM_LINUX_PROC_INFO_SUPPORT	.proc_info		= sym53c8xx_proc_info,	.proc_name		= NAME53C8XX,#endif};static int attach_count;static int __devinit sym2_probe(struct pci_dev *pdev,				const struct pci_device_id *ent){	struct sym_device sym_dev;	struct sym_nvram nvram;	struct Scsi_Host *instance;	memset(&sym_dev, 0, sizeof(sym_dev));	memset(&nvram, 0, sizeof(nvram));	if (pci_enable_device(pdev))		goto leave;	pci_set_master(pdev);	if (pci_request_regions(pdev, NAME53C8XX))		goto disable;	sym_init_device(pdev, &sym_dev);	if (sym_check_supported(&sym_dev))		goto free;	if (sym_check_raid(&sym_dev))		goto leave;	/* Don't disable the device */	if (sym_set_workarounds(&sym_dev))		goto free;	sym_config_pqs(pdev, &sym_dev);	sym_get_nvram(&sym_dev, &nvram);	instance = sym_attach(&sym2_template, attach_count, &sym_dev);	if (!instance)		goto free;	if (scsi_add_host(instance, &pdev->dev))		goto detach;	scsi_scan_host(instance);	attach_count++;	return 0; detach:	sym_detach(pci_get_drvdata(pdev), pdev); free:	pci_release_regions(pdev); disable:	pci_disable_device(pdev); leave:	return -ENODEV;}static void __devexit sym2_remove(struct pci_dev *pdev){	struct sym_hcb *np = pci_get_drvdata(pdev);	struct Scsi_Host *host = np->s.host;	scsi_remove_host(host);	scsi_host_put(host);	sym_detach(np, pdev);	pci_release_regions(pdev);	pci_disable_device(pdev);	attach_count--;}static void sym2_get_signalling(struct Scsi_Host *shost){	struct sym_hcb *np = sym_get_hcb(shost);	enum spi_signal_type type;	switch (np->scsi_mode) {	case SMODE_SE:		type = SPI_SIGNAL_SE;		break;	case SMODE_LVD:		type = SPI_SIGNAL_LVD;		break;	case SMODE_HVD:		type = SPI_SIGNAL_HVD;		break;	default:		type = SPI_SIGNAL_UNKNOWN;		break;	}	spi_signalling(shost) = type;}static void sym2_set_offset(struct scsi_target *starget, int offset){	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);	struct sym_hcb *np = sym_get_hcb(shost);	struct sym_tcb *tp = &np->target[starget->id];	tp->tgoal.offset = offset;	tp->tgoal.check_nego = 1;}static void sym2_set_period(struct scsi_target *starget, int period){	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);	struct sym_hcb *np = sym_get_hcb(shost);	struct sym_tcb *tp = &np->target[starget->id];	/* have to have DT for these transfers, but DT will also	 * set width, so check that this is allowed */	if (period <= np->minsync && spi_width(starget))		tp->tgoal.dt = 1;	tp->tgoal.period = period;	tp->tgoal.check_nego = 1;}static void sym2_set_width(struct scsi_target *starget, int width){	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);	struct sym_hcb *np = sym_get_hcb(shost);	struct sym_tcb *tp = &np->target[starget->id];	/* It is illegal to have DT set on narrow transfers.  If DT is	 * clear, we must also clear IU and QAS.  */	if (width == 0)		tp->tgoal.iu = tp->tgoal.dt = tp->tgoal.qas = 0;	tp->tgoal.width = width;	tp->tgoal.check_nego = 1;}static void sym2_set_dt(struct scsi_target *starget, int dt){	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);	struct sym_hcb *np = sym_get_hcb(shost);	struct sym_tcb *tp = &np->target[starget->id];	/* We must clear QAS and IU if DT is clear */	if (dt)		tp->tgoal.dt = 1;	else		tp->tgoal.iu = tp->tgoal.dt = tp->tgoal.qas = 0;	tp->tgoal.check_nego = 1;}#if 0static void sym2_set_iu(struct scsi_target *starget, int iu){	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);	struct sym_hcb *np = sym_get_hcb(shost);	struct sym_tcb *tp = &np->target[starget->id];	if (iu)		tp->tgoal.iu = tp->tgoal.dt = 1;	else		tp->tgoal.iu = 0;	tp->tgoal.check_nego = 1;}static void sym2_set_qas(struct scsi_target *starget, int qas){	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);	struct sym_hcb *np = sym_get_hcb(shost);	struct sym_tcb *tp = &np->target[starget->id];	if (qas)		tp->tgoal.dt = tp->tgoal.qas = 1;	else		tp->tgoal.qas = 0;	tp->tgoal.check_nego = 1;}#endifstatic struct spi_function_template sym2_transport_functions = {	.set_offset	= sym2_set_offset,	.show_offset	= 1,	.set_period	= sym2_set_period,	.show_period	= 1,	.set_width	= sym2_set_width,	.show_width	= 1,	.set_dt		= sym2_set_dt,	.show_dt	= 1,#if 0	.set_iu		= sym2_set_iu,	.show_iu	= 1,	.set_qas	= sym2_set_qas,	.show_qas	= 1,#endif	.get_signalling	= sym2_get_signalling,};static struct pci_device_id sym2_id_table[] __devinitdata = {	{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_NCR_53C810,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },	{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_NCR_53C820,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, /* new */	{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_NCR_53C825,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },	{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_NCR_53C815,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },	{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_53C810AP,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, /* new */	{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_NCR_53C860,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },	{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_53C1510,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },	{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_NCR_53C896,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },	{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_NCR_53C895,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },	{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_NCR_53C885,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },	{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_NCR_53C875,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },	{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_NCR_53C1510,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, /* new */	{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_53C895A,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },	{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_53C875A,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },	{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_53C1010_33,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },	{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_53C1010_66,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },	{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_NCR_53C875J,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },	{ 0, }};MODULE_DEVICE_TABLE(pci, sym2_id_table);static struct pci_driver sym2_driver = {	.name		= NAME53C8XX,	.id_table	= sym2_id_table,	.probe		= sym2_probe,	.remove		= __devexit_p(sym2_remove),};static int __init sym2_init(void){	int error;	sym2_setup_params();	sym2_transport_template = spi_attach_transport(&sym2_transport_functions);	if (!sym2_transport_template)		return -ENODEV;	error = pci_register_driver(&sym2_driver);	if (error)		spi_release_transport(sym2_transport_template);	return error;}static void __exit sym2_exit(void){	pci_unregister_driver(&sym2_driver);	spi_release_transport(sym2_transport_template);}module_init(sym2_init);module_exit(sym2_exit);

⌨️ 快捷键说明

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