blob: 6eb9fea32a56b63666508ea78fbfd5364a318336 [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
Linus Torvalds1da177e2005-04-16 15:20:36 -070048struct ide_disk_obj {
49 ide_drive_t *drive;
50 ide_driver_t *driver;
51 struct gendisk *disk;
52 struct kref kref;
Bartlomiej Zolnierkiewiczc94964a2007-02-17 02:40:24 +010053 unsigned int openers; /* protected by BKL for now */
Linus Torvalds1da177e2005-04-16 15:20:36 -070054};
55
Arjan van de Vencf8b8972006-03-23 03:00:45 -080056static DEFINE_MUTEX(idedisk_ref_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -070057
58#define to_ide_disk(obj) container_of(obj, struct ide_disk_obj, kref)
59
60#define ide_disk_g(disk) \
61 container_of((disk)->private_data, struct ide_disk_obj, driver)
62
Bartlomiej Zolnierkiewicz08da5912008-07-24 22:53:15 +020063static void ide_disk_release(struct kref *);
64
Linus Torvalds1da177e2005-04-16 15:20:36 -070065static struct ide_disk_obj *ide_disk_get(struct gendisk *disk)
66{
67 struct ide_disk_obj *idkp = NULL;
68
Arjan van de Vencf8b8972006-03-23 03:00:45 -080069 mutex_lock(&idedisk_ref_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -070070 idkp = ide_disk_g(disk);
Bartlomiej Zolnierkiewicz08da5912008-07-24 22:53:15 +020071 if (idkp) {
Bartlomiej Zolnierkiewiczd3e33ff2008-08-05 18:16:59 +020072 if (ide_device_get(idkp->drive))
Bartlomiej Zolnierkiewicz08da5912008-07-24 22:53:15 +020073 idkp = NULL;
Bartlomiej Zolnierkiewiczd3e33ff2008-08-05 18:16:59 +020074 else
75 kref_get(&idkp->kref);
Bartlomiej Zolnierkiewicz08da5912008-07-24 22:53:15 +020076 }
Arjan van de Vencf8b8972006-03-23 03:00:45 -080077 mutex_unlock(&idedisk_ref_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -070078 return idkp;
79}
80
Linus Torvalds1da177e2005-04-16 15:20:36 -070081static void ide_disk_put(struct ide_disk_obj *idkp)
82{
Bartlomiej Zolnierkiewiczd3e33ff2008-08-05 18:16:59 +020083 ide_drive_t *drive = idkp->drive;
84
Arjan van de Vencf8b8972006-03-23 03:00:45 -080085 mutex_lock(&idedisk_ref_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -070086 kref_put(&idkp->kref, ide_disk_release);
Bartlomiej Zolnierkiewiczd3e33ff2008-08-05 18:16:59 +020087 ide_device_put(drive);
Arjan van de Vencf8b8972006-03-23 03:00:45 -080088 mutex_unlock(&idedisk_ref_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -070089}
90
Bartlomiej Zolnierkiewiczba76ae32008-01-25 22:17:16 +010091static const u8 ide_rw_cmds[] = {
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +020092 ATA_CMD_READ_MULTI,
93 ATA_CMD_WRITE_MULTI,
94 ATA_CMD_READ_MULTI_EXT,
95 ATA_CMD_WRITE_MULTI_EXT,
96 ATA_CMD_PIO_READ,
97 ATA_CMD_PIO_WRITE,
98 ATA_CMD_PIO_READ_EXT,
99 ATA_CMD_PIO_WRITE_EXT,
100 ATA_CMD_READ,
101 ATA_CMD_WRITE,
102 ATA_CMD_READ_EXT,
103 ATA_CMD_WRITE_EXT,
Bartlomiej Zolnierkiewiczba76ae32008-01-25 22:17:16 +0100104};
105
106static const u8 ide_data_phases[] = {
107 TASKFILE_MULTI_IN,
108 TASKFILE_MULTI_OUT,
109 TASKFILE_IN,
110 TASKFILE_OUT,
111 TASKFILE_IN_DMA,
112 TASKFILE_OUT_DMA,
113};
114
115static void ide_tf_set_cmd(ide_drive_t *drive, ide_task_t *task, u8 dma)
116{
117 u8 index, lba48, write;
118
119 lba48 = (task->tf_flags & IDE_TFLAG_LBA48) ? 2 : 0;
120 write = (task->tf_flags & IDE_TFLAG_WRITE) ? 1 : 0;
121
122 if (dma)
Bartlomiej Zolnierkiewiczba4b2e62008-07-23 19:55:55 +0200123 index = 8;
Bartlomiej Zolnierkiewiczba76ae32008-01-25 22:17:16 +0100124 else
125 index = drive->mult_count ? 0 : 4;
126
127 task->tf.command = ide_rw_cmds[index + lba48 + write];
128
129 if (dma)
130 index = 8; /* fixup index */
131
132 task->data_phase = ide_data_phases[index / 2 + write];
133}
134
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135/*
136 * __ide_do_rw_disk() issues READ and WRITE commands to a disk,
137 * using LBA if supported, or CHS otherwise, to address sectors.
138 */
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200139static ide_startstop_t __ide_do_rw_disk(ide_drive_t *drive, struct request *rq,
140 sector_t block)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141{
142 ide_hwif_t *hwif = HWIF(drive);
Bartlomiej Zolnierkiewicz790d1232008-01-25 22:17:12 +0100143 u16 nsectors = (u16)rq->nr_sectors;
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200144 u8 lba48 = !!(drive->dev_flags & IDE_DFLAG_LBA48);
145 u8 dma = !!(drive->dev_flags & IDE_DFLAG_USING_DMA);
Bartlomiej Zolnierkiewicz9e422372008-01-25 22:17:07 +0100146 ide_task_t task;
147 struct ide_taskfile *tf = &task.tf;
Bartlomiej Zolnierkiewiczf6e29e32008-01-25 22:17:16 +0100148 ide_startstop_t rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149
Bartlomiej Zolnierkiewicz238e4f12007-10-19 00:30:07 +0200150 if ((hwif->host_flags & IDE_HFLAG_NO_LBA48_DMA) && lba48 && dma) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151 if (block + rq->nr_sectors > 1ULL << 28)
152 dma = 0;
153 else
154 lba48 = 0;
155 }
156
157 if (!dma) {
158 ide_init_sg_cmd(drive, rq);
159 ide_map_sg(drive, rq);
160 }
161
Bartlomiej Zolnierkiewicz9e422372008-01-25 22:17:07 +0100162 memset(&task, 0, sizeof(task));
Bartlomiej Zolnierkiewicz9a410e72008-07-15 21:21:48 +0200163 task.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
Bartlomiej Zolnierkiewicz2bd06b22008-01-25 22:17:06 +0100164
Bartlomiej Zolnierkiewiczd1d76712008-10-13 21:39:38 +0200165 if (drive->dev_flags & IDE_DFLAG_LBA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166 if (lba48) {
Michael Richardsonc2f83112006-02-07 12:58:33 -0800167 pr_debug("%s: LBA=0x%012llx\n", drive->name,
168 (unsigned long long)block);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169
Bartlomiej Zolnierkiewicz790d1232008-01-25 22:17:12 +0100170 tf->hob_nsect = (nsectors >> 8) & 0xff;
Bartlomiej Zolnierkiewicz2bd06b22008-01-25 22:17:06 +0100171 tf->hob_lbal = (u8)(block >> 24);
172 if (sizeof(block) != 4) {
173 tf->hob_lbam = (u8)((u64)block >> 32);
174 tf->hob_lbah = (u8)((u64)block >> 40);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175 }
Bartlomiej Zolnierkiewicz2bd06b22008-01-25 22:17:06 +0100176
Bartlomiej Zolnierkiewicz790d1232008-01-25 22:17:12 +0100177 tf->nsect = nsectors & 0xff;
Bartlomiej Zolnierkiewicz2bd06b22008-01-25 22:17:06 +0100178 tf->lbal = (u8) block;
179 tf->lbam = (u8)(block >> 8);
180 tf->lbah = (u8)(block >> 16);
Bartlomiej Zolnierkiewicz6dd9b832008-01-26 20:13:03 +0100181
Bartlomiej Zolnierkiewicz657cc1a2008-01-26 20:13:10 +0100182 task.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_HOB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183 } else {
Bartlomiej Zolnierkiewicz790d1232008-01-25 22:17:12 +0100184 tf->nsect = nsectors & 0xff;
Bartlomiej Zolnierkiewicz2bd06b22008-01-25 22:17:06 +0100185 tf->lbal = block;
186 tf->lbam = block >>= 8;
187 tf->lbah = block >>= 8;
188 tf->device = (block >> 8) & 0xf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189 }
Bartlomiej Zolnierkiewiczd1d76712008-10-13 21:39:38 +0200190
191 tf->device |= ATA_LBA;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192 } else {
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200193 unsigned int sect, head, cyl, track;
194
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195 track = (int)block / drive->sect;
196 sect = (int)block % drive->sect + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197 head = track % drive->head;
198 cyl = track / drive->head;
199
200 pr_debug("%s: CHS=%u/%u/%u\n", drive->name, cyl, head, sect);
201
Bartlomiej Zolnierkiewicz790d1232008-01-25 22:17:12 +0100202 tf->nsect = nsectors & 0xff;
Bartlomiej Zolnierkiewicz2bd06b22008-01-25 22:17:06 +0100203 tf->lbal = sect;
204 tf->lbam = cyl;
205 tf->lbah = cyl >> 8;
206 tf->device = head;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207 }
208
Bartlomiej Zolnierkiewiczba76ae32008-01-25 22:17:16 +0100209 if (rq_data_dir(rq))
210 task.tf_flags |= IDE_TFLAG_WRITE;
211
212 ide_tf_set_cmd(drive, &task, dma);
Bartlomiej Zolnierkiewiczf6e29e32008-01-25 22:17:16 +0100213 if (!dma)
214 hwif->data_phase = task.data_phase;
215 task.rq = rq;
Bartlomiej Zolnierkiewiczba76ae32008-01-25 22:17:16 +0100216
Bartlomiej Zolnierkiewiczf6e29e32008-01-25 22:17:16 +0100217 rc = do_rw_taskfile(drive, &task);
Bartlomiej Zolnierkiewicz2bd06b22008-01-25 22:17:06 +0100218
Bartlomiej Zolnierkiewiczf6e29e32008-01-25 22:17:16 +0100219 if (rc == ide_stopped && dma) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220 /* fallback to PIO */
Bartlomiej Zolnierkiewiczf6e29e32008-01-25 22:17:16 +0100221 task.tf_flags |= IDE_TFLAG_DMA_PIO_FALLBACK;
Bartlomiej Zolnierkiewiczba76ae32008-01-25 22:17:16 +0100222 ide_tf_set_cmd(drive, &task, 0);
Bartlomiej Zolnierkiewiczf6e29e32008-01-25 22:17:16 +0100223 hwif->data_phase = task.data_phase;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 ide_init_sg_cmd(drive, rq);
Bartlomiej Zolnierkiewiczf6e29e32008-01-25 22:17:16 +0100225 rc = do_rw_taskfile(drive, &task);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226 }
227
Bartlomiej Zolnierkiewiczf6e29e32008-01-25 22:17:16 +0100228 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229}
230
231/*
232 * 268435455 == 137439 MB or 28bit limit
233 * 320173056 == 163929 MB or 48bit addressing
234 * 1073741822 == 549756 MB or 48bit addressing fake drive
235 */
236
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200237static ide_startstop_t ide_do_rw_disk(ide_drive_t *drive, struct request *rq,
238 sector_t block)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239{
240 ide_hwif_t *hwif = HWIF(drive);
241
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200242 BUG_ON(drive->dev_flags & IDE_DFLAG_BLOCKED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243
244 if (!blk_fs_request(rq)) {
245 blk_dump_rq_flags(rq, "ide_do_rw_disk - bad command");
246 ide_end_request(drive, 0, 0);
247 return ide_stopped;
248 }
249
Richard Purdie2bfb6462006-03-31 02:31:16 -0800250 ledtrig_ide_activity();
251
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252 pr_debug("%s: %sing: block=%llu, sectors=%lu, buffer=0x%08lx\n",
253 drive->name, rq_data_dir(rq) == READ ? "read" : "writ",
Michael Richardsonc2f83112006-02-07 12:58:33 -0800254 (unsigned long long)block, rq->nr_sectors,
255 (unsigned long)rq->buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256
257 if (hwif->rw_disk)
258 hwif->rw_disk(drive, rq);
259
260 return __ide_do_rw_disk(drive, rq, block);
261}
262
263/*
264 * Queries for true maximum capacity of the drive.
265 * Returns maximum LBA address (> 0) of the drive, 0 if failed.
266 */
Bartlomiej Zolnierkiewicz7a3b7512008-01-25 22:17:06 +0100267static u64 idedisk_read_native_max_address(ide_drive_t *drive, int lba48)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268{
269 ide_task_t args;
Bartlomiej Zolnierkiewicz650d8412008-01-25 22:17:06 +0100270 struct ide_taskfile *tf = &args.tf;
Bartlomiej Zolnierkiewicz7a3b7512008-01-25 22:17:06 +0100271 u64 addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272
273 /* Create IDE/ATA command request structure */
274 memset(&args, 0, sizeof(ide_task_t));
Bartlomiej Zolnierkiewicz7a3b7512008-01-25 22:17:06 +0100275 if (lba48)
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200276 tf->command = ATA_CMD_READ_NATIVE_MAX_EXT;
Bartlomiej Zolnierkiewicz7a3b7512008-01-25 22:17:06 +0100277 else
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200278 tf->command = ATA_CMD_READ_NATIVE_MAX;
Bartlomiej Zolnierkiewicz650d8412008-01-25 22:17:06 +0100279 tf->device = ATA_LBA;
Bartlomiej Zolnierkiewicz657cc1a2008-01-26 20:13:10 +0100280 args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
Bartlomiej Zolnierkiewicza3bbb9d2008-01-25 22:17:10 +0100281 if (lba48)
Bartlomiej Zolnierkiewicz657cc1a2008-01-26 20:13:10 +0100282 args.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_HOB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 /* submit command request */
Bartlomiej Zolnierkiewicz9a3c49b2008-01-25 22:17:07 +0100284 ide_no_data_taskfile(drive, &args);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285
286 /* if OK, compute maximum address value */
Bartlomiej Zolnierkiewicza5016332008-01-25 22:17:17 +0100287 if ((tf->status & 0x01) == 0)
288 addr = ide_get_lba_addr(tf, lba48) + 1;
Bartlomiej Zolnierkiewicz650d8412008-01-25 22:17:06 +0100289
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290 return addr;
291}
292
293/*
294 * Sets maximum virtual LBA address of the drive.
295 * Returns new maximum virtual LBA address (> 0) or 0 on failure.
296 */
Bartlomiej Zolnierkiewicz7a3b7512008-01-25 22:17:06 +0100297static u64 idedisk_set_max_address(ide_drive_t *drive, u64 addr_req, int lba48)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298{
299 ide_task_t args;
Bartlomiej Zolnierkiewicz650d8412008-01-25 22:17:06 +0100300 struct ide_taskfile *tf = &args.tf;
Bartlomiej Zolnierkiewicz7a3b7512008-01-25 22:17:06 +0100301 u64 addr_set = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302
303 addr_req--;
304 /* Create IDE/ATA command request structure */
305 memset(&args, 0, sizeof(ide_task_t));
Bartlomiej Zolnierkiewicz650d8412008-01-25 22:17:06 +0100306 tf->lbal = (addr_req >> 0) & 0xff;
307 tf->lbam = (addr_req >>= 8) & 0xff;
308 tf->lbah = (addr_req >>= 8) & 0xff;
Bartlomiej Zolnierkiewicz7a3b7512008-01-25 22:17:06 +0100309 if (lba48) {
310 tf->hob_lbal = (addr_req >>= 8) & 0xff;
311 tf->hob_lbam = (addr_req >>= 8) & 0xff;
312 tf->hob_lbah = (addr_req >>= 8) & 0xff;
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200313 tf->command = ATA_CMD_SET_MAX_EXT;
Bartlomiej Zolnierkiewicz7a3b7512008-01-25 22:17:06 +0100314 } else {
315 tf->device = (addr_req >>= 8) & 0x0f;
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200316 tf->command = ATA_CMD_SET_MAX;
Bartlomiej Zolnierkiewicz7a3b7512008-01-25 22:17:06 +0100317 }
318 tf->device |= ATA_LBA;
Bartlomiej Zolnierkiewicz657cc1a2008-01-26 20:13:10 +0100319 args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
Bartlomiej Zolnierkiewicza3bbb9d2008-01-25 22:17:10 +0100320 if (lba48)
Bartlomiej Zolnierkiewicz657cc1a2008-01-26 20:13:10 +0100321 args.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_HOB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322 /* submit command request */
Bartlomiej Zolnierkiewicz9a3c49b2008-01-25 22:17:07 +0100323 ide_no_data_taskfile(drive, &args);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324 /* if OK, compute maximum address value */
Bartlomiej Zolnierkiewicza5016332008-01-25 22:17:17 +0100325 if ((tf->status & 0x01) == 0)
326 addr_set = ide_get_lba_addr(tf, lba48) + 1;
Bartlomiej Zolnierkiewicz650d8412008-01-25 22:17:06 +0100327
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328 return addr_set;
329}
330
331static unsigned long long sectors_to_MB(unsigned long long n)
332{
333 n <<= 9; /* make it bytes */
334 do_div(n, 1000000); /* make it MB */
335 return n;
336}
337
338/*
Bartlomiej Zolnierkiewiczb0244a02007-08-20 22:42:57 +0200339 * Some disks report total number of sectors instead of
340 * maximum sector address. We list them here.
341 */
342static const struct drive_list_entry hpa_list[] = {
343 { "ST340823A", NULL },
Jorge Juan Chico7062cdc2007-09-17 12:35:30 +0200344 { "ST320413A", NULL },
Mikko Rapelib152fcd2008-02-19 01:41:25 +0100345 { "ST310211A", NULL },
Bartlomiej Zolnierkiewiczb0244a02007-08-20 22:42:57 +0200346 { NULL, NULL }
347};
348
Arjan van de Ven858119e2006-01-14 13:20:43 -0800349static void idedisk_check_hpa(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350{
351 unsigned long long capacity, set_max;
Bartlomiej Zolnierkiewicz942dcd82008-10-10 22:39:30 +0200352 int lba48 = ata_id_lba48_enabled(drive->id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353
354 capacity = drive->capacity64;
Bartlomiej Zolnierkiewicz7a3b7512008-01-25 22:17:06 +0100355
356 set_max = idedisk_read_native_max_address(drive, lba48);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357
Bartlomiej Zolnierkiewiczb0244a02007-08-20 22:42:57 +0200358 if (ide_in_drive_list(drive->id, hpa_list)) {
359 /*
360 * Since we are inclusive wrt to firmware revisions do this
361 * extra check and apply the workaround only when needed.
362 */
363 if (set_max == capacity + 1)
364 set_max--;
365 }
366
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 if (set_max <= capacity)
368 return;
369
370 printk(KERN_INFO "%s: Host Protected Area detected.\n"
371 "\tcurrent capacity is %llu sectors (%llu MB)\n"
372 "\tnative capacity is %llu sectors (%llu MB)\n",
373 drive->name,
374 capacity, sectors_to_MB(capacity),
375 set_max, sectors_to_MB(set_max));
376
Bartlomiej Zolnierkiewicz7a3b7512008-01-25 22:17:06 +0100377 set_max = idedisk_set_max_address(drive, set_max, lba48);
378
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 if (set_max) {
380 drive->capacity64 = set_max;
381 printk(KERN_INFO "%s: Host Protected Area disabled.\n",
382 drive->name);
383 }
384}
385
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200386static void init_idedisk_capacity(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387{
Bartlomiej Zolnierkiewicz4dde4492008-10-10 22:39:19 +0200388 u16 *id = drive->id;
Bartlomiej Zolnierkiewiczd1d76712008-10-13 21:39:38 +0200389 int lba;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390
Bartlomiej Zolnierkiewicz942dcd82008-10-10 22:39:30 +0200391 if (ata_id_lba48_enabled(id)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 /* drive speaks 48-bit LBA */
Bartlomiej Zolnierkiewiczd1d76712008-10-13 21:39:38 +0200393 lba = 1;
Bartlomiej Zolnierkiewicz48fb2682008-10-10 22:39:19 +0200394 drive->capacity64 = ata_id_u64(id, ATA_ID_LBA_CAPACITY_2);
Bartlomiej Zolnierkiewicza02227c92008-10-10 22:39:31 +0200395 } else if (ata_id_has_lba(id) && ata_id_is_lba_capacity_ok(id)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 /* drive speaks 28-bit LBA */
Bartlomiej Zolnierkiewiczd1d76712008-10-13 21:39:38 +0200397 lba = 1;
Bartlomiej Zolnierkiewicz48fb2682008-10-10 22:39:19 +0200398 drive->capacity64 = ata_id_u32(id, ATA_ID_LBA_CAPACITY);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 } else {
400 /* drive speaks boring old 28-bit CHS */
Bartlomiej Zolnierkiewiczd1d76712008-10-13 21:39:38 +0200401 lba = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 drive->capacity64 = drive->cyl * drive->head * drive->sect;
403 }
Bartlomiej Zolnierkiewiczd1d76712008-10-13 21:39:38 +0200404
405 if (lba) {
406 drive->dev_flags |= IDE_DFLAG_LBA;
407
408 /*
409 * If this device supports the Host Protected Area feature set,
410 * then we may need to change our opinion about its capacity.
411 */
412 if (ata_id_hpa_enabled(id))
413 idedisk_check_hpa(drive);
414 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415}
416
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200417static sector_t idedisk_capacity(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418{
Bartlomiej Zolnierkiewicz3c619ff2008-10-10 22:39:22 +0200419 return drive->capacity64;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420}
421
Bartlomiej Zolnierkiewiczecfd80e2007-05-10 00:01:09 +0200422#ifdef CONFIG_IDE_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423static int smart_enable(ide_drive_t *drive)
424{
425 ide_task_t args;
Bartlomiej Zolnierkiewicz650d8412008-01-25 22:17:06 +0100426 struct ide_taskfile *tf = &args.tf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427
428 memset(&args, 0, sizeof(ide_task_t));
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200429 tf->feature = ATA_SMART_ENABLE;
430 tf->lbam = ATA_SMART_LBAM_PASS;
431 tf->lbah = ATA_SMART_LBAH_PASS;
432 tf->command = ATA_CMD_SMART;
Bartlomiej Zolnierkiewicz657cc1a2008-01-26 20:13:10 +0100433 args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
Bartlomiej Zolnierkiewicz9a3c49b2008-01-25 22:17:07 +0100434 return ide_no_data_taskfile(drive, &args);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435}
436
Bartlomiej Zolnierkiewicz43e7c0c2007-10-20 00:32:37 +0200437static int get_smart_data(ide_drive_t *drive, u8 *buf, u8 sub_cmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438{
439 ide_task_t args;
Bartlomiej Zolnierkiewicz650d8412008-01-25 22:17:06 +0100440 struct ide_taskfile *tf = &args.tf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441
442 memset(&args, 0, sizeof(ide_task_t));
Bartlomiej Zolnierkiewicz650d8412008-01-25 22:17:06 +0100443 tf->feature = sub_cmd;
444 tf->nsect = 0x01;
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200445 tf->lbam = ATA_SMART_LBAM_PASS;
446 tf->lbah = ATA_SMART_LBAH_PASS;
447 tf->command = ATA_CMD_SMART;
Bartlomiej Zolnierkiewicz657cc1a2008-01-26 20:13:10 +0100448 args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
Bartlomiej Zolnierkiewiczac026ff2008-01-25 22:17:14 +0100449 args.data_phase = TASKFILE_IN;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450 (void) smart_enable(drive);
Bartlomiej Zolnierkiewiczac026ff2008-01-25 22:17:14 +0100451 return ide_raw_taskfile(drive, &args, buf, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452}
453
454static int proc_idedisk_read_cache
455 (char *page, char **start, off_t off, int count, int *eof, void *data)
456{
457 ide_drive_t *drive = (ide_drive_t *) data;
458 char *out = page;
459 int len;
460
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200461 if (drive->dev_flags & IDE_DFLAG_ID_READ)
Bartlomiej Zolnierkiewicz4dde4492008-10-10 22:39:19 +0200462 len = sprintf(out, "%i\n", drive->id[ATA_ID_BUF_SIZE] / 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463 else
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200464 len = sprintf(out, "(none)\n");
465
466 PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467}
468
469static int proc_idedisk_read_capacity
470 (char *page, char **start, off_t off, int count, int *eof, void *data)
471{
472 ide_drive_t*drive = (ide_drive_t *)data;
473 int len;
474
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200475 len = sprintf(page, "%llu\n", (long long)idedisk_capacity(drive));
476
477 PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478}
479
Bartlomiej Zolnierkiewicz799ee572008-04-26 17:36:37 +0200480static int proc_idedisk_read_smart(char *page, char **start, off_t off,
481 int count, int *eof, void *data, u8 sub_cmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482{
483 ide_drive_t *drive = (ide_drive_t *)data;
484 int len = 0, i = 0;
485
Bartlomiej Zolnierkiewicz799ee572008-04-26 17:36:37 +0200486 if (get_smart_data(drive, page, sub_cmd) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487 unsigned short *val = (unsigned short *) page;
Bartlomiej Zolnierkiewicz151a6702008-10-10 22:39:28 +0200488 char *out = (char *)val + SECTOR_SIZE;
489
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 page = out;
491 do {
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200492 out += sprintf(out, "%04x%c", le16_to_cpu(*val),
493 (++i & 7) ? ' ' : '\n');
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 val += 1;
Bartlomiej Zolnierkiewicz151a6702008-10-10 22:39:28 +0200495 } while (i < SECTOR_SIZE / 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496 len = out - page;
497 }
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200498
499 PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500}
501
Bartlomiej Zolnierkiewicz799ee572008-04-26 17:36:37 +0200502static int proc_idedisk_read_sv
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 (char *page, char **start, off_t off, int count, int *eof, void *data)
504{
Bartlomiej Zolnierkiewicz799ee572008-04-26 17:36:37 +0200505 return proc_idedisk_read_smart(page, start, off, count, eof, data,
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200506 ATA_SMART_READ_VALUES);
Bartlomiej Zolnierkiewicz799ee572008-04-26 17:36:37 +0200507}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508
Bartlomiej Zolnierkiewicz799ee572008-04-26 17:36:37 +0200509static int proc_idedisk_read_st
510 (char *page, char **start, off_t off, int count, int *eof, void *data)
511{
512 return proc_idedisk_read_smart(page, start, off, count, eof, data,
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200513 ATA_SMART_READ_THRESHOLDS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514}
515
516static ide_proc_entry_t idedisk_proc[] = {
Bartlomiej Zolnierkiewicz799ee572008-04-26 17:36:37 +0200517 { "cache", S_IFREG|S_IRUGO, proc_idedisk_read_cache, NULL },
518 { "capacity", S_IFREG|S_IRUGO, proc_idedisk_read_capacity, NULL },
519 { "geometry", S_IFREG|S_IRUGO, proc_ide_read_geometry, NULL },
520 { "smart_values", S_IFREG|S_IRUSR, proc_idedisk_read_sv, NULL },
521 { "smart_thresholds", S_IFREG|S_IRUSR, proc_idedisk_read_st, NULL },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 { NULL, 0, NULL, NULL }
523};
Bartlomiej Zolnierkiewiczecfd80e2007-05-10 00:01:09 +0200524#endif /* CONFIG_IDE_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525
Jens Axboe165125e2007-07-24 09:28:11 +0200526static void idedisk_prepare_flush(struct request_queue *q, struct request *rq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527{
528 ide_drive_t *drive = q->queuedata;
Bartlomiej Zolnierkiewicz395d8ef2008-02-11 00:32:14 +0100529 ide_task_t *task = kmalloc(sizeof(*task), GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530
Bartlomiej Zolnierkiewicz395d8ef2008-02-11 00:32:14 +0100531 /* FIXME: map struct ide_taskfile on rq->cmd[] */
532 BUG_ON(task == NULL);
533
534 memset(task, 0, sizeof(*task));
Bartlomiej Zolnierkiewiczff2779b2008-10-10 22:39:31 +0200535 if (ata_id_flush_ext_enabled(drive->id) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536 (drive->capacity64 >= (1UL << 28)))
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200537 task->tf.command = ATA_CMD_FLUSH_EXT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 else
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200539 task->tf.command = ATA_CMD_FLUSH;
Bartlomiej Zolnierkiewicz395d8ef2008-02-11 00:32:14 +0100540 task->tf_flags = IDE_TFLAG_OUT_TF | IDE_TFLAG_OUT_DEVICE |
541 IDE_TFLAG_DYN;
542 task->data_phase = TASKFILE_NO_DATA;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543
Bartlomiej Zolnierkiewicz813a0eb2008-01-25 22:17:10 +0100544 rq->cmd_type = REQ_TYPE_ATA_TASKFILE;
Jens Axboe4aff5e22006-08-10 08:44:47 +0200545 rq->cmd_flags |= REQ_SOFTBARRIER;
Bartlomiej Zolnierkiewicz395d8ef2008-02-11 00:32:14 +0100546 rq->special = task;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547}
548
Bartlomiej Zolnierkiewicz8185d5a2008-10-10 22:39:28 +0200549ide_devset_get(multcount, mult_count);
550
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551/*
552 * This is tightly woven into the driver->do_special can not touch.
553 * DON'T do it again until a total personality rewrite is committed.
554 */
555static int set_multcount(ide_drive_t *drive, int arg)
556{
FUJITA Tomonoridd470872008-07-15 21:21:43 +0200557 struct request *rq;
558 int error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559
Bartlomiej Zolnierkiewicz48fb2682008-10-10 22:39:19 +0200560 if (arg < 0 || arg > (drive->id[ATA_ID_MAX_MULTSECT] & 0xff))
Bartlomiej Zolnierkiewicz14979432007-05-10 00:01:10 +0200561 return -EINVAL;
562
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563 if (drive->special.b.set_multmode)
564 return -EBUSY;
Bartlomiej Zolnierkiewicz852738f2008-01-26 20:13:12 +0100565
FUJITA Tomonoridd470872008-07-15 21:21:43 +0200566 rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
567 rq->cmd_type = REQ_TYPE_ATA_TASKFILE;
Bartlomiej Zolnierkiewicz852738f2008-01-26 20:13:12 +0100568
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569 drive->mult_req = arg;
570 drive->special.b.set_multmode = 1;
FUJITA Tomonoridd470872008-07-15 21:21:43 +0200571 error = blk_execute_rq(drive->queue, NULL, rq, 0);
572 blk_put_request(rq);
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200573
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574 return (drive->mult_count == arg) ? 0 : -EIO;
575}
576
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200577ide_devset_get_flag(nowerr, IDE_DFLAG_NOWERR);
Bartlomiej Zolnierkiewicz8185d5a2008-10-10 22:39:28 +0200578
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579static int set_nowerr(ide_drive_t *drive, int arg)
580{
Bartlomiej Zolnierkiewicz14979432007-05-10 00:01:10 +0200581 if (arg < 0 || arg > 1)
582 return -EINVAL;
583
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200584 if (arg)
585 drive->dev_flags |= IDE_DFLAG_NOWERR;
586 else
587 drive->dev_flags &= ~IDE_DFLAG_NOWERR;
588
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589 drive->bad_wstat = arg ? BAD_R_STAT : BAD_W_STAT;
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200590
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591 return 0;
592}
593
Bartlomiej Zolnierkiewiczbe3c0962008-10-13 21:39:36 +0200594static int ide_do_setfeature(ide_drive_t *drive, u8 feature, u8 nsect)
595{
596 ide_task_t task;
597
598 memset(&task, 0, sizeof(task));
599 task.tf.feature = feature;
600 task.tf.nsect = nsect;
601 task.tf.command = ATA_CMD_SET_FEATURES;
602 task.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
603
604 return ide_no_data_taskfile(drive, &task);
605}
606
Tejun Heo3e087b52006-01-06 09:57:31 +0100607static void update_ordered(ide_drive_t *drive)
608{
Bartlomiej Zolnierkiewicz4dde4492008-10-10 22:39:19 +0200609 u16 *id = drive->id;
Tejun Heo3e087b52006-01-06 09:57:31 +0100610 unsigned ordered = QUEUE_ORDERED_NONE;
611 prepare_flush_fn *prep_fn = NULL;
Tejun Heo3e087b52006-01-06 09:57:31 +0100612
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200613 if (drive->dev_flags & IDE_DFLAG_WCACHE) {
Tejun Heo3e087b52006-01-06 09:57:31 +0100614 unsigned long long capacity;
615 int barrier;
616 /*
617 * We must avoid issuing commands a drive does not
618 * understand or we may crash it. We check flush cache
619 * is supported. We also check we have the LBA48 flush
620 * cache if the drive capacity is too large. By this
621 * time we have trimmed the drive capacity if LBA48 is
622 * not available so we don't need to recheck that.
623 */
624 capacity = idedisk_capacity(drive);
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200625 barrier = ata_id_flush_enabled(id) &&
626 (drive->dev_flags & IDE_DFLAG_NOFLUSH) == 0 &&
627 ((drive->dev_flags & IDE_DFLAG_LBA48) == 0 ||
628 capacity <= (1ULL << 28) ||
Bartlomiej Zolnierkiewiczff2779b2008-10-10 22:39:31 +0200629 ata_id_flush_ext_enabled(id));
Tejun Heo3e087b52006-01-06 09:57:31 +0100630
631 printk(KERN_INFO "%s: cache flushes %ssupported\n",
Jean Delvaref7ad8362006-02-03 03:04:57 -0800632 drive->name, barrier ? "" : "not ");
Tejun Heo3e087b52006-01-06 09:57:31 +0100633
634 if (barrier) {
635 ordered = QUEUE_ORDERED_DRAIN_FLUSH;
636 prep_fn = idedisk_prepare_flush;
Tejun Heo3e087b52006-01-06 09:57:31 +0100637 }
638 } else
639 ordered = QUEUE_ORDERED_DRAIN;
640
641 blk_queue_ordered(drive->queue, ordered, prep_fn);
Tejun Heo3e087b52006-01-06 09:57:31 +0100642}
643
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200644ide_devset_get_flag(wcache, IDE_DFLAG_WCACHE);
Bartlomiej Zolnierkiewicz8185d5a2008-10-10 22:39:28 +0200645
646static int set_wcache(ide_drive_t *drive, int arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647{
Tejun Heo3e087b52006-01-06 09:57:31 +0100648 int err = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649
Bartlomiej Zolnierkiewicz14979432007-05-10 00:01:10 +0200650 if (arg < 0 || arg > 1)
651 return -EINVAL;
652
Bartlomiej Zolnierkiewicz4b58f172008-10-10 22:39:30 +0200653 if (ata_id_flush_enabled(drive->id)) {
Bartlomiej Zolnierkiewiczbe3c0962008-10-13 21:39:36 +0200654 err = ide_do_setfeature(drive,
655 arg ? SETFEATURES_WC_ON : SETFEATURES_WC_OFF, 0);
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200656 if (err == 0) {
657 if (arg)
658 drive->dev_flags |= IDE_DFLAG_WCACHE;
659 else
660 drive->dev_flags &= ~IDE_DFLAG_WCACHE;
661 }
Tejun Heo3e087b52006-01-06 09:57:31 +0100662 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663
Tejun Heo3e087b52006-01-06 09:57:31 +0100664 update_ordered(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665
Tejun Heo3e087b52006-01-06 09:57:31 +0100666 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667}
668
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200669static int do_idedisk_flushcache(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670{
671 ide_task_t args;
672
673 memset(&args, 0, sizeof(ide_task_t));
Bartlomiej Zolnierkiewiczff2779b2008-10-10 22:39:31 +0200674 if (ata_id_flush_ext_enabled(drive->id))
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200675 args.tf.command = ATA_CMD_FLUSH_EXT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 else
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200677 args.tf.command = ATA_CMD_FLUSH;
Bartlomiej Zolnierkiewicz657cc1a2008-01-26 20:13:10 +0100678 args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
Bartlomiej Zolnierkiewicz9a3c49b2008-01-25 22:17:07 +0100679 return ide_no_data_taskfile(drive, &args);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680}
681
Bartlomiej Zolnierkiewicz8185d5a2008-10-10 22:39:28 +0200682ide_devset_get(acoustic, acoustic);
683
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200684static int set_acoustic(ide_drive_t *drive, int arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685{
Bartlomiej Zolnierkiewicz14979432007-05-10 00:01:10 +0200686 if (arg < 0 || arg > 254)
687 return -EINVAL;
688
Bartlomiej Zolnierkiewiczbe3c0962008-10-13 21:39:36 +0200689 ide_do_setfeature(drive,
690 arg ? SETFEATURES_AAM_ON : SETFEATURES_AAM_OFF, arg);
691
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 drive->acoustic = arg;
Bartlomiej Zolnierkiewiczbe3c0962008-10-13 21:39:36 +0200693
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 return 0;
695}
696
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200697ide_devset_get_flag(addressing, IDE_DFLAG_LBA48);
Bartlomiej Zolnierkiewicz8185d5a2008-10-10 22:39:28 +0200698
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699/*
700 * drive->addressing:
701 * 0: 28-bit
702 * 1: 48-bit
703 * 2: 48-bit capable doing 28-bit
704 */
Bartlomiej Zolnierkiewiczaa7687732008-10-10 22:39:33 +0200705static int set_addressing(ide_drive_t *drive, int arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706{
Bartlomiej Zolnierkiewicz14979432007-05-10 00:01:10 +0200707 if (arg < 0 || arg > 2)
708 return -EINVAL;
709
Bartlomiej Zolnierkiewicz35c13752008-10-13 21:39:36 +0200710 if (arg && ((drive->hwif->host_flags & IDE_HFLAG_NO_LBA48) ||
711 ata_id_lba48_enabled(drive->id) == 0))
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200712 return -EIO;
Bartlomiej Zolnierkiewicz942dcd82008-10-10 22:39:30 +0200713
Bartlomiej Zolnierkiewicz35c13752008-10-13 21:39:36 +0200714 if (arg == 2)
715 arg = 0;
716
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200717 if (arg)
718 drive->dev_flags |= IDE_DFLAG_LBA48;
719 else
720 drive->dev_flags &= ~IDE_DFLAG_LBA48;
Bartlomiej Zolnierkiewicz942dcd82008-10-10 22:39:30 +0200721
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 return 0;
723}
724
Elias Oltmanns92f1f8f2008-10-10 22:39:40 +0200725ide_devset_rw(acoustic, acoustic);
726ide_devset_rw(address, addressing);
727ide_devset_rw(multcount, multcount);
728ide_devset_rw(wcache, wcache);
729
730ide_devset_rw_sync(nowerr, nowerr);
731
Bartlomiej Zolnierkiewicz7662d042007-05-10 00:01:10 +0200732#ifdef CONFIG_IDE_PROC_FS
Elias Oltmanns92f1f8f2008-10-10 22:39:40 +0200733ide_devset_rw_field(bios_cyl, bios_cyl);
734ide_devset_rw_field(bios_head, bios_head);
735ide_devset_rw_field(bios_sect, bios_sect);
736ide_devset_rw_field(failures, failures);
737ide_devset_rw_field(lun, lun);
738ide_devset_rw_field(max_failures, max_failures);
Bartlomiej Zolnierkiewicz8185d5a2008-10-10 22:39:28 +0200739
Elias Oltmanns92f1f8f2008-10-10 22:39:40 +0200740static const struct ide_proc_devset idedisk_settings[] = {
741 IDE_PROC_DEVSET(acoustic, 0, 254),
742 IDE_PROC_DEVSET(address, 0, 2),
743 IDE_PROC_DEVSET(bios_cyl, 0, 65535),
744 IDE_PROC_DEVSET(bios_head, 0, 255),
745 IDE_PROC_DEVSET(bios_sect, 0, 63),
746 IDE_PROC_DEVSET(failures, 0, 65535),
747 IDE_PROC_DEVSET(lun, 0, 7),
748 IDE_PROC_DEVSET(max_failures, 0, 65535),
749 IDE_PROC_DEVSET(multcount, 0, 16),
750 IDE_PROC_DEVSET(nowerr, 0, 1),
751 IDE_PROC_DEVSET(wcache, 0, 1),
752 { 0 },
Bartlomiej Zolnierkiewicz8185d5a2008-10-10 22:39:28 +0200753};
Bartlomiej Zolnierkiewicz7662d042007-05-10 00:01:10 +0200754#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200756static void idedisk_setup(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757{
Bartlomiej Zolnierkiewicz1e874f42008-10-10 22:39:27 +0200758 struct ide_disk_obj *idkp = drive->driver_data;
Bartlomiej Zolnierkiewicz238e4f12007-10-19 00:30:07 +0200759 ide_hwif_t *hwif = drive->hwif;
Bartlomiej Zolnierkiewicz4dde4492008-10-10 22:39:19 +0200760 u16 *id = drive->id;
761 char *m = (char *)&id[ATA_ID_PROD];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 unsigned long long capacity;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763
Bartlomiej Zolnierkiewicz1e874f42008-10-10 22:39:27 +0200764 ide_proc_register_driver(drive, idkp->driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200766 if ((drive->dev_flags & IDE_DFLAG_ID_READ) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 return;
768
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200769 if (drive->dev_flags & IDE_DFLAG_REMOVABLE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 /*
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200771 * Removable disks (eg. SYQUEST); ignore 'WD' drives
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 */
Bartlomiej Zolnierkiewicz4dde4492008-10-10 22:39:19 +0200773 if (m[0] != 'W' || m[1] != 'D')
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200774 drive->dev_flags |= IDE_DFLAG_DOORLOCKING;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 }
776
Bartlomiej Zolnierkiewiczaa7687732008-10-10 22:39:33 +0200777 (void)set_addressing(drive, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200779 if (drive->dev_flags & IDE_DFLAG_LBA48) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 int max_s = 2048;
781
782 if (max_s > hwif->rqsize)
783 max_s = hwif->rqsize;
784
785 blk_queue_max_sectors(drive->queue, max_s);
786 }
787
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200788 printk(KERN_INFO "%s: max request size: %dKiB\n", drive->name,
789 drive->queue->max_sectors / 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790
791 /* calculate drive capacity, and select LBA if possible */
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200792 init_idedisk_capacity(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793
794 /* limit drive capacity to 137GB if LBA48 cannot be used */
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200795 if ((drive->dev_flags & IDE_DFLAG_LBA48) == 0 &&
796 drive->capacity64 > 1ULL << 28) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797 printk(KERN_WARNING "%s: cannot use LBA48 - full capacity "
798 "%llu sectors (%llu MB)\n",
799 drive->name, (unsigned long long)drive->capacity64,
800 sectors_to_MB(drive->capacity64));
801 drive->capacity64 = 1ULL << 28;
802 }
803
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200804 if ((hwif->host_flags & IDE_HFLAG_NO_LBA48_DMA) &&
805 (drive->dev_flags & IDE_DFLAG_LBA48)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 if (drive->capacity64 > 1ULL << 28) {
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200807 printk(KERN_INFO "%s: cannot use LBA48 DMA - PIO mode"
808 " will be used for accessing sectors "
809 "> %u\n", drive->name, 1 << 28);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 } else
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200811 drive->dev_flags &= ~IDE_DFLAG_LBA48;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 }
813
814 /*
815 * if possible, give fdisk access to more of the drive,
816 * by correcting bios_cyls:
817 */
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200818 capacity = idedisk_capacity(drive);
819
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200820 if ((drive->dev_flags & IDE_DFLAG_FORCED_GEOM) == 0) {
Bartlomiej Zolnierkiewicz942dcd82008-10-10 22:39:30 +0200821 if (ata_id_lba48_enabled(drive->id)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 /* compatibility */
823 drive->bios_sect = 63;
824 drive->bios_head = 255;
825 }
826
827 if (drive->bios_sect && drive->bios_head) {
828 unsigned int cap0 = capacity; /* truncate to 32 bits */
829 unsigned int cylsz, cyl;
830
831 if (cap0 != capacity)
832 drive->bios_cyl = 65535;
833 else {
834 cylsz = drive->bios_sect * drive->bios_head;
835 cyl = cap0 / cylsz;
836 if (cyl > 65535)
837 cyl = 65535;
838 if (cyl > drive->bios_cyl)
839 drive->bios_cyl = cyl;
840 }
841 }
842 }
843 printk(KERN_INFO "%s: %llu sectors (%llu MB)",
844 drive->name, capacity, sectors_to_MB(capacity));
845
846 /* Only print cache size when it was specified */
Bartlomiej Zolnierkiewicz4dde4492008-10-10 22:39:19 +0200847 if (id[ATA_ID_BUF_SIZE])
848 printk(KERN_CONT " w/%dKiB Cache", id[ATA_ID_BUF_SIZE] / 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849
Bartlomiej Zolnierkiewicz3ab7efe2007-12-12 23:31:58 +0100850 printk(KERN_CONT ", CHS=%d/%d/%d\n",
851 drive->bios_cyl, drive->bios_head, drive->bios_sect);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853 /* write cache enabled? */
Bartlomiej Zolnierkiewicz8a089c62008-10-10 22:39:20 +0200854 if ((id[ATA_ID_CSFO] & 1) || ata_id_wcache_enabled(id))
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200855 drive->dev_flags |= IDE_DFLAG_WCACHE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856
Bartlomiej Zolnierkiewicz8185d5a2008-10-10 22:39:28 +0200857 set_wcache(drive, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858}
859
860static void ide_cacheflush_p(ide_drive_t *drive)
861{
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200862 if (ata_id_flush_enabled(drive->id) == 0 ||
863 (drive->dev_flags & IDE_DFLAG_WCACHE) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 return;
865
866 if (do_idedisk_flushcache(drive))
867 printk(KERN_INFO "%s: wcache flush failed!\n", drive->name);
868}
869
Russell King4031bbe2006-01-06 11:41:00 +0000870static void ide_disk_remove(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871{
872 struct ide_disk_obj *idkp = drive->driver_data;
873 struct gendisk *g = idkp->disk;
874
Bartlomiej Zolnierkiewicz7662d042007-05-10 00:01:10 +0200875 ide_proc_unregister_driver(drive, idkp->driver);
Bartlomiej Zolnierkiewicz8604aff2005-05-26 14:55:34 +0200876
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 del_gendisk(g);
878
Bartlomiej Zolnierkiewiczd36fef62005-12-15 02:19:20 +0100879 ide_cacheflush_p(drive);
880
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881 ide_disk_put(idkp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882}
883
884static void ide_disk_release(struct kref *kref)
885{
886 struct ide_disk_obj *idkp = to_ide_disk(kref);
887 ide_drive_t *drive = idkp->drive;
888 struct gendisk *g = idkp->disk;
889
890 drive->driver_data = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 g->private_data = NULL;
892 put_disk(g);
893 kfree(idkp);
894}
895
Russell King4031bbe2006-01-06 11:41:00 +0000896static int ide_disk_probe(ide_drive_t *drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897
Lee Trager0d2157f2007-06-08 15:14:30 +0200898/*
899 * On HPA drives the capacity needs to be
900 * reinitilized on resume otherwise the disk
901 * can not be used and a hard reset is required
902 */
903static void ide_disk_resume(ide_drive_t *drive)
904{
Bartlomiej Zolnierkiewiczf41891c2008-10-10 22:39:20 +0200905 if (ata_id_hpa_enabled(drive->id))
Lee Trager0d2157f2007-06-08 15:14:30 +0200906 init_idedisk_capacity(drive);
907}
908
Russell King4031bbe2006-01-06 11:41:00 +0000909static void ide_device_shutdown(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911#ifdef CONFIG_ALPHA
912 /* On Alpha, halt(8) doesn't actually turn the machine off,
913 it puts you into the sort of firmware monitor. Typically,
914 it's used to boot another kernel image, so it's not much
915 different from reboot(8). Therefore, we don't need to
916 spin down the disk in this case, especially since Alpha
917 firmware doesn't handle disks in standby mode properly.
918 On the other hand, it's reasonably safe to turn the power
919 off when the shutdown process reaches the firmware prompt,
920 as the firmware initialization takes rather long time -
921 at least 10 seconds, which should be sufficient for
922 the disk to expire its write cache. */
923 if (system_state != SYSTEM_POWER_OFF) {
924#else
925 if (system_state == SYSTEM_RESTART) {
926#endif
927 ide_cacheflush_p(drive);
928 return;
929 }
930
Bartlomiej Zolnierkiewiczd12faa22008-02-26 21:50:36 +0100931 printk(KERN_INFO "Shutdown: %s\n", drive->name);
932
Russell King4031bbe2006-01-06 11:41:00 +0000933 drive->gendev.bus->suspend(&drive->gendev, PMSG_SUSPEND);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934}
935
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936static ide_driver_t idedisk_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937 .gen_driver = {
Laurent Riffard4ef3b8f2005-11-18 22:15:40 +0100938 .owner = THIS_MODULE,
Bartlomiej Zolnierkiewicz8604aff2005-05-26 14:55:34 +0200939 .name = "ide-disk",
940 .bus = &ide_bus_type,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941 },
Russell King4031bbe2006-01-06 11:41:00 +0000942 .probe = ide_disk_probe,
943 .remove = ide_disk_remove,
Lee Trager0d2157f2007-06-08 15:14:30 +0200944 .resume = ide_disk_resume,
Russell King4031bbe2006-01-06 11:41:00 +0000945 .shutdown = ide_device_shutdown,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946 .version = IDEDISK_VERSION,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947 .do_request = ide_do_rw_disk,
948 .end_request = ide_end_request,
949 .error = __ide_error,
Bartlomiej Zolnierkiewicz7662d042007-05-10 00:01:10 +0200950#ifdef CONFIG_IDE_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951 .proc = idedisk_proc,
Bartlomiej Zolnierkiewicz8185d5a2008-10-10 22:39:28 +0200952 .settings = idedisk_settings,
Bartlomiej Zolnierkiewicz7662d042007-05-10 00:01:10 +0200953#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954};
955
Bartlomiej Zolnierkiewicz29ec6832008-01-26 20:12:59 +0100956static int idedisk_set_doorlock(ide_drive_t *drive, int on)
957{
958 ide_task_t task;
959
960 memset(&task, 0, sizeof(task));
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200961 task.tf.command = on ? ATA_CMD_MEDIA_LOCK : ATA_CMD_MEDIA_UNLOCK;
Bartlomiej Zolnierkiewicz657cc1a2008-01-26 20:13:10 +0100962 task.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
Bartlomiej Zolnierkiewicz29ec6832008-01-26 20:12:59 +0100963
964 return ide_no_data_taskfile(drive, &task);
965}
966
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967static int idedisk_open(struct inode *inode, struct file *filp)
968{
969 struct gendisk *disk = inode->i_bdev->bd_disk;
970 struct ide_disk_obj *idkp;
971 ide_drive_t *drive;
972
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200973 idkp = ide_disk_get(disk);
974 if (idkp == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975 return -ENXIO;
976
977 drive = idkp->drive;
978
Bartlomiej Zolnierkiewiczc94964a2007-02-17 02:40:24 +0100979 idkp->openers++;
980
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200981 if ((drive->dev_flags & IDE_DFLAG_REMOVABLE) && idkp->openers == 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 check_disk_change(inode->i_bdev);
983 /*
984 * Ignore the return code from door_lock,
985 * since the open() has already succeeded,
986 * and the door_lock is irrelevant at this point.
987 */
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200988 if ((drive->dev_flags & IDE_DFLAG_DOORLOCKING) &&
989 idedisk_set_doorlock(drive, 1))
990 drive->dev_flags &= ~IDE_DFLAG_DOORLOCKING;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991 }
992 return 0;
993}
994
995static int idedisk_release(struct inode *inode, struct file *filp)
996{
997 struct gendisk *disk = inode->i_bdev->bd_disk;
998 struct ide_disk_obj *idkp = ide_disk_g(disk);
999 ide_drive_t *drive = idkp->drive;
1000
Bartlomiej Zolnierkiewiczc94964a2007-02-17 02:40:24 +01001001 if (idkp->openers == 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 ide_cacheflush_p(drive);
Bartlomiej Zolnierkiewiczc94964a2007-02-17 02:40:24 +01001003
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +02001004 if ((drive->dev_flags & IDE_DFLAG_REMOVABLE) && idkp->openers == 1) {
1005 if ((drive->dev_flags & IDE_DFLAG_DOORLOCKING) &&
1006 idedisk_set_doorlock(drive, 0))
1007 drive->dev_flags &= ~IDE_DFLAG_DOORLOCKING;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 }
Bartlomiej Zolnierkiewiczc94964a2007-02-17 02:40:24 +01001009
1010 idkp->openers--;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011
1012 ide_disk_put(idkp);
1013
1014 return 0;
1015}
1016
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001017static int idedisk_getgeo(struct block_device *bdev, struct hd_geometry *geo)
1018{
1019 struct ide_disk_obj *idkp = ide_disk_g(bdev->bd_disk);
1020 ide_drive_t *drive = idkp->drive;
1021
1022 geo->heads = drive->bios_head;
1023 geo->sectors = drive->bios_sect;
1024 geo->cylinders = (u16)drive->bios_cyl; /* truncate */
1025 return 0;
1026}
1027
Bartlomiej Zolnierkiewiczaa7687732008-10-10 22:39:33 +02001028static const struct ide_ioctl_devset ide_disk_ioctl_settings[] = {
Elias Oltmanns92f1f8f2008-10-10 22:39:40 +02001029{ HDIO_GET_ADDRESS, HDIO_SET_ADDRESS, &ide_devset_address },
1030{ HDIO_GET_MULTCOUNT, HDIO_SET_MULTCOUNT, &ide_devset_multcount },
1031{ HDIO_GET_NOWERR, HDIO_SET_NOWERR, &ide_devset_nowerr },
1032{ HDIO_GET_WCACHE, HDIO_SET_WCACHE, &ide_devset_wcache },
1033{ HDIO_GET_ACOUSTIC, HDIO_SET_ACOUSTIC, &ide_devset_acoustic },
Bartlomiej Zolnierkiewiczaa7687732008-10-10 22:39:33 +02001034{ 0 }
1035};
1036
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037static int idedisk_ioctl(struct inode *inode, struct file *file,
1038 unsigned int cmd, unsigned long arg)
1039{
1040 struct block_device *bdev = inode->i_bdev;
1041 struct ide_disk_obj *idkp = ide_disk_g(bdev->bd_disk);
Bartlomiej Zolnierkiewicz14979432007-05-10 00:01:10 +02001042 ide_drive_t *drive = idkp->drive;
Bartlomiej Zolnierkiewiczaa7687732008-10-10 22:39:33 +02001043 int err;
Bartlomiej Zolnierkiewicz14979432007-05-10 00:01:10 +02001044
Bartlomiej Zolnierkiewiczaa7687732008-10-10 22:39:33 +02001045 err = ide_setting_ioctl(drive, bdev, cmd, arg, ide_disk_ioctl_settings);
1046 if (err != -EOPNOTSUPP)
1047 return err;
Bartlomiej Zolnierkiewicz14979432007-05-10 00:01:10 +02001048
1049 return generic_ide_ioctl(drive, file, bdev, cmd, arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050}
1051
1052static int idedisk_media_changed(struct gendisk *disk)
1053{
1054 struct ide_disk_obj *idkp = ide_disk_g(disk);
1055 ide_drive_t *drive = idkp->drive;
1056
1057 /* do not scan partitions twice if this is a removable device */
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +02001058 if (drive->dev_flags & IDE_DFLAG_ATTACH) {
1059 drive->dev_flags &= ~IDE_DFLAG_ATTACH;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060 return 0;
1061 }
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +02001062
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 /* if removable, always assume it was changed */
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +02001064 return !!(drive->dev_flags & IDE_DFLAG_REMOVABLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065}
1066
1067static int idedisk_revalidate_disk(struct gendisk *disk)
1068{
1069 struct ide_disk_obj *idkp = ide_disk_g(disk);
1070 set_capacity(disk, idedisk_capacity(idkp->drive));
1071 return 0;
1072}
1073
1074static struct block_device_operations idedisk_ops = {
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +02001075 .owner = THIS_MODULE,
1076 .open = idedisk_open,
1077 .release = idedisk_release,
1078 .ioctl = idedisk_ioctl,
1079 .getgeo = idedisk_getgeo,
1080 .media_changed = idedisk_media_changed,
1081 .revalidate_disk = idedisk_revalidate_disk
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082};
1083
1084MODULE_DESCRIPTION("ATA DISK Driver");
1085
Russell King4031bbe2006-01-06 11:41:00 +00001086static int ide_disk_probe(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087{
1088 struct ide_disk_obj *idkp;
1089 struct gendisk *g;
1090
1091 /* strstr("foo", "") is non-NULL */
1092 if (!strstr("ide-disk", drive->driver_req))
1093 goto failed;
Bartlomiej Zolnierkiewicz2a924662008-10-10 22:39:24 +02001094
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 if (drive->media != ide_disk)
1096 goto failed;
1097
Deepak Saxenaf5e3c2f2005-11-07 01:01:25 -08001098 idkp = kzalloc(sizeof(*idkp), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099 if (!idkp)
1100 goto failed;
1101
Tejun Heo689d6fa2008-08-25 19:56:16 +09001102 g = alloc_disk_node(IDE_DISK_MINORS, hwif_to_node(drive->hwif));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 if (!g)
1104 goto out_free_idkp;
1105
1106 ide_init_disk(g, drive);
1107
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108 kref_init(&idkp->kref);
1109
1110 idkp->drive = drive;
1111 idkp->driver = &idedisk_driver;
1112 idkp->disk = g;
1113
1114 g->private_data = &idkp->driver;
1115
1116 drive->driver_data = idkp;
1117
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118 idedisk_setup(drive);
Bartlomiej Zolnierkiewiczd1d76712008-10-13 21:39:38 +02001119 if ((drive->dev_flags & IDE_DFLAG_LBA) == 0 &&
1120 (drive->head == 0 || drive->head > 16)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 printk(KERN_ERR "%s: INVALID GEOMETRY: %d PHYSICAL HEADS?\n",
1122 drive->name, drive->head);
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +02001123 drive->dev_flags &= ~IDE_DFLAG_ATTACH;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124 } else
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +02001125 drive->dev_flags |= IDE_DFLAG_ATTACH;
Bartlomiej Zolnierkiewicz8604aff2005-05-26 14:55:34 +02001126
Tejun Heof615b482008-08-25 19:47:24 +09001127 g->minors = IDE_DISK_MINORS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128 g->driverfs_dev = &drive->gendev;
Tejun Heo689d6fa2008-08-25 19:56:16 +09001129 g->flags |= GENHD_FL_EXT_DEVT;
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +02001130 if (drive->dev_flags & IDE_DFLAG_REMOVABLE)
1131 g->flags = GENHD_FL_REMOVABLE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132 set_capacity(g, idedisk_capacity(drive));
1133 g->fops = &idedisk_ops;
1134 add_disk(g);
1135 return 0;
1136
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137out_free_idkp:
1138 kfree(idkp);
1139failed:
Bartlomiej Zolnierkiewicz8604aff2005-05-26 14:55:34 +02001140 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141}
1142
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +02001143static void __exit idedisk_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144{
Bartlomiej Zolnierkiewicz8604aff2005-05-26 14:55:34 +02001145 driver_unregister(&idedisk_driver.gen_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146}
1147
Bartlomiej Zolnierkiewicz17514e82005-11-19 22:24:35 +01001148static int __init idedisk_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149{
Bartlomiej Zolnierkiewicz8604aff2005-05-26 14:55:34 +02001150 return driver_register(&idedisk_driver.gen_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151}
1152
Kay Sievers263756e2005-12-12 18:03:44 +01001153MODULE_ALIAS("ide:*m-disk*");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154module_init(idedisk_init);
1155module_exit(idedisk_exit);
1156MODULE_LICENSE("GPL");