X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fide%2Fide-disk.c;h=a9fbe2c31210cc1400dc2ce132c74211dbd40642;hb=eaa958402ea40851097d051f52ba1bb7a885efe9;hp=8f49bc0ecbf868f7b8faf0b696f1711b77a25ce7;hpb=942dcd85bf8edf38cdc3745306ca250684d99a61;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c index 8f49bc0..a9fbe2c 100644 --- a/drivers/ide/ide-disk.c +++ b/drivers/ide/ide-disk.c @@ -2,7 +2,7 @@ * Copyright (C) 1994-1998 Linus Torvalds & authors (see below) * Copyright (C) 1998-2002 Linux ATA Development * Andre Hedrick - * Copyright (C) 2003 Red Hat + * Copyright (C) 2003 Red Hat * Copyright (C) 2003-2005, 2007 Bartlomiej Zolnierkiewicz */ @@ -14,9 +14,6 @@ * This is the IDE/ATA disk driver, as evolved from hd.c and ide.c. */ -#define IDEDISK_VERSION "1.18" - -#include #include #include #include @@ -31,7 +28,6 @@ #include #include #include -#include #include #include @@ -39,104 +35,7 @@ #include #include -#if !defined(CONFIG_DEBUG_BLOCK_EXT_DEVT) -#define IDE_DISK_MINORS (1 << PARTN_BITS) -#else -#define IDE_DISK_MINORS 0 -#endif - -struct ide_disk_obj { - ide_drive_t *drive; - ide_driver_t *driver; - struct gendisk *disk; - struct kref kref; - unsigned int openers; /* protected by BKL for now */ -}; - -static DEFINE_MUTEX(idedisk_ref_mutex); - -#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 void ide_disk_release(struct kref *); - -static struct ide_disk_obj *ide_disk_get(struct gendisk *disk) -{ - struct ide_disk_obj *idkp = NULL; - - mutex_lock(&idedisk_ref_mutex); - idkp = ide_disk_g(disk); - if (idkp) { - if (ide_device_get(idkp->drive)) - idkp = NULL; - else - kref_get(&idkp->kref); - } - mutex_unlock(&idedisk_ref_mutex); - return idkp; -} - -static void ide_disk_put(struct ide_disk_obj *idkp) -{ - ide_drive_t *drive = idkp->drive; - - mutex_lock(&idedisk_ref_mutex); - kref_put(&idkp->kref, ide_disk_release); - ide_device_put(drive); - mutex_unlock(&idedisk_ref_mutex); -} - -/* - * 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(u16 *id) -{ - unsigned long lba_sects, chs_sects, head, tail; - - /* No non-LBA info .. so valid! */ - if (id[ATA_ID_CYLS] == 0) - return 1; - - lba_sects = ata_id_u32(id, ATA_ID_LBA_CAPACITY); - - /* - * 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[ATA_ID_CYLS] == 16383 || - (id[ATA_ID_CYLS] == 4092 && id[ATA_ID_CUR_CYLS] == 16383)) && - id[ATA_ID_SECTORS] == 63 && - (id[ATA_ID_HEADS] == 15 || id[ATA_ID_HEADS] == 16) && - (lba_sects >= 16383 * 63 * id[ATA_ID_HEADS])) - return 1; - - chs_sects = id[ATA_ID_CYLS] * id[ATA_ID_HEADS] * id[ATA_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) { - *(__le32 *)&id[ATA_ID_LBA_CAPACITY] = __cpu_to_le32(lba_sects); - return 1; /* lba_capacity is (now) good */ - } - - return 0; /* lba_capacity value may be bad */ -} +#include "ide-disk.h" static const u8 ide_rw_cmds[] = { ATA_CMD_READ_MULTI, @@ -153,33 +52,26 @@ static const u8 ide_rw_cmds[] = { ATA_CMD_WRITE_EXT, }; -static const u8 ide_data_phases[] = { - TASKFILE_MULTI_IN, - TASKFILE_MULTI_OUT, - TASKFILE_IN, - TASKFILE_OUT, - TASKFILE_IN_DMA, - TASKFILE_OUT_DMA, -}; - -static void ide_tf_set_cmd(ide_drive_t *drive, ide_task_t *task, u8 dma) +static void ide_tf_set_cmd(ide_drive_t *drive, struct ide_cmd *cmd, u8 dma) { u8 index, lba48, write; - lba48 = (task->tf_flags & IDE_TFLAG_LBA48) ? 2 : 0; - write = (task->tf_flags & IDE_TFLAG_WRITE) ? 1 : 0; + lba48 = (cmd->tf_flags & IDE_TFLAG_LBA48) ? 2 : 0; + write = (cmd->tf_flags & IDE_TFLAG_WRITE) ? 1 : 0; - if (dma) + if (dma) { + cmd->protocol = ATA_PROT_DMA; index = 8; - else - index = drive->mult_count ? 0 : 4; - - task->tf.command = ide_rw_cmds[index + lba48 + write]; - - if (dma) - index = 8; /* fixup index */ + } else { + cmd->protocol = ATA_PROT_PIO; + if (drive->mult_count) { + cmd->tf_flags |= IDE_TFLAG_MULTI_PIO; + index = 0; + } else + index = 4; + } - task->data_phase = ide_data_phases[index / 2 + write]; + cmd->tf.command = ide_rw_cmds[index + lba48 + write]; } /* @@ -189,12 +81,12 @@ static void ide_tf_set_cmd(ide_drive_t *drive, ide_task_t *task, u8 dma) 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; + ide_hwif_t *hwif = drive->hwif; u16 nsectors = (u16)rq->nr_sectors; - u8 lba48 = (drive->addressing == 1) ? 1 : 0; - ide_task_t task; - struct ide_taskfile *tf = &task.tf; + u8 lba48 = !!(drive->dev_flags & IDE_DFLAG_LBA48); + u8 dma = !!(drive->dev_flags & IDE_DFLAG_USING_DMA); + struct ide_cmd cmd; + struct ide_taskfile *tf = &cmd.tf; ide_startstop_t rc; if ((hwif->host_flags & IDE_HFLAG_NO_LBA48_DMA) && lba48 && dma) { @@ -204,38 +96,38 @@ static ide_startstop_t __ide_do_rw_disk(ide_drive_t *drive, struct request *rq, lba48 = 0; } - if (!dma) { - ide_init_sg_cmd(drive, rq); - ide_map_sg(drive, rq); - } + memset(&cmd, 0, sizeof(cmd)); + cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE; + cmd.valid.in.tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE; - memset(&task, 0, sizeof(task)); - task.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE; - - if (drive->select.b.lba) { + if (drive->dev_flags & IDE_DFLAG_LBA) { if (lba48) { pr_debug("%s: LBA=0x%012llx\n", drive->name, (unsigned long long)block); - tf->hob_nsect = (nsectors >> 8) & 0xff; - tf->hob_lbal = (u8)(block >> 24); - if (sizeof(block) != 4) { - tf->hob_lbam = (u8)((u64)block >> 32); - tf->hob_lbah = (u8)((u64)block >> 40); - } - tf->nsect = nsectors & 0xff; tf->lbal = (u8) block; tf->lbam = (u8)(block >> 8); tf->lbah = (u8)(block >> 16); + tf->device = ATA_LBA; + + tf = &cmd.hob; + tf->nsect = (nsectors >> 8) & 0xff; + tf->lbal = (u8)(block >> 24); + if (sizeof(block) != 4) { + tf->lbam = (u8)((u64)block >> 32); + tf->lbah = (u8)((u64)block >> 40); + } - task.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_HOB); + cmd.valid.out.hob = IDE_VALID_OUT_HOB; + cmd.valid.in.hob = IDE_VALID_IN_HOB; + cmd.tf_flags |= IDE_TFLAG_LBA48; } else { tf->nsect = nsectors & 0xff; tf->lbal = block; tf->lbam = block >>= 8; tf->lbah = block >>= 8; - tf->device = (block >> 8) & 0xf; + tf->device = ((block >> 8) & 0xf) | ATA_LBA; } } else { unsigned int sect, head, cyl, track; @@ -254,23 +146,27 @@ static ide_startstop_t __ide_do_rw_disk(ide_drive_t *drive, struct request *rq, tf->device = head; } + cmd.tf_flags |= IDE_TFLAG_FS; + if (rq_data_dir(rq)) - task.tf_flags |= IDE_TFLAG_WRITE; + cmd.tf_flags |= IDE_TFLAG_WRITE; + + ide_tf_set_cmd(drive, &cmd, dma); + cmd.rq = rq; - ide_tf_set_cmd(drive, &task, dma); - if (!dma) - hwif->data_phase = task.data_phase; - task.rq = rq; + if (dma == 0) { + ide_init_sg_cmd(&cmd, nsectors << 9); + ide_map_sg(drive, &cmd); + } - rc = do_rw_taskfile(drive, &task); + rc = do_rw_taskfile(drive, &cmd); if (rc == ide_stopped && dma) { /* fallback to PIO */ - task.tf_flags |= IDE_TFLAG_DMA_PIO_FALLBACK; - ide_tf_set_cmd(drive, &task, 0); - hwif->data_phase = task.data_phase; - ide_init_sg_cmd(drive, rq); - rc = do_rw_taskfile(drive, &task); + cmd.tf_flags |= IDE_TFLAG_DMA_PIO_FALLBACK; + ide_tf_set_cmd(drive, &cmd, 0); + ide_init_sg_cmd(&cmd, nsectors << 9); + rc = do_rw_taskfile(drive, &cmd); } return rc; @@ -285,13 +181,15 @@ static ide_startstop_t __ide_do_rw_disk(ide_drive_t *drive, struct request *rq, static ide_startstop_t ide_do_rw_disk(ide_drive_t *drive, struct request *rq, sector_t block) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; - BUG_ON(drive->blocked); + BUG_ON(drive->dev_flags & IDE_DFLAG_BLOCKED); if (!blk_fs_request(rq)) { blk_dump_rq_flags(rq, "ide_do_rw_disk - bad command"); - ide_end_request(drive, 0, 0); + if (rq->errors == 0) + rq->errors = -EIO; + ide_complete_rq(drive, -EIO, ide_rq_bytes(rq)); return ide_stopped; } @@ -314,26 +212,30 @@ static ide_startstop_t ide_do_rw_disk(ide_drive_t *drive, struct request *rq, */ static u64 idedisk_read_native_max_address(ide_drive_t *drive, int lba48) { - ide_task_t args; - struct ide_taskfile *tf = &args.tf; + struct ide_cmd cmd; + struct ide_taskfile *tf = &cmd.tf; u64 addr = 0; - /* Create IDE/ATA command request structure */ - memset(&args, 0, sizeof(ide_task_t)); + memset(&cmd, 0, sizeof(cmd)); if (lba48) tf->command = ATA_CMD_READ_NATIVE_MAX_EXT; else tf->command = ATA_CMD_READ_NATIVE_MAX; tf->device = ATA_LBA; - args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE; - if (lba48) - args.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_HOB); - /* submit command request */ - ide_no_data_taskfile(drive, &args); + + cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE; + cmd.valid.in.tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE; + if (lba48) { + cmd.valid.out.hob = IDE_VALID_OUT_HOB; + cmd.valid.in.hob = IDE_VALID_IN_HOB; + cmd.tf_flags = IDE_TFLAG_LBA48; + } + + ide_no_data_taskfile(drive, &cmd); /* if OK, compute maximum address value */ - if ((tf->status & 0x01) == 0) - addr = ide_get_lba_addr(tf, lba48) + 1; + if (!(tf->status & ATA_ERR)) + addr = ide_get_lba_addr(&cmd, lba48) + 1; return addr; } @@ -344,34 +246,40 @@ static u64 idedisk_read_native_max_address(ide_drive_t *drive, int lba48) */ static u64 idedisk_set_max_address(ide_drive_t *drive, u64 addr_req, int lba48) { - ide_task_t args; - struct ide_taskfile *tf = &args.tf; + struct ide_cmd cmd; + struct ide_taskfile *tf = &cmd.tf; u64 addr_set = 0; addr_req--; - /* Create IDE/ATA command request structure */ - memset(&args, 0, sizeof(ide_task_t)); + + memset(&cmd, 0, sizeof(cmd)); tf->lbal = (addr_req >> 0) & 0xff; tf->lbam = (addr_req >>= 8) & 0xff; tf->lbah = (addr_req >>= 8) & 0xff; if (lba48) { - tf->hob_lbal = (addr_req >>= 8) & 0xff; - tf->hob_lbam = (addr_req >>= 8) & 0xff; - tf->hob_lbah = (addr_req >>= 8) & 0xff; + cmd.hob.lbal = (addr_req >>= 8) & 0xff; + cmd.hob.lbam = (addr_req >>= 8) & 0xff; + cmd.hob.lbah = (addr_req >>= 8) & 0xff; tf->command = ATA_CMD_SET_MAX_EXT; } else { tf->device = (addr_req >>= 8) & 0x0f; tf->command = ATA_CMD_SET_MAX; } tf->device |= ATA_LBA; - args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE; - if (lba48) - args.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_HOB); - /* submit command request */ - ide_no_data_taskfile(drive, &args); + + cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE; + cmd.valid.in.tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE; + if (lba48) { + cmd.valid.out.hob = IDE_VALID_OUT_HOB; + cmd.valid.in.hob = IDE_VALID_IN_HOB; + cmd.tf_flags = IDE_TFLAG_LBA48; + } + + ide_no_data_taskfile(drive, &cmd); + /* if OK, compute maximum address value */ - if ((tf->status & 0x01) == 0) - addr_set = ide_get_lba_addr(tf, lba48) + 1; + if (!(tf->status & ATA_ERR)) + addr_set = ide_get_lba_addr(&cmd, lba48) + 1; return addr_set; } @@ -431,163 +339,80 @@ static void idedisk_check_hpa(ide_drive_t *drive) } } -static void init_idedisk_capacity(ide_drive_t *drive) +static int ide_disk_get_capacity(ide_drive_t *drive) { u16 *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 = ata_id_hpa_enabled(id); + int lba; if (ata_id_lba48_enabled(id)) { /* drive speaks 48-bit LBA */ - drive->select.b.lba = 1; + lba = 1; drive->capacity64 = ata_id_u64(id, ATA_ID_LBA_CAPACITY_2); - if (hpa) - idedisk_check_hpa(drive); - } else if (ata_id_has_lba(id) && lba_capacity_is_ok(id)) { + } else if (ata_id_has_lba(id) && ata_id_is_lba_capacity_ok(id)) { /* drive speaks 28-bit LBA */ - drive->select.b.lba = 1; + lba = 1; drive->capacity64 = ata_id_u32(id, ATA_ID_LBA_CAPACITY); - if (hpa) - idedisk_check_hpa(drive); } else { /* drive speaks boring old 28-bit CHS */ + lba = 0; drive->capacity64 = drive->cyl * drive->head * drive->sect; } -} - -static sector_t idedisk_capacity(ide_drive_t *drive) -{ - return drive->capacity64; -} - -#ifdef CONFIG_IDE_PROC_FS -static int smart_enable(ide_drive_t *drive) -{ - ide_task_t args; - struct ide_taskfile *tf = &args.tf; - - memset(&args, 0, sizeof(ide_task_t)); - tf->feature = ATA_SMART_ENABLE; - tf->lbam = ATA_SMART_LBAM_PASS; - tf->lbah = ATA_SMART_LBAH_PASS; - tf->command = ATA_CMD_SMART; - args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE; - return ide_no_data_taskfile(drive, &args); -} - -static int get_smart_data(ide_drive_t *drive, u8 *buf, u8 sub_cmd) -{ - ide_task_t args; - struct ide_taskfile *tf = &args.tf; - - memset(&args, 0, sizeof(ide_task_t)); - tf->feature = sub_cmd; - tf->nsect = 0x01; - tf->lbam = ATA_SMART_LBAM_PASS; - tf->lbah = ATA_SMART_LBAH_PASS; - tf->command = ATA_CMD_SMART; - args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE; - args.data_phase = TASKFILE_IN; - (void) smart_enable(drive); - return ide_raw_taskfile(drive, &args, buf, 1); -} -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[ATA_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)); + if (lba) { + drive->dev_flags |= IDE_DFLAG_LBA; - PROC_IDE_READ_RETURN(page, start, off, count, eof, len); -} - -static int proc_idedisk_read_smart(char *page, char **start, off_t off, - int count, int *eof, void *data, u8 sub_cmd) -{ - ide_drive_t *drive = (ide_drive_t *)data; - int len = 0, i = 0; - - if (get_smart_data(drive, page, sub_cmd) == 0) { - unsigned short *val = (unsigned short *) page; - char *out = (char *)val + SECTOR_SIZE; - - page = out; - do { - out += sprintf(out, "%04x%c", le16_to_cpu(*val), - (++i & 7) ? ' ' : '\n'); - val += 1; - } while (i < SECTOR_SIZE / 2); - len = out - page; + /* + * If this device supports the Host Protected Area feature set, + * then we may need to change our opinion about its capacity. + */ + if (ata_id_hpa_enabled(id)) + idedisk_check_hpa(drive); } - PROC_IDE_READ_RETURN(page, start, off, count, eof, len); -} + /* limit drive capacity to 137GB if LBA48 cannot be used */ + if ((drive->dev_flags & IDE_DFLAG_LBA48) == 0 && + drive->capacity64 > 1ULL << 28) { + printk(KERN_WARNING "%s: cannot use LBA48 - full capacity " + "%llu sectors (%llu MB)\n", + drive->name, (unsigned long long)drive->capacity64, + sectors_to_MB(drive->capacity64)); + drive->capacity64 = 1ULL << 28; + } -static int proc_idedisk_read_sv - (char *page, char **start, off_t off, int count, int *eof, void *data) -{ - return proc_idedisk_read_smart(page, start, off, count, eof, data, - ATA_SMART_READ_VALUES); -} + if ((drive->hwif->host_flags & IDE_HFLAG_NO_LBA48_DMA) && + (drive->dev_flags & IDE_DFLAG_LBA48)) { + if (drive->capacity64 > 1ULL << 28) { + printk(KERN_INFO "%s: cannot use LBA48 DMA - PIO mode" + " will be used for accessing sectors " + "> %u\n", drive->name, 1 << 28); + } else + drive->dev_flags &= ~IDE_DFLAG_LBA48; + } -static int proc_idedisk_read_st - (char *page, char **start, off_t off, int count, int *eof, void *data) -{ - return proc_idedisk_read_smart(page, start, off, count, eof, data, - ATA_SMART_READ_THRESHOLDS); + return 0; } -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_sv, NULL }, - { "smart_thresholds", S_IFREG|S_IRUSR, proc_idedisk_read_st, 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; - ide_task_t *task = kmalloc(sizeof(*task), GFP_ATOMIC); + struct ide_cmd *cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC); /* FIXME: map struct ide_taskfile on rq->cmd[] */ - BUG_ON(task == NULL); + BUG_ON(cmd == NULL); - memset(task, 0, sizeof(*task)); - if (ide_id_has_flush_cache_ext(drive->id) && + memset(cmd, 0, sizeof(*cmd)); + if (ata_id_flush_ext_enabled(drive->id) && (drive->capacity64 >= (1UL << 28))) - task->tf.command = ATA_CMD_FLUSH_EXT; + cmd->tf.command = ATA_CMD_FLUSH_EXT; else - task->tf.command = ATA_CMD_FLUSH; - task->tf_flags = IDE_TFLAG_OUT_TF | IDE_TFLAG_OUT_DEVICE | - IDE_TFLAG_DYN; - task->data_phase = TASKFILE_NO_DATA; + cmd->tf.command = ATA_CMD_FLUSH; + cmd->valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE; + cmd->tf_flags = IDE_TFLAG_DYN; + cmd->protocol = ATA_PROT_NODATA; rq->cmd_type = REQ_TYPE_ATA_TASKFILE; rq->cmd_flags |= REQ_SOFTBARRIER; - rq->special = task; + rq->special = cmd; } ide_devset_get(multcount, mult_count); @@ -618,28 +443,44 @@ static int set_multcount(ide_drive_t *drive, int arg) return (drive->mult_count == arg) ? 0 : -EIO; } -ide_devset_get(nowerr, nowerr); +ide_devset_get_flag(nowerr, IDE_DFLAG_NOWERR); 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; + if (arg) + drive->dev_flags |= IDE_DFLAG_NOWERR; + else + drive->dev_flags &= ~IDE_DFLAG_NOWERR; + drive->bad_wstat = arg ? BAD_R_STAT : BAD_W_STAT; - spin_unlock_irq(&ide_lock); + return 0; } +static int ide_do_setfeature(ide_drive_t *drive, u8 feature, u8 nsect) +{ + struct ide_cmd cmd; + + memset(&cmd, 0, sizeof(cmd)); + cmd.tf.feature = feature; + cmd.tf.nsect = nsect; + cmd.tf.command = ATA_CMD_SET_FEATURES; + cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE; + cmd.valid.in.tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE; + + return ide_no_data_taskfile(drive, &cmd); +} + static void update_ordered(ide_drive_t *drive) { u16 *id = drive->id; unsigned ordered = QUEUE_ORDERED_NONE; prepare_flush_fn *prep_fn = NULL; - if (drive->wcache) { + if (drive->dev_flags & IDE_DFLAG_WCACHE) { unsigned long long capacity; int barrier; /* @@ -650,10 +491,12 @@ static void update_ordered(ide_drive_t *drive) * 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)); + capacity = ide_gd_capacity(drive); + barrier = ata_id_flush_enabled(id) && + (drive->dev_flags & IDE_DFLAG_NOFLUSH) == 0 && + ((drive->dev_flags & IDE_DFLAG_LBA48) == 0 || + capacity <= (1ULL << 28) || + ata_id_flush_ext_enabled(id)); printk(KERN_INFO "%s: cache flushes %ssupported\n", drive->name, barrier ? "" : "not "); @@ -668,25 +511,24 @@ static void update_ordered(ide_drive_t *drive) blk_queue_ordered(drive->queue, ordered, prep_fn); } -ide_devset_get(wcache, wcache); +ide_devset_get_flag(wcache, IDE_DFLAG_WCACHE); static int set_wcache(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.tf.feature = arg ? - SETFEATURES_WC_ON : SETFEATURES_WC_OFF; - args.tf.command = ATA_CMD_SET_FEATURES; - args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE; - err = ide_no_data_taskfile(drive, &args); - if (err == 0) - drive->wcache = arg; + if (ata_id_flush_enabled(drive->id)) { + err = ide_do_setfeature(drive, + arg ? SETFEATURES_WC_ON : SETFEATURES_WC_OFF, 0); + if (err == 0) { + if (arg) + drive->dev_flags |= IDE_DFLAG_WCACHE; + else + drive->dev_flags &= ~IDE_DFLAG_WCACHE; + } } update_ordered(drive); @@ -696,37 +538,35 @@ static int set_wcache(ide_drive_t *drive, int arg) static int do_idedisk_flushcache(ide_drive_t *drive) { - ide_task_t args; + struct ide_cmd cmd; - memset(&args, 0, sizeof(ide_task_t)); - if (ide_id_has_flush_cache_ext(drive->id)) - args.tf.command = ATA_CMD_FLUSH_EXT; + memset(&cmd, 0, sizeof(cmd)); + if (ata_id_flush_ext_enabled(drive->id)) + cmd.tf.command = ATA_CMD_FLUSH_EXT; else - args.tf.command = ATA_CMD_FLUSH; - args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE; - return ide_no_data_taskfile(drive, &args); + cmd.tf.command = ATA_CMD_FLUSH; + cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE; + cmd.valid.in.tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE; + + return ide_no_data_taskfile(drive, &cmd); } ide_devset_get(acoustic, acoustic); 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.tf.feature = arg ? SETFEATURES_AAM_ON : SETFEATURES_AAM_OFF; - args.tf.nsect = arg; - args.tf.command = ATA_CMD_SET_FEATURES; - args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE; - ide_no_data_taskfile(drive, &args); + ide_do_setfeature(drive, + arg ? SETFEATURES_AAM_ON : SETFEATURES_AAM_OFF, arg); + drive->acoustic = arg; + return 0; } -ide_devset_get(lba_addressing, addressing); +ide_devset_get_flag(addressing, IDE_DFLAG_LBA48); /* * drive->addressing: @@ -734,57 +574,42 @@ ide_devset_get(lba_addressing, addressing); * 1: 48-bit * 2: 48-bit capable doing 28-bit */ -static int set_lba_addressing(ide_drive_t *drive, int arg) +static int set_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 (ata_id_lba48_enabled(drive->id) == 0) + if (arg && ((drive->hwif->host_flags & IDE_HFLAG_NO_LBA48) || + ata_id_lba48_enabled(drive->id) == 0)) return -EIO; - drive->addressing = arg; + if (arg == 2) + arg = 0; + + if (arg) + drive->dev_flags |= IDE_DFLAG_LBA48; + else + drive->dev_flags &= ~IDE_DFLAG_LBA48; return 0; } -#ifdef CONFIG_IDE_PROC_FS -ide_devset_rw_nolock(acoustic, 0, 254, acoustic); -ide_devset_rw_nolock(address, 0, 2, lba_addressing); -ide_devset_rw_nolock(multcount, 0, 16, multcount); -ide_devset_rw_nolock(nowerr, 0, 1, nowerr); -ide_devset_rw_nolock(wcache, 0, 1, wcache); - -ide_devset_rw(bios_cyl, 0, 65535, bios_cyl); -ide_devset_rw(bios_head, 0, 255, bios_head); -ide_devset_rw(bios_sect, 0, 63, bios_sect); -ide_devset_rw(failures, 0, 65535, failures); -ide_devset_rw(lun, 0, 7, lun); -ide_devset_rw(max_failures, 0, 65535, max_failures); - -static const struct ide_devset *idedisk_settings[] = { - &ide_devset_acoustic, - &ide_devset_address, - &ide_devset_bios_cyl, - &ide_devset_bios_head, - &ide_devset_bios_sect, - &ide_devset_failures, - &ide_devset_lun, - &ide_devset_max_failures, - &ide_devset_multcount, - &ide_devset_nowerr, - &ide_devset_wcache, - NULL -}; -#endif +ide_ext_devset_rw(acoustic, acoustic); +ide_ext_devset_rw(address, addressing); +ide_ext_devset_rw(multcount, multcount); +ide_ext_devset_rw(wcache, wcache); -static void idedisk_setup(ide_drive_t *drive) +ide_ext_devset_rw_sync(nowerr, nowerr); + +static int ide_disk_check(ide_drive_t *drive, const char *s) +{ + return 1; +} + +static void ide_disk_setup(ide_drive_t *drive) { struct ide_disk_obj *idkp = drive->driver_data; + struct request_queue *q = drive->queue; ide_hwif_t *hwif = drive->hwif; u16 *id = drive->id; char *m = (char *)&id[ATA_ID_PROD]; @@ -792,59 +617,44 @@ static void idedisk_setup(ide_drive_t *drive) ide_proc_register_driver(drive, idkp->driver); - if (drive->id_read == 0) + if ((drive->dev_flags & IDE_DFLAG_ID_READ) == 0) return; - if (drive->removable) { + if (drive->dev_flags & IDE_DFLAG_REMOVABLE) { /* * Removable disks (eg. SYQUEST); ignore 'WD' drives */ if (m[0] != 'W' || m[1] != 'D') - drive->doorlocking = 1; + drive->dev_flags |= IDE_DFLAG_DOORLOCKING; } - (void)set_lba_addressing(drive, 1); + (void)set_addressing(drive, 1); - if (drive->addressing == 1) { + if (drive->dev_flags & IDE_DFLAG_LBA48) { int max_s = 2048; if (max_s > hwif->rqsize) max_s = hwif->rqsize; - blk_queue_max_sectors(drive->queue, max_s); + blk_queue_max_sectors(q, max_s); } printk(KERN_INFO "%s: max request size: %dKiB\n", drive->name, - drive->queue->max_sectors / 2); + q->max_sectors / 2); - /* calculate drive capacity, and select LBA if possible */ - init_idedisk_capacity(drive); - - /* limit drive capacity to 137GB if LBA48 cannot be used */ - if (drive->addressing == 0 && drive->capacity64 > 1ULL << 28) { - printk(KERN_WARNING "%s: cannot use LBA48 - full capacity " - "%llu sectors (%llu MB)\n", - drive->name, (unsigned long long)drive->capacity64, - sectors_to_MB(drive->capacity64)); - drive->capacity64 = 1ULL << 28; - } + if (ata_id_is_ssd(id)) + queue_flag_set_unlocked(QUEUE_FLAG_NONROT, q); - if ((hwif->host_flags & IDE_HFLAG_NO_LBA48_DMA) && drive->addressing) { - if (drive->capacity64 > 1ULL << 28) { - printk(KERN_INFO "%s: cannot use LBA48 DMA - PIO mode" - " will be used for accessing sectors " - "> %u\n", drive->name, 1 << 28); - } else - drive->addressing = 0; - } + /* calculate drive capacity, and select LBA if possible */ + ide_disk_get_capacity(drive); /* * if possible, give fdisk access to more of the drive, * by correcting bios_cyls: */ - capacity = idedisk_capacity(drive); + capacity = ide_gd_capacity(drive); - if (!drive->forced_geom) { + if ((drive->dev_flags & IDE_DFLAG_FORCED_GEOM) == 0) { if (ata_id_lba48_enabled(drive->id)) { /* compatibility */ drive->bios_sect = 63; @@ -879,324 +689,63 @@ static void idedisk_setup(ide_drive_t *drive) /* write cache enabled? */ if ((id[ATA_ID_CSFO] & 1) || ata_id_wcache_enabled(id)) - drive->wcache = 1; + drive->dev_flags |= IDE_DFLAG_WCACHE; set_wcache(drive, 1); + + if ((drive->dev_flags & IDE_DFLAG_LBA) == 0 && + (drive->head == 0 || drive->head > 16)) { + printk(KERN_ERR "%s: invalid geometry: %d physical heads?\n", + drive->name, drive->head); + drive->dev_flags &= ~IDE_DFLAG_ATTACH; + } else + drive->dev_flags |= IDE_DFLAG_ATTACH; } -static void ide_cacheflush_p(ide_drive_t *drive) +static void ide_disk_flush(ide_drive_t *drive) { - if (!drive->wcache || !ide_id_has_flush_cache(drive->id)) + if (ata_id_flush_enabled(drive->id) == 0 || + (drive->dev_flags & IDE_DFLAG_WCACHE) == 0) return; if (do_idedisk_flushcache(drive)) printk(KERN_INFO "%s: wcache flush failed!\n", drive->name); } -static void ide_disk_remove(ide_drive_t *drive) -{ - struct ide_disk_obj *idkp = drive->driver_data; - struct gendisk *g = idkp->disk; - - ide_proc_unregister_driver(drive, idkp->driver); - - del_gendisk(g); - - ide_cacheflush_p(drive); - - ide_disk_put(idkp); -} - -static void ide_disk_release(struct kref *kref) -{ - struct ide_disk_obj *idkp = to_ide_disk(kref); - ide_drive_t *drive = idkp->drive; - struct gendisk *g = idkp->disk; - - drive->driver_data = NULL; - g->private_data = NULL; - put_disk(g); - kfree(idkp); -} - -static int ide_disk_probe(ide_drive_t *drive); - -/* - * On HPA drives the capacity needs to be - * reinitilized on resume otherwise the disk - * can not be used and a hard reset is required - */ -static void ide_disk_resume(ide_drive_t *drive) -{ - if (ata_id_hpa_enabled(drive->id)) - init_idedisk_capacity(drive); -} - -static void ide_device_shutdown(ide_drive_t *drive) -{ -#ifdef CONFIG_ALPHA - /* On Alpha, halt(8) doesn't actually turn the machine off, - it puts you into the sort of firmware monitor. Typically, - it's used to boot another kernel image, so it's not much - different from reboot(8). Therefore, we don't need to - spin down the disk in this case, especially since Alpha - firmware doesn't handle disks in standby mode properly. - On the other hand, it's reasonably safe to turn the power - off when the shutdown process reaches the firmware prompt, - as the firmware initialization takes rather long time - - at least 10 seconds, which should be sufficient for - the disk to expire its write cache. */ - if (system_state != SYSTEM_POWER_OFF) { -#else - if (system_state == SYSTEM_RESTART) { -#endif - ide_cacheflush_p(drive); - return; - } - - printk(KERN_INFO "Shutdown: %s\n", drive->name); - - drive->gendev.bus->suspend(&drive->gendev, PMSG_SUSPEND); -} - -static ide_driver_t idedisk_driver = { - .gen_driver = { - .owner = THIS_MODULE, - .name = "ide-disk", - .bus = &ide_bus_type, - }, - .probe = ide_disk_probe, - .remove = ide_disk_remove, - .resume = ide_disk_resume, - .shutdown = ide_device_shutdown, - .version = IDEDISK_VERSION, - .media = ide_disk, - .do_request = ide_do_rw_disk, - .end_request = ide_end_request, - .error = __ide_error, -#ifdef CONFIG_IDE_PROC_FS - .proc = idedisk_proc, - .settings = idedisk_settings, -#endif -}; - -static int idedisk_set_doorlock(ide_drive_t *drive, int on) -{ - ide_task_t task; - - memset(&task, 0, sizeof(task)); - task.tf.command = on ? ATA_CMD_MEDIA_LOCK : ATA_CMD_MEDIA_UNLOCK; - task.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE; - - return ide_no_data_taskfile(drive, &task); -} - -static int idedisk_open(struct inode *inode, struct file *filp) -{ - struct gendisk *disk = inode->i_bdev->bd_disk; - struct ide_disk_obj *idkp; - ide_drive_t *drive; - - idkp = ide_disk_get(disk); - if (idkp == NULL) - return -ENXIO; - - drive = idkp->drive; - - idkp->openers++; - - if (drive->removable && idkp->openers == 1) { - check_disk_change(inode->i_bdev); - /* - * 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 && idedisk_set_doorlock(drive, 1)) - drive->doorlocking = 0; - } - return 0; -} - -static int idedisk_release(struct inode *inode, struct file *filp) -{ - struct gendisk *disk = inode->i_bdev->bd_disk; - struct ide_disk_obj *idkp = ide_disk_g(disk); - ide_drive_t *drive = idkp->drive; - - if (idkp->openers == 1) - ide_cacheflush_p(drive); - - if (drive->removable && idkp->openers == 1) { - if (drive->doorlocking && idedisk_set_doorlock(drive, 0)) - drive->doorlocking = 0; - } - - idkp->openers--; - - ide_disk_put(idkp); - - return 0; -} - -static int idedisk_getgeo(struct block_device *bdev, struct hd_geometry *geo) +static int ide_disk_init_media(ide_drive_t *drive, struct gendisk *disk) { - struct ide_disk_obj *idkp = ide_disk_g(bdev->bd_disk); - ide_drive_t *drive = idkp->drive; - - geo->heads = drive->bios_head; - geo->sectors = drive->bios_sect; - geo->cylinders = (u16)drive->bios_cyl; /* truncate */ return 0; } -static int idedisk_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - unsigned long flags; - struct block_device *bdev = inode->i_bdev; - struct ide_disk_obj *idkp = ide_disk_g(bdev->bd_disk); - ide_drive_t *drive = idkp->drive; - int err, (*getfunc)(ide_drive_t *), (*setfunc)(ide_drive_t *, int); - - switch (cmd) { - case HDIO_GET_ADDRESS: getfunc = get_lba_addressing; goto read_val; - case HDIO_GET_MULTCOUNT: getfunc = get_multcount; goto read_val; - case HDIO_GET_NOWERR: getfunc = get_nowerr; goto read_val; - case HDIO_GET_WCACHE: getfunc = get_wcache; goto read_val; - case HDIO_GET_ACOUSTIC: getfunc = get_acoustic; goto read_val; - case HDIO_SET_ADDRESS: setfunc = set_lba_addressing; goto set_val; - case HDIO_SET_MULTCOUNT: setfunc = set_multcount; goto set_val; - case HDIO_SET_NOWERR: setfunc = set_nowerr; goto set_val; - case HDIO_SET_WCACHE: setfunc = set_wcache; goto set_val; - case HDIO_SET_ACOUSTIC: setfunc = set_acoustic; goto set_val; - } - - return generic_ide_ioctl(drive, file, bdev, cmd, arg); - -read_val: - mutex_lock(&ide_setting_mtx); - spin_lock_irqsave(&ide_lock, flags); - err = getfunc(drive); - spin_unlock_irqrestore(&ide_lock, flags); - mutex_unlock(&ide_setting_mtx); - return err >= 0 ? put_user(err, (long __user *)arg) : err; - -set_val: - if (bdev != bdev->bd_contains) - err = -EINVAL; - else { - if (!capable(CAP_SYS_ADMIN)) - err = -EACCES; - else { - mutex_lock(&ide_setting_mtx); - err = setfunc(drive, arg); - mutex_unlock(&ide_setting_mtx); - } - } - return err; -} - -static int idedisk_media_changed(struct gendisk *disk) +static int ide_disk_set_doorlock(ide_drive_t *drive, struct gendisk *disk, + int on) { - struct ide_disk_obj *idkp = ide_disk_g(disk); - ide_drive_t *drive = idkp->drive; + struct ide_cmd cmd; + int ret; - /* do not scan partitions twice if this is a removable device */ - if (drive->attach) { - drive->attach = 0; + if ((drive->dev_flags & IDE_DFLAG_DOORLOCKING) == 0) return 0; - } - /* if removable, always assume it was changed */ - return drive->removable; -} - -static int idedisk_revalidate_disk(struct gendisk *disk) -{ - struct ide_disk_obj *idkp = ide_disk_g(disk); - set_capacity(disk, idedisk_capacity(idkp->drive)); - return 0; -} - -static struct block_device_operations idedisk_ops = { - .owner = THIS_MODULE, - .open = idedisk_open, - .release = idedisk_release, - .ioctl = idedisk_ioctl, - .getgeo = idedisk_getgeo, - .media_changed = idedisk_media_changed, - .revalidate_disk = idedisk_revalidate_disk -}; - -MODULE_DESCRIPTION("ATA DISK Driver"); - -static int ide_disk_probe(ide_drive_t *drive) -{ - struct ide_disk_obj *idkp; - struct gendisk *g; - - /* strstr("foo", "") is non-NULL */ - if (!strstr("ide-disk", drive->driver_req)) - goto failed; - - if (drive->media != ide_disk) - goto failed; - idkp = kzalloc(sizeof(*idkp), GFP_KERNEL); - if (!idkp) - goto failed; + memset(&cmd, 0, sizeof(cmd)); + cmd.tf.command = on ? ATA_CMD_MEDIA_LOCK : ATA_CMD_MEDIA_UNLOCK; + cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE; + cmd.valid.in.tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE; - g = alloc_disk_node(IDE_DISK_MINORS, hwif_to_node(drive->hwif)); - if (!g) - goto out_free_idkp; + ret = ide_no_data_taskfile(drive, &cmd); - ide_init_disk(g, drive); + if (ret) + drive->dev_flags &= ~IDE_DFLAG_DOORLOCKING; - kref_init(&idkp->kref); - - idkp->drive = drive; - idkp->driver = &idedisk_driver; - idkp->disk = g; - - g->private_data = &idkp->driver; - - drive->driver_data = idkp; - - 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); - drive->attach = 0; - } else - drive->attach = 1; - - g->minors = IDE_DISK_MINORS; - g->driverfs_dev = &drive->gendev; - g->flags |= GENHD_FL_EXT_DEVT; - if (drive->removable) - g->flags |= GENHD_FL_REMOVABLE; - set_capacity(g, idedisk_capacity(drive)); - g->fops = &idedisk_ops; - add_disk(g); - return 0; - -out_free_idkp: - kfree(idkp); -failed: - return -ENODEV; + return ret; } -static void __exit idedisk_exit(void) -{ - driver_unregister(&idedisk_driver.gen_driver); -} - -static int __init idedisk_init(void) -{ - return driver_register(&idedisk_driver.gen_driver); -} - -MODULE_ALIAS("ide:*m-disk*"); -module_init(idedisk_init); -module_exit(idedisk_exit); -MODULE_LICENSE("GPL"); +const struct ide_disk_ops ide_ata_disk_ops = { + .check = ide_disk_check, + .get_capacity = ide_disk_get_capacity, + .setup = ide_disk_setup, + .flush = ide_disk_flush, + .init_media = ide_disk_init_media, + .set_doorlock = ide_disk_set_doorlock, + .do_request = ide_do_rw_disk, + .ioctl = ide_disk_ioctl, +};