blob: 70b75f23a70e436d5ebd2be2ab6c3697c4b8d0df [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Bartlomiej Zolnierkiewicz59bca8c2008-02-01 23:09:33 +01002 * Copyright (C) 1994-1998 Linus Torvalds & authors (see below)
3 * Copyright (C) 1998-2002 Linux ATA Development
4 * Andre Hedrick <andre@linux-ide.org>
5 * Copyright (C) 2003 Red Hat <alan@redhat.com>
6 * Copyright (C) 2003-2005, 2007 Bartlomiej Zolnierkiewicz
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 */
8
9/*
10 * Mostly written by Mark Lord <mlord@pobox.com>
11 * and Gadi Oxman <gadio@netvision.net.il>
12 * and Andre Hedrick <andre@linux-ide.org>
13 *
14 * This is the IDE/ATA disk driver, as evolved from hd.c and ide.c.
Linus Torvalds1da177e2005-04-16 15:20:36 -070015 */
16
17#define IDEDISK_VERSION "1.18"
18
Linus Torvalds1da177e2005-04-16 15:20:36 -070019#include <linux/module.h>
20#include <linux/types.h>
21#include <linux/string.h>
22#include <linux/kernel.h>
23#include <linux/timer.h>
24#include <linux/mm.h>
25#include <linux/interrupt.h>
26#include <linux/major.h>
27#include <linux/errno.h>
28#include <linux/genhd.h>
29#include <linux/slab.h>
30#include <linux/delay.h>
Arjan van de Vencf8b8972006-03-23 03:00:45 -080031#include <linux/mutex.h>
Richard Purdie2bfb6462006-03-31 02:31:16 -080032#include <linux/leds.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#include <linux/ide.h>
Bartlomiej Zolnierkiewicz3ceca722008-10-10 22:39:27 +020034#include <linux/hdreg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070035
36#include <asm/byteorder.h>
37#include <asm/irq.h>
38#include <asm/uaccess.h>
39#include <asm/io.h>
40#include <asm/div64.h>
41
Tejun Heo870d6652008-08-25 19:47:25 +090042#if !defined(CONFIG_DEBUG_BLOCK_EXT_DEVT)
Tejun Heo689d6fa2008-08-25 19:56:16 +090043#define IDE_DISK_MINORS (1 << PARTN_BITS)
Tejun Heo870d6652008-08-25 19:47:25 +090044#else
Tejun Heo3e1a7ff2008-08-25 19:56:17 +090045#define IDE_DISK_MINORS 0
Tejun Heo870d6652008-08-25 19:47:25 +090046#endif
47
Bartlomiej Zolnierkiewiczf8790482008-10-13 21:39:45 +020048#include "ide-disk.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070049
Arjan van de Vencf8b8972006-03-23 03:00:45 -080050static DEFINE_MUTEX(idedisk_ref_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -070051
Bartlomiej Zolnierkiewicz08da5912008-07-24 22:53:15 +020052static void ide_disk_release(struct kref *);
53
Linus Torvalds1da177e2005-04-16 15:20:36 -070054static struct ide_disk_obj *ide_disk_get(struct gendisk *disk)
55{
56 struct ide_disk_obj *idkp = NULL;
57
Arjan van de Vencf8b8972006-03-23 03:00:45 -080058 mutex_lock(&idedisk_ref_mutex);
Bartlomiej Zolnierkiewiczd7e74752008-10-17 18:09:09 +020059 idkp = ide_drv_g(disk, ide_disk_obj);
Bartlomiej Zolnierkiewicz08da5912008-07-24 22:53:15 +020060 if (idkp) {
Bartlomiej Zolnierkiewiczd3e33ff2008-08-05 18:16:59 +020061 if (ide_device_get(idkp->drive))
Bartlomiej Zolnierkiewicz08da5912008-07-24 22:53:15 +020062 idkp = NULL;
Bartlomiej Zolnierkiewiczd3e33ff2008-08-05 18:16:59 +020063 else
64 kref_get(&idkp->kref);
Bartlomiej Zolnierkiewicz08da5912008-07-24 22:53:15 +020065 }
Arjan van de Vencf8b8972006-03-23 03:00:45 -080066 mutex_unlock(&idedisk_ref_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -070067 return idkp;
68}
69
Linus Torvalds1da177e2005-04-16 15:20:36 -070070static void ide_disk_put(struct ide_disk_obj *idkp)
71{
Bartlomiej Zolnierkiewiczd3e33ff2008-08-05 18:16:59 +020072 ide_drive_t *drive = idkp->drive;
73
Arjan van de Vencf8b8972006-03-23 03:00:45 -080074 mutex_lock(&idedisk_ref_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -070075 kref_put(&idkp->kref, ide_disk_release);
Bartlomiej Zolnierkiewiczd3e33ff2008-08-05 18:16:59 +020076 ide_device_put(drive);
Arjan van de Vencf8b8972006-03-23 03:00:45 -080077 mutex_unlock(&idedisk_ref_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -070078}
79
Bartlomiej Zolnierkiewiczba76ae32008-01-25 22:17:16 +010080static const u8 ide_rw_cmds[] = {
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +020081 ATA_CMD_READ_MULTI,
82 ATA_CMD_WRITE_MULTI,
83 ATA_CMD_READ_MULTI_EXT,
84 ATA_CMD_WRITE_MULTI_EXT,
85 ATA_CMD_PIO_READ,
86 ATA_CMD_PIO_WRITE,
87 ATA_CMD_PIO_READ_EXT,
88 ATA_CMD_PIO_WRITE_EXT,
89 ATA_CMD_READ,
90 ATA_CMD_WRITE,
91 ATA_CMD_READ_EXT,
92 ATA_CMD_WRITE_EXT,
Bartlomiej Zolnierkiewiczba76ae32008-01-25 22:17:16 +010093};
94
95static const u8 ide_data_phases[] = {
96 TASKFILE_MULTI_IN,
97 TASKFILE_MULTI_OUT,
98 TASKFILE_IN,
99 TASKFILE_OUT,
100 TASKFILE_IN_DMA,
101 TASKFILE_OUT_DMA,
102};
103
104static void ide_tf_set_cmd(ide_drive_t *drive, ide_task_t *task, u8 dma)
105{
106 u8 index, lba48, write;
107
108 lba48 = (task->tf_flags & IDE_TFLAG_LBA48) ? 2 : 0;
109 write = (task->tf_flags & IDE_TFLAG_WRITE) ? 1 : 0;
110
111 if (dma)
Bartlomiej Zolnierkiewiczba4b2e62008-07-23 19:55:55 +0200112 index = 8;
Bartlomiej Zolnierkiewiczba76ae32008-01-25 22:17:16 +0100113 else
114 index = drive->mult_count ? 0 : 4;
115
116 task->tf.command = ide_rw_cmds[index + lba48 + write];
117
118 if (dma)
119 index = 8; /* fixup index */
120
121 task->data_phase = ide_data_phases[index / 2 + write];
122}
123
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124/*
125 * __ide_do_rw_disk() issues READ and WRITE commands to a disk,
126 * using LBA if supported, or CHS otherwise, to address sectors.
127 */
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200128static ide_startstop_t __ide_do_rw_disk(ide_drive_t *drive, struct request *rq,
129 sector_t block)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130{
131 ide_hwif_t *hwif = HWIF(drive);
Bartlomiej Zolnierkiewicz790d1232008-01-25 22:17:12 +0100132 u16 nsectors = (u16)rq->nr_sectors;
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200133 u8 lba48 = !!(drive->dev_flags & IDE_DFLAG_LBA48);
134 u8 dma = !!(drive->dev_flags & IDE_DFLAG_USING_DMA);
Bartlomiej Zolnierkiewicz9e422372008-01-25 22:17:07 +0100135 ide_task_t task;
136 struct ide_taskfile *tf = &task.tf;
Bartlomiej Zolnierkiewiczf6e29e32008-01-25 22:17:16 +0100137 ide_startstop_t rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138
Bartlomiej Zolnierkiewicz238e4f12007-10-19 00:30:07 +0200139 if ((hwif->host_flags & IDE_HFLAG_NO_LBA48_DMA) && lba48 && dma) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140 if (block + rq->nr_sectors > 1ULL << 28)
141 dma = 0;
142 else
143 lba48 = 0;
144 }
145
146 if (!dma) {
147 ide_init_sg_cmd(drive, rq);
148 ide_map_sg(drive, rq);
149 }
150
Bartlomiej Zolnierkiewicz9e422372008-01-25 22:17:07 +0100151 memset(&task, 0, sizeof(task));
Bartlomiej Zolnierkiewicz9a410e72008-07-15 21:21:48 +0200152 task.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
Bartlomiej Zolnierkiewicz2bd06b22008-01-25 22:17:06 +0100153
Bartlomiej Zolnierkiewiczd1d76712008-10-13 21:39:38 +0200154 if (drive->dev_flags & IDE_DFLAG_LBA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155 if (lba48) {
Michael Richardsonc2f83112006-02-07 12:58:33 -0800156 pr_debug("%s: LBA=0x%012llx\n", drive->name,
157 (unsigned long long)block);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158
Bartlomiej Zolnierkiewicz790d1232008-01-25 22:17:12 +0100159 tf->hob_nsect = (nsectors >> 8) & 0xff;
Bartlomiej Zolnierkiewicz2bd06b22008-01-25 22:17:06 +0100160 tf->hob_lbal = (u8)(block >> 24);
161 if (sizeof(block) != 4) {
162 tf->hob_lbam = (u8)((u64)block >> 32);
163 tf->hob_lbah = (u8)((u64)block >> 40);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164 }
Bartlomiej Zolnierkiewicz2bd06b22008-01-25 22:17:06 +0100165
Bartlomiej Zolnierkiewicz790d1232008-01-25 22:17:12 +0100166 tf->nsect = nsectors & 0xff;
Bartlomiej Zolnierkiewicz2bd06b22008-01-25 22:17:06 +0100167 tf->lbal = (u8) block;
168 tf->lbam = (u8)(block >> 8);
169 tf->lbah = (u8)(block >> 16);
Bartlomiej Zolnierkiewicz6dd9b832008-01-26 20:13:03 +0100170
Bartlomiej Zolnierkiewicz657cc1a2008-01-26 20:13:10 +0100171 task.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_HOB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 } else {
Bartlomiej Zolnierkiewicz790d1232008-01-25 22:17:12 +0100173 tf->nsect = nsectors & 0xff;
Bartlomiej Zolnierkiewicz2bd06b22008-01-25 22:17:06 +0100174 tf->lbal = block;
175 tf->lbam = block >>= 8;
176 tf->lbah = block >>= 8;
177 tf->device = (block >> 8) & 0xf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178 }
Bartlomiej Zolnierkiewiczd1d76712008-10-13 21:39:38 +0200179
180 tf->device |= ATA_LBA;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181 } else {
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200182 unsigned int sect, head, cyl, track;
183
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184 track = (int)block / drive->sect;
185 sect = (int)block % drive->sect + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186 head = track % drive->head;
187 cyl = track / drive->head;
188
189 pr_debug("%s: CHS=%u/%u/%u\n", drive->name, cyl, head, sect);
190
Bartlomiej Zolnierkiewicz790d1232008-01-25 22:17:12 +0100191 tf->nsect = nsectors & 0xff;
Bartlomiej Zolnierkiewicz2bd06b22008-01-25 22:17:06 +0100192 tf->lbal = sect;
193 tf->lbam = cyl;
194 tf->lbah = cyl >> 8;
195 tf->device = head;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196 }
197
Bartlomiej Zolnierkiewiczba76ae32008-01-25 22:17:16 +0100198 if (rq_data_dir(rq))
199 task.tf_flags |= IDE_TFLAG_WRITE;
200
201 ide_tf_set_cmd(drive, &task, dma);
Bartlomiej Zolnierkiewiczf6e29e32008-01-25 22:17:16 +0100202 if (!dma)
203 hwif->data_phase = task.data_phase;
204 task.rq = rq;
Bartlomiej Zolnierkiewiczba76ae32008-01-25 22:17:16 +0100205
Bartlomiej Zolnierkiewiczf6e29e32008-01-25 22:17:16 +0100206 rc = do_rw_taskfile(drive, &task);
Bartlomiej Zolnierkiewicz2bd06b22008-01-25 22:17:06 +0100207
Bartlomiej Zolnierkiewiczf6e29e32008-01-25 22:17:16 +0100208 if (rc == ide_stopped && dma) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 /* fallback to PIO */
Bartlomiej Zolnierkiewiczf6e29e32008-01-25 22:17:16 +0100210 task.tf_flags |= IDE_TFLAG_DMA_PIO_FALLBACK;
Bartlomiej Zolnierkiewiczba76ae32008-01-25 22:17:16 +0100211 ide_tf_set_cmd(drive, &task, 0);
Bartlomiej Zolnierkiewiczf6e29e32008-01-25 22:17:16 +0100212 hwif->data_phase = task.data_phase;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 ide_init_sg_cmd(drive, rq);
Bartlomiej Zolnierkiewiczf6e29e32008-01-25 22:17:16 +0100214 rc = do_rw_taskfile(drive, &task);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 }
216
Bartlomiej Zolnierkiewiczf6e29e32008-01-25 22:17:16 +0100217 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218}
219
220/*
221 * 268435455 == 137439 MB or 28bit limit
222 * 320173056 == 163929 MB or 48bit addressing
223 * 1073741822 == 549756 MB or 48bit addressing fake drive
224 */
225
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200226static ide_startstop_t ide_do_rw_disk(ide_drive_t *drive, struct request *rq,
227 sector_t block)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228{
229 ide_hwif_t *hwif = HWIF(drive);
230
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200231 BUG_ON(drive->dev_flags & IDE_DFLAG_BLOCKED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232
233 if (!blk_fs_request(rq)) {
234 blk_dump_rq_flags(rq, "ide_do_rw_disk - bad command");
235 ide_end_request(drive, 0, 0);
236 return ide_stopped;
237 }
238
Richard Purdie2bfb6462006-03-31 02:31:16 -0800239 ledtrig_ide_activity();
240
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241 pr_debug("%s: %sing: block=%llu, sectors=%lu, buffer=0x%08lx\n",
242 drive->name, rq_data_dir(rq) == READ ? "read" : "writ",
Michael Richardsonc2f83112006-02-07 12:58:33 -0800243 (unsigned long long)block, rq->nr_sectors,
244 (unsigned long)rq->buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245
246 if (hwif->rw_disk)
247 hwif->rw_disk(drive, rq);
248
249 return __ide_do_rw_disk(drive, rq, block);
250}
251
252/*
253 * Queries for true maximum capacity of the drive.
254 * Returns maximum LBA address (> 0) of the drive, 0 if failed.
255 */
Bartlomiej Zolnierkiewicz7a3b7512008-01-25 22:17:06 +0100256static u64 idedisk_read_native_max_address(ide_drive_t *drive, int lba48)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257{
258 ide_task_t args;
Bartlomiej Zolnierkiewicz650d8412008-01-25 22:17:06 +0100259 struct ide_taskfile *tf = &args.tf;
Bartlomiej Zolnierkiewicz7a3b7512008-01-25 22:17:06 +0100260 u64 addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261
262 /* Create IDE/ATA command request structure */
263 memset(&args, 0, sizeof(ide_task_t));
Bartlomiej Zolnierkiewicz7a3b7512008-01-25 22:17:06 +0100264 if (lba48)
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200265 tf->command = ATA_CMD_READ_NATIVE_MAX_EXT;
Bartlomiej Zolnierkiewicz7a3b7512008-01-25 22:17:06 +0100266 else
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200267 tf->command = ATA_CMD_READ_NATIVE_MAX;
Bartlomiej Zolnierkiewicz650d8412008-01-25 22:17:06 +0100268 tf->device = ATA_LBA;
Bartlomiej Zolnierkiewicz657cc1a2008-01-26 20:13:10 +0100269 args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
Bartlomiej Zolnierkiewicza3bbb9d2008-01-25 22:17:10 +0100270 if (lba48)
Bartlomiej Zolnierkiewicz657cc1a2008-01-26 20:13:10 +0100271 args.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_HOB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 /* submit command request */
Bartlomiej Zolnierkiewicz9a3c49b2008-01-25 22:17:07 +0100273 ide_no_data_taskfile(drive, &args);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274
275 /* if OK, compute maximum address value */
Bartlomiej Zolnierkiewicza5016332008-01-25 22:17:17 +0100276 if ((tf->status & 0x01) == 0)
277 addr = ide_get_lba_addr(tf, lba48) + 1;
Bartlomiej Zolnierkiewicz650d8412008-01-25 22:17:06 +0100278
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279 return addr;
280}
281
282/*
283 * Sets maximum virtual LBA address of the drive.
284 * Returns new maximum virtual LBA address (> 0) or 0 on failure.
285 */
Bartlomiej Zolnierkiewicz7a3b7512008-01-25 22:17:06 +0100286static u64 idedisk_set_max_address(ide_drive_t *drive, u64 addr_req, int lba48)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287{
288 ide_task_t args;
Bartlomiej Zolnierkiewicz650d8412008-01-25 22:17:06 +0100289 struct ide_taskfile *tf = &args.tf;
Bartlomiej Zolnierkiewicz7a3b7512008-01-25 22:17:06 +0100290 u64 addr_set = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291
292 addr_req--;
293 /* Create IDE/ATA command request structure */
294 memset(&args, 0, sizeof(ide_task_t));
Bartlomiej Zolnierkiewicz650d8412008-01-25 22:17:06 +0100295 tf->lbal = (addr_req >> 0) & 0xff;
296 tf->lbam = (addr_req >>= 8) & 0xff;
297 tf->lbah = (addr_req >>= 8) & 0xff;
Bartlomiej Zolnierkiewicz7a3b7512008-01-25 22:17:06 +0100298 if (lba48) {
299 tf->hob_lbal = (addr_req >>= 8) & 0xff;
300 tf->hob_lbam = (addr_req >>= 8) & 0xff;
301 tf->hob_lbah = (addr_req >>= 8) & 0xff;
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200302 tf->command = ATA_CMD_SET_MAX_EXT;
Bartlomiej Zolnierkiewicz7a3b7512008-01-25 22:17:06 +0100303 } else {
304 tf->device = (addr_req >>= 8) & 0x0f;
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200305 tf->command = ATA_CMD_SET_MAX;
Bartlomiej Zolnierkiewicz7a3b7512008-01-25 22:17:06 +0100306 }
307 tf->device |= ATA_LBA;
Bartlomiej Zolnierkiewicz657cc1a2008-01-26 20:13:10 +0100308 args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
Bartlomiej Zolnierkiewicza3bbb9d2008-01-25 22:17:10 +0100309 if (lba48)
Bartlomiej Zolnierkiewicz657cc1a2008-01-26 20:13:10 +0100310 args.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_HOB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 /* submit command request */
Bartlomiej Zolnierkiewicz9a3c49b2008-01-25 22:17:07 +0100312 ide_no_data_taskfile(drive, &args);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313 /* if OK, compute maximum address value */
Bartlomiej Zolnierkiewicza5016332008-01-25 22:17:17 +0100314 if ((tf->status & 0x01) == 0)
315 addr_set = ide_get_lba_addr(tf, lba48) + 1;
Bartlomiej Zolnierkiewicz650d8412008-01-25 22:17:06 +0100316
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317 return addr_set;
318}
319
320static unsigned long long sectors_to_MB(unsigned long long n)
321{
322 n <<= 9; /* make it bytes */
323 do_div(n, 1000000); /* make it MB */
324 return n;
325}
326
327/*
Bartlomiej Zolnierkiewiczb0244a02007-08-20 22:42:57 +0200328 * Some disks report total number of sectors instead of
329 * maximum sector address. We list them here.
330 */
331static const struct drive_list_entry hpa_list[] = {
332 { "ST340823A", NULL },
Jorge Juan Chico7062cdc2007-09-17 12:35:30 +0200333 { "ST320413A", NULL },
Mikko Rapelib152fcd2008-02-19 01:41:25 +0100334 { "ST310211A", NULL },
Bartlomiej Zolnierkiewiczb0244a02007-08-20 22:42:57 +0200335 { NULL, NULL }
336};
337
Arjan van de Ven858119e2006-01-14 13:20:43 -0800338static void idedisk_check_hpa(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339{
340 unsigned long long capacity, set_max;
Bartlomiej Zolnierkiewicz942dcd82008-10-10 22:39:30 +0200341 int lba48 = ata_id_lba48_enabled(drive->id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342
343 capacity = drive->capacity64;
Bartlomiej Zolnierkiewicz7a3b7512008-01-25 22:17:06 +0100344
345 set_max = idedisk_read_native_max_address(drive, lba48);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346
Bartlomiej Zolnierkiewiczb0244a02007-08-20 22:42:57 +0200347 if (ide_in_drive_list(drive->id, hpa_list)) {
348 /*
349 * Since we are inclusive wrt to firmware revisions do this
350 * extra check and apply the workaround only when needed.
351 */
352 if (set_max == capacity + 1)
353 set_max--;
354 }
355
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 if (set_max <= capacity)
357 return;
358
359 printk(KERN_INFO "%s: Host Protected Area detected.\n"
360 "\tcurrent capacity is %llu sectors (%llu MB)\n"
361 "\tnative capacity is %llu sectors (%llu MB)\n",
362 drive->name,
363 capacity, sectors_to_MB(capacity),
364 set_max, sectors_to_MB(set_max));
365
Bartlomiej Zolnierkiewicz7a3b7512008-01-25 22:17:06 +0100366 set_max = idedisk_set_max_address(drive, set_max, lba48);
367
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 if (set_max) {
369 drive->capacity64 = set_max;
370 printk(KERN_INFO "%s: Host Protected Area disabled.\n",
371 drive->name);
372 }
373}
374
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200375static void init_idedisk_capacity(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376{
Bartlomiej Zolnierkiewicz4dde4492008-10-10 22:39:19 +0200377 u16 *id = drive->id;
Bartlomiej Zolnierkiewiczd1d76712008-10-13 21:39:38 +0200378 int lba;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379
Bartlomiej Zolnierkiewicz942dcd82008-10-10 22:39:30 +0200380 if (ata_id_lba48_enabled(id)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381 /* drive speaks 48-bit LBA */
Bartlomiej Zolnierkiewiczd1d76712008-10-13 21:39:38 +0200382 lba = 1;
Bartlomiej Zolnierkiewicz48fb2682008-10-10 22:39:19 +0200383 drive->capacity64 = ata_id_u64(id, ATA_ID_LBA_CAPACITY_2);
Bartlomiej Zolnierkiewicza02227c2008-10-10 22:39:31 +0200384 } else if (ata_id_has_lba(id) && ata_id_is_lba_capacity_ok(id)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 /* drive speaks 28-bit LBA */
Bartlomiej Zolnierkiewiczd1d76712008-10-13 21:39:38 +0200386 lba = 1;
Bartlomiej Zolnierkiewicz48fb2682008-10-10 22:39:19 +0200387 drive->capacity64 = ata_id_u32(id, ATA_ID_LBA_CAPACITY);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 } else {
389 /* drive speaks boring old 28-bit CHS */
Bartlomiej Zolnierkiewiczd1d76712008-10-13 21:39:38 +0200390 lba = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 drive->capacity64 = drive->cyl * drive->head * drive->sect;
392 }
Bartlomiej Zolnierkiewiczd1d76712008-10-13 21:39:38 +0200393
394 if (lba) {
395 drive->dev_flags |= IDE_DFLAG_LBA;
396
397 /*
398 * If this device supports the Host Protected Area feature set,
399 * then we may need to change our opinion about its capacity.
400 */
401 if (ata_id_hpa_enabled(id))
402 idedisk_check_hpa(drive);
403 }
Bartlomiej Zolnierkiewicz0a70c7f2008-10-17 18:09:09 +0200404
405 /* limit drive capacity to 137GB if LBA48 cannot be used */
406 if ((drive->dev_flags & IDE_DFLAG_LBA48) == 0 &&
407 drive->capacity64 > 1ULL << 28) {
408 printk(KERN_WARNING "%s: cannot use LBA48 - full capacity "
409 "%llu sectors (%llu MB)\n",
410 drive->name, (unsigned long long)drive->capacity64,
411 sectors_to_MB(drive->capacity64));
412 drive->capacity64 = 1ULL << 28;
413 }
414
415 if ((drive->hwif->host_flags & IDE_HFLAG_NO_LBA48_DMA) &&
416 (drive->dev_flags & IDE_DFLAG_LBA48)) {
417 if (drive->capacity64 > 1ULL << 28) {
418 printk(KERN_INFO "%s: cannot use LBA48 DMA - PIO mode"
419 " will be used for accessing sectors "
420 "> %u\n", drive->name, 1 << 28);
421 } else
422 drive->dev_flags &= ~IDE_DFLAG_LBA48;
423 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424}
425
Bartlomiej Zolnierkiewicz06b89512008-10-13 21:39:45 +0200426sector_t ide_disk_capacity(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427{
Bartlomiej Zolnierkiewicz3c619ff2008-10-10 22:39:22 +0200428 return drive->capacity64;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429}
430
Jens Axboe165125e2007-07-24 09:28:11 +0200431static void idedisk_prepare_flush(struct request_queue *q, struct request *rq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432{
433 ide_drive_t *drive = q->queuedata;
Bartlomiej Zolnierkiewicz395d8ef2008-02-11 00:32:14 +0100434 ide_task_t *task = kmalloc(sizeof(*task), GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435
Bartlomiej Zolnierkiewicz395d8ef2008-02-11 00:32:14 +0100436 /* FIXME: map struct ide_taskfile on rq->cmd[] */
437 BUG_ON(task == NULL);
438
439 memset(task, 0, sizeof(*task));
Bartlomiej Zolnierkiewiczff2779b2008-10-10 22:39:31 +0200440 if (ata_id_flush_ext_enabled(drive->id) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 (drive->capacity64 >= (1UL << 28)))
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200442 task->tf.command = ATA_CMD_FLUSH_EXT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 else
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200444 task->tf.command = ATA_CMD_FLUSH;
Bartlomiej Zolnierkiewicz395d8ef2008-02-11 00:32:14 +0100445 task->tf_flags = IDE_TFLAG_OUT_TF | IDE_TFLAG_OUT_DEVICE |
446 IDE_TFLAG_DYN;
447 task->data_phase = TASKFILE_NO_DATA;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448
Bartlomiej Zolnierkiewicz813a0eb2008-01-25 22:17:10 +0100449 rq->cmd_type = REQ_TYPE_ATA_TASKFILE;
Jens Axboe4aff5e22006-08-10 08:44:47 +0200450 rq->cmd_flags |= REQ_SOFTBARRIER;
Bartlomiej Zolnierkiewicz395d8ef2008-02-11 00:32:14 +0100451 rq->special = task;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452}
453
Bartlomiej Zolnierkiewicz8185d5a2008-10-10 22:39:28 +0200454ide_devset_get(multcount, mult_count);
455
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456/*
457 * This is tightly woven into the driver->do_special can not touch.
458 * DON'T do it again until a total personality rewrite is committed.
459 */
460static int set_multcount(ide_drive_t *drive, int arg)
461{
FUJITA Tomonoridd470872008-07-15 21:21:43 +0200462 struct request *rq;
463 int error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464
Bartlomiej Zolnierkiewicz48fb2682008-10-10 22:39:19 +0200465 if (arg < 0 || arg > (drive->id[ATA_ID_MAX_MULTSECT] & 0xff))
Bartlomiej Zolnierkiewicz14979432007-05-10 00:01:10 +0200466 return -EINVAL;
467
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 if (drive->special.b.set_multmode)
469 return -EBUSY;
Bartlomiej Zolnierkiewicz852738f2008-01-26 20:13:12 +0100470
FUJITA Tomonoridd470872008-07-15 21:21:43 +0200471 rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
472 rq->cmd_type = REQ_TYPE_ATA_TASKFILE;
Bartlomiej Zolnierkiewicz852738f2008-01-26 20:13:12 +0100473
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474 drive->mult_req = arg;
475 drive->special.b.set_multmode = 1;
FUJITA Tomonoridd470872008-07-15 21:21:43 +0200476 error = blk_execute_rq(drive->queue, NULL, rq, 0);
477 blk_put_request(rq);
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200478
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479 return (drive->mult_count == arg) ? 0 : -EIO;
480}
481
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200482ide_devset_get_flag(nowerr, IDE_DFLAG_NOWERR);
Bartlomiej Zolnierkiewicz8185d5a2008-10-10 22:39:28 +0200483
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484static int set_nowerr(ide_drive_t *drive, int arg)
485{
Bartlomiej Zolnierkiewicz14979432007-05-10 00:01:10 +0200486 if (arg < 0 || arg > 1)
487 return -EINVAL;
488
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200489 if (arg)
490 drive->dev_flags |= IDE_DFLAG_NOWERR;
491 else
492 drive->dev_flags &= ~IDE_DFLAG_NOWERR;
493
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 drive->bad_wstat = arg ? BAD_R_STAT : BAD_W_STAT;
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200495
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496 return 0;
497}
498
Bartlomiej Zolnierkiewiczbe3c0962008-10-13 21:39:36 +0200499static int ide_do_setfeature(ide_drive_t *drive, u8 feature, u8 nsect)
500{
501 ide_task_t task;
502
503 memset(&task, 0, sizeof(task));
504 task.tf.feature = feature;
505 task.tf.nsect = nsect;
506 task.tf.command = ATA_CMD_SET_FEATURES;
507 task.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
508
509 return ide_no_data_taskfile(drive, &task);
510}
511
Tejun Heo3e087b52006-01-06 09:57:31 +0100512static void update_ordered(ide_drive_t *drive)
513{
Bartlomiej Zolnierkiewicz4dde4492008-10-10 22:39:19 +0200514 u16 *id = drive->id;
Tejun Heo3e087b52006-01-06 09:57:31 +0100515 unsigned ordered = QUEUE_ORDERED_NONE;
516 prepare_flush_fn *prep_fn = NULL;
Tejun Heo3e087b52006-01-06 09:57:31 +0100517
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200518 if (drive->dev_flags & IDE_DFLAG_WCACHE) {
Tejun Heo3e087b52006-01-06 09:57:31 +0100519 unsigned long long capacity;
520 int barrier;
521 /*
522 * We must avoid issuing commands a drive does not
523 * understand or we may crash it. We check flush cache
524 * is supported. We also check we have the LBA48 flush
525 * cache if the drive capacity is too large. By this
526 * time we have trimmed the drive capacity if LBA48 is
527 * not available so we don't need to recheck that.
528 */
Bartlomiej Zolnierkiewicz06b89512008-10-13 21:39:45 +0200529 capacity = ide_disk_capacity(drive);
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200530 barrier = ata_id_flush_enabled(id) &&
531 (drive->dev_flags & IDE_DFLAG_NOFLUSH) == 0 &&
532 ((drive->dev_flags & IDE_DFLAG_LBA48) == 0 ||
533 capacity <= (1ULL << 28) ||
Bartlomiej Zolnierkiewiczff2779b2008-10-10 22:39:31 +0200534 ata_id_flush_ext_enabled(id));
Tejun Heo3e087b52006-01-06 09:57:31 +0100535
536 printk(KERN_INFO "%s: cache flushes %ssupported\n",
Jean Delvaref7ad8362006-02-03 03:04:57 -0800537 drive->name, barrier ? "" : "not ");
Tejun Heo3e087b52006-01-06 09:57:31 +0100538
539 if (barrier) {
540 ordered = QUEUE_ORDERED_DRAIN_FLUSH;
541 prep_fn = idedisk_prepare_flush;
Tejun Heo3e087b52006-01-06 09:57:31 +0100542 }
543 } else
544 ordered = QUEUE_ORDERED_DRAIN;
545
546 blk_queue_ordered(drive->queue, ordered, prep_fn);
Tejun Heo3e087b52006-01-06 09:57:31 +0100547}
548
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200549ide_devset_get_flag(wcache, IDE_DFLAG_WCACHE);
Bartlomiej Zolnierkiewicz8185d5a2008-10-10 22:39:28 +0200550
551static int set_wcache(ide_drive_t *drive, int arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552{
Tejun Heo3e087b52006-01-06 09:57:31 +0100553 int err = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554
Bartlomiej Zolnierkiewicz14979432007-05-10 00:01:10 +0200555 if (arg < 0 || arg > 1)
556 return -EINVAL;
557
Bartlomiej Zolnierkiewicz4b58f172008-10-10 22:39:30 +0200558 if (ata_id_flush_enabled(drive->id)) {
Bartlomiej Zolnierkiewiczbe3c0962008-10-13 21:39:36 +0200559 err = ide_do_setfeature(drive,
560 arg ? SETFEATURES_WC_ON : SETFEATURES_WC_OFF, 0);
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200561 if (err == 0) {
562 if (arg)
563 drive->dev_flags |= IDE_DFLAG_WCACHE;
564 else
565 drive->dev_flags &= ~IDE_DFLAG_WCACHE;
566 }
Tejun Heo3e087b52006-01-06 09:57:31 +0100567 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568
Tejun Heo3e087b52006-01-06 09:57:31 +0100569 update_ordered(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570
Tejun Heo3e087b52006-01-06 09:57:31 +0100571 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572}
573
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200574static int do_idedisk_flushcache(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575{
576 ide_task_t args;
577
578 memset(&args, 0, sizeof(ide_task_t));
Bartlomiej Zolnierkiewiczff2779b2008-10-10 22:39:31 +0200579 if (ata_id_flush_ext_enabled(drive->id))
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200580 args.tf.command = ATA_CMD_FLUSH_EXT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 else
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200582 args.tf.command = ATA_CMD_FLUSH;
Bartlomiej Zolnierkiewicz657cc1a2008-01-26 20:13:10 +0100583 args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
Bartlomiej Zolnierkiewicz9a3c49b2008-01-25 22:17:07 +0100584 return ide_no_data_taskfile(drive, &args);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585}
586
Bartlomiej Zolnierkiewicz8185d5a2008-10-10 22:39:28 +0200587ide_devset_get(acoustic, acoustic);
588
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200589static int set_acoustic(ide_drive_t *drive, int arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590{
Bartlomiej Zolnierkiewicz14979432007-05-10 00:01:10 +0200591 if (arg < 0 || arg > 254)
592 return -EINVAL;
593
Bartlomiej Zolnierkiewiczbe3c0962008-10-13 21:39:36 +0200594 ide_do_setfeature(drive,
595 arg ? SETFEATURES_AAM_ON : SETFEATURES_AAM_OFF, arg);
596
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 drive->acoustic = arg;
Bartlomiej Zolnierkiewiczbe3c0962008-10-13 21:39:36 +0200598
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 return 0;
600}
601
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200602ide_devset_get_flag(addressing, IDE_DFLAG_LBA48);
Bartlomiej Zolnierkiewicz8185d5a2008-10-10 22:39:28 +0200603
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604/*
605 * drive->addressing:
606 * 0: 28-bit
607 * 1: 48-bit
608 * 2: 48-bit capable doing 28-bit
609 */
Bartlomiej Zolnierkiewiczaa7687732008-10-10 22:39:33 +0200610static int set_addressing(ide_drive_t *drive, int arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611{
Bartlomiej Zolnierkiewicz14979432007-05-10 00:01:10 +0200612 if (arg < 0 || arg > 2)
613 return -EINVAL;
614
Bartlomiej Zolnierkiewicz35c13752008-10-13 21:39:36 +0200615 if (arg && ((drive->hwif->host_flags & IDE_HFLAG_NO_LBA48) ||
616 ata_id_lba48_enabled(drive->id) == 0))
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200617 return -EIO;
Bartlomiej Zolnierkiewicz942dcd82008-10-10 22:39:30 +0200618
Bartlomiej Zolnierkiewicz35c13752008-10-13 21:39:36 +0200619 if (arg == 2)
620 arg = 0;
621
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200622 if (arg)
623 drive->dev_flags |= IDE_DFLAG_LBA48;
624 else
625 drive->dev_flags &= ~IDE_DFLAG_LBA48;
Bartlomiej Zolnierkiewicz942dcd82008-10-10 22:39:30 +0200626
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 return 0;
628}
629
Bartlomiej Zolnierkiewiczf8790482008-10-13 21:39:45 +0200630ide_ext_devset_rw(acoustic, acoustic);
631ide_ext_devset_rw(address, addressing);
632ide_ext_devset_rw(multcount, multcount);
633ide_ext_devset_rw(wcache, wcache);
Elias Oltmanns92f1f8f2008-10-10 22:39:40 +0200634
Bartlomiej Zolnierkiewiczf8790482008-10-13 21:39:45 +0200635ide_ext_devset_rw_sync(nowerr, nowerr);
Elias Oltmanns92f1f8f2008-10-10 22:39:40 +0200636
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200637static void idedisk_setup(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638{
Bartlomiej Zolnierkiewicz1e874f42008-10-10 22:39:27 +0200639 struct ide_disk_obj *idkp = drive->driver_data;
Bartlomiej Zolnierkiewicz238e4f12007-10-19 00:30:07 +0200640 ide_hwif_t *hwif = drive->hwif;
Bartlomiej Zolnierkiewicz4dde4492008-10-10 22:39:19 +0200641 u16 *id = drive->id;
642 char *m = (char *)&id[ATA_ID_PROD];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 unsigned long long capacity;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644
Bartlomiej Zolnierkiewicz1e874f42008-10-10 22:39:27 +0200645 ide_proc_register_driver(drive, idkp->driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200647 if ((drive->dev_flags & IDE_DFLAG_ID_READ) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 return;
649
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200650 if (drive->dev_flags & IDE_DFLAG_REMOVABLE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651 /*
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200652 * Removable disks (eg. SYQUEST); ignore 'WD' drives
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 */
Bartlomiej Zolnierkiewicz4dde4492008-10-10 22:39:19 +0200654 if (m[0] != 'W' || m[1] != 'D')
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200655 drive->dev_flags |= IDE_DFLAG_DOORLOCKING;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 }
657
Bartlomiej Zolnierkiewiczaa7687732008-10-10 22:39:33 +0200658 (void)set_addressing(drive, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200660 if (drive->dev_flags & IDE_DFLAG_LBA48) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 int max_s = 2048;
662
663 if (max_s > hwif->rqsize)
664 max_s = hwif->rqsize;
665
666 blk_queue_max_sectors(drive->queue, max_s);
667 }
668
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200669 printk(KERN_INFO "%s: max request size: %dKiB\n", drive->name,
670 drive->queue->max_sectors / 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671
672 /* calculate drive capacity, and select LBA if possible */
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200673 init_idedisk_capacity(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 /*
676 * if possible, give fdisk access to more of the drive,
677 * by correcting bios_cyls:
678 */
Bartlomiej Zolnierkiewicz06b89512008-10-13 21:39:45 +0200679 capacity = ide_disk_capacity(drive);
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200680
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200681 if ((drive->dev_flags & IDE_DFLAG_FORCED_GEOM) == 0) {
Bartlomiej Zolnierkiewicz942dcd82008-10-10 22:39:30 +0200682 if (ata_id_lba48_enabled(drive->id)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 /* compatibility */
684 drive->bios_sect = 63;
685 drive->bios_head = 255;
686 }
687
688 if (drive->bios_sect && drive->bios_head) {
689 unsigned int cap0 = capacity; /* truncate to 32 bits */
690 unsigned int cylsz, cyl;
691
692 if (cap0 != capacity)
693 drive->bios_cyl = 65535;
694 else {
695 cylsz = drive->bios_sect * drive->bios_head;
696 cyl = cap0 / cylsz;
697 if (cyl > 65535)
698 cyl = 65535;
699 if (cyl > drive->bios_cyl)
700 drive->bios_cyl = cyl;
701 }
702 }
703 }
704 printk(KERN_INFO "%s: %llu sectors (%llu MB)",
705 drive->name, capacity, sectors_to_MB(capacity));
706
707 /* Only print cache size when it was specified */
Bartlomiej Zolnierkiewicz4dde4492008-10-10 22:39:19 +0200708 if (id[ATA_ID_BUF_SIZE])
709 printk(KERN_CONT " w/%dKiB Cache", id[ATA_ID_BUF_SIZE] / 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710
Bartlomiej Zolnierkiewicz3ab7efe2007-12-12 23:31:58 +0100711 printk(KERN_CONT ", CHS=%d/%d/%d\n",
712 drive->bios_cyl, drive->bios_head, drive->bios_sect);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 /* write cache enabled? */
Bartlomiej Zolnierkiewicz8a089c62008-10-10 22:39:20 +0200715 if ((id[ATA_ID_CSFO] & 1) || ata_id_wcache_enabled(id))
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200716 drive->dev_flags |= IDE_DFLAG_WCACHE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717
Bartlomiej Zolnierkiewicz8185d5a2008-10-10 22:39:28 +0200718 set_wcache(drive, 1);
Bartlomiej Zolnierkiewiczae9f9f02008-10-17 18:09:10 +0200719
720 if ((drive->dev_flags & IDE_DFLAG_LBA) == 0 &&
721 (drive->head == 0 || drive->head > 16)) {
722 printk(KERN_ERR "%s: invalid geometry: %d physical heads?\n",
723 drive->name, drive->head);
724 drive->dev_flags &= ~IDE_DFLAG_ATTACH;
725 } else
726 drive->dev_flags |= IDE_DFLAG_ATTACH;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727}
728
729static void ide_cacheflush_p(ide_drive_t *drive)
730{
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200731 if (ata_id_flush_enabled(drive->id) == 0 ||
732 (drive->dev_flags & IDE_DFLAG_WCACHE) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 return;
734
735 if (do_idedisk_flushcache(drive))
736 printk(KERN_INFO "%s: wcache flush failed!\n", drive->name);
737}
738
Russell King4031bbe2006-01-06 11:41:00 +0000739static void ide_disk_remove(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740{
741 struct ide_disk_obj *idkp = drive->driver_data;
742 struct gendisk *g = idkp->disk;
743
Bartlomiej Zolnierkiewicz7662d042007-05-10 00:01:10 +0200744 ide_proc_unregister_driver(drive, idkp->driver);
Bartlomiej Zolnierkiewicz8604aff2005-05-26 14:55:34 +0200745
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 del_gendisk(g);
747
Bartlomiej Zolnierkiewiczd36fef62005-12-15 02:19:20 +0100748 ide_cacheflush_p(drive);
749
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 ide_disk_put(idkp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751}
752
753static void ide_disk_release(struct kref *kref)
754{
Bartlomiej Zolnierkiewiczd7e74752008-10-17 18:09:09 +0200755 struct ide_disk_obj *idkp = to_ide_drv(kref, ide_disk_obj);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 ide_drive_t *drive = idkp->drive;
757 struct gendisk *g = idkp->disk;
758
759 drive->driver_data = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 g->private_data = NULL;
761 put_disk(g);
762 kfree(idkp);
763}
764
Russell King4031bbe2006-01-06 11:41:00 +0000765static int ide_disk_probe(ide_drive_t *drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766
Lee Trager0d2157f2007-06-08 15:14:30 +0200767/*
768 * On HPA drives the capacity needs to be
769 * reinitilized on resume otherwise the disk
770 * can not be used and a hard reset is required
771 */
772static void ide_disk_resume(ide_drive_t *drive)
773{
Bartlomiej Zolnierkiewiczf41891c2008-10-10 22:39:20 +0200774 if (ata_id_hpa_enabled(drive->id))
Lee Trager0d2157f2007-06-08 15:14:30 +0200775 init_idedisk_capacity(drive);
776}
777
Russell King4031bbe2006-01-06 11:41:00 +0000778static void ide_device_shutdown(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780#ifdef CONFIG_ALPHA
781 /* On Alpha, halt(8) doesn't actually turn the machine off,
782 it puts you into the sort of firmware monitor. Typically,
783 it's used to boot another kernel image, so it's not much
784 different from reboot(8). Therefore, we don't need to
785 spin down the disk in this case, especially since Alpha
786 firmware doesn't handle disks in standby mode properly.
787 On the other hand, it's reasonably safe to turn the power
788 off when the shutdown process reaches the firmware prompt,
789 as the firmware initialization takes rather long time -
790 at least 10 seconds, which should be sufficient for
791 the disk to expire its write cache. */
792 if (system_state != SYSTEM_POWER_OFF) {
793#else
794 if (system_state == SYSTEM_RESTART) {
795#endif
796 ide_cacheflush_p(drive);
797 return;
798 }
799
Bartlomiej Zolnierkiewiczd12faa22008-02-26 21:50:36 +0100800 printk(KERN_INFO "Shutdown: %s\n", drive->name);
801
Russell King4031bbe2006-01-06 11:41:00 +0000802 drive->gendev.bus->suspend(&drive->gendev, PMSG_SUSPEND);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803}
804
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805static ide_driver_t idedisk_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 .gen_driver = {
Laurent Riffard4ef3b8f2005-11-18 22:15:40 +0100807 .owner = THIS_MODULE,
Bartlomiej Zolnierkiewicz8604aff2005-05-26 14:55:34 +0200808 .name = "ide-disk",
809 .bus = &ide_bus_type,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 },
Russell King4031bbe2006-01-06 11:41:00 +0000811 .probe = ide_disk_probe,
812 .remove = ide_disk_remove,
Lee Trager0d2157f2007-06-08 15:14:30 +0200813 .resume = ide_disk_resume,
Russell King4031bbe2006-01-06 11:41:00 +0000814 .shutdown = ide_device_shutdown,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 .version = IDEDISK_VERSION,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 .do_request = ide_do_rw_disk,
817 .end_request = ide_end_request,
818 .error = __ide_error,
Bartlomiej Zolnierkiewicz7662d042007-05-10 00:01:10 +0200819#ifdef CONFIG_IDE_PROC_FS
Bartlomiej Zolnierkiewicz06b89512008-10-13 21:39:45 +0200820 .proc = ide_disk_proc,
821 .settings = ide_disk_settings,
Bartlomiej Zolnierkiewicz7662d042007-05-10 00:01:10 +0200822#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823};
824
Bartlomiej Zolnierkiewicz29ec6832008-01-26 20:12:59 +0100825static int idedisk_set_doorlock(ide_drive_t *drive, int on)
826{
827 ide_task_t task;
Bartlomiej Zolnierkiewicz81ee1bb2008-10-17 18:09:10 +0200828 int ret;
829
830 if ((drive->dev_flags & IDE_DFLAG_DOORLOCKING) == 0)
831 return 0;
Bartlomiej Zolnierkiewicz29ec6832008-01-26 20:12:59 +0100832
833 memset(&task, 0, sizeof(task));
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200834 task.tf.command = on ? ATA_CMD_MEDIA_LOCK : ATA_CMD_MEDIA_UNLOCK;
Bartlomiej Zolnierkiewicz657cc1a2008-01-26 20:13:10 +0100835 task.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
Bartlomiej Zolnierkiewicz29ec6832008-01-26 20:12:59 +0100836
Bartlomiej Zolnierkiewicz81ee1bb2008-10-17 18:09:10 +0200837 ret = ide_no_data_taskfile(drive, &task);
838
839 if (ret)
840 drive->dev_flags &= ~IDE_DFLAG_DOORLOCKING;
841
842 return ret;
Bartlomiej Zolnierkiewicz29ec6832008-01-26 20:12:59 +0100843}
844
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845static int idedisk_open(struct inode *inode, struct file *filp)
846{
847 struct gendisk *disk = inode->i_bdev->bd_disk;
848 struct ide_disk_obj *idkp;
849 ide_drive_t *drive;
850
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200851 idkp = ide_disk_get(disk);
852 if (idkp == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853 return -ENXIO;
854
855 drive = idkp->drive;
856
Bartlomiej Zolnierkiewiczc94964a2007-02-17 02:40:24 +0100857 idkp->openers++;
858
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200859 if ((drive->dev_flags & IDE_DFLAG_REMOVABLE) && idkp->openers == 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 /*
861 * Ignore the return code from door_lock,
862 * since the open() has already succeeded,
863 * and the door_lock is irrelevant at this point.
864 */
Bartlomiej Zolnierkiewicz81ee1bb2008-10-17 18:09:10 +0200865 idedisk_set_doorlock(drive, 1);
Bartlomiej Zolnierkiewicz099ed4c2008-10-17 18:09:09 +0200866 check_disk_change(inode->i_bdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 }
868 return 0;
869}
870
871static int idedisk_release(struct inode *inode, struct file *filp)
872{
873 struct gendisk *disk = inode->i_bdev->bd_disk;
Bartlomiej Zolnierkiewiczd7e74752008-10-17 18:09:09 +0200874 struct ide_disk_obj *idkp = ide_drv_g(disk, ide_disk_obj);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 ide_drive_t *drive = idkp->drive;
876
Bartlomiej Zolnierkiewiczc94964a2007-02-17 02:40:24 +0100877 if (idkp->openers == 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 ide_cacheflush_p(drive);
Bartlomiej Zolnierkiewiczc94964a2007-02-17 02:40:24 +0100879
Bartlomiej Zolnierkiewicz81ee1bb2008-10-17 18:09:10 +0200880 if ((drive->dev_flags & IDE_DFLAG_REMOVABLE) && idkp->openers == 1)
881 idedisk_set_doorlock(drive, 0);
Bartlomiej Zolnierkiewiczc94964a2007-02-17 02:40:24 +0100882
883 idkp->openers--;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884
885 ide_disk_put(idkp);
886
887 return 0;
888}
889
Christoph Hellwiga885c8c2006-01-08 01:02:50 -0800890static int idedisk_getgeo(struct block_device *bdev, struct hd_geometry *geo)
891{
Bartlomiej Zolnierkiewiczd7e74752008-10-17 18:09:09 +0200892 struct ide_disk_obj *idkp = ide_drv_g(bdev->bd_disk, ide_disk_obj);
Christoph Hellwiga885c8c2006-01-08 01:02:50 -0800893 ide_drive_t *drive = idkp->drive;
894
895 geo->heads = drive->bios_head;
896 geo->sectors = drive->bios_sect;
897 geo->cylinders = (u16)drive->bios_cyl; /* truncate */
898 return 0;
899}
900
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901static int idedisk_media_changed(struct gendisk *disk)
902{
Bartlomiej Zolnierkiewiczd7e74752008-10-17 18:09:09 +0200903 struct ide_disk_obj *idkp = ide_drv_g(disk, ide_disk_obj);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 ide_drive_t *drive = idkp->drive;
905
906 /* do not scan partitions twice if this is a removable device */
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200907 if (drive->dev_flags & IDE_DFLAG_ATTACH) {
908 drive->dev_flags &= ~IDE_DFLAG_ATTACH;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 return 0;
910 }
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200911
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 /* if removable, always assume it was changed */
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200913 return !!(drive->dev_flags & IDE_DFLAG_REMOVABLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914}
915
916static int idedisk_revalidate_disk(struct gendisk *disk)
917{
Bartlomiej Zolnierkiewiczd7e74752008-10-17 18:09:09 +0200918 struct ide_disk_obj *idkp = ide_drv_g(disk, ide_disk_obj);
Bartlomiej Zolnierkiewicz06b89512008-10-13 21:39:45 +0200919 set_capacity(disk, ide_disk_capacity(idkp->drive));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 return 0;
921}
922
923static struct block_device_operations idedisk_ops = {
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200924 .owner = THIS_MODULE,
925 .open = idedisk_open,
926 .release = idedisk_release,
Bartlomiej Zolnierkiewiczf8790482008-10-13 21:39:45 +0200927 .ioctl = ide_disk_ioctl,
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200928 .getgeo = idedisk_getgeo,
929 .media_changed = idedisk_media_changed,
930 .revalidate_disk = idedisk_revalidate_disk
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931};
932
933MODULE_DESCRIPTION("ATA DISK Driver");
934
Russell King4031bbe2006-01-06 11:41:00 +0000935static int ide_disk_probe(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936{
937 struct ide_disk_obj *idkp;
938 struct gendisk *g;
939
940 /* strstr("foo", "") is non-NULL */
941 if (!strstr("ide-disk", drive->driver_req))
942 goto failed;
Bartlomiej Zolnierkiewicz2a924662008-10-10 22:39:24 +0200943
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944 if (drive->media != ide_disk)
945 goto failed;
946
Deepak Saxenaf5e3c2f2005-11-07 01:01:25 -0800947 idkp = kzalloc(sizeof(*idkp), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948 if (!idkp)
949 goto failed;
950
Tejun Heo689d6fa2008-08-25 19:56:16 +0900951 g = alloc_disk_node(IDE_DISK_MINORS, hwif_to_node(drive->hwif));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952 if (!g)
953 goto out_free_idkp;
954
955 ide_init_disk(g, drive);
956
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957 kref_init(&idkp->kref);
958
959 idkp->drive = drive;
960 idkp->driver = &idedisk_driver;
961 idkp->disk = g;
962
963 g->private_data = &idkp->driver;
964
965 drive->driver_data = idkp;
966
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967 idedisk_setup(drive);
Bartlomiej Zolnierkiewiczae9f9f02008-10-17 18:09:10 +0200968
969 set_capacity(g, ide_disk_capacity(drive));
Bartlomiej Zolnierkiewicz8604aff2005-05-26 14:55:34 +0200970
Tejun Heof615b482008-08-25 19:47:24 +0900971 g->minors = IDE_DISK_MINORS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972 g->driverfs_dev = &drive->gendev;
Tejun Heo689d6fa2008-08-25 19:56:16 +0900973 g->flags |= GENHD_FL_EXT_DEVT;
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200974 if (drive->dev_flags & IDE_DFLAG_REMOVABLE)
975 g->flags = GENHD_FL_REMOVABLE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 g->fops = &idedisk_ops;
977 add_disk(g);
978 return 0;
979
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980out_free_idkp:
981 kfree(idkp);
982failed:
Bartlomiej Zolnierkiewicz8604aff2005-05-26 14:55:34 +0200983 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984}
985
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200986static void __exit idedisk_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987{
Bartlomiej Zolnierkiewicz8604aff2005-05-26 14:55:34 +0200988 driver_unregister(&idedisk_driver.gen_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989}
990
Bartlomiej Zolnierkiewicz17514e82005-11-19 22:24:35 +0100991static int __init idedisk_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992{
Bartlomiej Zolnierkiewicz8604aff2005-05-26 14:55:34 +0200993 return driver_register(&idedisk_driver.gen_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994}
995
Kay Sievers263756e2005-12-12 18:03:44 +0100996MODULE_ALIAS("ide:*m-disk*");
Bartlomiej Zolnierkiewiczf8790482008-10-13 21:39:45 +0200997MODULE_ALIAS("ide-disk");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998module_init(idedisk_init);
999module_exit(idedisk_exit);
1000MODULE_LICENSE("GPL");