ide-disk.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,865 行 · 第 1/4 页

C
1,865
字号
	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 inline 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 (!drive->stroke)		return;	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;}static ide_startstop_t idedisk_special (ide_drive_t *drive){	special_t *s = &drive->special;	if (s->b.set_geometry) {		s->b.set_geometry	= 0;		if (!IS_PDC4030_DRIVE) {			ide_task_t args;			memset(&args, 0, sizeof(ide_task_t));			args.tfRegister[IDE_NSECTOR_OFFSET] = drive->sect;			args.tfRegister[IDE_SECTOR_OFFSET]  = drive->sect;			args.tfRegister[IDE_LCYL_OFFSET]    = drive->cyl;			args.tfRegister[IDE_HCYL_OFFSET]    = drive->cyl>>8;			args.tfRegister[IDE_SELECT_OFFSET]  = ((drive->head-1)|drive->select.all)&0xBF;			args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SPECIFY;			args.command_type = IDE_DRIVE_TASK_NO_DATA;			args.handler	  = &set_geometry_intr;			do_rw_taskfile(drive, &args);		}	} else if (s->b.recalibrate) {		s->b.recalibrate = 0;		if (!IS_PDC4030_DRIVE) {			ide_task_t args;			memset(&args, 0, sizeof(ide_task_t));			args.tfRegister[IDE_NSECTOR_OFFSET] = drive->sect;			args.tfRegister[IDE_COMMAND_OFFSET] = WIN_RESTORE;			args.command_type = IDE_DRIVE_TASK_NO_DATA;			args.handler	  = &recal_intr;			do_rw_taskfile(drive, &args);		}	} else if (s->b.set_multmode) {		s->b.set_multmode = 0;		if (drive->mult_req > drive->id->max_multsect)			drive->mult_req = drive->id->max_multsect;		if (!IS_PDC4030_DRIVE) {			ide_task_t args;			memset(&args, 0, sizeof(ide_task_t));			args.tfRegister[IDE_NSECTOR_OFFSET] = drive->mult_req;			args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SETMULT;			args.command_type = IDE_DRIVE_TASK_NO_DATA;			args.handler	  = &set_multmode_intr;			do_rw_taskfile(drive, &args);		}	} else if (s->all) {		int special = s->all;		s->all = 0;		printk(KERN_ERR "%s: bad special flag: 0x%02x\n", drive->name, special);		return ide_stopped;	}	return IS_PDC4030_DRIVE ? ide_stopped : ide_started;}static void idedisk_pre_reset (ide_drive_t *drive){	int legacy = (drive->id->cfs_enable_2 & 0x0400) ? 0 : 1;	drive->special.all = 0;	drive->special.b.set_geometry = legacy;	drive->special.b.recalibrate  = legacy;	if (OK_TO_RESET_CONTROLLER)		drive->mult_count = 0;	if (!drive->keep_settings && !drive->using_dma)		drive->mult_req = 0;	if (drive->mult_req != drive->mult_count)		drive->special.b.set_multmode = 1;}#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.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_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 },	{ "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 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);	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 | REQ_SOFTBARRIER;	rq->buffer = rq->cmd;	ret = blk_execute_rq(q, disk, rq);	/*	 * 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 int write_cache(ide_drive_t *drive, int arg){	ide_task_t args;	int err;	if (!ide_id_has_flush_cache(drive->id))		return 1;	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)		return err;	drive->wcache = arg;	return 0;}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;	memset(&args, 0, sizeof(ide_task_t));	args.tfRegister[IDE_FEATURE_OFFSET]	= (arg) ? SETFEATURES_EN_AAM :							  SETFEATURES_DIS_AAM;	args.tfRegister[IDE_NSECTOR_OFFSET]	= arg;	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SETFEATURES;	args.command_type = IDE_DRIVE_TASK_NO_DATA;	args.handler	  = &task_no_data_intr;	ide_raw_taskfile(drive, &args, NULL);	drive->acoustic = arg;	return 0;}/* * drive->addressing: *	0: 28-bit *	1: 48-bit *	2: 48-bit capable doing 28-bit */static int set_lba_addressing(ide_drive_t *drive, int arg){	drive->addressing =  0;	if (HWIF(drive)->no_lba48)		return 0;	if (!idedisk_supports_lba48(drive->id))                return -EIO;	drive->addressing = arg;	return 0;}static void idedisk_add_settings(ide_drive_t *drive){	struct hd_driveid *id = drive->id;	ide_add_setting(drive,	"bios_cyl",		SETTING_RW,					-1,			-1,			TYPE_INT,	0,	65535,				1,	1,	&drive->bios_cyl,		NULL);	ide_add_setting(drive,	"bios_head",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	255,				1,	1,	&drive->bios_head,		NULL);	ide_add_setting(drive,	"bios_sect",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	63,				1,	1,	&drive->bios_sect,		NULL);	ide_add_setting(drive,	"address",		SETTING_RW,					HDIO_GET_ADDRESS,	HDIO_SET_ADDRESS,	TYPE_INTA,	0,	2,				1,	1,	&drive->addressing,	set_lba_addressing);	ide_add_setting(drive,	"bswap",		SETTING_READ,					-1,			-1,			TYPE_BYTE,	0,	1,				1,	1,	&drive->bswap,			NULL);	ide_add_setting(drive,	"multcount",		id ? SETTING_RW : SETTING_READ,			HDIO_GET_MULTCOUNT,	HDIO_SET_MULTCOUNT,	TYPE_BYTE,	0,	id ? id->max_multsect : 0,	1,	1,	&drive->mult_count,		set_multcount);	ide_add_setting(drive,	"nowerr",		SETTING_RW,					HDIO_GET_NOWERR,	HDIO_SET_NOWERR,	TYPE_BYTE,	0,	1,				1,	1,	&drive->nowerr,			set_nowerr);	ide_add_setting(drive,	"lun",			SETTING_RW,					-1,			-1,			TYPE_INT,	0,	7,				1,	1,	&drive->lun,			NULL);	ide_add_setting(drive,	"wcache",		SETTING_RW,					HDIO_GET_WCACHE,	HDIO_SET_WCACHE,	TYPE_BYTE,	0,	1,				1,	1,	&drive->wcache,			write_cache);	ide_add_setting(drive,	"acoustic",		SETTING_RW,					HDIO_GET_ACOUSTIC,	HDIO_SET_ACOUSTIC,	TYPE_BYTE,	0,	254,				1,	1,	&drive->acoustic,		set_acoustic); 	ide_add_setting(drive,	"failures",		SETTING_RW,					-1,			-1,			TYPE_INT,	0,	65535,				1,	1,	&drive->failures,		NULL); 	ide_add_setting(drive,	"max_failures",		SETTING_RW,					-1,			-1,			TYPE_INT,	0,	65535,				1,	1,	&drive->max_failures,		NULL);

⌨️ 快捷键说明

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