blob: 474070c1ddb6bb2f29cc9c3a568eb039420255a2 [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
91/*
92 * lba_capacity_is_ok() performs a sanity check on the claimed "lba_capacity"
93 * value for this drive (from its reported identification information).
94 *
95 * Returns: 1 if lba_capacity looks sensible
96 * 0 otherwise
97 *
98 * It is called only once for each drive.
99 */
Bartlomiej Zolnierkiewicz4dde4492008-10-10 22:39:19 +0200100static int lba_capacity_is_ok(u16 *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101{
102 unsigned long lba_sects, chs_sects, head, tail;
103
Alan Cox6efd9362005-06-27 15:24:22 -0700104 /* No non-LBA info .. so valid! */
Bartlomiej Zolnierkiewicz4dde4492008-10-10 22:39:19 +0200105 if (id[ATA_ID_CYLS] == 0)
Alan Cox6efd9362005-06-27 15:24:22 -0700106 return 1;
107
Bartlomiej Zolnierkiewicz48fb2682008-10-10 22:39:19 +0200108 lba_sects = ata_id_u32(id, ATA_ID_LBA_CAPACITY);
109
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110 /*
111 * The ATA spec tells large drives to return
112 * C/H/S = 16383/16/63 independent of their size.
113 * Some drives can be jumpered to use 15 heads instead of 16.
114 * Some drives can be jumpered to use 4092 cyls instead of 16383.
115 */
Bartlomiej Zolnierkiewicz4dde4492008-10-10 22:39:19 +0200116 if ((id[ATA_ID_CYLS] == 16383 ||
117 (id[ATA_ID_CYLS] == 4092 && id[ATA_ID_CUR_CYLS] == 16383)) &&
118 id[ATA_ID_SECTORS] == 63 &&
119 (id[ATA_ID_HEADS] == 15 || id[ATA_ID_HEADS] == 16) &&
Bartlomiej Zolnierkiewicz48fb2682008-10-10 22:39:19 +0200120 (lba_sects >= 16383 * 63 * id[ATA_ID_HEADS]))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121 return 1;
122
Bartlomiej Zolnierkiewicz4dde4492008-10-10 22:39:19 +0200123 chs_sects = id[ATA_ID_CYLS] * id[ATA_ID_HEADS] * id[ATA_ID_SECTORS];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124
125 /* perform a rough sanity check on lba_sects: within 10% is OK */
126 if ((lba_sects - chs_sects) < chs_sects/10)
127 return 1;
128
129 /* some drives have the word order reversed */
130 head = ((lba_sects >> 16) & 0xffff);
131 tail = (lba_sects & 0xffff);
132 lba_sects = (head | (tail << 16));
133 if ((lba_sects - chs_sects) < chs_sects/10) {
Bartlomiej Zolnierkiewicz48fb2682008-10-10 22:39:19 +0200134 *(__le32 *)&id[ATA_ID_LBA_CAPACITY] = __cpu_to_le32(lba_sects);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135 return 1; /* lba_capacity is (now) good */
136 }
137
138 return 0; /* lba_capacity value may be bad */
139}
140
Bartlomiej Zolnierkiewiczba76ae32008-01-25 22:17:16 +0100141static const u8 ide_rw_cmds[] = {
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200142 ATA_CMD_READ_MULTI,
143 ATA_CMD_WRITE_MULTI,
144 ATA_CMD_READ_MULTI_EXT,
145 ATA_CMD_WRITE_MULTI_EXT,
146 ATA_CMD_PIO_READ,
147 ATA_CMD_PIO_WRITE,
148 ATA_CMD_PIO_READ_EXT,
149 ATA_CMD_PIO_WRITE_EXT,
150 ATA_CMD_READ,
151 ATA_CMD_WRITE,
152 ATA_CMD_READ_EXT,
153 ATA_CMD_WRITE_EXT,
Bartlomiej Zolnierkiewiczba76ae32008-01-25 22:17:16 +0100154};
155
156static const u8 ide_data_phases[] = {
157 TASKFILE_MULTI_IN,
158 TASKFILE_MULTI_OUT,
159 TASKFILE_IN,
160 TASKFILE_OUT,
161 TASKFILE_IN_DMA,
162 TASKFILE_OUT_DMA,
163};
164
165static void ide_tf_set_cmd(ide_drive_t *drive, ide_task_t *task, u8 dma)
166{
167 u8 index, lba48, write;
168
169 lba48 = (task->tf_flags & IDE_TFLAG_LBA48) ? 2 : 0;
170 write = (task->tf_flags & IDE_TFLAG_WRITE) ? 1 : 0;
171
172 if (dma)
Bartlomiej Zolnierkiewiczba4b2e62008-07-23 19:55:55 +0200173 index = 8;
Bartlomiej Zolnierkiewiczba76ae32008-01-25 22:17:16 +0100174 else
175 index = drive->mult_count ? 0 : 4;
176
177 task->tf.command = ide_rw_cmds[index + lba48 + write];
178
179 if (dma)
180 index = 8; /* fixup index */
181
182 task->data_phase = ide_data_phases[index / 2 + write];
183}
184
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185/*
186 * __ide_do_rw_disk() issues READ and WRITE commands to a disk,
187 * using LBA if supported, or CHS otherwise, to address sectors.
188 */
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200189static ide_startstop_t __ide_do_rw_disk(ide_drive_t *drive, struct request *rq,
190 sector_t block)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191{
192 ide_hwif_t *hwif = HWIF(drive);
193 unsigned int dma = drive->using_dma;
Bartlomiej Zolnierkiewicz790d1232008-01-25 22:17:12 +0100194 u16 nsectors = (u16)rq->nr_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195 u8 lba48 = (drive->addressing == 1) ? 1 : 0;
Bartlomiej Zolnierkiewicz9e422372008-01-25 22:17:07 +0100196 ide_task_t task;
197 struct ide_taskfile *tf = &task.tf;
Bartlomiej Zolnierkiewiczf6e29e32008-01-25 22:17:16 +0100198 ide_startstop_t rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199
Bartlomiej Zolnierkiewicz238e4f12007-10-19 00:30:07 +0200200 if ((hwif->host_flags & IDE_HFLAG_NO_LBA48_DMA) && lba48 && dma) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201 if (block + rq->nr_sectors > 1ULL << 28)
202 dma = 0;
203 else
204 lba48 = 0;
205 }
206
207 if (!dma) {
208 ide_init_sg_cmd(drive, rq);
209 ide_map_sg(drive, rq);
210 }
211
Bartlomiej Zolnierkiewicz9e422372008-01-25 22:17:07 +0100212 memset(&task, 0, sizeof(task));
Bartlomiej Zolnierkiewicz9a410e72008-07-15 21:21:48 +0200213 task.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
Bartlomiej Zolnierkiewicz2bd06b22008-01-25 22:17:06 +0100214
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 if (drive->select.b.lba) {
216 if (lba48) {
Michael Richardsonc2f83112006-02-07 12:58:33 -0800217 pr_debug("%s: LBA=0x%012llx\n", drive->name,
218 (unsigned long long)block);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219
Bartlomiej Zolnierkiewicz790d1232008-01-25 22:17:12 +0100220 tf->hob_nsect = (nsectors >> 8) & 0xff;
Bartlomiej Zolnierkiewicz2bd06b22008-01-25 22:17:06 +0100221 tf->hob_lbal = (u8)(block >> 24);
222 if (sizeof(block) != 4) {
223 tf->hob_lbam = (u8)((u64)block >> 32);
224 tf->hob_lbah = (u8)((u64)block >> 40);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 }
Bartlomiej Zolnierkiewicz2bd06b22008-01-25 22:17:06 +0100226
Bartlomiej Zolnierkiewicz790d1232008-01-25 22:17:12 +0100227 tf->nsect = nsectors & 0xff;
Bartlomiej Zolnierkiewicz2bd06b22008-01-25 22:17:06 +0100228 tf->lbal = (u8) block;
229 tf->lbam = (u8)(block >> 8);
230 tf->lbah = (u8)(block >> 16);
Bartlomiej Zolnierkiewicz6dd9b832008-01-26 20:13:03 +0100231
Bartlomiej Zolnierkiewicz657cc1a2008-01-26 20:13:10 +0100232 task.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_HOB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233 } else {
Bartlomiej Zolnierkiewicz790d1232008-01-25 22:17:12 +0100234 tf->nsect = nsectors & 0xff;
Bartlomiej Zolnierkiewicz2bd06b22008-01-25 22:17:06 +0100235 tf->lbal = block;
236 tf->lbam = block >>= 8;
237 tf->lbah = block >>= 8;
238 tf->device = (block >> 8) & 0xf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239 }
240 } else {
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200241 unsigned int sect, head, cyl, track;
242
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243 track = (int)block / drive->sect;
244 sect = (int)block % drive->sect + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245 head = track % drive->head;
246 cyl = track / drive->head;
247
248 pr_debug("%s: CHS=%u/%u/%u\n", drive->name, cyl, head, sect);
249
Bartlomiej Zolnierkiewicz790d1232008-01-25 22:17:12 +0100250 tf->nsect = nsectors & 0xff;
Bartlomiej Zolnierkiewicz2bd06b22008-01-25 22:17:06 +0100251 tf->lbal = sect;
252 tf->lbam = cyl;
253 tf->lbah = cyl >> 8;
254 tf->device = head;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255 }
256
Bartlomiej Zolnierkiewiczba76ae32008-01-25 22:17:16 +0100257 if (rq_data_dir(rq))
258 task.tf_flags |= IDE_TFLAG_WRITE;
259
260 ide_tf_set_cmd(drive, &task, dma);
Bartlomiej Zolnierkiewiczf6e29e32008-01-25 22:17:16 +0100261 if (!dma)
262 hwif->data_phase = task.data_phase;
263 task.rq = rq;
Bartlomiej Zolnierkiewiczba76ae32008-01-25 22:17:16 +0100264
Bartlomiej Zolnierkiewiczf6e29e32008-01-25 22:17:16 +0100265 rc = do_rw_taskfile(drive, &task);
Bartlomiej Zolnierkiewicz2bd06b22008-01-25 22:17:06 +0100266
Bartlomiej Zolnierkiewiczf6e29e32008-01-25 22:17:16 +0100267 if (rc == ide_stopped && dma) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268 /* fallback to PIO */
Bartlomiej Zolnierkiewiczf6e29e32008-01-25 22:17:16 +0100269 task.tf_flags |= IDE_TFLAG_DMA_PIO_FALLBACK;
Bartlomiej Zolnierkiewiczba76ae32008-01-25 22:17:16 +0100270 ide_tf_set_cmd(drive, &task, 0);
Bartlomiej Zolnierkiewiczf6e29e32008-01-25 22:17:16 +0100271 hwif->data_phase = task.data_phase;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 ide_init_sg_cmd(drive, rq);
Bartlomiej Zolnierkiewiczf6e29e32008-01-25 22:17:16 +0100273 rc = do_rw_taskfile(drive, &task);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274 }
275
Bartlomiej Zolnierkiewiczf6e29e32008-01-25 22:17:16 +0100276 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277}
278
279/*
280 * 268435455 == 137439 MB or 28bit limit
281 * 320173056 == 163929 MB or 48bit addressing
282 * 1073741822 == 549756 MB or 48bit addressing fake drive
283 */
284
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200285static ide_startstop_t ide_do_rw_disk(ide_drive_t *drive, struct request *rq,
286 sector_t block)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287{
288 ide_hwif_t *hwif = HWIF(drive);
289
290 BUG_ON(drive->blocked);
291
292 if (!blk_fs_request(rq)) {
293 blk_dump_rq_flags(rq, "ide_do_rw_disk - bad command");
294 ide_end_request(drive, 0, 0);
295 return ide_stopped;
296 }
297
Richard Purdie2bfb6462006-03-31 02:31:16 -0800298 ledtrig_ide_activity();
299
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 pr_debug("%s: %sing: block=%llu, sectors=%lu, buffer=0x%08lx\n",
301 drive->name, rq_data_dir(rq) == READ ? "read" : "writ",
Michael Richardsonc2f83112006-02-07 12:58:33 -0800302 (unsigned long long)block, rq->nr_sectors,
303 (unsigned long)rq->buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304
305 if (hwif->rw_disk)
306 hwif->rw_disk(drive, rq);
307
308 return __ide_do_rw_disk(drive, rq, block);
309}
310
311/*
312 * Queries for true maximum capacity of the drive.
313 * Returns maximum LBA address (> 0) of the drive, 0 if failed.
314 */
Bartlomiej Zolnierkiewicz7a3b7512008-01-25 22:17:06 +0100315static u64 idedisk_read_native_max_address(ide_drive_t *drive, int lba48)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316{
317 ide_task_t args;
Bartlomiej Zolnierkiewicz650d8412008-01-25 22:17:06 +0100318 struct ide_taskfile *tf = &args.tf;
Bartlomiej Zolnierkiewicz7a3b7512008-01-25 22:17:06 +0100319 u64 addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320
321 /* Create IDE/ATA command request structure */
322 memset(&args, 0, sizeof(ide_task_t));
Bartlomiej Zolnierkiewicz7a3b7512008-01-25 22:17:06 +0100323 if (lba48)
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200324 tf->command = ATA_CMD_READ_NATIVE_MAX_EXT;
Bartlomiej Zolnierkiewicz7a3b7512008-01-25 22:17:06 +0100325 else
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200326 tf->command = ATA_CMD_READ_NATIVE_MAX;
Bartlomiej Zolnierkiewicz650d8412008-01-25 22:17:06 +0100327 tf->device = ATA_LBA;
Bartlomiej Zolnierkiewicz657cc1a2008-01-26 20:13:10 +0100328 args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
Bartlomiej Zolnierkiewicza3bbb9d2008-01-25 22:17:10 +0100329 if (lba48)
Bartlomiej Zolnierkiewicz657cc1a2008-01-26 20:13:10 +0100330 args.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_HOB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331 /* submit command request */
Bartlomiej Zolnierkiewicz9a3c49b2008-01-25 22:17:07 +0100332 ide_no_data_taskfile(drive, &args);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333
334 /* if OK, compute maximum address value */
Bartlomiej Zolnierkiewicza5016332008-01-25 22:17:17 +0100335 if ((tf->status & 0x01) == 0)
336 addr = ide_get_lba_addr(tf, lba48) + 1;
Bartlomiej Zolnierkiewicz650d8412008-01-25 22:17:06 +0100337
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 return addr;
339}
340
341/*
342 * Sets maximum virtual LBA address of the drive.
343 * Returns new maximum virtual LBA address (> 0) or 0 on failure.
344 */
Bartlomiej Zolnierkiewicz7a3b7512008-01-25 22:17:06 +0100345static u64 idedisk_set_max_address(ide_drive_t *drive, u64 addr_req, int lba48)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346{
347 ide_task_t args;
Bartlomiej Zolnierkiewicz650d8412008-01-25 22:17:06 +0100348 struct ide_taskfile *tf = &args.tf;
Bartlomiej Zolnierkiewicz7a3b7512008-01-25 22:17:06 +0100349 u64 addr_set = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350
351 addr_req--;
352 /* Create IDE/ATA command request structure */
353 memset(&args, 0, sizeof(ide_task_t));
Bartlomiej Zolnierkiewicz650d8412008-01-25 22:17:06 +0100354 tf->lbal = (addr_req >> 0) & 0xff;
355 tf->lbam = (addr_req >>= 8) & 0xff;
356 tf->lbah = (addr_req >>= 8) & 0xff;
Bartlomiej Zolnierkiewicz7a3b7512008-01-25 22:17:06 +0100357 if (lba48) {
358 tf->hob_lbal = (addr_req >>= 8) & 0xff;
359 tf->hob_lbam = (addr_req >>= 8) & 0xff;
360 tf->hob_lbah = (addr_req >>= 8) & 0xff;
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200361 tf->command = ATA_CMD_SET_MAX_EXT;
Bartlomiej Zolnierkiewicz7a3b7512008-01-25 22:17:06 +0100362 } else {
363 tf->device = (addr_req >>= 8) & 0x0f;
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200364 tf->command = ATA_CMD_SET_MAX;
Bartlomiej Zolnierkiewicz7a3b7512008-01-25 22:17:06 +0100365 }
366 tf->device |= ATA_LBA;
Bartlomiej Zolnierkiewicz657cc1a2008-01-26 20:13:10 +0100367 args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
Bartlomiej Zolnierkiewicza3bbb9d2008-01-25 22:17:10 +0100368 if (lba48)
Bartlomiej Zolnierkiewicz657cc1a2008-01-26 20:13:10 +0100369 args.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_HOB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 /* submit command request */
Bartlomiej Zolnierkiewicz9a3c49b2008-01-25 22:17:07 +0100371 ide_no_data_taskfile(drive, &args);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 /* if OK, compute maximum address value */
Bartlomiej Zolnierkiewicza5016332008-01-25 22:17:17 +0100373 if ((tf->status & 0x01) == 0)
374 addr_set = ide_get_lba_addr(tf, lba48) + 1;
Bartlomiej Zolnierkiewicz650d8412008-01-25 22:17:06 +0100375
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 return addr_set;
377}
378
379static unsigned long long sectors_to_MB(unsigned long long n)
380{
381 n <<= 9; /* make it bytes */
382 do_div(n, 1000000); /* make it MB */
383 return n;
384}
385
386/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 * The same here.
388 */
Bartlomiej Zolnierkiewicz4dde4492008-10-10 22:39:19 +0200389static inline int idedisk_supports_lba48(const u16 *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390{
Bartlomiej Zolnierkiewicz4dde4492008-10-10 22:39:19 +0200391 return (id[ATA_ID_COMMAND_SET_2] & 0x0400) &&
392 (id[ATA_ID_CFS_ENABLE_2] & 0x0400) &&
Bartlomiej Zolnierkiewicz48fb2682008-10-10 22:39:19 +0200393 ata_id_u64(id, ATA_ID_LBA_CAPACITY_2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394}
395
Bartlomiej Zolnierkiewiczb0244a02007-08-20 22:42:57 +0200396/*
397 * Some disks report total number of sectors instead of
398 * maximum sector address. We list them here.
399 */
400static const struct drive_list_entry hpa_list[] = {
401 { "ST340823A", NULL },
Jorge Juan Chico7062cdc2007-09-17 12:35:30 +0200402 { "ST320413A", NULL },
Mikko Rapelib152fcd2008-02-19 01:41:25 +0100403 { "ST310211A", NULL },
Bartlomiej Zolnierkiewiczb0244a02007-08-20 22:42:57 +0200404 { NULL, NULL }
405};
406
Arjan van de Ven858119e2006-01-14 13:20:43 -0800407static void idedisk_check_hpa(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408{
409 unsigned long long capacity, set_max;
410 int lba48 = idedisk_supports_lba48(drive->id);
411
412 capacity = drive->capacity64;
Bartlomiej Zolnierkiewicz7a3b7512008-01-25 22:17:06 +0100413
414 set_max = idedisk_read_native_max_address(drive, lba48);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415
Bartlomiej Zolnierkiewiczb0244a02007-08-20 22:42:57 +0200416 if (ide_in_drive_list(drive->id, hpa_list)) {
417 /*
418 * Since we are inclusive wrt to firmware revisions do this
419 * extra check and apply the workaround only when needed.
420 */
421 if (set_max == capacity + 1)
422 set_max--;
423 }
424
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 if (set_max <= capacity)
426 return;
427
428 printk(KERN_INFO "%s: Host Protected Area detected.\n"
429 "\tcurrent capacity is %llu sectors (%llu MB)\n"
430 "\tnative capacity is %llu sectors (%llu MB)\n",
431 drive->name,
432 capacity, sectors_to_MB(capacity),
433 set_max, sectors_to_MB(set_max));
434
Bartlomiej Zolnierkiewicz7a3b7512008-01-25 22:17:06 +0100435 set_max = idedisk_set_max_address(drive, set_max, lba48);
436
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 if (set_max) {
438 drive->capacity64 = set_max;
439 printk(KERN_INFO "%s: Host Protected Area disabled.\n",
440 drive->name);
441 }
442}
443
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200444static void init_idedisk_capacity(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445{
Bartlomiej Zolnierkiewicz4dde4492008-10-10 22:39:19 +0200446 u16 *id = drive->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447 /*
448 * If this drive supports the Host Protected Area feature set,
449 * then we may need to change our opinion about the drive's capacity.
450 */
Bartlomiej Zolnierkiewiczf41891c2008-10-10 22:39:20 +0200451 int hpa = ata_id_hpa_enabled(id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452
453 if (idedisk_supports_lba48(id)) {
454 /* drive speaks 48-bit LBA */
455 drive->select.b.lba = 1;
Bartlomiej Zolnierkiewicz48fb2682008-10-10 22:39:19 +0200456 drive->capacity64 = ata_id_u64(id, ATA_ID_LBA_CAPACITY_2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 if (hpa)
458 idedisk_check_hpa(drive);
Bartlomiej Zolnierkiewicz48fb2682008-10-10 22:39:19 +0200459 } else if (ata_id_has_lba(id) && lba_capacity_is_ok(id)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 /* drive speaks 28-bit LBA */
461 drive->select.b.lba = 1;
Bartlomiej Zolnierkiewicz48fb2682008-10-10 22:39:19 +0200462 drive->capacity64 = ata_id_u32(id, ATA_ID_LBA_CAPACITY);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463 if (hpa)
464 idedisk_check_hpa(drive);
465 } else {
466 /* drive speaks boring old 28-bit CHS */
467 drive->capacity64 = drive->cyl * drive->head * drive->sect;
468 }
469}
470
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200471static sector_t idedisk_capacity(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472{
Bartlomiej Zolnierkiewicz3c619ff2008-10-10 22:39:22 +0200473 return drive->capacity64;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474}
475
Bartlomiej Zolnierkiewiczecfd80e2007-05-10 00:01:09 +0200476#ifdef CONFIG_IDE_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477static int smart_enable(ide_drive_t *drive)
478{
479 ide_task_t args;
Bartlomiej Zolnierkiewicz650d8412008-01-25 22:17:06 +0100480 struct ide_taskfile *tf = &args.tf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481
482 memset(&args, 0, sizeof(ide_task_t));
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200483 tf->feature = ATA_SMART_ENABLE;
484 tf->lbam = ATA_SMART_LBAM_PASS;
485 tf->lbah = ATA_SMART_LBAH_PASS;
486 tf->command = ATA_CMD_SMART;
Bartlomiej Zolnierkiewicz657cc1a2008-01-26 20:13:10 +0100487 args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
Bartlomiej Zolnierkiewicz9a3c49b2008-01-25 22:17:07 +0100488 return ide_no_data_taskfile(drive, &args);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489}
490
Bartlomiej Zolnierkiewicz43e7c0c2007-10-20 00:32:37 +0200491static int get_smart_data(ide_drive_t *drive, u8 *buf, u8 sub_cmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492{
493 ide_task_t args;
Bartlomiej Zolnierkiewicz650d8412008-01-25 22:17:06 +0100494 struct ide_taskfile *tf = &args.tf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495
496 memset(&args, 0, sizeof(ide_task_t));
Bartlomiej Zolnierkiewicz650d8412008-01-25 22:17:06 +0100497 tf->feature = sub_cmd;
498 tf->nsect = 0x01;
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200499 tf->lbam = ATA_SMART_LBAM_PASS;
500 tf->lbah = ATA_SMART_LBAH_PASS;
501 tf->command = ATA_CMD_SMART;
Bartlomiej Zolnierkiewicz657cc1a2008-01-26 20:13:10 +0100502 args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
Bartlomiej Zolnierkiewiczac026ff2008-01-25 22:17:14 +0100503 args.data_phase = TASKFILE_IN;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504 (void) smart_enable(drive);
Bartlomiej Zolnierkiewiczac026ff2008-01-25 22:17:14 +0100505 return ide_raw_taskfile(drive, &args, buf, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506}
507
508static int proc_idedisk_read_cache
509 (char *page, char **start, off_t off, int count, int *eof, void *data)
510{
511 ide_drive_t *drive = (ide_drive_t *) data;
512 char *out = page;
513 int len;
514
515 if (drive->id_read)
Bartlomiej Zolnierkiewicz4dde4492008-10-10 22:39:19 +0200516 len = sprintf(out, "%i\n", drive->id[ATA_ID_BUF_SIZE] / 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517 else
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200518 len = sprintf(out, "(none)\n");
519
520 PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521}
522
523static int proc_idedisk_read_capacity
524 (char *page, char **start, off_t off, int count, int *eof, void *data)
525{
526 ide_drive_t*drive = (ide_drive_t *)data;
527 int len;
528
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200529 len = sprintf(page, "%llu\n", (long long)idedisk_capacity(drive));
530
531 PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532}
533
Bartlomiej Zolnierkiewicz799ee572008-04-26 17:36:37 +0200534static int proc_idedisk_read_smart(char *page, char **start, off_t off,
535 int count, int *eof, void *data, u8 sub_cmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536{
537 ide_drive_t *drive = (ide_drive_t *)data;
538 int len = 0, i = 0;
539
Bartlomiej Zolnierkiewicz799ee572008-04-26 17:36:37 +0200540 if (get_smart_data(drive, page, sub_cmd) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541 unsigned short *val = (unsigned short *) page;
Bartlomiej Zolnierkiewicz151a6702008-10-10 22:39:28 +0200542 char *out = (char *)val + SECTOR_SIZE;
543
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 page = out;
545 do {
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200546 out += sprintf(out, "%04x%c", le16_to_cpu(*val),
547 (++i & 7) ? ' ' : '\n');
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548 val += 1;
Bartlomiej Zolnierkiewicz151a6702008-10-10 22:39:28 +0200549 } while (i < SECTOR_SIZE / 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550 len = out - page;
551 }
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200552
553 PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554}
555
Bartlomiej Zolnierkiewicz799ee572008-04-26 17:36:37 +0200556static int proc_idedisk_read_sv
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 (char *page, char **start, off_t off, int count, int *eof, void *data)
558{
Bartlomiej Zolnierkiewicz799ee572008-04-26 17:36:37 +0200559 return proc_idedisk_read_smart(page, start, off, count, eof, data,
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200560 ATA_SMART_READ_VALUES);
Bartlomiej Zolnierkiewicz799ee572008-04-26 17:36:37 +0200561}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562
Bartlomiej Zolnierkiewicz799ee572008-04-26 17:36:37 +0200563static int proc_idedisk_read_st
564 (char *page, char **start, off_t off, int count, int *eof, void *data)
565{
566 return proc_idedisk_read_smart(page, start, off, count, eof, data,
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200567 ATA_SMART_READ_THRESHOLDS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568}
569
570static ide_proc_entry_t idedisk_proc[] = {
Bartlomiej Zolnierkiewicz799ee572008-04-26 17:36:37 +0200571 { "cache", S_IFREG|S_IRUGO, proc_idedisk_read_cache, NULL },
572 { "capacity", S_IFREG|S_IRUGO, proc_idedisk_read_capacity, NULL },
573 { "geometry", S_IFREG|S_IRUGO, proc_ide_read_geometry, NULL },
574 { "smart_values", S_IFREG|S_IRUSR, proc_idedisk_read_sv, NULL },
575 { "smart_thresholds", S_IFREG|S_IRUSR, proc_idedisk_read_st, NULL },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 { NULL, 0, NULL, NULL }
577};
Bartlomiej Zolnierkiewiczecfd80e2007-05-10 00:01:09 +0200578#endif /* CONFIG_IDE_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579
Jens Axboe165125e2007-07-24 09:28:11 +0200580static void idedisk_prepare_flush(struct request_queue *q, struct request *rq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581{
582 ide_drive_t *drive = q->queuedata;
Bartlomiej Zolnierkiewicz395d8ef2008-02-11 00:32:14 +0100583 ide_task_t *task = kmalloc(sizeof(*task), GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584
Bartlomiej Zolnierkiewicz395d8ef2008-02-11 00:32:14 +0100585 /* FIXME: map struct ide_taskfile on rq->cmd[] */
586 BUG_ON(task == NULL);
587
588 memset(task, 0, sizeof(*task));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589 if (ide_id_has_flush_cache_ext(drive->id) &&
590 (drive->capacity64 >= (1UL << 28)))
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200591 task->tf.command = ATA_CMD_FLUSH_EXT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592 else
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200593 task->tf.command = ATA_CMD_FLUSH;
Bartlomiej Zolnierkiewicz395d8ef2008-02-11 00:32:14 +0100594 task->tf_flags = IDE_TFLAG_OUT_TF | IDE_TFLAG_OUT_DEVICE |
595 IDE_TFLAG_DYN;
596 task->data_phase = TASKFILE_NO_DATA;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597
Bartlomiej Zolnierkiewicz813a0eb2008-01-25 22:17:10 +0100598 rq->cmd_type = REQ_TYPE_ATA_TASKFILE;
Jens Axboe4aff5e22006-08-10 08:44:47 +0200599 rq->cmd_flags |= REQ_SOFTBARRIER;
Bartlomiej Zolnierkiewicz395d8ef2008-02-11 00:32:14 +0100600 rq->special = task;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601}
602
Bartlomiej Zolnierkiewicz8185d5a2008-10-10 22:39:28 +0200603ide_devset_get(multcount, mult_count);
604
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605/*
606 * This is tightly woven into the driver->do_special can not touch.
607 * DON'T do it again until a total personality rewrite is committed.
608 */
609static int set_multcount(ide_drive_t *drive, int arg)
610{
FUJITA Tomonoridd470872008-07-15 21:21:43 +0200611 struct request *rq;
612 int error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613
Bartlomiej Zolnierkiewicz48fb2682008-10-10 22:39:19 +0200614 if (arg < 0 || arg > (drive->id[ATA_ID_MAX_MULTSECT] & 0xff))
Bartlomiej Zolnierkiewicz14979432007-05-10 00:01:10 +0200615 return -EINVAL;
616
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 if (drive->special.b.set_multmode)
618 return -EBUSY;
Bartlomiej Zolnierkiewicz852738f2008-01-26 20:13:12 +0100619
FUJITA Tomonoridd470872008-07-15 21:21:43 +0200620 rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
621 rq->cmd_type = REQ_TYPE_ATA_TASKFILE;
Bartlomiej Zolnierkiewicz852738f2008-01-26 20:13:12 +0100622
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 drive->mult_req = arg;
624 drive->special.b.set_multmode = 1;
FUJITA Tomonoridd470872008-07-15 21:21:43 +0200625 error = blk_execute_rq(drive->queue, NULL, rq, 0);
626 blk_put_request(rq);
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200627
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628 return (drive->mult_count == arg) ? 0 : -EIO;
629}
630
Bartlomiej Zolnierkiewicz8185d5a2008-10-10 22:39:28 +0200631ide_devset_get(nowerr, nowerr);
632
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633static int set_nowerr(ide_drive_t *drive, int arg)
634{
Bartlomiej Zolnierkiewicz14979432007-05-10 00:01:10 +0200635 if (arg < 0 || arg > 1)
636 return -EINVAL;
637
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 if (ide_spin_wait_hwgroup(drive))
639 return -EBUSY;
640 drive->nowerr = arg;
641 drive->bad_wstat = arg ? BAD_R_STAT : BAD_W_STAT;
642 spin_unlock_irq(&ide_lock);
643 return 0;
644}
645
Tejun Heo3e087b52006-01-06 09:57:31 +0100646static void update_ordered(ide_drive_t *drive)
647{
Bartlomiej Zolnierkiewicz4dde4492008-10-10 22:39:19 +0200648 u16 *id = drive->id;
Tejun Heo3e087b52006-01-06 09:57:31 +0100649 unsigned ordered = QUEUE_ORDERED_NONE;
650 prepare_flush_fn *prep_fn = NULL;
Tejun Heo3e087b52006-01-06 09:57:31 +0100651
652 if (drive->wcache) {
653 unsigned long long capacity;
654 int barrier;
655 /*
656 * We must avoid issuing commands a drive does not
657 * understand or we may crash it. We check flush cache
658 * is supported. We also check we have the LBA48 flush
659 * cache if the drive capacity is too large. By this
660 * time we have trimmed the drive capacity if LBA48 is
661 * not available so we don't need to recheck that.
662 */
663 capacity = idedisk_capacity(drive);
Jens Axboe36193482006-07-28 08:54:59 +0200664 barrier = ide_id_has_flush_cache(id) && !drive->noflush &&
Tejun Heo3e087b52006-01-06 09:57:31 +0100665 (drive->addressing == 0 || capacity <= (1ULL << 28) ||
666 ide_id_has_flush_cache_ext(id));
667
668 printk(KERN_INFO "%s: cache flushes %ssupported\n",
Jean Delvaref7ad8362006-02-03 03:04:57 -0800669 drive->name, barrier ? "" : "not ");
Tejun Heo3e087b52006-01-06 09:57:31 +0100670
671 if (barrier) {
672 ordered = QUEUE_ORDERED_DRAIN_FLUSH;
673 prep_fn = idedisk_prepare_flush;
Tejun Heo3e087b52006-01-06 09:57:31 +0100674 }
675 } else
676 ordered = QUEUE_ORDERED_DRAIN;
677
678 blk_queue_ordered(drive->queue, ordered, prep_fn);
Tejun Heo3e087b52006-01-06 09:57:31 +0100679}
680
Bartlomiej Zolnierkiewicz8185d5a2008-10-10 22:39:28 +0200681ide_devset_get(wcache, wcache);
682
683static int set_wcache(ide_drive_t *drive, int arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684{
685 ide_task_t args;
Tejun Heo3e087b52006-01-06 09:57:31 +0100686 int err = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687
Bartlomiej Zolnierkiewicz14979432007-05-10 00:01:10 +0200688 if (arg < 0 || arg > 1)
689 return -EINVAL;
690
Tejun Heo3e087b52006-01-06 09:57:31 +0100691 if (ide_id_has_flush_cache(drive->id)) {
692 memset(&args, 0, sizeof(ide_task_t));
Bartlomiej Zolnierkiewicz650d8412008-01-25 22:17:06 +0100693 args.tf.feature = arg ?
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200694 SETFEATURES_WC_ON : SETFEATURES_WC_OFF;
695 args.tf.command = ATA_CMD_SET_FEATURES;
Bartlomiej Zolnierkiewicz657cc1a2008-01-26 20:13:10 +0100696 args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
Bartlomiej Zolnierkiewicz9a3c49b2008-01-25 22:17:07 +0100697 err = ide_no_data_taskfile(drive, &args);
Tejun Heo3e087b52006-01-06 09:57:31 +0100698 if (err == 0)
699 drive->wcache = arg;
700 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701
Tejun Heo3e087b52006-01-06 09:57:31 +0100702 update_ordered(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703
Tejun Heo3e087b52006-01-06 09:57:31 +0100704 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705}
706
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200707static int do_idedisk_flushcache(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708{
709 ide_task_t args;
710
711 memset(&args, 0, sizeof(ide_task_t));
712 if (ide_id_has_flush_cache_ext(drive->id))
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200713 args.tf.command = ATA_CMD_FLUSH_EXT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 else
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200715 args.tf.command = ATA_CMD_FLUSH;
Bartlomiej Zolnierkiewicz657cc1a2008-01-26 20:13:10 +0100716 args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
Bartlomiej Zolnierkiewicz9a3c49b2008-01-25 22:17:07 +0100717 return ide_no_data_taskfile(drive, &args);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718}
719
Bartlomiej Zolnierkiewicz8185d5a2008-10-10 22:39:28 +0200720ide_devset_get(acoustic, acoustic);
721
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200722static int set_acoustic(ide_drive_t *drive, int arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723{
724 ide_task_t args;
725
Bartlomiej Zolnierkiewicz14979432007-05-10 00:01:10 +0200726 if (arg < 0 || arg > 254)
727 return -EINVAL;
728
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 memset(&args, 0, sizeof(ide_task_t));
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200730 args.tf.feature = arg ? SETFEATURES_AAM_ON : SETFEATURES_AAM_OFF;
Bartlomiej Zolnierkiewicz650d8412008-01-25 22:17:06 +0100731 args.tf.nsect = arg;
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200732 args.tf.command = ATA_CMD_SET_FEATURES;
Bartlomiej Zolnierkiewicz657cc1a2008-01-26 20:13:10 +0100733 args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
Bartlomiej Zolnierkiewicz9a3c49b2008-01-25 22:17:07 +0100734 ide_no_data_taskfile(drive, &args);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 drive->acoustic = arg;
736 return 0;
737}
738
Bartlomiej Zolnierkiewicz8185d5a2008-10-10 22:39:28 +0200739ide_devset_get(lba_addressing, addressing);
740
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741/*
742 * drive->addressing:
743 * 0: 28-bit
744 * 1: 48-bit
745 * 2: 48-bit capable doing 28-bit
746 */
747static int set_lba_addressing(ide_drive_t *drive, int arg)
748{
Bartlomiej Zolnierkiewicz14979432007-05-10 00:01:10 +0200749 if (arg < 0 || arg > 2)
750 return -EINVAL;
751
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 drive->addressing = 0;
753
Bartlomiej Zolnierkiewicz238e4f12007-10-19 00:30:07 +0200754 if (drive->hwif->host_flags & IDE_HFLAG_NO_LBA48)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 return 0;
756
757 if (!idedisk_supports_lba48(drive->id))
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200758 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 drive->addressing = arg;
760 return 0;
761}
762
Bartlomiej Zolnierkiewicz7662d042007-05-10 00:01:10 +0200763#ifdef CONFIG_IDE_PROC_FS
Bartlomiej Zolnierkiewicz8185d5a2008-10-10 22:39:28 +0200764ide_devset_rw_nolock(acoustic, 0, 254, acoustic);
765ide_devset_rw_nolock(address, 0, 2, lba_addressing);
766ide_devset_rw_nolock(multcount, 0, 16, multcount);
767ide_devset_rw_nolock(nowerr, 0, 1, nowerr);
768ide_devset_rw_nolock(wcache, 0, 1, wcache);
769
770ide_devset_rw(bios_cyl, 0, 65535, bios_cyl);
771ide_devset_rw(bios_head, 0, 255, bios_head);
772ide_devset_rw(bios_sect, 0, 63, bios_sect);
773ide_devset_rw(failures, 0, 65535, failures);
774ide_devset_rw(lun, 0, 7, lun);
775ide_devset_rw(max_failures, 0, 65535, max_failures);
776
777static const struct ide_devset *idedisk_settings[] = {
778 &ide_devset_acoustic,
779 &ide_devset_address,
780 &ide_devset_bios_cyl,
781 &ide_devset_bios_head,
782 &ide_devset_bios_sect,
783 &ide_devset_failures,
784 &ide_devset_lun,
785 &ide_devset_max_failures,
786 &ide_devset_multcount,
787 &ide_devset_nowerr,
788 &ide_devset_wcache,
789 NULL
790};
Bartlomiej Zolnierkiewicz7662d042007-05-10 00:01:10 +0200791#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200793static void idedisk_setup(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794{
Bartlomiej Zolnierkiewicz1e874f42008-10-10 22:39:27 +0200795 struct ide_disk_obj *idkp = drive->driver_data;
Bartlomiej Zolnierkiewicz238e4f12007-10-19 00:30:07 +0200796 ide_hwif_t *hwif = drive->hwif;
Bartlomiej Zolnierkiewicz4dde4492008-10-10 22:39:19 +0200797 u16 *id = drive->id;
798 char *m = (char *)&id[ATA_ID_PROD];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 unsigned long long capacity;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800
Bartlomiej Zolnierkiewicz1e874f42008-10-10 22:39:27 +0200801 ide_proc_register_driver(drive, idkp->driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802
803 if (drive->id_read == 0)
804 return;
805
Richard Purdie98109332006-02-03 03:04:55 -0800806 if (drive->removable) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807 /*
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200808 * Removable disks (eg. SYQUEST); ignore 'WD' drives
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 */
Bartlomiej Zolnierkiewicz4dde4492008-10-10 22:39:19 +0200810 if (m[0] != 'W' || m[1] != 'D')
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 drive->doorlocking = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 }
813
814 (void)set_lba_addressing(drive, 1);
815
816 if (drive->addressing == 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 int max_s = 2048;
818
819 if (max_s > hwif->rqsize)
820 max_s = hwif->rqsize;
821
822 blk_queue_max_sectors(drive->queue, max_s);
823 }
824
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200825 printk(KERN_INFO "%s: max request size: %dKiB\n", drive->name,
826 drive->queue->max_sectors / 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827
828 /* calculate drive capacity, and select LBA if possible */
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200829 init_idedisk_capacity(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830
831 /* limit drive capacity to 137GB if LBA48 cannot be used */
832 if (drive->addressing == 0 && drive->capacity64 > 1ULL << 28) {
833 printk(KERN_WARNING "%s: cannot use LBA48 - full capacity "
834 "%llu sectors (%llu MB)\n",
835 drive->name, (unsigned long long)drive->capacity64,
836 sectors_to_MB(drive->capacity64));
837 drive->capacity64 = 1ULL << 28;
838 }
839
Bartlomiej Zolnierkiewicz238e4f12007-10-19 00:30:07 +0200840 if ((hwif->host_flags & IDE_HFLAG_NO_LBA48_DMA) && drive->addressing) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 if (drive->capacity64 > 1ULL << 28) {
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200842 printk(KERN_INFO "%s: cannot use LBA48 DMA - PIO mode"
843 " will be used for accessing sectors "
844 "> %u\n", drive->name, 1 << 28);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845 } else
846 drive->addressing = 0;
847 }
848
849 /*
850 * if possible, give fdisk access to more of the drive,
851 * by correcting bios_cyls:
852 */
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200853 capacity = idedisk_capacity(drive);
854
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 if (!drive->forced_geom) {
856
857 if (idedisk_supports_lba48(drive->id)) {
858 /* compatibility */
859 drive->bios_sect = 63;
860 drive->bios_head = 255;
861 }
862
863 if (drive->bios_sect && drive->bios_head) {
864 unsigned int cap0 = capacity; /* truncate to 32 bits */
865 unsigned int cylsz, cyl;
866
867 if (cap0 != capacity)
868 drive->bios_cyl = 65535;
869 else {
870 cylsz = drive->bios_sect * drive->bios_head;
871 cyl = cap0 / cylsz;
872 if (cyl > 65535)
873 cyl = 65535;
874 if (cyl > drive->bios_cyl)
875 drive->bios_cyl = cyl;
876 }
877 }
878 }
879 printk(KERN_INFO "%s: %llu sectors (%llu MB)",
880 drive->name, capacity, sectors_to_MB(capacity));
881
882 /* Only print cache size when it was specified */
Bartlomiej Zolnierkiewicz4dde4492008-10-10 22:39:19 +0200883 if (id[ATA_ID_BUF_SIZE])
884 printk(KERN_CONT " w/%dKiB Cache", id[ATA_ID_BUF_SIZE] / 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885
Bartlomiej Zolnierkiewicz3ab7efe2007-12-12 23:31:58 +0100886 printk(KERN_CONT ", CHS=%d/%d/%d\n",
887 drive->bios_cyl, drive->bios_head, drive->bios_sect);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 /* write cache enabled? */
Bartlomiej Zolnierkiewicz8a089c62008-10-10 22:39:20 +0200890 if ((id[ATA_ID_CSFO] & 1) || ata_id_wcache_enabled(id))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 drive->wcache = 1;
892
Bartlomiej Zolnierkiewicz8185d5a2008-10-10 22:39:28 +0200893 set_wcache(drive, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894}
895
896static void ide_cacheflush_p(ide_drive_t *drive)
897{
898 if (!drive->wcache || !ide_id_has_flush_cache(drive->id))
899 return;
900
901 if (do_idedisk_flushcache(drive))
902 printk(KERN_INFO "%s: wcache flush failed!\n", drive->name);
903}
904
Russell King4031bbe2006-01-06 11:41:00 +0000905static void ide_disk_remove(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906{
907 struct ide_disk_obj *idkp = drive->driver_data;
908 struct gendisk *g = idkp->disk;
909
Bartlomiej Zolnierkiewicz7662d042007-05-10 00:01:10 +0200910 ide_proc_unregister_driver(drive, idkp->driver);
Bartlomiej Zolnierkiewicz8604aff2005-05-26 14:55:34 +0200911
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 del_gendisk(g);
913
Bartlomiej Zolnierkiewiczd36fef62005-12-15 02:19:20 +0100914 ide_cacheflush_p(drive);
915
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916 ide_disk_put(idkp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917}
918
919static void ide_disk_release(struct kref *kref)
920{
921 struct ide_disk_obj *idkp = to_ide_disk(kref);
922 ide_drive_t *drive = idkp->drive;
923 struct gendisk *g = idkp->disk;
924
925 drive->driver_data = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926 g->private_data = NULL;
927 put_disk(g);
928 kfree(idkp);
929}
930
Russell King4031bbe2006-01-06 11:41:00 +0000931static int ide_disk_probe(ide_drive_t *drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932
Lee Trager0d2157f2007-06-08 15:14:30 +0200933/*
934 * On HPA drives the capacity needs to be
935 * reinitilized on resume otherwise the disk
936 * can not be used and a hard reset is required
937 */
938static void ide_disk_resume(ide_drive_t *drive)
939{
Bartlomiej Zolnierkiewiczf41891c2008-10-10 22:39:20 +0200940 if (ata_id_hpa_enabled(drive->id))
Lee Trager0d2157f2007-06-08 15:14:30 +0200941 init_idedisk_capacity(drive);
942}
943
Russell King4031bbe2006-01-06 11:41:00 +0000944static void ide_device_shutdown(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946#ifdef CONFIG_ALPHA
947 /* On Alpha, halt(8) doesn't actually turn the machine off,
948 it puts you into the sort of firmware monitor. Typically,
949 it's used to boot another kernel image, so it's not much
950 different from reboot(8). Therefore, we don't need to
951 spin down the disk in this case, especially since Alpha
952 firmware doesn't handle disks in standby mode properly.
953 On the other hand, it's reasonably safe to turn the power
954 off when the shutdown process reaches the firmware prompt,
955 as the firmware initialization takes rather long time -
956 at least 10 seconds, which should be sufficient for
957 the disk to expire its write cache. */
958 if (system_state != SYSTEM_POWER_OFF) {
959#else
960 if (system_state == SYSTEM_RESTART) {
961#endif
962 ide_cacheflush_p(drive);
963 return;
964 }
965
Bartlomiej Zolnierkiewiczd12faa22008-02-26 21:50:36 +0100966 printk(KERN_INFO "Shutdown: %s\n", drive->name);
967
Russell King4031bbe2006-01-06 11:41:00 +0000968 drive->gendev.bus->suspend(&drive->gendev, PMSG_SUSPEND);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969}
970
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971static ide_driver_t idedisk_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972 .gen_driver = {
Laurent Riffard4ef3b8f2005-11-18 22:15:40 +0100973 .owner = THIS_MODULE,
Bartlomiej Zolnierkiewicz8604aff2005-05-26 14:55:34 +0200974 .name = "ide-disk",
975 .bus = &ide_bus_type,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 },
Russell King4031bbe2006-01-06 11:41:00 +0000977 .probe = ide_disk_probe,
978 .remove = ide_disk_remove,
Lee Trager0d2157f2007-06-08 15:14:30 +0200979 .resume = ide_disk_resume,
Russell King4031bbe2006-01-06 11:41:00 +0000980 .shutdown = ide_device_shutdown,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981 .version = IDEDISK_VERSION,
982 .media = ide_disk,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 .supports_dsc_overlap = 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 .do_request = ide_do_rw_disk,
985 .end_request = ide_end_request,
986 .error = __ide_error,
Bartlomiej Zolnierkiewicz7662d042007-05-10 00:01:10 +0200987#ifdef CONFIG_IDE_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988 .proc = idedisk_proc,
Bartlomiej Zolnierkiewicz8185d5a2008-10-10 22:39:28 +0200989 .settings = idedisk_settings,
Bartlomiej Zolnierkiewicz7662d042007-05-10 00:01:10 +0200990#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991};
992
Bartlomiej Zolnierkiewicz29ec6832008-01-26 20:12:59 +0100993static int idedisk_set_doorlock(ide_drive_t *drive, int on)
994{
995 ide_task_t task;
996
997 memset(&task, 0, sizeof(task));
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200998 task.tf.command = on ? ATA_CMD_MEDIA_LOCK : ATA_CMD_MEDIA_UNLOCK;
Bartlomiej Zolnierkiewicz657cc1a2008-01-26 20:13:10 +0100999 task.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
Bartlomiej Zolnierkiewicz29ec6832008-01-26 20:12:59 +01001000
1001 return ide_no_data_taskfile(drive, &task);
1002}
1003
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004static int idedisk_open(struct inode *inode, struct file *filp)
1005{
1006 struct gendisk *disk = inode->i_bdev->bd_disk;
1007 struct ide_disk_obj *idkp;
1008 ide_drive_t *drive;
1009
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +02001010 idkp = ide_disk_get(disk);
1011 if (idkp == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012 return -ENXIO;
1013
1014 drive = idkp->drive;
1015
Bartlomiej Zolnierkiewiczc94964a2007-02-17 02:40:24 +01001016 idkp->openers++;
1017
1018 if (drive->removable && idkp->openers == 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019 check_disk_change(inode->i_bdev);
1020 /*
1021 * Ignore the return code from door_lock,
1022 * since the open() has already succeeded,
1023 * and the door_lock is irrelevant at this point.
1024 */
Bartlomiej Zolnierkiewicz29ec6832008-01-26 20:12:59 +01001025 if (drive->doorlocking && idedisk_set_doorlock(drive, 1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026 drive->doorlocking = 0;
1027 }
1028 return 0;
1029}
1030
1031static int idedisk_release(struct inode *inode, struct file *filp)
1032{
1033 struct gendisk *disk = inode->i_bdev->bd_disk;
1034 struct ide_disk_obj *idkp = ide_disk_g(disk);
1035 ide_drive_t *drive = idkp->drive;
1036
Bartlomiej Zolnierkiewiczc94964a2007-02-17 02:40:24 +01001037 if (idkp->openers == 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 ide_cacheflush_p(drive);
Bartlomiej Zolnierkiewiczc94964a2007-02-17 02:40:24 +01001039
1040 if (drive->removable && idkp->openers == 1) {
Bartlomiej Zolnierkiewicz29ec6832008-01-26 20:12:59 +01001041 if (drive->doorlocking && idedisk_set_doorlock(drive, 0))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042 drive->doorlocking = 0;
1043 }
Bartlomiej Zolnierkiewiczc94964a2007-02-17 02:40:24 +01001044
1045 idkp->openers--;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046
1047 ide_disk_put(idkp);
1048
1049 return 0;
1050}
1051
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001052static int idedisk_getgeo(struct block_device *bdev, struct hd_geometry *geo)
1053{
1054 struct ide_disk_obj *idkp = ide_disk_g(bdev->bd_disk);
1055 ide_drive_t *drive = idkp->drive;
1056
1057 geo->heads = drive->bios_head;
1058 geo->sectors = drive->bios_sect;
1059 geo->cylinders = (u16)drive->bios_cyl; /* truncate */
1060 return 0;
1061}
1062
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063static int idedisk_ioctl(struct inode *inode, struct file *file,
1064 unsigned int cmd, unsigned long arg)
1065{
Bartlomiej Zolnierkiewicz14979432007-05-10 00:01:10 +02001066 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067 struct block_device *bdev = inode->i_bdev;
1068 struct ide_disk_obj *idkp = ide_disk_g(bdev->bd_disk);
Bartlomiej Zolnierkiewicz14979432007-05-10 00:01:10 +02001069 ide_drive_t *drive = idkp->drive;
Bartlomiej Zolnierkiewicz8185d5a2008-10-10 22:39:28 +02001070 int err, (*getfunc)(ide_drive_t *), (*setfunc)(ide_drive_t *, int);
Bartlomiej Zolnierkiewicz14979432007-05-10 00:01:10 +02001071
1072 switch (cmd) {
Bartlomiej Zolnierkiewicz8185d5a2008-10-10 22:39:28 +02001073 case HDIO_GET_ADDRESS: getfunc = get_lba_addressing; goto read_val;
1074 case HDIO_GET_MULTCOUNT: getfunc = get_multcount; goto read_val;
1075 case HDIO_GET_NOWERR: getfunc = get_nowerr; goto read_val;
1076 case HDIO_GET_WCACHE: getfunc = get_wcache; goto read_val;
1077 case HDIO_GET_ACOUSTIC: getfunc = get_acoustic; goto read_val;
Bartlomiej Zolnierkiewicz14979432007-05-10 00:01:10 +02001078 case HDIO_SET_ADDRESS: setfunc = set_lba_addressing; goto set_val;
1079 case HDIO_SET_MULTCOUNT: setfunc = set_multcount; goto set_val;
1080 case HDIO_SET_NOWERR: setfunc = set_nowerr; goto set_val;
Bartlomiej Zolnierkiewicz8185d5a2008-10-10 22:39:28 +02001081 case HDIO_SET_WCACHE: setfunc = set_wcache; goto set_val;
Bartlomiej Zolnierkiewicz14979432007-05-10 00:01:10 +02001082 case HDIO_SET_ACOUSTIC: setfunc = set_acoustic; goto set_val;
1083 }
1084
1085 return generic_ide_ioctl(drive, file, bdev, cmd, arg);
1086
1087read_val:
Matthias Kaehlckef9383c42007-07-09 23:17:56 +02001088 mutex_lock(&ide_setting_mtx);
Bartlomiej Zolnierkiewicz14979432007-05-10 00:01:10 +02001089 spin_lock_irqsave(&ide_lock, flags);
Bartlomiej Zolnierkiewicz8185d5a2008-10-10 22:39:28 +02001090 err = getfunc(drive);
Bartlomiej Zolnierkiewicz14979432007-05-10 00:01:10 +02001091 spin_unlock_irqrestore(&ide_lock, flags);
Matthias Kaehlckef9383c42007-07-09 23:17:56 +02001092 mutex_unlock(&ide_setting_mtx);
Bartlomiej Zolnierkiewicz14979432007-05-10 00:01:10 +02001093 return err >= 0 ? put_user(err, (long __user *)arg) : err;
1094
1095set_val:
1096 if (bdev != bdev->bd_contains)
1097 err = -EINVAL;
1098 else {
1099 if (!capable(CAP_SYS_ADMIN))
1100 err = -EACCES;
1101 else {
Matthias Kaehlckef9383c42007-07-09 23:17:56 +02001102 mutex_lock(&ide_setting_mtx);
Bartlomiej Zolnierkiewicz14979432007-05-10 00:01:10 +02001103 err = setfunc(drive, arg);
Matthias Kaehlckef9383c42007-07-09 23:17:56 +02001104 mutex_unlock(&ide_setting_mtx);
Bartlomiej Zolnierkiewicz14979432007-05-10 00:01:10 +02001105 }
1106 }
1107 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108}
1109
1110static int idedisk_media_changed(struct gendisk *disk)
1111{
1112 struct ide_disk_obj *idkp = ide_disk_g(disk);
1113 ide_drive_t *drive = idkp->drive;
1114
1115 /* do not scan partitions twice if this is a removable device */
1116 if (drive->attach) {
1117 drive->attach = 0;
1118 return 0;
1119 }
1120 /* if removable, always assume it was changed */
1121 return drive->removable;
1122}
1123
1124static int idedisk_revalidate_disk(struct gendisk *disk)
1125{
1126 struct ide_disk_obj *idkp = ide_disk_g(disk);
1127 set_capacity(disk, idedisk_capacity(idkp->drive));
1128 return 0;
1129}
1130
1131static struct block_device_operations idedisk_ops = {
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +02001132 .owner = THIS_MODULE,
1133 .open = idedisk_open,
1134 .release = idedisk_release,
1135 .ioctl = idedisk_ioctl,
1136 .getgeo = idedisk_getgeo,
1137 .media_changed = idedisk_media_changed,
1138 .revalidate_disk = idedisk_revalidate_disk
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139};
1140
1141MODULE_DESCRIPTION("ATA DISK Driver");
1142
Russell King4031bbe2006-01-06 11:41:00 +00001143static int ide_disk_probe(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144{
1145 struct ide_disk_obj *idkp;
1146 struct gendisk *g;
1147
1148 /* strstr("foo", "") is non-NULL */
1149 if (!strstr("ide-disk", drive->driver_req))
1150 goto failed;
Bartlomiej Zolnierkiewicz2a924662008-10-10 22:39:24 +02001151
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152 if (drive->media != ide_disk)
1153 goto failed;
1154
Deepak Saxenaf5e3c2f2005-11-07 01:01:25 -08001155 idkp = kzalloc(sizeof(*idkp), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156 if (!idkp)
1157 goto failed;
1158
Tejun Heo689d6fa2008-08-25 19:56:16 +09001159 g = alloc_disk_node(IDE_DISK_MINORS, hwif_to_node(drive->hwif));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160 if (!g)
1161 goto out_free_idkp;
1162
1163 ide_init_disk(g, drive);
1164
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 kref_init(&idkp->kref);
1166
1167 idkp->drive = drive;
1168 idkp->driver = &idedisk_driver;
1169 idkp->disk = g;
1170
1171 g->private_data = &idkp->driver;
1172
1173 drive->driver_data = idkp;
1174
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175 idedisk_setup(drive);
1176 if ((!drive->head || drive->head > 16) && !drive->select.b.lba) {
1177 printk(KERN_ERR "%s: INVALID GEOMETRY: %d PHYSICAL HEADS?\n",
1178 drive->name, drive->head);
1179 drive->attach = 0;
1180 } else
1181 drive->attach = 1;
Bartlomiej Zolnierkiewicz8604aff2005-05-26 14:55:34 +02001182
Tejun Heof615b482008-08-25 19:47:24 +09001183 g->minors = IDE_DISK_MINORS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 g->driverfs_dev = &drive->gendev;
Tejun Heo689d6fa2008-08-25 19:56:16 +09001185 g->flags |= GENHD_FL_EXT_DEVT;
1186 if (drive->removable)
1187 g->flags |= GENHD_FL_REMOVABLE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188 set_capacity(g, idedisk_capacity(drive));
1189 g->fops = &idedisk_ops;
1190 add_disk(g);
1191 return 0;
1192
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193out_free_idkp:
1194 kfree(idkp);
1195failed:
Bartlomiej Zolnierkiewicz8604aff2005-05-26 14:55:34 +02001196 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197}
1198
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +02001199static void __exit idedisk_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200{
Bartlomiej Zolnierkiewicz8604aff2005-05-26 14:55:34 +02001201 driver_unregister(&idedisk_driver.gen_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202}
1203
Bartlomiej Zolnierkiewicz17514e82005-11-19 22:24:35 +01001204static int __init idedisk_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205{
Bartlomiej Zolnierkiewicz8604aff2005-05-26 14:55:34 +02001206 return driver_register(&idedisk_driver.gen_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207}
1208
Kay Sievers263756e2005-12-12 18:03:44 +01001209MODULE_ALIAS("ide:*m-disk*");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210module_init(idedisk_init);
1211module_exit(idedisk_exit);
1212MODULE_LICENSE("GPL");