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

📄 libata-core.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	WARN_ON(!(len & 1));	ata_id_string(id, s, ofs, len - 1);	p = s + strnlen(s, len - 1);	while (p > s && p[-1] == ' ')		p--;	*p = '\0';}static u64 ata_id_n_sectors(const u16 *id){	if (ata_id_has_lba(id)) {		if (ata_id_has_lba48(id))			return ata_id_u64(id, 100);		else			return ata_id_u32(id, 60);	} else {		if (ata_id_current_chs_valid(id))			return ata_id_u32(id, 57);		else			return id[1] * id[3] * id[6];	}}static u64 ata_tf_to_lba48(struct ata_taskfile *tf){	u64 sectors = 0;	sectors |= ((u64)(tf->hob_lbah & 0xff)) << 40;	sectors |= ((u64)(tf->hob_lbam & 0xff)) << 32;	sectors |= (tf->hob_lbal & 0xff) << 24;	sectors |= (tf->lbah & 0xff) << 16;	sectors |= (tf->lbam & 0xff) << 8;	sectors |= (tf->lbal & 0xff);	return ++sectors;}static u64 ata_tf_to_lba(struct ata_taskfile *tf){	u64 sectors = 0;	sectors |= (tf->device & 0x0f) << 24;	sectors |= (tf->lbah & 0xff) << 16;	sectors |= (tf->lbam & 0xff) << 8;	sectors |= (tf->lbal & 0xff);	return ++sectors;}/** *	ata_read_native_max_address - Read native max address *	@dev: target device *	@max_sectors: out parameter for the result native max address * *	Perform an LBA48 or LBA28 native size query upon the device in *	question. * *	RETURNS: *	0 on success, -EACCES if command is aborted by the drive. *	-EIO on other errors. */static int ata_read_native_max_address(struct ata_device *dev, u64 *max_sectors){	unsigned int err_mask;	struct ata_taskfile tf;	int lba48 = ata_id_has_lba48(dev->id);	ata_tf_init(dev, &tf);	/* always clear all address registers */	tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR;	if (lba48) {		tf.command = ATA_CMD_READ_NATIVE_MAX_EXT;		tf.flags |= ATA_TFLAG_LBA48;	} else		tf.command = ATA_CMD_READ_NATIVE_MAX;	tf.protocol |= ATA_PROT_NODATA;	tf.device |= ATA_LBA;	err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);	if (err_mask) {		ata_dev_printk(dev, KERN_WARNING, "failed to read native "			       "max address (err_mask=0x%x)\n", err_mask);		if (err_mask == AC_ERR_DEV && (tf.feature & ATA_ABORTED))			return -EACCES;		return -EIO;	}	if (lba48)		*max_sectors = ata_tf_to_lba48(&tf);	else		*max_sectors = ata_tf_to_lba(&tf);	if (dev->horkage & ATA_HORKAGE_HPA_SIZE)		(*max_sectors)--;	return 0;}/** *	ata_set_max_sectors - Set max sectors *	@dev: target device *	@new_sectors: new max sectors value to set for the device * *	Set max sectors of @dev to @new_sectors. * *	RETURNS: *	0 on success, -EACCES if command is aborted or denied (due to *	previous non-volatile SET_MAX) by the drive.  -EIO on other *	errors. */static int ata_set_max_sectors(struct ata_device *dev, u64 new_sectors){	unsigned int err_mask;	struct ata_taskfile tf;	int lba48 = ata_id_has_lba48(dev->id);	new_sectors--;	ata_tf_init(dev, &tf);	tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR;	if (lba48) {		tf.command = ATA_CMD_SET_MAX_EXT;		tf.flags |= ATA_TFLAG_LBA48;		tf.hob_lbal = (new_sectors >> 24) & 0xff;		tf.hob_lbam = (new_sectors >> 32) & 0xff;		tf.hob_lbah = (new_sectors >> 40) & 0xff;	} else {		tf.command = ATA_CMD_SET_MAX;		tf.device |= (new_sectors >> 24) & 0xf;	}	tf.protocol |= ATA_PROT_NODATA;	tf.device |= ATA_LBA;	tf.lbal = (new_sectors >> 0) & 0xff;	tf.lbam = (new_sectors >> 8) & 0xff;	tf.lbah = (new_sectors >> 16) & 0xff;	err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);	if (err_mask) {		ata_dev_printk(dev, KERN_WARNING, "failed to set "			       "max address (err_mask=0x%x)\n", err_mask);		if (err_mask == AC_ERR_DEV &&		    (tf.feature & (ATA_ABORTED | ATA_IDNF)))			return -EACCES;		return -EIO;	}	return 0;}/** *	ata_hpa_resize		-	Resize a device with an HPA set *	@dev: Device to resize * *	Read the size of an LBA28 or LBA48 disk with HPA features and resize *	it if required to the full size of the media. The caller must check *	the drive has the HPA feature set enabled. * *	RETURNS: *	0 on success, -errno on failure. */static int ata_hpa_resize(struct ata_device *dev){	struct ata_eh_context *ehc = &dev->link->eh_context;	int print_info = ehc->i.flags & ATA_EHI_PRINTINFO;	u64 sectors = ata_id_n_sectors(dev->id);	u64 native_sectors;	int rc;	/* do we need to do it? */	if (dev->class != ATA_DEV_ATA ||	    !ata_id_has_lba(dev->id) || !ata_id_hpa_enabled(dev->id) ||	    (dev->horkage & ATA_HORKAGE_BROKEN_HPA))		return 0;	/* read native max address */	rc = ata_read_native_max_address(dev, &native_sectors);	if (rc) {		/* If HPA isn't going to be unlocked, skip HPA		 * resizing from the next try.		 */		if (!ata_ignore_hpa) {			ata_dev_printk(dev, KERN_WARNING, "HPA support seems "				       "broken, will skip HPA handling\n");			dev->horkage |= ATA_HORKAGE_BROKEN_HPA;			/* we can continue if device aborted the command */			if (rc == -EACCES)				rc = 0;		}		return rc;	}	/* nothing to do? */	if (native_sectors <= sectors || !ata_ignore_hpa) {		if (!print_info || native_sectors == sectors)			return 0;		if (native_sectors > sectors)			ata_dev_printk(dev, KERN_INFO,				"HPA detected: current %llu, native %llu\n",				(unsigned long long)sectors,				(unsigned long long)native_sectors);		else if (native_sectors < sectors)			ata_dev_printk(dev, KERN_WARNING,				"native sectors (%llu) is smaller than "				"sectors (%llu)\n",				(unsigned long long)native_sectors,				(unsigned long long)sectors);		return 0;	}	/* let's unlock HPA */	rc = ata_set_max_sectors(dev, native_sectors);	if (rc == -EACCES) {		/* if device aborted the command, skip HPA resizing */		ata_dev_printk(dev, KERN_WARNING, "device aborted resize "			       "(%llu -> %llu), skipping HPA handling\n",			       (unsigned long long)sectors,			       (unsigned long long)native_sectors);		dev->horkage |= ATA_HORKAGE_BROKEN_HPA;		return 0;	} else if (rc)		return rc;	/* re-read IDENTIFY data */	rc = ata_dev_reread_id(dev, 0);	if (rc) {		ata_dev_printk(dev, KERN_ERR, "failed to re-read IDENTIFY "			       "data after HPA resizing\n");		return rc;	}	if (print_info) {		u64 new_sectors = ata_id_n_sectors(dev->id);		ata_dev_printk(dev, KERN_INFO,			"HPA unlocked: %llu -> %llu, native %llu\n",			(unsigned long long)sectors,			(unsigned long long)new_sectors,			(unsigned long long)native_sectors);	}	return 0;}/** *	ata_id_to_dma_mode	-	Identify DMA mode from id block *	@dev: device to identify *	@unknown: mode to assume if we cannot tell * *	Set up the timing values for the device based upon the identify *	reported values for the DMA mode. This function is used by drivers *	which rely upon firmware configured modes, but wish to report the *	mode correctly when possible. * *	In addition we emit similarly formatted messages to the default *	ata_dev_set_mode handler, in order to provide consistency of *	presentation. */void ata_id_to_dma_mode(struct ata_device *dev, u8 unknown){	unsigned int mask;	u8 mode;	/* Pack the DMA modes */	mask = ((dev->id[63] >> 8) << ATA_SHIFT_MWDMA) & ATA_MASK_MWDMA;	if (dev->id[53] & 0x04)		mask |= ((dev->id[88] >> 8) << ATA_SHIFT_UDMA) & ATA_MASK_UDMA;	/* Select the mode in use */	mode = ata_xfer_mask2mode(mask);	if (mode != 0) {		ata_dev_printk(dev, KERN_INFO, "configured for %s\n",		       ata_mode_string(mask));	} else {		/* SWDMA perhaps ? */		mode = unknown;		ata_dev_printk(dev, KERN_INFO, "configured for DMA\n");	}	/* Configure the device reporting */	dev->xfer_mode = mode;	dev->xfer_shift = ata_xfer_mode2shift(mode);}/** *	ata_noop_dev_select - Select device 0/1 on ATA bus *	@ap: ATA channel to manipulate *	@device: ATA device (numbered from zero) to select * *	This function performs no actual function. * *	May be used as the dev_select() entry in ata_port_operations. * *	LOCKING: *	caller. */void ata_noop_dev_select(struct ata_port *ap, unsigned int device){}/** *	ata_std_dev_select - Select device 0/1 on ATA bus *	@ap: ATA channel to manipulate *	@device: ATA device (numbered from zero) to select * *	Use the method defined in the ATA specification to *	make either device 0, or device 1, active on the *	ATA channel.  Works with both PIO and MMIO. * *	May be used as the dev_select() entry in ata_port_operations. * *	LOCKING: *	caller. */void ata_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;	iowrite8(tmp, ap->ioaddr.device_addr);	ata_pause(ap);		/* needed; also flushes, for mmio */}/** *	ata_dev_select - Select device 0/1 on ATA bus *	@ap: ATA channel to manipulate *	@device: ATA device (numbered from zero) to select *	@wait: non-zero to wait for Status register BSY bit to clear *	@can_sleep: non-zero if context allows sleeping * *	Use the method defined in the ATA specification to *	make either device 0, or device 1, active on the *	ATA channel. * *	This is a high-level version of ata_std_dev_select(), *	which additionally provides the services of inserting *	the proper pauses and status polling, where needed. * *	LOCKING: *	caller. */void ata_dev_select(struct ata_port *ap, unsigned int device,			   unsigned int wait, unsigned int can_sleep){	if (ata_msg_probe(ap))		ata_port_printk(ap, KERN_INFO, "ata_dev_select: ENTER, "				"device %u, wait %u\n", device, wait);	if (wait)		ata_wait_idle(ap);	ap->ops->dev_select(ap, device);	if (wait) {		if (can_sleep && ap->link.device[device].class == ATA_DEV_ATAPI)			msleep(150);		ata_wait_idle(ap);	}}/** *	ata_dump_id - IDENTIFY DEVICE info debugging output *	@id: IDENTIFY DEVICE page to dump * *	Dump selected 16-bit words from the given IDENTIFY DEVICE *	page. * *	LOCKING: *	caller. */static inline void ata_dump_id(const u16 *id){	DPRINTK("49==0x%04x  "		"53==0x%04x  "		"63==0x%04x  "		"64==0x%04x  "		"75==0x%04x  \n",		id[49],		id[53],		id[63],		id[64],		id[75]);	DPRINTK("80==0x%04x  "		"81==0x%04x  "		"82==0x%04x  "		"83==0x%04x  "		"84==0x%04x  \n",		id[80],		id[81],		id[82],		id[83],		id[84]);	DPRINTK("88==0x%04x  "		"93==0x%04x\n",		id[88],		id[93]);}/** *	ata_id_xfermask - Compute xfermask from the given IDENTIFY data *	@id: IDENTIFY data to compute xfer mask from * *	Compute the xfermask for this device. This is not as trivial *	as it seems if we must consider early devices correctly. * *	FIXME: pre IDE drive timing (do we care ?). * *	LOCKING: *	None. * *	RETURNS: *	Computed xfermask */static unsigned int ata_id_xfermask(const u16 *id){	unsigned int pio_mask, mwdma_mask, udma_mask;	/* Usual case. Word 53 indicates word 64 is valid */	if (id[ATA_ID_FIELD_VALID] & (1 << 1)) {		pio_mask = id[ATA_ID_PIO_MODES] & 0x03;		pio_mask <<= 3;		pio_mask |= 0x7;	} else {		/* If word 64 isn't valid then Word 51 high byte holds		 * the PIO timing number for the maximum. Turn it into		 * a mask.		 */		u8 mode = (id[ATA_ID_OLD_PIO_MODES] >> 8) & 0xFF;		if (mode < 5)	/* Valid PIO range */			pio_mask = (2 << mode) - 1;		else			pio_mask = 1;		/* But wait.. there's more. Design your standards by		 * committee and you too can get a free iordy field to		 * process. However its the speeds not the modes that		 * are supported... Note drivers using the timing API		 * will get this right anyway		 */	}	mwdma_mask = id[ATA_ID_MWDMA_MODES] & 0x07;	if (ata_id_is_cfa(id)) {		/*		 *	Process compact flash extended modes		 */		int pio = id[163] & 0x7;		int dma = (id[163] >> 3) & 7;		if (pio)			pio_mask |= (1 << 5);		if (pio > 1)			pio_mask |= (1 << 6);		if (dma)			mwdma_mask |= (1 << 3);		if (dma > 1)			mwdma_mask |= (1 << 4);	}	udma_mask = 0;	if (id[ATA_ID_FIELD_VALID] & (1 << 2))		udma_mask = id[ATA_ID_UDMA_MODES] & 0xff;	return ata_pack_xfermask(pio_mask, mwdma_mask, udma_mask);}/** *	ata_port_queue_task - Queue port_task *	@ap: The ata_port to queue port_task for *	@fn: workqueue function to be scheduled *	@data: data for @fn to use *	@delay: delay time for workqueue function * *	Schedule @fn(@data) for execution after @delay jiffies using *	port_task.  There is one port_task per port and it's the *	user(low level driver)'s responsibility to make sure that only *	one task is active at any given time. * *	libata core layer takes care of synchronization between *	port_task and EH.  ata_port_queue_task() may be ignored for EH *	synchronization. * *	LOCKING: *	Inherited from caller. */void ata_port_queue_task(struct ata_port *ap, work_func_t fn, void *data,			 unsigned long delay){	PREPARE_DELAYED_WORK(&ap->port_task, fn);	ap->port_task_data = data;	/* may fail if ata_port_flush_task() in progress */	queue_delayed_work(ata_wq, &ap->port_task, delay);}

⌨️ 快捷键说明

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