pata_it821x.c

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

C
799
字号
/** *	it821x_smart_qc_issue_prot	-	wrap qc issue prot *	@qc: command * *	Wrap the command issue sequence for the IT821x. We need to *	perform out own device selection timing loads before the *	usual happenings kick off */static unsigned int it821x_smart_qc_issue_prot(struct ata_queued_cmd *qc){	switch(qc->tf.command)	{		/* Commands the firmware supports */		case ATA_CMD_READ:		case ATA_CMD_READ_EXT:		case ATA_CMD_WRITE:		case ATA_CMD_WRITE_EXT:		case ATA_CMD_PIO_READ:		case ATA_CMD_PIO_READ_EXT:		case ATA_CMD_PIO_WRITE:		case ATA_CMD_PIO_WRITE_EXT:		case ATA_CMD_READ_MULTI:		case ATA_CMD_READ_MULTI_EXT:		case ATA_CMD_WRITE_MULTI:		case ATA_CMD_WRITE_MULTI_EXT:		case ATA_CMD_ID_ATA:		/* Arguably should just no-op this one */		case ATA_CMD_SET_FEATURES:			return ata_qc_issue_prot(qc);	}	printk(KERN_DEBUG "it821x: can't process command 0x%02X\n", qc->tf.command);	return AC_ERR_INVALID;}/** *	it821x_passthru_qc_issue_prot	-	wrap qc issue prot *	@qc: command * *	Wrap the command issue sequence for the IT821x. We need to *	perform out own device selection timing loads before the *	usual happenings kick off */static unsigned int it821x_passthru_qc_issue_prot(struct ata_queued_cmd *qc){	it821x_passthru_dev_select(qc->ap, qc->dev->devno);	return ata_qc_issue_prot(qc);}/** *	it821x_smart_set_mode	-	mode setting *	@link: interface to set up *	@unused: device that failed (error only) * *	Use a non standard set_mode function. We don't want to be tuned. *	The BIOS configured everything. Our job is not to fiddle. We *	read the dma enabled bits from the PCI configuration of the device *	and respect them. */static int it821x_smart_set_mode(struct ata_link *link, struct ata_device **unused){	struct ata_device *dev;	ata_link_for_each_dev(dev, link) {		if (ata_dev_enabled(dev)) {			/* We don't really care */			dev->pio_mode = XFER_PIO_0;			dev->dma_mode = XFER_MW_DMA_0;			/* We do need the right mode information for DMA or PIO			   and this comes from the current configuration flags */			if (ata_id_has_dma(dev->id)) {				ata_dev_printk(dev, KERN_INFO, "configured for DMA\n");				dev->xfer_mode = XFER_MW_DMA_0;				dev->xfer_shift = ATA_SHIFT_MWDMA;				dev->flags &= ~ATA_DFLAG_PIO;			} else {				ata_dev_printk(dev, KERN_INFO, "configured for PIO\n");				dev->xfer_mode = XFER_PIO_0;				dev->xfer_shift = ATA_SHIFT_PIO;				dev->flags |= ATA_DFLAG_PIO;			}		}	}	return 0;}/** *	it821x_dev_config	-	Called each device identify *	@adev: Device that has just been identified * *	Perform the initial setup needed for each device that is chip *	special. In our case we need to lock the sector count to avoid *	blowing the brains out of the firmware with large LBA48 requests * *	FIXME: When FUA appears we need to block FUA too. And SMART and *	basically we need to filter commands for this chip. */static void it821x_dev_config(struct ata_device *adev){	unsigned char model_num[ATA_ID_PROD_LEN + 1];	ata_id_c_string(adev->id, model_num, ATA_ID_PROD, sizeof(model_num));	if (adev->max_sectors > 255)		adev->max_sectors = 255;	if (strstr(model_num, "Integrated Technology Express")) {		/* RAID mode */		printk(KERN_INFO "IT821x %sRAID%d volume",			adev->id[147]?"Bootable ":"",			adev->id[129]);		if (adev->id[129] != 1)			printk("(%dK stripe)", adev->id[146]);		printk(".\n");	}}/** *	it821x_check_atapi_dma	-	ATAPI DMA handler *	@qc: Command we are about to issue * *	Decide if this ATAPI command can be issued by DMA on this *	controller. Return 0 if it can be. */static int it821x_check_atapi_dma(struct ata_queued_cmd *qc){	struct ata_port *ap = qc->ap;	struct it821x_dev *itdev = ap->private_data;	/* Only use dma for transfers to/from the media. */	if (qc->nbytes < 2048)		return -EOPNOTSUPP;	/* No ATAPI DMA in smart mode */	if (itdev->smart)		return -EOPNOTSUPP;	/* No ATAPI DMA on rev 10 */	if (itdev->timing10)		return -EOPNOTSUPP;	/* Cool */	return 0;}/** *	it821x_port_start	-	port setup *	@ap: ATA port being set up * *	The it821x needs to maintain private data structures and also to *	use the standard PCI interface which lacks support for this *	functionality. We instead set up the private data on the port *	start hook, and tear it down on port stop */static int it821x_port_start(struct ata_port *ap){	struct pci_dev *pdev = to_pci_dev(ap->host->dev);	struct it821x_dev *itdev;	u8 conf;	int ret = ata_sff_port_start(ap);	if (ret < 0)		return ret;	itdev = devm_kzalloc(&pdev->dev, sizeof(struct it821x_dev), GFP_KERNEL);	if (itdev == NULL)		return -ENOMEM;	ap->private_data = itdev;	pci_read_config_byte(pdev, 0x50, &conf);	if (conf & 1) {		itdev->smart = 1;		/* Long I/O's although allowed in LBA48 space cause the		   onboard firmware to enter the twighlight zone */		/* No ATAPI DMA in this mode either */	}	/* Pull the current clocks from 0x50 */	if (conf & (1 << (1 + ap->port_no)))		itdev->clock_mode = ATA_50;	else		itdev->clock_mode = ATA_66;	itdev->want[0][1] = ATA_ANY;	itdev->want[1][1] = ATA_ANY;	itdev->last_device = -1;	if (pdev->revision == 0x10) {		itdev->timing10 = 1;		/* Need to disable ATAPI DMA for this case */		if (!itdev->smart)			printk(KERN_WARNING DRV_NAME": Revision 0x10, workarounds activated.\n");	}	return 0;}static struct scsi_host_template it821x_sht = {	.module			= THIS_MODULE,	.name			= DRV_NAME,	.ioctl			= ata_scsi_ioctl,	.queuecommand		= ata_scsi_queuecmd,	.can_queue		= ATA_DEF_QUEUE,	.this_id		= ATA_SHT_THIS_ID,	.sg_tablesize		= LIBATA_MAX_PRD,	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,	.emulated		= ATA_SHT_EMULATED,	.use_clustering		= ATA_SHT_USE_CLUSTERING,	.proc_name		= DRV_NAME,	.dma_boundary		= ATA_DMA_BOUNDARY,	.slave_configure	= ata_scsi_slave_config,	.slave_destroy		= ata_scsi_slave_destroy,	.bios_param		= ata_std_bios_param,};static struct ata_port_operations it821x_smart_port_ops = {	.set_mode	= it821x_smart_set_mode,	.tf_load	= ata_tf_load,	.tf_read	= ata_tf_read,	.mode_filter	= ata_pci_default_filter,	.check_status 	= ata_check_status,	.check_atapi_dma= it821x_check_atapi_dma,	.exec_command	= ata_exec_command,	.dev_select 	= ata_std_dev_select,	.dev_config	= it821x_dev_config,	.freeze		= ata_bmdma_freeze,	.thaw		= ata_bmdma_thaw,	.error_handler	= ata_bmdma_error_handler,	.post_internal_cmd = ata_bmdma_post_internal_cmd,	.cable_detect	= ata_cable_unknown,	.bmdma_setup 	= ata_bmdma_setup,	.bmdma_start 	= ata_bmdma_start,	.bmdma_stop	= ata_bmdma_stop,	.bmdma_status 	= ata_bmdma_status,	.qc_prep 	= ata_qc_prep,	.qc_issue	= it821x_smart_qc_issue_prot,	.data_xfer	= ata_data_xfer,	.irq_handler	= ata_interrupt,	.irq_clear	= ata_bmdma_irq_clear,	.irq_on		= ata_irq_on,	.port_start	= it821x_port_start,};static struct ata_port_operations it821x_passthru_port_ops = {	.set_piomode	= it821x_passthru_set_piomode,	.set_dmamode	= it821x_passthru_set_dmamode,	.mode_filter	= ata_pci_default_filter,	.tf_load	= ata_tf_load,	.tf_read	= ata_tf_read,	.check_status 	= ata_check_status,	.exec_command	= ata_exec_command,	.check_atapi_dma= it821x_check_atapi_dma,	.dev_select 	= it821x_passthru_dev_select,	.freeze		= ata_bmdma_freeze,	.thaw		= ata_bmdma_thaw,	.error_handler	= ata_bmdma_error_handler,	.post_internal_cmd = ata_bmdma_post_internal_cmd,	.cable_detect	= ata_cable_unknown,	.bmdma_setup 	= ata_bmdma_setup,	.bmdma_start 	= it821x_passthru_bmdma_start,	.bmdma_stop	= it821x_passthru_bmdma_stop,	.bmdma_status 	= ata_bmdma_status,	.qc_prep 	= ata_qc_prep,	.qc_issue	= it821x_passthru_qc_issue_prot,	.data_xfer	= ata_data_xfer,	.irq_clear	= ata_bmdma_irq_clear,	.irq_handler	= ata_interrupt,	.irq_on		= ata_irq_on,	.port_start	= it821x_port_start,};static void it821x_disable_raid(struct pci_dev *pdev){	/* Reset local CPU, and set BIOS not ready */	pci_write_config_byte(pdev, 0x5E, 0x01);	/* Set to bypass mode, and reset PCI bus */	pci_write_config_byte(pdev, 0x50, 0x00);	pci_write_config_word(pdev, PCI_COMMAND,			      PCI_COMMAND_PARITY | PCI_COMMAND_IO |			      PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);	pci_write_config_word(pdev, 0x40, 0xA0F3);	pci_write_config_dword(pdev,0x4C, 0x02040204);	pci_write_config_byte(pdev, 0x42, 0x36);	pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x20);}static int it821x_init_one(struct pci_dev *pdev, const struct pci_device_id *id){	u8 conf;	static const struct ata_port_info info_smart = {		.sht = &it821x_sht,		.flags = ATA_FLAG_SLAVE_POSS,		.pio_mask = 0x1f,		.mwdma_mask = 0x07,		.port_ops = &it821x_smart_port_ops	};	static const struct ata_port_info info_passthru = {		.sht = &it821x_sht,		.flags = ATA_FLAG_SLAVE_POSS,		.pio_mask = 0x1f,		.mwdma_mask = 0x07,		.udma_mask = ATA_UDMA6,		.port_ops = &it821x_passthru_port_ops	};	const struct ata_port_info *ppi[] = { NULL, NULL };	static char *mode[2] = { "pass through", "smart" };	/* Force the card into bypass mode if so requested */	if (it8212_noraid) {		printk(KERN_INFO DRV_NAME ": forcing bypass mode.\n");		it821x_disable_raid(pdev);	}	pci_read_config_byte(pdev, 0x50, &conf);	conf &= 1;	printk(KERN_INFO DRV_NAME ": controller in %s mode.\n", mode[conf]);	if (conf == 0)		ppi[0] = &info_passthru;	else		ppi[0] = &info_smart;	return ata_pci_init_one(pdev, ppi);}#ifdef CONFIG_PMstatic int it821x_reinit_one(struct pci_dev *pdev){	/* Resume - turn raid back off if need be */	if (it8212_noraid)		it821x_disable_raid(pdev);	return ata_pci_device_resume(pdev);}#endifstatic const struct pci_device_id it821x[] = {	{ PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8211), },	{ PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8212), },	{ },};static struct pci_driver it821x_pci_driver = {	.name 		= DRV_NAME,	.id_table	= it821x,	.probe 		= it821x_init_one,	.remove		= ata_pci_remove_one,#ifdef CONFIG_PM	.suspend	= ata_pci_device_suspend,	.resume		= it821x_reinit_one,#endif};static int __init it821x_init(void){	return pci_register_driver(&it821x_pci_driver);}static void __exit it821x_exit(void){	pci_unregister_driver(&it821x_pci_driver);}MODULE_AUTHOR("Alan Cox");MODULE_DESCRIPTION("low-level driver for the IT8211/IT8212 IDE RAID controller");MODULE_LICENSE("GPL");MODULE_DEVICE_TABLE(pci, it821x);MODULE_VERSION(DRV_VERSION);module_param_named(noraid, it8212_noraid, int, S_IRUGO);MODULE_PARM_DESC(noraid, "Force card into bypass mode");module_init(it821x_init);module_exit(it821x_exit);

⌨️ 快捷键说明

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