📄 ide-disk.c
字号:
/* * linux/drivers/ide/ide-disk.c Version 1.18 Mar 05, 2003 * * Copyright (C) 1994-1998 Linus Torvalds & authors (see below) * Copyright (C) 1998-2002 Linux ATA Development * Andre Hedrick <andre@linux-ide.org> * Copyright (C) 2003 Red Hat <alan@redhat.com> *//* * Mostly written by Mark Lord <mlord@pobox.com> * and Gadi Oxman <gadio@netvision.net.il> * and Andre Hedrick <andre@linux-ide.org> * * This is the IDE/ATA disk driver, as evolved from hd.c and ide.c. * * Version 1.00 move disk only code from ide.c to ide-disk.c * support optional byte-swapping of all data * Version 1.01 fix previous byte-swapping code * Version 1.02 remove ", LBA" from drive identification msgs * Version 1.03 fix display of id->buf_size for big-endian * Version 1.04 add /proc configurable settings and S.M.A.R.T support * Version 1.05 add capacity support for ATA3 >= 8GB * Version 1.06 get boot-up messages to show full cyl count * Version 1.07 disable door-locking if it fails * Version 1.08 fixed CHS/LBA translations for ATA4 > 8GB, * process of adding new ATA4 compliance. * fixed problems in allowing fdisk to see * the entire disk. * Version 1.09 added increment of rq->sector in ide_multwrite * added UDMA 3/4 reporting * Version 1.10 request queue changes, Ultra DMA 100 * Version 1.11 added 48-bit lba * Version 1.12 adding taskfile io access method * Version 1.13 added standby and flush-cache for notifier * Version 1.14 added acoustic-wcache * Version 1.15 convert all calls to ide_raw_taskfile * since args will return register content. * Version 1.16 added suspend-resume-checkpower * Version 1.17 do flush on standy, do flush on ATA < ATA6 * fix wcache setup. */#define IDEDISK_VERSION "1.18"#undef REALLY_SLOW_IO /* most systems can safely undef this *///#define DEBUG#include <linux/config.h>#include <linux/module.h>#include <linux/types.h>#include <linux/string.h>#include <linux/kernel.h>#include <linux/timer.h>#include <linux/mm.h>#include <linux/interrupt.h>#include <linux/major.h>#include <linux/errno.h>#include <linux/genhd.h>#include <linux/slab.h>#include <linux/delay.h>#define _IDE_DISK#include <linux/ide.h>#include <asm/byteorder.h>#include <asm/irq.h>#include <asm/uaccess.h>#include <asm/io.h>#include <asm/div64.h>struct ide_disk_obj { ide_drive_t *drive; ide_driver_t *driver; struct gendisk *disk; struct kref kref;};static DECLARE_MUTEX(idedisk_ref_sem);#define to_ide_disk(obj) container_of(obj, struct ide_disk_obj, kref)#define ide_disk_g(disk) \ container_of((disk)->private_data, struct ide_disk_obj, driver)static struct ide_disk_obj *ide_disk_get(struct gendisk *disk){ struct ide_disk_obj *idkp = NULL; down(&idedisk_ref_sem); idkp = ide_disk_g(disk); if (idkp) kref_get(&idkp->kref); up(&idedisk_ref_sem); return idkp;}static void ide_disk_release(struct kref *);static void ide_disk_put(struct ide_disk_obj *idkp){ down(&idedisk_ref_sem); kref_put(&idkp->kref, ide_disk_release); up(&idedisk_ref_sem);}/* * lba_capacity_is_ok() performs a sanity check on the claimed "lba_capacity" * value for this drive (from its reported identification information). * * Returns: 1 if lba_capacity looks sensible * 0 otherwise * * It is called only once for each drive. */static int lba_capacity_is_ok (struct hd_driveid *id){ unsigned long lba_sects, chs_sects, head, tail; /* No non-LBA info .. so valid! */ if (id->cyls == 0) return 1; /* * The ATA spec tells large drives to return * C/H/S = 16383/16/63 independent of their size. * Some drives can be jumpered to use 15 heads instead of 16. * Some drives can be jumpered to use 4092 cyls instead of 16383. */ if ((id->cyls == 16383 || (id->cyls == 4092 && id->cur_cyls == 16383)) && id->sectors == 63 && (id->heads == 15 || id->heads == 16) && (id->lba_capacity >= 16383*63*id->heads)) return 1; lba_sects = id->lba_capacity; chs_sects = id->cyls * id->heads * id->sectors; /* perform a rough sanity check on lba_sects: within 10% is OK */ if ((lba_sects - chs_sects) < chs_sects/10) return 1; /* some drives have the word order reversed */ head = ((lba_sects >> 16) & 0xffff); tail = (lba_sects & 0xffff); lba_sects = (head | (tail << 16)); if ((lba_sects - chs_sects) < chs_sects/10) { id->lba_capacity = lba_sects; return 1; /* lba_capacity is (now) good */ } return 0; /* lba_capacity value may be bad */}/* * __ide_do_rw_disk() issues READ and WRITE commands to a disk, * using LBA if supported, or CHS otherwise, to address sectors. */static ide_startstop_t __ide_do_rw_disk(ide_drive_t *drive, struct request *rq, sector_t block){ ide_hwif_t *hwif = HWIF(drive); unsigned int dma = drive->using_dma; u8 lba48 = (drive->addressing == 1) ? 1 : 0; task_ioreg_t command = WIN_NOP; ata_nsector_t nsectors; nsectors.all = (u16) rq->nr_sectors; if (hwif->no_lba48_dma && lba48 && dma) { if (block + rq->nr_sectors > 1ULL << 28) dma = 0; else lba48 = 0; } if (!dma) { ide_init_sg_cmd(drive, rq); ide_map_sg(drive, rq); } if (IDE_CONTROL_REG) hwif->OUTB(drive->ctl, IDE_CONTROL_REG); /* FIXME: SELECT_MASK(drive, 0) ? */ if (drive->select.b.lba) { if (lba48) { task_ioreg_t tasklets[10]; pr_debug("%s: LBA=0x%012llx\n", drive->name, (unsigned long long)block); tasklets[0] = 0; tasklets[1] = 0; tasklets[2] = nsectors.b.low; tasklets[3] = nsectors.b.high; tasklets[4] = (task_ioreg_t) block; tasklets[5] = (task_ioreg_t) (block>>8); tasklets[6] = (task_ioreg_t) (block>>16); tasklets[7] = (task_ioreg_t) (block>>24); if (sizeof(block) == 4) { tasklets[8] = (task_ioreg_t) 0; tasklets[9] = (task_ioreg_t) 0; } else { tasklets[8] = (task_ioreg_t)((u64)block >> 32); tasklets[9] = (task_ioreg_t)((u64)block >> 40); }#ifdef DEBUG printk("%s: 0x%02x%02x 0x%02x%02x%02x%02x%02x%02x\n", drive->name, tasklets[3], tasklets[2], tasklets[9], tasklets[8], tasklets[7], tasklets[6], tasklets[5], tasklets[4]);#endif hwif->OUTB(tasklets[1], IDE_FEATURE_REG); hwif->OUTB(tasklets[3], IDE_NSECTOR_REG); hwif->OUTB(tasklets[7], IDE_SECTOR_REG); hwif->OUTB(tasklets[8], IDE_LCYL_REG); hwif->OUTB(tasklets[9], IDE_HCYL_REG); hwif->OUTB(tasklets[0], IDE_FEATURE_REG); hwif->OUTB(tasklets[2], IDE_NSECTOR_REG); hwif->OUTB(tasklets[4], IDE_SECTOR_REG); hwif->OUTB(tasklets[5], IDE_LCYL_REG); hwif->OUTB(tasklets[6], IDE_HCYL_REG); hwif->OUTB(0x00|drive->select.all,IDE_SELECT_REG); } else { hwif->OUTB(0x00, IDE_FEATURE_REG); hwif->OUTB(nsectors.b.low, IDE_NSECTOR_REG); hwif->OUTB(block, IDE_SECTOR_REG); hwif->OUTB(block>>=8, IDE_LCYL_REG); hwif->OUTB(block>>=8, IDE_HCYL_REG); hwif->OUTB(((block>>8)&0x0f)|drive->select.all,IDE_SELECT_REG); } } else { unsigned int sect,head,cyl,track; track = (int)block / drive->sect; sect = (int)block % drive->sect + 1; hwif->OUTB(sect, IDE_SECTOR_REG); head = track % drive->head; cyl = track / drive->head; pr_debug("%s: CHS=%u/%u/%u\n", drive->name, cyl, head, sect); hwif->OUTB(0x00, IDE_FEATURE_REG); hwif->OUTB(nsectors.b.low, IDE_NSECTOR_REG); hwif->OUTB(cyl, IDE_LCYL_REG); hwif->OUTB(cyl>>8, IDE_HCYL_REG); hwif->OUTB(head|drive->select.all,IDE_SELECT_REG); } if (dma) { if (!hwif->dma_setup(drive)) { if (rq_data_dir(rq)) { command = lba48 ? WIN_WRITEDMA_EXT : WIN_WRITEDMA; if (drive->vdma) command = lba48 ? WIN_WRITE_EXT: WIN_WRITE; } else { command = lba48 ? WIN_READDMA_EXT : WIN_READDMA; if (drive->vdma) command = lba48 ? WIN_READ_EXT: WIN_READ; } hwif->dma_exec_cmd(drive, command); hwif->dma_start(drive); return ide_started; } /* fallback to PIO */ ide_init_sg_cmd(drive, rq); } if (rq_data_dir(rq) == READ) { if (drive->mult_count) { hwif->data_phase = TASKFILE_MULTI_IN; command = lba48 ? WIN_MULTREAD_EXT : WIN_MULTREAD; } else { hwif->data_phase = TASKFILE_IN; command = lba48 ? WIN_READ_EXT : WIN_READ; } ide_execute_command(drive, command, &task_in_intr, WAIT_CMD, NULL); return ide_started; } else { if (drive->mult_count) { hwif->data_phase = TASKFILE_MULTI_OUT; command = lba48 ? WIN_MULTWRITE_EXT : WIN_MULTWRITE; } else { hwif->data_phase = TASKFILE_OUT; command = lba48 ? WIN_WRITE_EXT : WIN_WRITE; } /* FIXME: ->OUTBSYNC ? */ hwif->OUTB(command, IDE_COMMAND_REG); return pre_task_out_intr(drive, rq); }}/* * 268435455 == 137439 MB or 28bit limit * 320173056 == 163929 MB or 48bit addressing * 1073741822 == 549756 MB or 48bit addressing fake drive */static ide_startstop_t ide_do_rw_disk (ide_drive_t *drive, struct request *rq, sector_t block){ ide_hwif_t *hwif = HWIF(drive); BUG_ON(drive->blocked); if (!blk_fs_request(rq)) { blk_dump_rq_flags(rq, "ide_do_rw_disk - bad command"); ide_end_request(drive, 0, 0); return ide_stopped; } pr_debug("%s: %sing: block=%llu, sectors=%lu, buffer=0x%08lx\n", drive->name, rq_data_dir(rq) == READ ? "read" : "writ", (unsigned long long)block, rq->nr_sectors, (unsigned long)rq->buffer); if (hwif->rw_disk) hwif->rw_disk(drive, rq); return __ide_do_rw_disk(drive, rq, block);}/* * Queries for true maximum capacity of the drive. * Returns maximum LBA address (> 0) of the drive, 0 if failed. */static unsigned long idedisk_read_native_max_address(ide_drive_t *drive){ ide_task_t args; unsigned 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; 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) { 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.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 = ((__u64)high << 24) | low; addr++; /* since the return value is (maxlba - 1), we add 1 */ } return addr;}/* * 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.command_type = IDE_DRIVE_TASK_NO_DATA; 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -