📄 ide-disk.c
字号:
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;}/* * Some disks report total number of sectors instead of * maximum sector address. We list them here. */static const struct drive_list_entry hpa_list[] = { { "ST340823A", NULL }, { "ST320413A", NULL }, { NULL, NULL }};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 (ide_in_drive_list(drive->id, hpa_list)) { /* * Since we are inclusive wrt to firmware revisions do this * extra check and apply the workaround only when needed. */ if (set_max == capacity + 1) set_max--; } 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_IDE_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_data(ide_drive_t *drive, u8 *buf, u8 sub_cmd){ ide_task_t args; memset(&args, 0, sizeof(ide_task_t)); args.tfRegister[IDE_FEATURE_OFFSET] = sub_cmd; 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_data(drive, page, SMART_READ_THRESHOLDS) == 0) { 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_data(drive, page, SMART_READ_VALUES) == 0) { 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 }};#endif /* CONFIG_IDE_PROC_FS */static void idedisk_prepare_flush(struct request_queue *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->cmd_type = REQ_TYPE_ATA_TASK; rq->cmd_flags |= REQ_SOFTBARRIER; rq->buffer = rq->cmd;}/* * 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 (arg < 0 || arg > drive->id->max_multsect) return -EINVAL; if (drive->special.b.set_multmode) return -EBUSY; ide_init_drive_cmd (&rq); rq.cmd_type = REQ_TYPE_ATA_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 (arg < 0 || arg > 1) return -EINVAL; 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; 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->noflush && (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; } } else ordered = QUEUE_ORDERED_DRAIN; blk_queue_ordered(drive->queue, ordered, prep_fn);}static int write_cache(ide_drive_t *drive, int arg){ ide_task_t args; int err = 1; if (arg < 0 || arg > 1) return -EINVAL; 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; if (arg < 0 || arg > 254) return -EINVAL; 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){ if (arg < 0 || arg > 2) return -EINVAL; drive->addressing = 0; if (drive->hwif->host_flags & IDE_HFLAG_NO_LBA48) return 0; if (!idedisk_supports_lba48(drive->id)) return -EIO; drive->addressing = arg; return 0;}#ifdef CONFIG_IDE_PROC_FSstatic void idedisk_add_settings(ide_drive_t *drive){ struct hd_driveid *id = drive->id; ide_add_setting(drive, "bios_cyl", SETTING_RW, TYPE_INT, 0, 65535, 1, 1, &drive->bios_cyl, NULL); ide_add_setting(drive, "bios_head", SETTING_RW, TYPE_BYTE, 0, 255, 1, 1, &drive->bios_head, NULL); ide_add_setting(drive, "bios_sect", SETTING_RW, TYPE_BYTE, 0, 63, 1, 1, &drive->bios_sect, NULL); ide_add_setting(drive, "address", SETTING_RW, TYPE_BYTE, 0, 2, 1, 1, &drive->addressing, set_lba_addressing); ide_add_setting(drive, "bswap", SETTING_READ, TYPE_BYTE, 0, 1, 1, 1, &drive->bswap, NULL); ide_add_setting(drive, "multcount", SETTING_RW, TYPE_BYTE, 0, id->max_multsect, 1, 1, &drive->mult_count, set_multcount); ide_add_setting(drive, "nowerr", SETTING_RW, TYPE_BYTE, 0, 1, 1, 1, &drive->nowerr, set_nowerr); ide_add_setting(drive, "lun", SETTING_RW, TYPE_INT, 0, 7, 1, 1, &drive->lun, NULL); ide_add_setting(drive, "wcache", SETTING_RW, TYPE_BYTE, 0, 1, 1, 1, &drive->wcache, write_cache); ide_add_setting(drive, "acoustic", SETTING_RW, TYPE_BYTE, 0, 254, 1, 1, &drive->acoustic, set_acoustic); ide_add_setting(drive, "failures", SETTING_RW, TYPE_INT, 0, 65535, 1, 1, &drive->failures, NULL); ide_add_setting(drive, "max_failures", SETTING_RW, TYPE_INT, 0, 65535, 1, 1, &drive->max_failures, NULL);}#else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -