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

📄 sata_promise.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
			ap->prd[idx].addr = cpu_to_le32(addr);			ap->prd[idx].flags_len = cpu_to_le32(len & 0xffff);			VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx, addr, len);			idx++;			sg_len -= len;			addr += len;		}	}	if (idx) {		u32 len = le32_to_cpu(ap->prd[idx - 1].flags_len);		if (len > SG_COUNT_ASIC_BUG) {			u32 addr;			VPRINTK("Splitting last PRD.\n");			addr = le32_to_cpu(ap->prd[idx - 1].addr);			ap->prd[idx - 1].flags_len = cpu_to_le32(len - SG_COUNT_ASIC_BUG);			VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx - 1, addr, SG_COUNT_ASIC_BUG);			addr = addr + len - SG_COUNT_ASIC_BUG;			len = SG_COUNT_ASIC_BUG;			ap->prd[idx].addr = cpu_to_le32(addr);			ap->prd[idx].flags_len = cpu_to_le32(len);			VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx, addr, len);			idx++;		}		ap->prd[idx - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT);	}}static void pdc_qc_prep(struct ata_queued_cmd *qc){	struct pdc_port_priv *pp = qc->ap->private_data;	unsigned int i;	VPRINTK("ENTER\n");	switch (qc->tf.protocol) {	case ATA_PROT_DMA:		pdc_fill_sg(qc);		/* fall through */	case ATA_PROT_NODATA:		i = pdc_pkt_header(&qc->tf, qc->ap->prd_dma,				   qc->dev->devno, pp->pkt);		if (qc->tf.flags & ATA_TFLAG_LBA48)			i = pdc_prep_lba48(&qc->tf, pp->pkt, i);		else			i = pdc_prep_lba28(&qc->tf, pp->pkt, i);		pdc_pkt_footer(&qc->tf, pp->pkt, i);		break;	case ATA_PROT_ATAPI:		pdc_fill_sg(qc);		break;	case ATA_PROT_ATAPI_DMA:		pdc_fill_sg(qc);		/*FALLTHROUGH*/	case ATA_PROT_ATAPI_NODATA:		pdc_atapi_pkt(qc);		break;	default:		break;	}}static void pdc_freeze(struct ata_port *ap){	void __iomem *mmio = ap->ioaddr.cmd_addr;	u32 tmp;	tmp = readl(mmio + PDC_CTLSTAT);	tmp |= PDC_IRQ_DISABLE;	tmp &= ~PDC_DMA_ENABLE;	writel(tmp, mmio + PDC_CTLSTAT);	readl(mmio + PDC_CTLSTAT); /* flush */}static void pdc_thaw(struct ata_port *ap){	void __iomem *mmio = ap->ioaddr.cmd_addr;	u32 tmp;	/* clear IRQ */	readl(mmio + PDC_INT_SEQMASK);	/* turn IRQ back on */	tmp = readl(mmio + PDC_CTLSTAT);	tmp &= ~PDC_IRQ_DISABLE;	writel(tmp, mmio + PDC_CTLSTAT);	readl(mmio + PDC_CTLSTAT); /* flush */}static void pdc_common_error_handler(struct ata_port *ap, ata_reset_fn_t hardreset){	if (!(ap->pflags & ATA_PFLAG_FROZEN))		pdc_reset_port(ap);	/* perform recovery */	ata_do_eh(ap, ata_std_prereset, ata_std_softreset, hardreset,		  ata_std_postreset);}static void pdc_pata_error_handler(struct ata_port *ap){	pdc_common_error_handler(ap, NULL);}static void pdc_sata_error_handler(struct ata_port *ap){	pdc_common_error_handler(ap, sata_std_hardreset);}static void pdc_post_internal_cmd(struct ata_queued_cmd *qc){	struct ata_port *ap = qc->ap;	/* make DMA engine forget about the failed command */	if (qc->flags & ATA_QCFLAG_FAILED)		pdc_reset_port(ap);}static void pdc_error_intr(struct ata_port *ap, struct ata_queued_cmd *qc,			   u32 port_status, u32 err_mask){	struct ata_eh_info *ehi = &ap->link.eh_info;	unsigned int ac_err_mask = 0;	ata_ehi_clear_desc(ehi);	ata_ehi_push_desc(ehi, "port_status 0x%08x", port_status);	port_status &= err_mask;	if (port_status & PDC_DRIVE_ERR)		ac_err_mask |= AC_ERR_DEV;	if (port_status & (PDC_OVERRUN_ERR | PDC_UNDERRUN_ERR))		ac_err_mask |= AC_ERR_HSM;	if (port_status & (PDC2_ATA_HBA_ERR | PDC2_ATA_DMA_CNT_ERR))		ac_err_mask |= AC_ERR_ATA_BUS;	if (port_status & (PDC_PH_ERR | PDC_SH_ERR | PDC_DH_ERR | PDC2_HTO_ERR			   | PDC_PCI_SYS_ERR | PDC1_PCI_PARITY_ERR))		ac_err_mask |= AC_ERR_HOST_BUS;	if (sata_scr_valid(&ap->link)) {		u32 serror;		pdc_sata_scr_read(ap, SCR_ERROR, &serror);		ehi->serror |= serror;	}	qc->err_mask |= ac_err_mask;	pdc_reset_port(ap);	ata_port_abort(ap);}static inline unsigned int pdc_host_intr(struct ata_port *ap,					 struct ata_queued_cmd *qc){	unsigned int handled = 0;	void __iomem *port_mmio = ap->ioaddr.cmd_addr;	u32 port_status, err_mask;	err_mask = PDC_ERR_MASK;	if (ap->flags & PDC_FLAG_GEN_II)		err_mask &= ~PDC1_ERR_MASK;	else		err_mask &= ~PDC2_ERR_MASK;	port_status = readl(port_mmio + PDC_GLOBAL_CTL);	if (unlikely(port_status & err_mask)) {		pdc_error_intr(ap, qc, port_status, err_mask);		return 1;	}	switch (qc->tf.protocol) {	case ATA_PROT_DMA:	case ATA_PROT_NODATA:	case ATA_PROT_ATAPI_DMA:	case ATA_PROT_ATAPI_NODATA:		qc->err_mask |= ac_err_mask(ata_wait_idle(ap));		ata_qc_complete(qc);		handled = 1;		break;	default:		ap->stats.idle_irq++;		break;	}	return handled;}static void pdc_irq_clear(struct ata_port *ap){	struct ata_host *host = ap->host;	void __iomem *mmio = host->iomap[PDC_MMIO_BAR];	readl(mmio + PDC_INT_SEQMASK);}static int pdc_is_sataii_tx4(unsigned long flags){	const unsigned long mask = PDC_FLAG_GEN_II | PDC_FLAG_4_PORTS;	return (flags & mask) == mask;}static unsigned int pdc_port_no_to_ata_no(unsigned int port_no,					  int is_sataii_tx4){	static const unsigned char sataii_tx4_port_remap[4] = { 3, 1, 0, 2};	return is_sataii_tx4 ? sataii_tx4_port_remap[port_no] : port_no;}static irqreturn_t pdc_interrupt(int irq, void *dev_instance){	struct ata_host *host = dev_instance;	struct ata_port *ap;	u32 mask = 0;	unsigned int i, tmp;	unsigned int handled = 0;	void __iomem *mmio_base;	unsigned int hotplug_offset, ata_no;	u32 hotplug_status;	int is_sataii_tx4;	VPRINTK("ENTER\n");	if (!host || !host->iomap[PDC_MMIO_BAR]) {		VPRINTK("QUICK EXIT\n");		return IRQ_NONE;	}	mmio_base = host->iomap[PDC_MMIO_BAR];	/* read and clear hotplug flags for all ports */	if (host->ports[0]->flags & PDC_FLAG_GEN_II)		hotplug_offset = PDC2_SATA_PLUG_CSR;	else		hotplug_offset = PDC_SATA_PLUG_CSR;	hotplug_status = readl(mmio_base + hotplug_offset);	if (hotplug_status & 0xff)		writel(hotplug_status | 0xff, mmio_base + hotplug_offset);	hotplug_status &= 0xff;	/* clear uninteresting bits */	/* reading should also clear interrupts */	mask = readl(mmio_base + PDC_INT_SEQMASK);	if (mask == 0xffffffff && hotplug_status == 0) {		VPRINTK("QUICK EXIT 2\n");		return IRQ_NONE;	}	spin_lock(&host->lock);	mask &= 0xffff;		/* only 16 tags possible */	if (mask == 0 && hotplug_status == 0) {		VPRINTK("QUICK EXIT 3\n");		goto done_irq;	}	writel(mask, mmio_base + PDC_INT_SEQMASK);	is_sataii_tx4 = pdc_is_sataii_tx4(host->ports[0]->flags);	for (i = 0; i < host->n_ports; i++) {		VPRINTK("port %u\n", i);		ap = host->ports[i];		/* check for a plug or unplug event */		ata_no = pdc_port_no_to_ata_no(i, is_sataii_tx4);		tmp = hotplug_status & (0x11 << ata_no);		if (tmp && ap &&		    !(ap->flags & ATA_FLAG_DISABLED)) {			struct ata_eh_info *ehi = &ap->link.eh_info;			ata_ehi_clear_desc(ehi);			ata_ehi_hotplugged(ehi);			ata_ehi_push_desc(ehi, "hotplug_status %#x", tmp);			ata_port_freeze(ap);			++handled;			continue;		}		/* check for a packet interrupt */		tmp = mask & (1 << (i + 1));		if (tmp && ap &&		    !(ap->flags & ATA_FLAG_DISABLED)) {			struct ata_queued_cmd *qc;			qc = ata_qc_from_tag(ap, ap->link.active_tag);			if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)))				handled += pdc_host_intr(ap, qc);		}	}	VPRINTK("EXIT\n");done_irq:	spin_unlock(&host->lock);	return IRQ_RETVAL(handled);}static inline void pdc_packet_start(struct ata_queued_cmd *qc){	struct ata_port *ap = qc->ap;	struct pdc_port_priv *pp = ap->private_data;	void __iomem *mmio = ap->host->iomap[PDC_MMIO_BAR];	unsigned int port_no = ap->port_no;	u8 seq = (u8) (port_no + 1);	VPRINTK("ENTER, ap %p\n", ap);	writel(0x00000001, mmio + (seq * 4));	readl(mmio + (seq * 4));	/* flush */	pp->pkt[2] = seq;	wmb();			/* flush PRD, pkt writes */	writel(pp->pkt_dma, ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);	readl(ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); /* flush */}static unsigned int pdc_qc_issue_prot(struct ata_queued_cmd *qc){	switch (qc->tf.protocol) {	case ATA_PROT_ATAPI_NODATA:		if (qc->dev->flags & ATA_DFLAG_CDB_INTR)			break;		/*FALLTHROUGH*/	case ATA_PROT_NODATA:		if (qc->tf.flags & ATA_TFLAG_POLLING)			break;		/*FALLTHROUGH*/	case ATA_PROT_ATAPI_DMA:	case ATA_PROT_DMA:		pdc_packet_start(qc);		return 0;	default:		break;	}	return ata_qc_issue_prot(qc);}static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf){	WARN_ON(tf->protocol == ATA_PROT_DMA ||		tf->protocol == ATA_PROT_ATAPI_DMA);	ata_tf_load(ap, tf);}static void pdc_exec_command_mmio(struct ata_port *ap,				  const struct ata_taskfile *tf){	WARN_ON(tf->protocol == ATA_PROT_DMA ||		tf->protocol == ATA_PROT_ATAPI_DMA);	ata_exec_command(ap, tf);}static int pdc_check_atapi_dma(struct ata_queued_cmd *qc){	u8 *scsicmd = qc->scsicmd->cmnd;	int pio = 1; /* atapi dma off by default */	/* Whitelist commands that may use DMA. */	switch (scsicmd[0]) {	case WRITE_12:	case WRITE_10:	case WRITE_6:	case READ_12:	case READ_10:	case READ_6:	case 0xad: /* READ_DVD_STRUCTURE */	case 0xbe: /* READ_CD */		pio = 0;	}	/* -45150 (FFFF4FA2) to -1 (FFFFFFFF) shall use PIO mode */	if (scsicmd[0] == WRITE_10) {		unsigned int lba =			(scsicmd[2] << 24) |			(scsicmd[3] << 16) |			(scsicmd[4] << 8) |			scsicmd[5];		if (lba >= 0xFFFF4FA2)			pio = 1;	}	return pio;}static int pdc_old_sata_check_atapi_dma(struct ata_queued_cmd *qc){	/* First generation chips cannot use ATAPI DMA on SATA ports */	return 1;}static void pdc_ata_setup_port(struct ata_port *ap,			       void __iomem *base, void __iomem *scr_addr){	ap->ioaddr.cmd_addr		= base;	ap->ioaddr.data_addr		= base;	ap->ioaddr.feature_addr		=	ap->ioaddr.error_addr		= base + 0x4;	ap->ioaddr.nsect_addr		= base + 0x8;	ap->ioaddr.lbal_addr		= base + 0xc;	ap->ioaddr.lbam_addr		= base + 0x10;	ap->ioaddr.lbah_addr		= base + 0x14;	ap->ioaddr.device_addr		= base + 0x18;	ap->ioaddr.command_addr		=	ap->ioaddr.status_addr		= base + 0x1c;	ap->ioaddr.altstatus_addr	=	ap->ioaddr.ctl_addr		= base + 0x38;	ap->ioaddr.scr_addr		= scr_addr;}static void pdc_host_init(struct ata_host *host){	void __iomem *mmio = host->iomap[PDC_MMIO_BAR];	int is_gen2 = host->ports[0]->flags & PDC_FLAG_GEN_II;	int hotplug_offset;	u32 tmp;	if (is_gen2)		hotplug_offset = PDC2_SATA_PLUG_CSR;	else		hotplug_offset = PDC_SATA_PLUG_CSR;	/*	 * Except for the hotplug stuff, this is voodoo from the	 * Promise driver.  Label this entire section	 * "TODO: figure out why we do this"	 */	/* enable BMR_BURST, maybe change FIFO_SHD to 8 dwords */	tmp = readl(mmio + PDC_FLASH_CTL);	tmp |= 0x02000;	/* bit 13 (enable bmr burst) */	if (!is_gen2)		tmp |= 0x10000;	/* bit 16 (fifo threshold at 8 dw) */	writel(tmp, mmio + PDC_FLASH_CTL);	/* clear plug/unplug flags for all ports */	tmp = readl(mmio + hotplug_offset);	writel(tmp | 0xff, mmio + hotplug_offset);	/* unmask plug/unplug ints */	tmp = readl(mmio + hotplug_offset);	writel(tmp & ~0xff0000, mmio + hotplug_offset);	/* don't initialise TBG or SLEW on 2nd generation chips */	if (is_gen2)		return;	/* reduce TBG clock to 133 Mhz. */	tmp = readl(mmio + PDC_TBG_MODE);	tmp &= ~0x30000; /* clear bit 17, 16*/	tmp |= 0x10000;  /* set bit 17:16 = 0:1 */	writel(tmp, mmio + PDC_TBG_MODE);	readl(mmio + PDC_TBG_MODE);	/* flush */	msleep(10);	/* adjust slew rate control register. */	tmp = readl(mmio + PDC_SLEW_CTL);	tmp &= 0xFFFFF03F; /* clear bit 11 ~ 6 */	tmp  |= 0x00000900; /* set bit 11-9 = 100b , bit 8-6 = 100 */	writel(tmp, mmio + PDC_SLEW_CTL);}static int pdc_ata_init_one(struct pci_dev *pdev,			    const struct pci_device_id *ent){	static int printed_version;	const struct ata_port_info *pi = &pdc_port_info[ent->driver_data];	const struct ata_port_info *ppi[PDC_MAX_PORTS];	struct ata_host *host;	void __iomem *base;	int n_ports, i, rc;	int is_sataii_tx4;	if (!printed_version++)		dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");	/* enable and acquire resources */	rc = pcim_enable_device(pdev);	if (rc)		return rc;	rc = pcim_iomap_regions(pdev, 1 << PDC_MMIO_BAR, DRV_NAME);	if (rc == -EBUSY)		pcim_pin_device(pdev);	if (rc)		return rc;	base = pcim_iomap_table(pdev)[PDC_MMIO_BAR];	/* determine port configuration and setup host */	n_ports = 2;	if (pi->flags & PDC_FLAG_4_PORTS)		n_ports = 4;	for (i = 0; i < n_ports; i++)		ppi[i] = pi;	if (pi->flags & PDC_FLAG_SATA_PATA) {		u8 tmp = readb(base + PDC_FLASH_CTL+1);		if (!(tmp & 0x80))			ppi[n_ports++] = pi + 1;	}	host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);	if (!host) {		dev_printk(KERN_ERR, &pdev->dev, "failed to allocate host\n");		return -ENOMEM;	}	host->iomap = pcim_iomap_table(pdev);	is_sataii_tx4 = pdc_is_sataii_tx4(pi->flags);	for (i = 0; i < host->n_ports; i++) {		struct ata_port *ap = host->ports[i];		unsigned int ata_no = pdc_port_no_to_ata_no(i, is_sataii_tx4);		unsigned int port_offset = 0x200 + ata_no * 0x80;		unsigned int scr_offset = 0x400 + ata_no * 0x100;		pdc_ata_setup_port(ap, base + port_offset, base + scr_offset);		ata_port_pbar_desc(ap, PDC_MMIO_BAR, -1, "mmio");		ata_port_pbar_desc(ap, PDC_MMIO_BAR, port_offset, "port");	}	/* initialize adapter */	pdc_host_init(host);	rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);	if (rc)		return rc;	rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);	if (rc)		return rc;	/* start host, request IRQ and attach */	pci_set_master(pdev);	return ata_host_activate(host, pdev->irq, pdc_interrupt, IRQF_SHARED,				 &pdc_ata_sht);}static int __init pdc_ata_init(void){	return pci_register_driver(&pdc_ata_pci_driver);}static void __exit pdc_ata_exit(void){	pci_unregister_driver(&pdc_ata_pci_driver);}MODULE_AUTHOR("Jeff Garzik");MODULE_DESCRIPTION("Promise ATA TX2/TX4/TX4000 low-level driver");MODULE_LICENSE("GPL");MODULE_DEVICE_TABLE(pci, pdc_ata_pci_tbl);MODULE_VERSION(DRV_VERSION);module_init(pdc_ata_init);module_exit(pdc_ata_exit);

⌨️ 快捷键说明

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