📄 ide-disk.c
字号:
* of data to be written. If we hit an error (corrupted buffer list) * in ide_multwrite(), then we need to remove the handler/timer * before returning. Fortunately, this NEVER happens (right?). * * Except when you get an error it seems... */ hwgroup->wrq = *rq; /* scratchpad */ ide_set_handler (drive, &multwrite_intr, WAIT_CMD, NULL); if (ide_multwrite(drive, drive->mult_count)) { unsigned long flags; spin_lock_irqsave(&io_request_lock, flags); hwgroup->handler = NULL; del_timer(&hwgroup->timer); spin_unlock_irqrestore(&io_request_lock, flags); return ide_stopped; } } else { ide_set_handler (drive, &write_intr, WAIT_CMD, NULL); idedisk_output_data(drive, rq->buffer, SECTOR_WORDS); } return ide_started; } printk(KERN_ERR "%s: bad command: %d\n", drive->name, rq->cmd); ide_end_request(0, HWGROUP(drive)); return ide_stopped;}static int idedisk_open (struct inode *inode, struct file *filp, ide_drive_t *drive){ MOD_INC_USE_COUNT; if (drive->removable && drive->usage == 1) { check_disk_change(inode->i_rdev); /* * Ignore the return code from door_lock, * since the open() has already succeeded, * and the door_lock is irrelevant at this point. */ if (drive->doorlocking && ide_wait_cmd(drive, WIN_DOORLOCK, 0, 0, 0, NULL)) drive->doorlocking = 0; } return 0;}static void idedisk_release (struct inode *inode, struct file *filp, ide_drive_t *drive){ if (drive->removable && !drive->usage) { invalidate_buffers(inode->i_rdev); if (drive->doorlocking && ide_wait_cmd(drive, WIN_DOORUNLOCK, 0, 0, 0, NULL)) drive->doorlocking = 0; } MOD_DEC_USE_COUNT;}static int idedisk_media_change (ide_drive_t *drive){ return drive->removable; /* if removable, always assume it was changed */}static void idedisk_revalidate (ide_drive_t *drive){ grok_partitions(HWIF(drive)->gd, drive->select.b.unit, 1<<PARTN_BITS, current_capacity(drive));}/* * Compute drive->capacity, the full capacity of the drive * Called with drive->id != NULL. */static void init_idedisk_capacity (ide_drive_t *drive){ struct hd_driveid *id = drive->id; unsigned long capacity = drive->cyl * drive->head * drive->sect; drive->select.b.lba = 0; /* Determine capacity, and use LBA if the drive properly supports it */ 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; } drive->capacity = capacity;}static unsigned long idedisk_capacity (ide_drive_t *drive){ 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) { s->b.set_geometry = 0; OUT_BYTE(drive->sect,IDE_SECTOR_REG); OUT_BYTE(drive->cyl,IDE_LCYL_REG); OUT_BYTE(drive->cyl>>8,IDE_HCYL_REG); OUT_BYTE(((drive->head-1)|drive->select.all)&0xBF,IDE_SELECT_REG); if (!IS_PDC4030_DRIVE) ide_cmd(drive, WIN_SPECIFY, drive->sect, &set_geometry_intr); } else if (s->b.recalibrate) { s->b.recalibrate = 0; if (!IS_PDC4030_DRIVE) ide_cmd(drive, WIN_RESTORE, drive->sect, &recal_intr); } 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) ide_cmd(drive, WIN_SETMULT, drive->mult_req, &set_multmode_intr); } 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){ drive->special.all = 0; drive->special.b.set_geometry = 1; drive->special.b.recalibrate = 1; 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){ return ide_wait_cmd(drive, WIN_SMART, 0, SMART_ENABLE, 0, NULL);}static int get_smart_values(ide_drive_t *drive, byte *buf){ (void) smart_enable(drive); return ide_wait_cmd(drive, WIN_SMART, 0, SMART_READ_VALUES, 1, buf);}static int get_smart_thresholds(ide_drive_t *drive, byte *buf){ (void) smart_enable(drive); return ide_wait_cmd(drive, WIN_SMART, 0, SMART_READ_THRESHOLDS, 1, 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) + 2; 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) + 2; 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 set_multcount(ide_drive_t *drive, int arg){ struct request rq; if (drive->special.b.set_multmode) return -EBUSY; ide_init_drive_cmd (&rq); 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(&io_request_lock); return 0;}static void idedisk_add_settings(ide_drive_t *drive){ struct hd_driveid *id = drive->id; int major = HWIF(drive)->major; int minor = drive->select.b.unit << PARTN_BITS; 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, "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, 2, &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, "breada_readahead", SETTING_RW, BLKRAGET, BLKRASET, TYPE_INT, 0, 255, 1, 2, &read_ahead[major], NULL); ide_add_setting(drive, "file_readahead", SETTING_RW, BLKFRAGET, BLKFRASET, TYPE_INTA, 0, INT_MAX, 1, 1024, &max_readahead[major][minor], NULL); ide_add_setting(drive, "max_kb_per_request", SETTING_RW, BLKSECTGET, BLKSECTSET, TYPE_INTA, 1, 255, 1, 2, &max_sectors[major][minor], NULL); ide_add_setting(drive, "lun", SETTING_RW, -1, -1, TYPE_INT, 0, 7, 1, 1, &drive->lun, NULL);}/* * IDE subdriver functions, registered with ide.c */static ide_driver_t idedisk_driver = { "ide-disk", /* name */ IDEDISK_VERSION, /* version */ ide_disk, /* media */ 0, /* busy */ 1, /* supports_dma */ 0, /* supports_dsc_overlap */ NULL, /* cleanup */ do_rw_disk, /* do_request */ NULL, /* end_request */ NULL, /* ioctl */ idedisk_open, /* open */ idedisk_release, /* release */ idedisk_media_change, /* media_change */ idedisk_revalidate, /* revalidate */ idedisk_pre_reset, /* pre_reset */ idedisk_capacity, /* capacity */ idedisk_special, /* special */ idedisk_proc /* proc */};int idedisk_init (void);static ide_module_t idedisk_module = { IDE_DRIVER_MODULE, idedisk_init, &idedisk_driver, NULL};static int idedisk_cleanup (ide_drive_t *drive){ return ide_unregister_subdriver(drive);}static void idedisk_setup (ide_drive_t *drive){ int i; struct hd_driveid *id = drive->id; unsigned long capacity; idedisk_add_settings(drive); if (id == NULL) return; /* * CompactFlash cards and their brethern look just like hard drives * to us, but they are removable and don't have a doorlock mechanism. */ if (drive->removable && !drive_is_flashcard(drive)) { /* * Removable disks (eg. SYQUEST); ignore 'WD' drives */ if (id->model[0] != 'W' || id->model[1] != 'D') { drive->doorlocking = 1; } } for (i = 0; i < MAX_DRIVES; ++i) { ide_hwif_t *hwif = HWIF(drive); if (drive != &hwif->drives[i]) continue; hwif->gd->de_arr[i] = drive->de; if (drive->removable) hwif->gd->flags[i] |= GENHD_FL_REMOVABLE; break; } /* Extract geometry if we did not already have one for the drive */ if (!drive->cyl || !drive->head || !drive->sect) { drive->cyl = drive->bios_cyl = id->cyls; drive->head = drive->bios_head = id->heads; drive->sect = drive->bios_sect = id->sectors; } /* Handle logical geometry translation by the drive */ if ((id->field_valid & 1) && id->cur_cyls && id->cur_heads && (id->cur_heads <= 16) && id->cur_sectors) { drive->cyl = id->cur_cyls; drive->head = id->cur_heads; drive->sect = id->cur_sectors; } /* Use physical geometry if what we have still makes no sense */ if (drive->head > 16 && id->heads && id->heads <= 16) { drive->cyl = id->cyls; drive->head = id->heads; drive->sect = id->sectors; } /* calculate drive capacity, and select LBA if possible */ init_idedisk_capacity (drive); /* * if possible, give fdisk access to more of the drive, * by correcting bios_cyls: */ capacity = idedisk_capacity (drive); if ((capacity >= (drive->bios_cyl * drive->bios_sect * drive->bios_head)) && (!drive->forced_geom) && drive->bios_sect && drive->bios_head) drive->bios_cyl = (capacity / drive->bios_sect) / drive->bios_head; printk (KERN_INFO "%s: %ld sectors", drive->name, capacity); /* Give size in megabytes (MB), not mebibytes (MiB). */ /* We compute the exact rounded value, avoiding overflow. */ printk (" (%ld MB)", (capacity - capacity/625 + 974)/1950); /* Only print cache size when it was specified */ if (id->buf_size) printk (" w/%dKiB Cache", id->buf_size/2); printk(", CHS=%d/%d/%d", drive->bios_cyl, drive->bios_head, drive->bios_sect);#ifdef CONFIG_BLK_DEV_IDEDMA if (drive->using_dma) (void) HWIF(drive)->dmaproc(ide_dma_verbose, drive);#endif /* CONFIG_BLK_DEV_IDEDMA */ printk("\n"); drive->mult_count = 0; if (id->max_multsect) {#ifdef CONFIG_IDEDISK_MULTI_MODE id->multsect = ((id->max_multsect/2) > 1) ? id->max_multsect : 0; id->multsect_valid = id->multsect ? 1 : 0; drive->mult_req = id->multsect_valid ? id->max_multsect : INITIAL_MULT_COUNT; drive->special.b.set_multmode = drive->mult_req ? 1 : 0;#else /* original, pre IDE-NFG, per request of AC */ drive->mult_req = INITIAL_MULT_COUNT; if (drive->mult_req > id->max_multsect) drive->mult_req = id->max_multsect; if (drive->mult_req || ((id->multsect_valid & 1) && id->multsect)) drive->special.b.set_multmode = 1;#endif } drive->no_io_32bit = id->dword_io ? 1 : 0;}int idedisk_init (void){ ide_drive_t *drive; int failed = 0; MOD_INC_USE_COUNT; while ((drive = ide_scan_devices (ide_disk, idedisk_driver.name, NULL, failed++)) != NULL) { if (ide_register_subdriver (drive, &idedisk_driver, IDE_SUBDRIVER_VERSION)) { printk (KERN_ERR "ide-disk: %s: Failed to register the driver with ide.c\n", drive->name); continue; } idedisk_setup(drive); if ((!drive->head || drive->head > 16) && !drive->select.b.lba) { printk(KERN_ERR "%s: INVALID GEOMETRY: %d PHYSICAL HEADS?\n", drive->name, drive->head); (void) idedisk_cleanup(drive); continue; } failed--; } ide_register_module(&idedisk_module); MOD_DEC_USE_COUNT; return 0;}#ifdef MODULEint init_module (void){ return idedisk_init();}void cleanup_module (void){ ide_drive_t *drive; int failed = 0; while ((drive = ide_scan_devices (ide_disk, idedisk_driver.name, &idedisk_driver, failed)) != NULL) { if (idedisk_cleanup (drive)) { printk (KERN_ERR "%s: cleanup_module() called while still busy\n", drive->name); failed++; } /* We must remove proc entries defined in this module. Otherwise we oops while accessing these entries */ if (drive->proc) ide_remove_proc_entries(drive->proc, idedisk_proc); } ide_unregister_module(&idedisk_module);}#endif /* MODULE */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -