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 + -
显示快捷键?