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

📄 libata-core.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
}/** *	ata_xfer_mode2mask - Find matching xfer_mask for XFER_* *	@xfer_mode: XFER_* of interest * *	Return matching xfer_mask for @xfer_mode. * *	LOCKING: *	None. * *	RETURNS: *	Matching xfer_mask, 0 if no match found. */static unsigned int ata_xfer_mode2mask(u8 xfer_mode){	const struct ata_xfer_ent *ent;	for (ent = ata_xfer_tbl; ent->shift >= 0; ent++)		if (xfer_mode >= ent->base && xfer_mode < ent->base + ent->bits)			return 1 << (ent->shift + xfer_mode - ent->base);	return 0;}/** *	ata_xfer_mode2shift - Find matching xfer_shift for XFER_* *	@xfer_mode: XFER_* of interest * *	Return matching xfer_shift for @xfer_mode. * *	LOCKING: *	None. * *	RETURNS: *	Matching xfer_shift, -1 if no match found. */static int ata_xfer_mode2shift(unsigned int xfer_mode){	const struct ata_xfer_ent *ent;	for (ent = ata_xfer_tbl; ent->shift >= 0; ent++)		if (xfer_mode >= ent->base && xfer_mode < ent->base + ent->bits)			return ent->shift;	return -1;}/** *	ata_mode_string - convert xfer_mask to string *	@xfer_mask: mask of bits supported; only highest bit counts. * *	Determine string which represents the highest speed *	(highest bit in @modemask). * *	LOCKING: *	None. * *	RETURNS: *	Constant C string representing highest speed listed in *	@mode_mask, or the constant C string "<n/a>". */static const char *ata_mode_string(unsigned int xfer_mask){	static const char * const xfer_mode_str[] = {		"PIO0",		"PIO1",		"PIO2",		"PIO3",		"PIO4",		"PIO5",		"PIO6",		"MWDMA0",		"MWDMA1",		"MWDMA2",		"MWDMA3",		"MWDMA4",		"UDMA/16",		"UDMA/25",		"UDMA/33",		"UDMA/44",		"UDMA/66",		"UDMA/100",		"UDMA/133",		"UDMA7",	};	int highbit;	highbit = fls(xfer_mask) - 1;	if (highbit >= 0 && highbit < ARRAY_SIZE(xfer_mode_str))		return xfer_mode_str[highbit];	return "<n/a>";}static const char *sata_spd_string(unsigned int spd){	static const char * const spd_str[] = {		"1.5 Gbps",		"3.0 Gbps",	};	if (spd == 0 || (spd - 1) >= ARRAY_SIZE(spd_str))		return "<unknown>";	return spd_str[spd - 1];}void ata_dev_disable(struct ata_device *dev){	if (ata_dev_enabled(dev)) {		if (ata_msg_drv(dev->link->ap))			ata_dev_printk(dev, KERN_WARNING, "disabled\n");		ata_acpi_on_disable(dev);		ata_down_xfermask_limit(dev, ATA_DNXFER_FORCE_PIO0 |					     ATA_DNXFER_QUIET);		dev->class++;	}}static int ata_dev_set_dipm(struct ata_device *dev, enum link_pm policy){	struct ata_link *link = dev->link;	struct ata_port *ap = link->ap;	u32 scontrol;	unsigned int err_mask;	int rc;	/*	 * disallow DIPM for drivers which haven't set	 * ATA_FLAG_IPM.  This is because when DIPM is enabled,	 * phy ready will be set in the interrupt status on	 * state changes, which will cause some drivers to	 * think there are errors - additionally drivers will	 * need to disable hot plug.	 */	if (!(ap->flags & ATA_FLAG_IPM) || !ata_dev_enabled(dev)) {		ap->pm_policy = NOT_AVAILABLE;		return -EINVAL;	}	/*	 * For DIPM, we will only enable it for the	 * min_power setting.	 *	 * Why?  Because Disks are too stupid to know that	 * If the host rejects a request to go to SLUMBER	 * they should retry at PARTIAL, and instead it	 * just would give up.  So, for medium_power to	 * work at all, we need to only allow HIPM.	 */	rc = sata_scr_read(link, SCR_CONTROL, &scontrol);	if (rc)		return rc;	switch (policy) {	case MIN_POWER:		/* no restrictions on IPM transitions */		scontrol &= ~(0x3 << 8);		rc = sata_scr_write(link, SCR_CONTROL, scontrol);		if (rc)			return rc;		/* enable DIPM */		if (dev->flags & ATA_DFLAG_DIPM)			err_mask = ata_dev_set_feature(dev,					SETFEATURES_SATA_ENABLE, SATA_DIPM);		break;	case MEDIUM_POWER:		/* allow IPM to PARTIAL */		scontrol &= ~(0x1 << 8);		scontrol |= (0x2 << 8);		rc = sata_scr_write(link, SCR_CONTROL, scontrol);		if (rc)			return rc;		/*		 * we don't have to disable DIPM since IPM flags		 * disallow transitions to SLUMBER, which effectively		 * disable DIPM if it does not support PARTIAL		 */		break;	case NOT_AVAILABLE:	case MAX_PERFORMANCE:		/* disable all IPM transitions */		scontrol |= (0x3 << 8);		rc = sata_scr_write(link, SCR_CONTROL, scontrol);		if (rc)			return rc;		/*		 * we don't have to disable DIPM since IPM flags		 * disallow all transitions which effectively		 * disable DIPM anyway.		 */		break;	}	/* FIXME: handle SET FEATURES failure */	(void) err_mask;	return 0;}/** *	ata_dev_enable_pm - enable SATA interface power management *	@dev:  device to enable power management *	@policy: the link power management policy * *	Enable SATA Interface power management.  This will enable *	Device Interface Power Management (DIPM) for min_power * 	policy, and then call driver specific callbacks for *	enabling Host Initiated Power management. * *	Locking: Caller. *	Returns: -EINVAL if IPM is not supported, 0 otherwise. */void ata_dev_enable_pm(struct ata_device *dev, enum link_pm policy){	int rc = 0;	struct ata_port *ap = dev->link->ap;	/* set HIPM first, then DIPM */	if (ap->ops->enable_pm)		rc = ap->ops->enable_pm(ap, policy);	if (rc)		goto enable_pm_out;	rc = ata_dev_set_dipm(dev, policy);enable_pm_out:	if (rc)		ap->pm_policy = MAX_PERFORMANCE;	else		ap->pm_policy = policy;	return /* rc */;	/* hopefully we can use 'rc' eventually */}#ifdef CONFIG_PM/** *	ata_dev_disable_pm - disable SATA interface power management *	@dev: device to disable power management * *	Disable SATA Interface power management.  This will disable *	Device Interface Power Management (DIPM) without changing * 	policy,  call driver specific callbacks for disabling Host * 	Initiated Power management. * *	Locking: Caller. *	Returns: void */static void ata_dev_disable_pm(struct ata_device *dev){	struct ata_port *ap = dev->link->ap;	ata_dev_set_dipm(dev, MAX_PERFORMANCE);	if (ap->ops->disable_pm)		ap->ops->disable_pm(ap);}#endif	/* CONFIG_PM */void ata_lpm_schedule(struct ata_port *ap, enum link_pm policy){	ap->pm_policy = policy;	ap->link.eh_info.action |= ATA_EHI_LPM;	ap->link.eh_info.flags |= ATA_EHI_NO_AUTOPSY;	ata_port_schedule_eh(ap);}#ifdef CONFIG_PMstatic void ata_lpm_enable(struct ata_host *host){	struct ata_link *link;	struct ata_port *ap;	struct ata_device *dev;	int i;	for (i = 0; i < host->n_ports; i++) {		ap = host->ports[i];		ata_port_for_each_link(link, ap) {			ata_link_for_each_dev(dev, link)				ata_dev_disable_pm(dev);		}	}}static void ata_lpm_disable(struct ata_host *host){	int i;	for (i = 0; i < host->n_ports; i++) {		struct ata_port *ap = host->ports[i];		ata_lpm_schedule(ap, ap->pm_policy);	}}#endif	/* CONFIG_PM *//** *	ata_devchk - PATA device presence detection *	@ap: ATA channel to examine *	@device: Device to examine (starting at zero) * *	This technique was originally described in *	Hale Landis's ATADRVR (www.ata-atapi.com), and *	later found its way into the ATA/ATAPI spec. * *	Write a pattern to the ATA shadow registers, *	and if a device is present, it will respond by *	correctly storing and echoing back the *	ATA shadow register contents. * *	LOCKING: *	caller. */static unsigned int ata_devchk(struct ata_port *ap, unsigned int device){	struct ata_ioports *ioaddr = &ap->ioaddr;	u8 nsect, lbal;	ap->ops->dev_select(ap, device);	iowrite8(0x55, ioaddr->nsect_addr);	iowrite8(0xaa, ioaddr->lbal_addr);	iowrite8(0xaa, ioaddr->nsect_addr);	iowrite8(0x55, ioaddr->lbal_addr);	iowrite8(0x55, ioaddr->nsect_addr);	iowrite8(0xaa, ioaddr->lbal_addr);	nsect = ioread8(ioaddr->nsect_addr);	lbal = ioread8(ioaddr->lbal_addr);	if ((nsect == 0x55) && (lbal == 0xaa))		return 1;	/* we found a device */	return 0;		/* nothing found */}/** *	ata_dev_classify - determine device type based on ATA-spec signature *	@tf: ATA taskfile register set for device to be identified * *	Determine from taskfile register contents whether a device is *	ATA or ATAPI, as per "Signature and persistence" section *	of ATA/PI spec (volume 1, sect 5.14). * *	LOCKING: *	None. * *	RETURNS: *	Device type, %ATA_DEV_ATA, %ATA_DEV_ATAPI, %ATA_DEV_PMP or *	%ATA_DEV_UNKNOWN the event of failure. */unsigned int ata_dev_classify(const struct ata_taskfile *tf){	/* Apple's open source Darwin code hints that some devices only	 * put a proper signature into the LBA mid/high registers,	 * So, we only check those.  It's sufficient for uniqueness.	 *	 * ATA/ATAPI-7 (d1532v1r1: Feb. 19, 2003) specified separate	 * signatures for ATA and ATAPI devices attached on SerialATA,	 * 0x3c/0xc3 and 0x69/0x96 respectively.  However, SerialATA	 * spec has never mentioned about using different signatures	 * for ATA/ATAPI devices.  Then, Serial ATA II: Port	 * Multiplier specification began to use 0x69/0x96 to identify	 * port multpliers and 0x3c/0xc3 to identify SEMB device.	 * ATA/ATAPI-7 dropped descriptions about 0x3c/0xc3 and	 * 0x69/0x96 shortly and described them as reserved for	 * SerialATA.	 *	 * We follow the current spec and consider that 0x69/0x96	 * identifies a port multiplier and 0x3c/0xc3 a SEMB device.	 */	if ((tf->lbam == 0) && (tf->lbah == 0)) {		DPRINTK("found ATA device by sig\n");		return ATA_DEV_ATA;	}	if ((tf->lbam == 0x14) && (tf->lbah == 0xeb)) {		DPRINTK("found ATAPI device by sig\n");		return ATA_DEV_ATAPI;	}	if ((tf->lbam == 0x69) && (tf->lbah == 0x96)) {		DPRINTK("found PMP device by sig\n");		return ATA_DEV_PMP;	}	if ((tf->lbam == 0x3c) && (tf->lbah == 0xc3)) {		printk(KERN_INFO "ata: SEMB device ignored\n");		return ATA_DEV_SEMB_UNSUP; /* not yet */	}	DPRINTK("unknown device\n");	return ATA_DEV_UNKNOWN;}/** *	ata_dev_try_classify - Parse returned ATA device signature *	@dev: ATA device to classify (starting at zero) *	@present: device seems present *	@r_err: Value of error register on completion * *	After an event -- SRST, E.D.D., or SATA COMRESET -- occurs, *	an ATA/ATAPI-defined set of values is placed in the ATA *	shadow registers, indicating the results of device detection *	and diagnostics. * *	Select the ATA device, and read the values from the ATA shadow *	registers.  Then parse according to the Error register value, *	and the spec-defined values examined by ata_dev_classify(). * *	LOCKING: *	caller. * *	RETURNS: *	Device type - %ATA_DEV_ATA, %ATA_DEV_ATAPI or %ATA_DEV_NONE. */unsigned int ata_dev_try_classify(struct ata_device *dev, int present,				  u8 *r_err){	struct ata_port *ap = dev->link->ap;	struct ata_taskfile tf;	unsigned int class;	u8 err;	ap->ops->dev_select(ap, dev->devno);	memset(&tf, 0, sizeof(tf));	ap->ops->tf_read(ap, &tf);	err = tf.feature;	if (r_err)		*r_err = err;	/* see if device passed diags: if master then continue and warn later */	if (err == 0 && dev->devno == 0)		/* diagnostic fail : do nothing _YET_ */		dev->horkage |= ATA_HORKAGE_DIAGNOSTIC;	else if (err == 1)		/* do nothing */ ;	else if ((dev->devno == 0) && (err == 0x81))		/* do nothing */ ;	else		return ATA_DEV_NONE;	/* determine if device is ATA or ATAPI */	class = ata_dev_classify(&tf);	if (class == ATA_DEV_UNKNOWN) {		/* If the device failed diagnostic, it's likely to		 * have reported incorrect device signature too.		 * Assume ATA device if the device seems present but		 * device signature is invalid with diagnostic		 * failure.		 */		if (present && (dev->horkage & ATA_HORKAGE_DIAGNOSTIC))			class = ATA_DEV_ATA;		else			class = ATA_DEV_NONE;	} else if ((class == ATA_DEV_ATA) && (ata_chk_status(ap) == 0))		class = ATA_DEV_NONE;	return class;}/** *	ata_id_string - Convert IDENTIFY DEVICE page into string *	@id: IDENTIFY DEVICE results we will examine *	@s: string into which data is output *	@ofs: offset into identify device page *	@len: length of string to return. must be an even number. * *	The strings in the IDENTIFY DEVICE page are broken up into *	16-bit chunks.  Run through the string, and output each *	8-bit chunk linearly, regardless of platform. * *	LOCKING: *	caller. */void ata_id_string(const u16 *id, unsigned char *s,		   unsigned int ofs, unsigned int len){	unsigned int c;	while (len > 0) {		c = id[ofs] >> 8;		*s = c;		s++;		c = id[ofs] & 0xff;		*s = c;		s++;		ofs++;		len -= 2;	}}/** *	ata_id_c_string - Convert IDENTIFY DEVICE page into C string *	@id: IDENTIFY DEVICE results we will examine *	@s: string into which data is output *	@ofs: offset into identify device page *	@len: length of string to return. must be an odd number. * *	This function is identical to ata_id_string except that it *	trims trailing spaces and terminates the resulting string with *	null.  @len must be actual maximum length (even number) + 1. * *	LOCKING: *	caller. */void ata_id_c_string(const u16 *id, unsigned char *s,		     unsigned int ofs, unsigned int len){	unsigned char *p;

⌨️ 快捷键说明

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