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

📄 ide-disk.c

📁 linux设备驱动开发详解(书代码)
💻 C
📖 第 1 页 / 共 3 页
字号:
}static unsigned long long idedisk_set_max_address_ext(ide_drive_t *drive, unsigned long long addr_req){	ide_task_t args;	unsigned long long addr_set = 0;	addr_req--;	/* Create IDE/ATA command request structure */	memset(&args, 0, sizeof(ide_task_t));	args.tfRegister[IDE_SECTOR_OFFSET]	= ((addr_req >>  0) & 0xff);	args.tfRegister[IDE_LCYL_OFFSET]	= ((addr_req >>= 8) & 0xff);	args.tfRegister[IDE_HCYL_OFFSET]	= ((addr_req >>= 8) & 0xff);	args.tfRegister[IDE_SELECT_OFFSET]      = 0x40;	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SET_MAX_EXT;	args.hobRegister[IDE_SECTOR_OFFSET]	= (addr_req >>= 8) & 0xff;	args.hobRegister[IDE_LCYL_OFFSET]	= (addr_req >>= 8) & 0xff;	args.hobRegister[IDE_HCYL_OFFSET]	= (addr_req >>= 8) & 0xff;	args.hobRegister[IDE_SELECT_OFFSET]	= 0x40;	args.hobRegister[IDE_CONTROL_OFFSET_HOB]= (drive->ctl|0x80);	args.command_type			= IDE_DRIVE_TASK_NO_DATA;	args.handler				= &task_no_data_intr;	/* submit command request */	ide_raw_taskfile(drive, &args, NULL);	/* if OK, compute maximum address value */	if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) {		u32 high = (args.hobRegister[IDE_HCYL_OFFSET] << 16) |			   (args.hobRegister[IDE_LCYL_OFFSET] <<  8) |			    args.hobRegister[IDE_SECTOR_OFFSET];		u32 low  = ((args.tfRegister[IDE_HCYL_OFFSET])<<16) |			   ((args.tfRegister[IDE_LCYL_OFFSET])<<8) |			    (args.tfRegister[IDE_SECTOR_OFFSET]);		addr_set = ((__u64)high << 24) | low;		addr_set++;	}	return addr_set;}static unsigned long long sectors_to_MB(unsigned long long n){	n <<= 9;		/* make it bytes */	do_div(n, 1000000);	/* make it MB */	return n;}/* * Bits 10 of command_set_1 and cfs_enable_1 must be equal, * so on non-buggy drives we need test only one. * However, we should also check whether these fields are valid. */static inline int idedisk_supports_hpa(const struct hd_driveid *id){	return (id->command_set_1 & 0x0400) && (id->cfs_enable_1 & 0x0400);}/* * The same here. */static inline int idedisk_supports_lba48(const struct hd_driveid *id){	return (id->command_set_2 & 0x0400) && (id->cfs_enable_2 & 0x0400)	       && id->lba_capacity_2;}static void idedisk_check_hpa(ide_drive_t *drive){	unsigned long long capacity, set_max;	int lba48 = idedisk_supports_lba48(drive->id);	capacity = drive->capacity64;	if (lba48)		set_max = idedisk_read_native_max_address_ext(drive);	else		set_max = idedisk_read_native_max_address(drive);	if (set_max <= capacity)		return;	printk(KERN_INFO "%s: Host Protected Area detected.\n"			 "\tcurrent capacity is %llu sectors (%llu MB)\n"			 "\tnative  capacity is %llu sectors (%llu MB)\n",			 drive->name,			 capacity, sectors_to_MB(capacity),			 set_max, sectors_to_MB(set_max));	if (lba48)		set_max = idedisk_set_max_address_ext(drive, set_max);	else		set_max = idedisk_set_max_address(drive, set_max);	if (set_max) {		drive->capacity64 = set_max;		printk(KERN_INFO "%s: Host Protected Area disabled.\n",				 drive->name);	}}/* * Compute drive->capacity, the full capacity of the drive * Called with drive->id != NULL. * * To compute capacity, this uses either of * *    1. CHS value set by user       (whatever user sets will be trusted) *    2. LBA value from target drive (require new ATA feature) *    3. LBA value from system BIOS  (new one is OK, old one may break) *    4. CHS value from system BIOS  (traditional style) * * in above order (i.e., if value of higher priority is available, * reset will be ignored). */static void init_idedisk_capacity (ide_drive_t  *drive){	struct hd_driveid *id = drive->id;	/*	 * If this drive supports the Host Protected Area feature set,	 * then we may need to change our opinion about the drive's capacity.	 */	int hpa = idedisk_supports_hpa(id);	if (idedisk_supports_lba48(id)) {		/* drive speaks 48-bit LBA */		drive->select.b.lba = 1;		drive->capacity64 = id->lba_capacity_2;		if (hpa)			idedisk_check_hpa(drive);	} else if ((id->capability & 2) && lba_capacity_is_ok(id)) {		/* drive speaks 28-bit LBA */		drive->select.b.lba = 1;		drive->capacity64 = id->lba_capacity;		if (hpa)			idedisk_check_hpa(drive);	} else {		/* drive speaks boring old 28-bit CHS */		drive->capacity64 = drive->cyl * drive->head * drive->sect;	}}static sector_t idedisk_capacity (ide_drive_t *drive){	return drive->capacity64 - drive->sect0;}#ifdef CONFIG_PROC_FSstatic int smart_enable(ide_drive_t *drive){	ide_task_t args;	memset(&args, 0, sizeof(ide_task_t));	args.tfRegister[IDE_FEATURE_OFFSET]	= SMART_ENABLE;	args.tfRegister[IDE_LCYL_OFFSET]	= SMART_LCYL_PASS;	args.tfRegister[IDE_HCYL_OFFSET]	= SMART_HCYL_PASS;	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SMART;	args.command_type			= IDE_DRIVE_TASK_NO_DATA;	args.handler				= &task_no_data_intr;	return ide_raw_taskfile(drive, &args, NULL);}static int get_smart_values(ide_drive_t *drive, u8 *buf){	ide_task_t args;	memset(&args, 0, sizeof(ide_task_t));	args.tfRegister[IDE_FEATURE_OFFSET]	= SMART_READ_VALUES;	args.tfRegister[IDE_NSECTOR_OFFSET]	= 0x01;	args.tfRegister[IDE_LCYL_OFFSET]	= SMART_LCYL_PASS;	args.tfRegister[IDE_HCYL_OFFSET]	= SMART_HCYL_PASS;	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SMART;	args.command_type			= IDE_DRIVE_TASK_IN;	args.data_phase				= TASKFILE_IN;	args.handler				= &task_in_intr;	(void) smart_enable(drive);	return ide_raw_taskfile(drive, &args, buf);}static int get_smart_thresholds(ide_drive_t *drive, u8 *buf){	ide_task_t args;	memset(&args, 0, sizeof(ide_task_t));	args.tfRegister[IDE_FEATURE_OFFSET]	= SMART_READ_THRESHOLDS;	args.tfRegister[IDE_NSECTOR_OFFSET]	= 0x01;	args.tfRegister[IDE_LCYL_OFFSET]	= SMART_LCYL_PASS;	args.tfRegister[IDE_HCYL_OFFSET]	= SMART_HCYL_PASS;	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SMART;	args.command_type			= IDE_DRIVE_TASK_IN;	args.data_phase				= TASKFILE_IN;	args.handler				= &task_in_intr;	(void) smart_enable(drive);	return ide_raw_taskfile(drive, &args, buf);}static int proc_idedisk_read_cache	(char *page, char **start, off_t off, int count, int *eof, void *data){	ide_drive_t	*drive = (ide_drive_t *) data;	char		*out = page;	int		len;	if (drive->id_read)		len = sprintf(out,"%i\n", drive->id->buf_size / 2);	else		len = sprintf(out,"(none)\n");	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);}static int proc_idedisk_read_capacity	(char *page, char **start, off_t off, int count, int *eof, void *data){	ide_drive_t*drive = (ide_drive_t *)data;	int len;	len = sprintf(page,"%llu\n", (long long)idedisk_capacity(drive));	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);}static int proc_idedisk_read_smart_thresholds	(char *page, char **start, off_t off, int count, int *eof, void *data){	ide_drive_t	*drive = (ide_drive_t *)data;	int		len = 0, i = 0;	if (!get_smart_thresholds(drive, page)) {		unsigned short *val = (unsigned short *) page;		char *out = ((char *)val) + (SECTOR_WORDS * 4);		page = out;		do {			out += sprintf(out, "%04x%c", le16_to_cpu(*val), (++i & 7) ? ' ' : '\n');			val += 1;		} while (i < (SECTOR_WORDS * 2));		len = out - page;	}	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);}static int proc_idedisk_read_smart_values	(char *page, char **start, off_t off, int count, int *eof, void *data){	ide_drive_t	*drive = (ide_drive_t *)data;	int		len = 0, i = 0;	if (!get_smart_values(drive, page)) {		unsigned short *val = (unsigned short *) page;		char *out = ((char *)val) + (SECTOR_WORDS * 4);		page = out;		do {			out += sprintf(out, "%04x%c", le16_to_cpu(*val), (++i & 7) ? ' ' : '\n');			val += 1;		} while (i < (SECTOR_WORDS * 2));		len = out - page;	}	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);}static ide_proc_entry_t idedisk_proc[] = {	{ "cache",		S_IFREG|S_IRUGO,	proc_idedisk_read_cache,		NULL },	{ "capacity",		S_IFREG|S_IRUGO,	proc_idedisk_read_capacity,		NULL },	{ "geometry",		S_IFREG|S_IRUGO,	proc_ide_read_geometry,			NULL },	{ "smart_values",	S_IFREG|S_IRUSR,	proc_idedisk_read_smart_values,		NULL },	{ "smart_thresholds",	S_IFREG|S_IRUSR,	proc_idedisk_read_smart_thresholds,	NULL },	{ NULL, 0, NULL, NULL }};#else#define	idedisk_proc	NULL#endif	/* CONFIG_PROC_FS */static void idedisk_prepare_flush(request_queue_t *q, struct request *rq){	ide_drive_t *drive = q->queuedata;	memset(rq->cmd, 0, sizeof(rq->cmd));	if (ide_id_has_flush_cache_ext(drive->id) &&	    (drive->capacity64 >= (1UL << 28)))		rq->cmd[0] = WIN_FLUSH_CACHE_EXT;	else		rq->cmd[0] = WIN_FLUSH_CACHE;	rq->flags |= REQ_DRIVE_TASK;	rq->buffer = rq->cmd;}static int idedisk_issue_flush(request_queue_t *q, struct gendisk *disk,			       sector_t *error_sector){	ide_drive_t *drive = q->queuedata;	struct request *rq;	int ret;	if (!drive->wcache)		return 0;	rq = blk_get_request(q, WRITE, __GFP_WAIT);	idedisk_prepare_flush(q, rq);	ret = blk_execute_rq(q, disk, rq, 0);	/*	 * if we failed and caller wants error offset, get it	 */	if (ret && error_sector)		*error_sector = ide_get_error_location(drive, rq->cmd);	blk_put_request(rq);	return ret;}/* * This is tightly woven into the driver->do_special can not touch. * DON'T do it again until a total personality rewrite is committed. */static int set_multcount(ide_drive_t *drive, int arg){	struct request rq;	if (drive->special.b.set_multmode)		return -EBUSY;	ide_init_drive_cmd (&rq);	rq.flags = REQ_DRIVE_CMD;	drive->mult_req = arg;	drive->special.b.set_multmode = 1;	(void) ide_do_drive_cmd (drive, &rq, ide_wait);	return (drive->mult_count == arg) ? 0 : -EIO;}static int set_nowerr(ide_drive_t *drive, int arg){	if (ide_spin_wait_hwgroup(drive))		return -EBUSY;	drive->nowerr = arg;	drive->bad_wstat = arg ? BAD_R_STAT : BAD_W_STAT;	spin_unlock_irq(&ide_lock);	return 0;}static void update_ordered(ide_drive_t *drive){	struct hd_driveid *id = drive->id;	unsigned ordered = QUEUE_ORDERED_NONE;	prepare_flush_fn *prep_fn = NULL;	issue_flush_fn *issue_fn = NULL;	if (drive->wcache) {		unsigned long long capacity;		int barrier;		/*		 * We must avoid issuing commands a drive does not		 * understand or we may crash it. We check flush cache		 * is supported. We also check we have the LBA48 flush		 * cache if the drive capacity is too large. By this		 * time we have trimmed the drive capacity if LBA48 is		 * not available so we don't need to recheck that.		 */		capacity = idedisk_capacity(drive);		barrier = ide_id_has_flush_cache(id) &&			(drive->addressing == 0 || capacity <= (1ULL << 28) ||			 ide_id_has_flush_cache_ext(id));		printk(KERN_INFO "%s: cache flushes %ssupported\n",		       drive->name, barrier ? "" : "not ");		if (barrier) {			ordered = QUEUE_ORDERED_DRAIN_FLUSH;			prep_fn = idedisk_prepare_flush;			issue_fn = idedisk_issue_flush;		}	} else		ordered = QUEUE_ORDERED_DRAIN;	blk_queue_ordered(drive->queue, ordered, prep_fn);	blk_queue_issue_flush_fn(drive->queue, issue_fn);}static int write_cache(ide_drive_t *drive, int arg){	ide_task_t args;	int err = 1;	if (ide_id_has_flush_cache(drive->id)) {		memset(&args, 0, sizeof(ide_task_t));		args.tfRegister[IDE_FEATURE_OFFSET]	= (arg) ?			SETFEATURES_EN_WCACHE : SETFEATURES_DIS_WCACHE;		args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SETFEATURES;		args.command_type		= IDE_DRIVE_TASK_NO_DATA;		args.handler			= &task_no_data_intr;		err = ide_raw_taskfile(drive, &args, NULL);		if (err == 0)			drive->wcache = arg;	}	update_ordered(drive);	return err;}static int do_idedisk_flushcache (ide_drive_t *drive){	ide_task_t args;	memset(&args, 0, sizeof(ide_task_t));	if (ide_id_has_flush_cache_ext(drive->id))		args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_FLUSH_CACHE_EXT;	else		args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_FLUSH_CACHE;	args.command_type			= IDE_DRIVE_TASK_NO_DATA;	args.handler				= &task_no_data_intr;	return ide_raw_taskfile(drive, &args, NULL);}static int set_acoustic (ide_drive_t *drive, int arg){	ide_task_t args;

⌨️ 快捷键说明

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