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

📄 pata_scc.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
 *	Note: Original code is ata_std_dev_select(). */static void scc_std_dev_select (struct ata_port *ap, unsigned int device){	u8 tmp;	if (device == 0)		tmp = ATA_DEVICE_OBS;	else		tmp = ATA_DEVICE_OBS | ATA_DEV1;	out_be32(ap->ioaddr.device_addr, tmp);	ata_pause(ap);}/** *	scc_bmdma_setup - Set up PCI IDE BMDMA transaction *	@qc: Info associated with this ATA transaction. * *	Note: Original code is ata_bmdma_setup(). */static void scc_bmdma_setup (struct ata_queued_cmd *qc){	struct ata_port *ap = qc->ap;	unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);	u8 dmactl;	void __iomem *mmio = ap->ioaddr.bmdma_addr;	/* load PRD table addr */	out_be32(mmio + SCC_DMA_TABLE_OFS, ap->prd_dma);	/* specify data direction, triple-check start bit is clear */	dmactl = in_be32(mmio + SCC_DMA_CMD);	dmactl &= ~(ATA_DMA_WR | ATA_DMA_START);	if (!rw)		dmactl |= ATA_DMA_WR;	out_be32(mmio + SCC_DMA_CMD, dmactl);	/* issue r/w command */	ap->ops->exec_command(ap, &qc->tf);}/** *	scc_bmdma_start - Start a PCI IDE BMDMA transaction *	@qc: Info associated with this ATA transaction. * *	Note: Original code is ata_bmdma_start(). */static void scc_bmdma_start (struct ata_queued_cmd *qc){	struct ata_port *ap = qc->ap;	u8 dmactl;	void __iomem *mmio = ap->ioaddr.bmdma_addr;	/* start host DMA transaction */	dmactl = in_be32(mmio + SCC_DMA_CMD);	out_be32(mmio + SCC_DMA_CMD, dmactl | ATA_DMA_START);}/** *	scc_devchk - PATA device presence detection *	@ap: ATA channel to examine *	@device: Device to examine (starting at zero) * *	Note: Original code is ata_devchk(). */static unsigned int scc_devchk (struct ata_port *ap,				unsigned int device){	struct ata_ioports *ioaddr = &ap->ioaddr;	u8 nsect, lbal;	ap->ops->dev_select(ap, device);	out_be32(ioaddr->nsect_addr, 0x55);	out_be32(ioaddr->lbal_addr, 0xaa);	out_be32(ioaddr->nsect_addr, 0xaa);	out_be32(ioaddr->lbal_addr, 0x55);	out_be32(ioaddr->nsect_addr, 0x55);	out_be32(ioaddr->lbal_addr, 0xaa);	nsect = in_be32(ioaddr->nsect_addr);	lbal = in_be32(ioaddr->lbal_addr);	if ((nsect == 0x55) && (lbal == 0xaa))		return 1;	/* we found a device */	return 0;		/* nothing found */}/** *	scc_bus_post_reset - PATA device post reset * *	Note: Original code is ata_bus_post_reset(). */static int scc_bus_post_reset(struct ata_port *ap, unsigned int devmask,                              unsigned long deadline){	struct ata_ioports *ioaddr = &ap->ioaddr;	unsigned int dev0 = devmask & (1 << 0);	unsigned int dev1 = devmask & (1 << 1);	int rc;	/* if device 0 was found in ata_devchk, wait for its	 * BSY bit to clear	 */	if (dev0) {		rc = ata_wait_ready(ap, deadline);		if (rc && rc != -ENODEV)			return rc;	}	/* if device 1 was found in ata_devchk, wait for	 * register access, then wait for BSY to clear	 */	while (dev1) {		u8 nsect, lbal;		ap->ops->dev_select(ap, 1);		nsect = in_be32(ioaddr->nsect_addr);		lbal = in_be32(ioaddr->lbal_addr);		if ((nsect == 1) && (lbal == 1))			break;		if (time_after(jiffies, deadline))			return -EBUSY;		msleep(50);	/* give drive a breather */	}	if (dev1) {		rc = ata_wait_ready(ap, deadline);		if (rc && rc != -ENODEV)			return rc;	}	/* is all this really necessary? */	ap->ops->dev_select(ap, 0);	if (dev1)		ap->ops->dev_select(ap, 1);	if (dev0)		ap->ops->dev_select(ap, 0);	return 0;}/** *	scc_bus_softreset - PATA device software reset * *	Note: Original code is ata_bus_softreset(). */static unsigned int scc_bus_softreset(struct ata_port *ap, unsigned int devmask,                                      unsigned long deadline){	struct ata_ioports *ioaddr = &ap->ioaddr;	DPRINTK("ata%u: bus reset via SRST\n", ap->print_id);	/* software reset.  causes dev0 to be selected */	out_be32(ioaddr->ctl_addr, ap->ctl);	udelay(20);	out_be32(ioaddr->ctl_addr, ap->ctl | ATA_SRST);	udelay(20);	out_be32(ioaddr->ctl_addr, ap->ctl);	/* wait a while before checking status */	ata_wait_after_reset(ap, deadline);	/* Before we perform post reset processing we want to see if	 * the bus shows 0xFF because the odd clown forgets the D7	 * pulldown resistor.	 */	if (scc_check_status(ap) == 0xFF)		return 0;	scc_bus_post_reset(ap, devmask, deadline);	return 0;}/** *	scc_std_softreset - reset host port via ATA SRST *	@ap: port to reset *	@classes: resulting classes of attached devices *	@deadline: deadline jiffies for the operation * *	Note: Original code is ata_std_softreset(). */static int scc_std_softreset(struct ata_link *link, unsigned int *classes,                             unsigned long deadline){	struct ata_port *ap = link->ap;	unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS;	unsigned int devmask = 0, err_mask;	u8 err;	DPRINTK("ENTER\n");	if (ata_link_offline(link)) {		classes[0] = ATA_DEV_NONE;		goto out;	}	/* determine if device 0/1 are present */	if (scc_devchk(ap, 0))		devmask |= (1 << 0);	if (slave_possible && scc_devchk(ap, 1))		devmask |= (1 << 1);	/* select device 0 again */	ap->ops->dev_select(ap, 0);	/* issue bus reset */	DPRINTK("about to softreset, devmask=%x\n", devmask);	err_mask = scc_bus_softreset(ap, devmask, deadline);	if (err_mask) {		ata_port_printk(ap, KERN_ERR, "SRST failed (err_mask=0x%x)\n",				err_mask);		return -EIO;	}	/* determine by signature whether we have ATA or ATAPI devices */	classes[0] = ata_dev_try_classify(&ap->link.device[0],					  devmask & (1 << 0), &err);	if (slave_possible && err != 0x81)		classes[1] = ata_dev_try_classify(&ap->link.device[1],						  devmask & (1 << 1), &err); out:	DPRINTK("EXIT, classes[0]=%u [1]=%u\n", classes[0], classes[1]);	return 0;}/** *	scc_bmdma_stop - Stop PCI IDE BMDMA transfer *	@qc: Command we are ending DMA for */static void scc_bmdma_stop (struct ata_queued_cmd *qc){	struct ata_port *ap = qc->ap;	void __iomem *ctrl_base = ap->host->iomap[SCC_CTRL_BAR];	void __iomem *bmid_base = ap->host->iomap[SCC_BMID_BAR];	u32 reg;	while (1) {		reg = in_be32(bmid_base + SCC_DMA_INTST);		if (reg & INTSTS_SERROR) {			printk(KERN_WARNING "%s: SERROR\n", DRV_NAME);			out_be32(bmid_base + SCC_DMA_INTST, INTSTS_SERROR|INTSTS_BMSINT);			out_be32(bmid_base + SCC_DMA_CMD,				 in_be32(bmid_base + SCC_DMA_CMD) & ~ATA_DMA_START);			continue;		}		if (reg & INTSTS_PRERR) {			u32 maea0, maec0;			maea0 = in_be32(ctrl_base + SCC_CTL_MAEA0);			maec0 = in_be32(ctrl_base + SCC_CTL_MAEC0);			printk(KERN_WARNING "%s: PRERR [addr:%x cmd:%x]\n", DRV_NAME, maea0, maec0);			out_be32(bmid_base + SCC_DMA_INTST, INTSTS_PRERR|INTSTS_BMSINT);			out_be32(bmid_base + SCC_DMA_CMD,				 in_be32(bmid_base + SCC_DMA_CMD) & ~ATA_DMA_START);			continue;		}		if (reg & INTSTS_RERR) {			printk(KERN_WARNING "%s: Response Error\n", DRV_NAME);			out_be32(bmid_base + SCC_DMA_INTST, INTSTS_RERR|INTSTS_BMSINT);			out_be32(bmid_base + SCC_DMA_CMD,				 in_be32(bmid_base + SCC_DMA_CMD) & ~ATA_DMA_START);			continue;		}		if (reg & INTSTS_ICERR) {			out_be32(bmid_base + SCC_DMA_CMD,				 in_be32(bmid_base + SCC_DMA_CMD) & ~ATA_DMA_START);			printk(KERN_WARNING "%s: Illegal Configuration\n", DRV_NAME);			out_be32(bmid_base + SCC_DMA_INTST, INTSTS_ICERR|INTSTS_BMSINT);			continue;		}		if (reg & INTSTS_BMSINT) {			unsigned int classes;			unsigned long deadline = jiffies + ATA_TMOUT_BOOT;			printk(KERN_WARNING "%s: Internal Bus Error\n", DRV_NAME);			out_be32(bmid_base + SCC_DMA_INTST, INTSTS_BMSINT);			/* TBD: SW reset */			scc_std_softreset(&ap->link, &classes, deadline);			continue;		}		if (reg & INTSTS_BMHE) {			out_be32(bmid_base + SCC_DMA_INTST, INTSTS_BMHE);			continue;		}		if (reg & INTSTS_ACTEINT) {			out_be32(bmid_base + SCC_DMA_INTST, INTSTS_ACTEINT);			continue;		}		if (reg & INTSTS_IOIRQS) {			out_be32(bmid_base + SCC_DMA_INTST, INTSTS_IOIRQS);			continue;		}		break;	}	/* clear start/stop bit */	out_be32(bmid_base + SCC_DMA_CMD,		 in_be32(bmid_base + SCC_DMA_CMD) & ~ATA_DMA_START);	/* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */	ata_altstatus(ap);	/* dummy read */}/** *	scc_bmdma_status - Read PCI IDE BMDMA status *	@ap: Port associated with this ATA transaction. */static u8 scc_bmdma_status (struct ata_port *ap){	void __iomem *mmio = ap->ioaddr.bmdma_addr;	u8 host_stat = in_be32(mmio + SCC_DMA_STATUS);	u32 int_status = in_be32(mmio + SCC_DMA_INTST);	struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->link.active_tag);	static int retry = 0;	/* return if IOS_SS is cleared */	if (!(in_be32(mmio + SCC_DMA_CMD) & ATA_DMA_START))		return host_stat;	/* errata A252,A308 workaround: Step4 */	if ((ata_altstatus(ap) & ATA_ERR) && (int_status & INTSTS_INTRQ))		return (host_stat | ATA_DMA_INTR);	/* errata A308 workaround Step5 */	if (int_status & INTSTS_IOIRQS) {		host_stat |= ATA_DMA_INTR;		/* We don't check ATAPI DMA because it is limited to UDMA4 */		if ((qc->tf.protocol == ATA_PROT_DMA &&		     qc->dev->xfer_mode > XFER_UDMA_4)) {			if (!(int_status & INTSTS_ACTEINT)) {				printk(KERN_WARNING "ata%u: operation failed (transfer data loss)\n",				       ap->print_id);				host_stat |= ATA_DMA_ERR;				if (retry++)					ap->udma_mask &= ~(1 << qc->dev->xfer_mode);			} else				retry = 0;		}	}	return host_stat;}/** *	scc_data_xfer - Transfer data by PIO *	@adev: device for this I/O *	@buf: data buffer *	@buflen: buffer length *	@write_data: read/write * *	Note: Original code is ata_data_xfer(). */static void scc_data_xfer (struct ata_device *adev, unsigned char *buf,			   unsigned int buflen, int write_data){	struct ata_port *ap = adev->link->ap;	unsigned int words = buflen >> 1;	unsigned int i;	u16 *buf16 = (u16 *) buf;	void __iomem *mmio = ap->ioaddr.data_addr;	/* Transfer multiple of 2 bytes */	if (write_data) {		for (i = 0; i < words; i++)			out_be32(mmio, cpu_to_le16(buf16[i]));	} else {		for (i = 0; i < words; i++)			buf16[i] = le16_to_cpu(in_be32(mmio));	}	/* Transfer trailing 1 byte, if any. */	if (unlikely(buflen & 0x01)) {		u16 align_buf[1] = { 0 };		unsigned char *trailing_buf = buf + buflen - 1;		if (write_data) {			memcpy(align_buf, trailing_buf, 1);			out_be32(mmio, cpu_to_le16(align_buf[0]));

⌨️ 快捷键说明

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