📄 ide-disk.c
字号:
return addr; /* Create IDE/ATA command request structure */ memset(&args, 0, sizeof(ide_task_t)); args.tfRegister[IDE_SELECT_OFFSET] = 0x40; args.tfRegister[IDE_COMMAND_OFFSET] = WIN_READ_NATIVE_MAX; 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) { addr = ((args.tfRegister[IDE_SELECT_OFFSET] & 0x0f) << 24) | ((args.tfRegister[ IDE_HCYL_OFFSET] ) << 16) | ((args.tfRegister[ IDE_LCYL_OFFSET] ) << 8) | ((args.tfRegister[IDE_SECTOR_OFFSET] )); } addr++; /* since the return value is (maxlba - 1), we add 1 */ return addr;}static unsigned long long idedisk_read_native_max_address_ext(ide_drive_t *drive){ ide_task_t args; unsigned long long addr = 0; /* Create IDE/ATA command request structure */ memset(&args, 0, sizeof(ide_task_t)); args.tfRegister[IDE_SELECT_OFFSET] = 0x40; args.tfRegister[IDE_COMMAND_OFFSET] = WIN_READ_NATIVE_MAX_EXT; 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_HOB])<<16) | ((args.hobRegister[IDE_LCYL_OFFSET_HOB])<<8) | (args.hobRegister[IDE_SECTOR_OFFSET_HOB]); u32 low = ((args.tfRegister[IDE_HCYL_OFFSET])<<16) | ((args.tfRegister[IDE_LCYL_OFFSET])<<8) | (args.tfRegister[IDE_SECTOR_OFFSET]); addr = ((__u64)high << 24) | low; } addr++; /* since the return value is (maxlba - 1), we add 1 */ return addr;}#ifdef CONFIG_IDEDISK_STROKE/* * Sets maximum virtual LBA address of the drive. * Returns new maximum virtual LBA address (> 0) or 0 on failure. */static unsigned long idedisk_set_max_address(ide_drive_t *drive, unsigned long addr_req){ ide_task_t args; unsigned 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 >> 16) & 0xff); args.tfRegister[IDE_SELECT_OFFSET] = ((addr_req >> 24) & 0x0f) | 0x40; args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SET_MAX; args.handler = task_no_data_intr; /* submit command request */ ide_raw_taskfile(drive, &args, NULL); /* if OK, read new maximum address value */ if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) { addr_set = ((args.tfRegister[IDE_SELECT_OFFSET] & 0x0f) << 24) | ((args.tfRegister[ IDE_HCYL_OFFSET] ) << 16) | ((args.tfRegister[ IDE_LCYL_OFFSET] ) << 8) | ((args.tfRegister[IDE_SECTOR_OFFSET] )); } addr_set++; return addr_set;}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_HOB] = ((addr_req >>= 8) & 0xff); args.hobRegister[IDE_LCYL_OFFSET_HOB] = ((addr_req >>= 8) & 0xff); args.hobRegister[IDE_HCYL_OFFSET_HOB] = ((addr_req >>= 8) & 0xff); args.hobRegister[IDE_SELECT_OFFSET_HOB] = 0x40; args.hobRegister[IDE_CONTROL_OFFSET_HOB]= (drive->ctl|0x80); 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_HOB])<<16) | ((args.hobRegister[IDE_LCYL_OFFSET_HOB])<<8) | (args.hobRegister[IDE_SECTOR_OFFSET_HOB]); 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; } return addr_set;}/* * Tests if the drive supports Host Protected Area feature. * Returns true if supported, false otherwise. */static inline int idedisk_supports_host_protected_area(ide_drive_t *drive){ int flag = (drive->id->cfs_enable_1 & 0x0400) ? 1 : 0; printk("%s: host protected area => %d\n", drive->name, flag); return flag;}#endif /* CONFIG_IDEDISK_STROKE *//* * 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; unsigned long capacity = drive->cyl * drive->head * drive->sect; unsigned long set_max = idedisk_read_native_max_address(drive); unsigned long long capacity_2 = capacity; unsigned long long set_max_ext; drive->capacity48 = 0; drive->select.b.lba = 0; if (id->cfs_enable_2 & 0x0400) { capacity_2 = id->lba_capacity_2; drive->head = drive->bios_head = 255; drive->sect = drive->bios_sect = 63; drive->cyl = (unsigned int) capacity_2 / (drive->head * drive->sect); drive->select.b.lba = 1; set_max_ext = idedisk_read_native_max_address_ext(drive); if (set_max_ext > capacity_2) {#ifdef CONFIG_IDEDISK_STROKE set_max_ext = idedisk_read_native_max_address_ext(drive); set_max_ext = idedisk_set_max_address_ext(drive, set_max_ext); if (set_max_ext) { drive->capacity48 = capacity_2 = set_max_ext; drive->cyl = (unsigned int) set_max_ext / (drive->head * drive->sect); drive->select.b.lba = 1; drive->id->lba_capacity_2 = capacity_2; }#else /* !CONFIG_IDEDISK_STROKE */ printk("%s: setmax_ext LBA %llu, native %llu\n", drive->name, set_max_ext, capacity_2);#endif /* CONFIG_IDEDISK_STROKE */ } drive->bios_cyl = drive->cyl; drive->capacity48 = capacity_2; drive->capacity = (unsigned long) capacity_2; return; /* Determine capacity, and use LBA if the drive properly supports it */ } else if ((id->capability & 2) && lba_capacity_is_ok(id)) { capacity = id->lba_capacity; drive->cyl = capacity / (drive->head * drive->sect); drive->select.b.lba = 1; } if (set_max > capacity) {#ifdef CONFIG_IDEDISK_STROKE set_max = idedisk_read_native_max_address(drive); set_max = idedisk_set_max_address(drive, set_max); if (set_max) { drive->capacity = capacity = set_max; drive->cyl = set_max / (drive->head * drive->sect); drive->select.b.lba = 1; drive->id->lba_capacity = capacity; }#else /* !CONFIG_IDEDISK_STROKE */ printk("%s: setmax LBA %lu, native %lu\n", drive->name, set_max, capacity);#endif /* CONFIG_IDEDISK_STROKE */ } drive->capacity = capacity; if ((id->command_set_2 & 0x0400) && (id->cfs_enable_2 & 0x0400)) { drive->capacity48 = id->lba_capacity_2; drive->head = 255; drive->sect = 63; drive->cyl = (unsigned long)(drive->capacity48) / (drive->head * drive->sect); }}static unsigned long idedisk_capacity (ide_drive_t *drive){ if (drive->id->cfs_enable_2 & 0x0400) return (drive->capacity48 - drive->sect0); return (drive->capacity - drive->sect0);}static ide_startstop_t idedisk_special (ide_drive_t *drive){ special_t *s = &drive->special; if (s->b.set_geometry) { struct hd_drive_task_hdr taskfile; struct hd_drive_hob_hdr hobfile; ide_handler_t *handler = NULL; memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr)); memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr)); s->b.set_geometry = 0; taskfile.sector_number = drive->sect; taskfile.low_cylinder = drive->cyl; taskfile.high_cylinder = drive->cyl>>8; taskfile.device_head = ((drive->head-1)|drive->select.all)&0xBF; if (!IS_PDC4030_DRIVE) { taskfile.sector_count = drive->sect; taskfile.command = WIN_SPECIFY; handler = ide_handler_parser(&taskfile, &hobfile); } do_taskfile(drive, &taskfile, &hobfile, handler); } else if (s->b.recalibrate) { s->b.recalibrate = 0; if (!IS_PDC4030_DRIVE) { struct hd_drive_task_hdr taskfile; struct hd_drive_hob_hdr hobfile; memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr)); memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr)); taskfile.sector_count = drive->sect; taskfile.command = WIN_RESTORE; do_taskfile(drive, &taskfile, &hobfile, ide_handler_parser(&taskfile, &hobfile)); } } else if (s->b.set_multmode) { s->b.set_multmode = 0; if (drive->id && drive->mult_req > drive->id->max_multsect) drive->mult_req = drive->id->max_multsect; if (!IS_PDC4030_DRIVE) { struct hd_drive_task_hdr taskfile; struct hd_drive_hob_hdr hobfile; memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr)); memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr)); taskfile.sector_count = drive->mult_req; taskfile.command = WIN_SETMULT; do_taskfile(drive, &taskfile, &hobfile, ide_handler_parser(&taskfile, &hobfile)); } } 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){ struct hd_drive_task_hdr taskfile; struct hd_drive_hob_hdr hobfile; memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr)); memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr)); taskfile.feature = SMART_ENABLE; taskfile.low_cylinder = SMART_LCYL_PASS; taskfile.high_cylinder = SMART_HCYL_PASS; taskfile.command = WIN_SMART; return ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);}static int get_smart_values(ide_drive_t *drive, byte *buf){ struct hd_drive_task_hdr taskfile; struct hd_drive_hob_hdr hobfile; memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr)); memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr)); taskfile.feature = SMART_READ_VALUES; taskfile.sector_count = 0x01; taskfile.low_cylinder = SMART_LCYL_PASS; taskfile.high_cylinder = SMART_HCYL_PASS; taskfile.command = WIN_SMART; (void) smart_enable(drive); return ide_wait_taskfile(drive, &taskfile, &hobfile, buf);}static int get_smart_thresholds(ide_drive_t *drive, byte *buf){ struct hd_drive_task_hdr taskfile; struct hd_drive_hob_hdr hobfile; memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr)); memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr)); taskfile.feature = SMART_READ_THRESHOLDS; taskfile.sector_count = 0x01; taskfile.low_cylinder = SMART_LCYL_PASS; taskfile.high_cylinder = SMART_HCYL_PASS; taskfile.command = WIN_SMART; (void) smart_enable(drive); return ide_wait_taskfile(drive, &taskfile, &hobfile, 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) 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -