blob: 587d5aac7d5d318f1194c160afcd816f3890fc72 [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/*
Bartlomiej Zolnierkiewiczb0244a02007-08-20 22:42:57 +0200387 * Some disks report total number of sectors instead of
388 * maximum sector address. We list them here.
389 */
390static const struct drive_list_entry hpa_list[] = {
391 { "ST340823A", NULL },
Jorge Juan Chico7062cdc2007-09-17 12:35:30 +0200392 { "ST320413A", NULL },
Mikko Rapelib152fcd2008-02-19 01:41:25 +0100393 { "ST310211A", NULL },
Bartlomiej Zolnierkiewiczb0244a02007-08-20 22:42:57 +0200394 { NULL, NULL }
395};
396
Arjan van de Ven858119e2006-01-14 13:20:43 -0800397static void idedisk_check_hpa(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398{
399 unsigned long long capacity, set_max;
Bartlomiej Zolnierkiewicz942dcd82008-10-10 22:39:30 +0200400 int lba48 = ata_id_lba48_enabled(drive->id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401
402 capacity = drive->capacity64;
Bartlomiej Zolnierkiewicz7a3b7512008-01-25 22:17:06 +0100403
404 set_max = idedisk_read_native_max_address(drive, lba48);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405
Bartlomiej Zolnierkiewiczb0244a02007-08-20 22:42:57 +0200406 if (ide_in_drive_list(drive->id, hpa_list)) {
407 /*
408 * Since we are inclusive wrt to firmware revisions do this
409 * extra check and apply the workaround only when needed.
410 */
411 if (set_max == capacity + 1)
412 set_max--;
413 }
414
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 if (set_max <= capacity)
416 return;
417
418 printk(KERN_INFO "%s: Host Protected Area detected.\n"
419 "\tcurrent capacity is %llu sectors (%llu MB)\n"
420 "\tnative capacity is %llu sectors (%llu MB)\n",
421 drive->name,
422 capacity, sectors_to_MB(capacity),
423 set_max, sectors_to_MB(set_max));
424
Bartlomiej Zolnierkiewicz7a3b7512008-01-25 22:17:06 +0100425 set_max = idedisk_set_max_address(drive, set_max, lba48);
426
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 if (set_max) {
428 drive->capacity64 = set_max;
429 printk(KERN_INFO "%s: Host Protected Area disabled.\n",
430 drive->name);
431 }
432}
433
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200434static void init_idedisk_capacity(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435{
Bartlomiej Zolnierkiewicz4dde4492008-10-10 22:39:19 +0200436 u16 *id = drive->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 /*
438 * If this drive supports the Host Protected Area feature set,
439 * then we may need to change our opinion about the drive's capacity.
440 */
Bartlomiej Zolnierkiewiczf41891c2008-10-10 22:39:20 +0200441 int hpa = ata_id_hpa_enabled(id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442
Bartlomiej Zolnierkiewicz942dcd82008-10-10 22:39:30 +0200443 if (ata_id_lba48_enabled(id)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 /* drive speaks 48-bit LBA */
445 drive->select.b.lba = 1;
Bartlomiej Zolnierkiewicz48fb2682008-10-10 22:39:19 +0200446 drive->capacity64 = ata_id_u64(id, ATA_ID_LBA_CAPACITY_2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447 if (hpa)
448 idedisk_check_hpa(drive);
Bartlomiej Zolnierkiewicz48fb2682008-10-10 22:39:19 +0200449 } else if (ata_id_has_lba(id) && lba_capacity_is_ok(id)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450 /* drive speaks 28-bit LBA */
451 drive->select.b.lba = 1;
Bartlomiej Zolnierkiewicz48fb2682008-10-10 22:39:19 +0200452 drive->capacity64 = ata_id_u32(id, ATA_ID_LBA_CAPACITY);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453 if (hpa)
454 idedisk_check_hpa(drive);
455 } else {
456 /* drive speaks boring old 28-bit CHS */
457 drive->capacity64 = drive->cyl * drive->head * drive->sect;
458 }
459}
460
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200461static sector_t idedisk_capacity(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462{
Bartlomiej Zolnierkiewicz3c619ff2008-10-10 22:39:22 +0200463 return drive->capacity64;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464}
465
Bartlomiej Zolnierkiewiczecfd80e2007-05-10 00:01:09 +0200466#ifdef CONFIG_IDE_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467static int smart_enable(ide_drive_t *drive)
468{
469 ide_task_t args;
Bartlomiej Zolnierkiewicz650d8412008-01-25 22:17:06 +0100470 struct ide_taskfile *tf = &args.tf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471
472 memset(&args, 0, sizeof(ide_task_t));
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200473 tf->feature = ATA_SMART_ENABLE;
474 tf->lbam = ATA_SMART_LBAM_PASS;
475 tf->lbah = ATA_SMART_LBAH_PASS;
476 tf->command = ATA_CMD_SMART;
Bartlomiej Zolnierkiewicz657cc1a2008-01-26 20:13:10 +0100477 args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
Bartlomiej Zolnierkiewicz9a3c49b2008-01-25 22:17:07 +0100478 return ide_no_data_taskfile(drive, &args);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479}
480
Bartlomiej Zolnierkiewicz43e7c0c2007-10-20 00:32:37 +0200481static int get_smart_data(ide_drive_t *drive, u8 *buf, u8 sub_cmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482{
483 ide_task_t args;
Bartlomiej Zolnierkiewicz650d8412008-01-25 22:17:06 +0100484 struct ide_taskfile *tf = &args.tf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485
486 memset(&args, 0, sizeof(ide_task_t));
Bartlomiej Zolnierkiewicz650d8412008-01-25 22:17:06 +0100487 tf->feature = sub_cmd;
488 tf->nsect = 0x01;
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200489 tf->lbam = ATA_SMART_LBAM_PASS;
490 tf->lbah = ATA_SMART_LBAH_PASS;
491 tf->command = ATA_CMD_SMART;
Bartlomiej Zolnierkiewicz657cc1a2008-01-26 20:13:10 +0100492 args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
Bartlomiej Zolnierkiewiczac026ff2008-01-25 22:17:14 +0100493 args.data_phase = TASKFILE_IN;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 (void) smart_enable(drive);
Bartlomiej Zolnierkiewiczac026ff2008-01-25 22:17:14 +0100495 return ide_raw_taskfile(drive, &args, buf, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496}
497
498static int proc_idedisk_read_cache
499 (char *page, char **start, off_t off, int count, int *eof, void *data)
500{
501 ide_drive_t *drive = (ide_drive_t *) data;
502 char *out = page;
503 int len;
504
505 if (drive->id_read)
Bartlomiej Zolnierkiewicz4dde4492008-10-10 22:39:19 +0200506 len = sprintf(out, "%i\n", drive->id[ATA_ID_BUF_SIZE] / 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 else
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200508 len = sprintf(out, "(none)\n");
509
510 PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511}
512
513static int proc_idedisk_read_capacity
514 (char *page, char **start, off_t off, int count, int *eof, void *data)
515{
516 ide_drive_t*drive = (ide_drive_t *)data;
517 int len;
518
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200519 len = sprintf(page, "%llu\n", (long long)idedisk_capacity(drive));
520
521 PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522}
523
Bartlomiej Zolnierkiewicz799ee572008-04-26 17:36:37 +0200524static int proc_idedisk_read_smart(char *page, char **start, off_t off,
525 int count, int *eof, void *data, u8 sub_cmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526{
527 ide_drive_t *drive = (ide_drive_t *)data;
528 int len = 0, i = 0;
529
Bartlomiej Zolnierkiewicz799ee572008-04-26 17:36:37 +0200530 if (get_smart_data(drive, page, sub_cmd) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531 unsigned short *val = (unsigned short *) page;
Bartlomiej Zolnierkiewicz151a6702008-10-10 22:39:28 +0200532 char *out = (char *)val + SECTOR_SIZE;
533
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534 page = out;
535 do {
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200536 out += sprintf(out, "%04x%c", le16_to_cpu(*val),
537 (++i & 7) ? ' ' : '\n');
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 val += 1;
Bartlomiej Zolnierkiewicz151a6702008-10-10 22:39:28 +0200539 } while (i < SECTOR_SIZE / 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 len = out - page;
541 }
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200542
543 PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544}
545
Bartlomiej Zolnierkiewicz799ee572008-04-26 17:36:37 +0200546static int proc_idedisk_read_sv
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 (char *page, char **start, off_t off, int count, int *eof, void *data)
548{
Bartlomiej Zolnierkiewicz799ee572008-04-26 17:36:37 +0200549 return proc_idedisk_read_smart(page, start, off, count, eof, data,
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200550 ATA_SMART_READ_VALUES);
Bartlomiej Zolnierkiewicz799ee572008-04-26 17:36:37 +0200551}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552
Bartlomiej Zolnierkiewicz799ee572008-04-26 17:36:37 +0200553static int proc_idedisk_read_st
554 (char *page, char **start, off_t off, int count, int *eof, void *data)
555{
556 return proc_idedisk_read_smart(page, start, off, count, eof, data,
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200557 ATA_SMART_READ_THRESHOLDS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558}
559
560static ide_proc_entry_t idedisk_proc[] = {
Bartlomiej Zolnierkiewicz799ee572008-04-26 17:36:37 +0200561 { "cache", S_IFREG|S_IRUGO, proc_idedisk_read_cache, NULL },
562 { "capacity", S_IFREG|S_IRUGO, proc_idedisk_read_capacity, NULL },
563 { "geometry", S_IFREG|S_IRUGO, proc_ide_read_geometry, NULL },
564 { "smart_values", S_IFREG|S_IRUSR, proc_idedisk_read_sv, NULL },
565 { "smart_thresholds", S_IFREG|S_IRUSR, proc_idedisk_read_st, NULL },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566 { NULL, 0, NULL, NULL }
567};
Bartlomiej Zolnierkiewiczecfd80e2007-05-10 00:01:09 +0200568#endif /* CONFIG_IDE_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569
Jens Axboe165125e2007-07-24 09:28:11 +0200570static void idedisk_prepare_flush(struct request_queue *q, struct request *rq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571{
572 ide_drive_t *drive = q->queuedata;
Bartlomiej Zolnierkiewicz395d8ef2008-02-11 00:32:14 +0100573 ide_task_t *task = kmalloc(sizeof(*task), GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574
Bartlomiej Zolnierkiewicz395d8ef2008-02-11 00:32:14 +0100575 /* FIXME: map struct ide_taskfile on rq->cmd[] */
576 BUG_ON(task == NULL);
577
578 memset(task, 0, sizeof(*task));
Bartlomiej Zolnierkiewiczff2779b2008-10-10 22:39:31 +0200579 if (ata_id_flush_ext_enabled(drive->id) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 (drive->capacity64 >= (1UL << 28)))
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200581 task->tf.command = ATA_CMD_FLUSH_EXT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 else
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200583 task->tf.command = ATA_CMD_FLUSH;
Bartlomiej Zolnierkiewicz395d8ef2008-02-11 00:32:14 +0100584 task->tf_flags = IDE_TFLAG_OUT_TF | IDE_TFLAG_OUT_DEVICE |
585 IDE_TFLAG_DYN;
586 task->data_phase = TASKFILE_NO_DATA;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587
Bartlomiej Zolnierkiewicz813a0eb2008-01-25 22:17:10 +0100588 rq->cmd_type = REQ_TYPE_ATA_TASKFILE;
Jens Axboe4aff5e22006-08-10 08:44:47 +0200589 rq->cmd_flags |= REQ_SOFTBARRIER;
Bartlomiej Zolnierkiewicz395d8ef2008-02-11 00:32:14 +0100590 rq->special = task;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591}
592
Bartlomiej Zolnierkiewicz8185d5a2008-10-10 22:39:28 +0200593ide_devset_get(multcount, mult_count);
594
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595/*
596 * This is tightly woven into the driver->do_special can not touch.
597 * DON'T do it again until a total personality rewrite is committed.
598 */
599static int set_multcount(ide_drive_t *drive, int arg)
600{
FUJITA Tomonoridd470872008-07-15 21:21:43 +0200601 struct request *rq;
602 int error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603
Bartlomiej Zolnierkiewicz48fb2682008-10-10 22:39:19 +0200604 if (arg < 0 || arg > (drive->id[ATA_ID_MAX_MULTSECT] & 0xff))
Bartlomiej Zolnierkiewicz14979432007-05-10 00:01:10 +0200605 return -EINVAL;
606
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 if (drive->special.b.set_multmode)
608 return -EBUSY;
Bartlomiej Zolnierkiewicz852738f2008-01-26 20:13:12 +0100609
FUJITA Tomonoridd470872008-07-15 21:21:43 +0200610 rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
611 rq->cmd_type = REQ_TYPE_ATA_TASKFILE;
Bartlomiej Zolnierkiewicz852738f2008-01-26 20:13:12 +0100612
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 drive->mult_req = arg;
614 drive->special.b.set_multmode = 1;
FUJITA Tomonoridd470872008-07-15 21:21:43 +0200615 error = blk_execute_rq(drive->queue, NULL, rq, 0);
616 blk_put_request(rq);
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200617
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 return (drive->mult_count == arg) ? 0 : -EIO;
619}
620
Bartlomiej Zolnierkiewicz8185d5a2008-10-10 22:39:28 +0200621ide_devset_get(nowerr, nowerr);
622
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623static int set_nowerr(ide_drive_t *drive, int arg)
624{
Bartlomiej Zolnierkiewicz14979432007-05-10 00:01:10 +0200625 if (arg < 0 || arg > 1)
626 return -EINVAL;
627
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628 if (ide_spin_wait_hwgroup(drive))
629 return -EBUSY;
630 drive->nowerr = arg;
631 drive->bad_wstat = arg ? BAD_R_STAT : BAD_W_STAT;
632 spin_unlock_irq(&ide_lock);
633 return 0;
634}
635
Tejun Heo3e087b52006-01-06 09:57:31 +0100636static void update_ordered(ide_drive_t *drive)
637{
Bartlomiej Zolnierkiewicz4dde4492008-10-10 22:39:19 +0200638 u16 *id = drive->id;
Tejun Heo3e087b52006-01-06 09:57:31 +0100639 unsigned ordered = QUEUE_ORDERED_NONE;
640 prepare_flush_fn *prep_fn = NULL;
Tejun Heo3e087b52006-01-06 09:57:31 +0100641
642 if (drive->wcache) {
643 unsigned long long capacity;
644 int barrier;
645 /*
646 * We must avoid issuing commands a drive does not
647 * understand or we may crash it. We check flush cache
648 * is supported. We also check we have the LBA48 flush
649 * cache if the drive capacity is too large. By this
650 * time we have trimmed the drive capacity if LBA48 is
651 * not available so we don't need to recheck that.
652 */
653 capacity = idedisk_capacity(drive);
Bartlomiej Zolnierkiewicz4b58f172008-10-10 22:39:30 +0200654 barrier = ata_id_flush_enabled(id) && !drive->noflush &&
Tejun Heo3e087b52006-01-06 09:57:31 +0100655 (drive->addressing == 0 || capacity <= (1ULL << 28) ||
Bartlomiej Zolnierkiewiczff2779b2008-10-10 22:39:31 +0200656 ata_id_flush_ext_enabled(id));
Tejun Heo3e087b52006-01-06 09:57:31 +0100657
658 printk(KERN_INFO "%s: cache flushes %ssupported\n",
Jean Delvaref7ad8362006-02-03 03:04:57 -0800659 drive->name, barrier ? "" : "not ");
Tejun Heo3e087b52006-01-06 09:57:31 +0100660
661 if (barrier) {
662 ordered = QUEUE_ORDERED_DRAIN_FLUSH;
663 prep_fn = idedisk_prepare_flush;
Tejun Heo3e087b52006-01-06 09:57:31 +0100664 }
665 } else
666 ordered = QUEUE_ORDERED_DRAIN;
667
668 blk_queue_ordered(drive->queue, ordered, prep_fn);
Tejun Heo3e087b52006-01-06 09:57:31 +0100669}
670
Bartlomiej Zolnierkiewicz8185d5a2008-10-10 22:39:28 +0200671ide_devset_get(wcache, wcache);
672
673static int set_wcache(ide_drive_t *drive, int arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674{
675 ide_task_t args;
Tejun Heo3e087b52006-01-06 09:57:31 +0100676 int err = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677
Bartlomiej Zolnierkiewicz14979432007-05-10 00:01:10 +0200678 if (arg < 0 || arg > 1)
679 return -EINVAL;
680
Bartlomiej Zolnierkiewicz4b58f172008-10-10 22:39:30 +0200681 if (ata_id_flush_enabled(drive->id)) {
Tejun Heo3e087b52006-01-06 09:57:31 +0100682 memset(&args, 0, sizeof(ide_task_t));
Bartlomiej Zolnierkiewicz650d8412008-01-25 22:17:06 +0100683 args.tf.feature = arg ?
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200684 SETFEATURES_WC_ON : SETFEATURES_WC_OFF;
685 args.tf.command = ATA_CMD_SET_FEATURES;
Bartlomiej Zolnierkiewicz657cc1a2008-01-26 20:13:10 +0100686 args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
Bartlomiej Zolnierkiewicz9a3c49b2008-01-25 22:17:07 +0100687 err = ide_no_data_taskfile(drive, &args);
Tejun Heo3e087b52006-01-06 09:57:31 +0100688 if (err == 0)
689 drive->wcache = arg;
690 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691
Tejun Heo3e087b52006-01-06 09:57:31 +0100692 update_ordered(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693
Tejun Heo3e087b52006-01-06 09:57:31 +0100694 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695}
696
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200697static int do_idedisk_flushcache(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698{
699 ide_task_t args;
700
701 memset(&args, 0, sizeof(ide_task_t));
Bartlomiej Zolnierkiewiczff2779b2008-10-10 22:39:31 +0200702 if (ata_id_flush_ext_enabled(drive->id))
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200703 args.tf.command = ATA_CMD_FLUSH_EXT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 else
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200705 args.tf.command = ATA_CMD_FLUSH;
Bartlomiej Zolnierkiewicz657cc1a2008-01-26 20:13:10 +0100706 args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
Bartlomiej Zolnierkiewicz9a3c49b2008-01-25 22:17:07 +0100707 return ide_no_data_taskfile(drive, &args);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708}
709
Bartlomiej Zolnierkiewicz8185d5a2008-10-10 22:39:28 +0200710ide_devset_get(acoustic, acoustic);
711
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200712static int set_acoustic(ide_drive_t *drive, int arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713{
714 ide_task_t args;
715
Bartlomiej Zolnierkiewicz14979432007-05-10 00:01:10 +0200716 if (arg < 0 || arg > 254)
717 return -EINVAL;
718
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 memset(&args, 0, sizeof(ide_task_t));
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200720 args.tf.feature = arg ? SETFEATURES_AAM_ON : SETFEATURES_AAM_OFF;
Bartlomiej Zolnierkiewicz650d8412008-01-25 22:17:06 +0100721 args.tf.nsect = arg;
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200722 args.tf.command = ATA_CMD_SET_FEATURES;
Bartlomiej Zolnierkiewicz657cc1a2008-01-26 20:13:10 +0100723 args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
Bartlomiej Zolnierkiewicz9a3c49b2008-01-25 22:17:07 +0100724 ide_no_data_taskfile(drive, &args);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 drive->acoustic = arg;
726 return 0;
727}
728
Bartlomiej Zolnierkiewicz8185d5a2008-10-10 22:39:28 +0200729ide_devset_get(lba_addressing, addressing);
730
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731/*
732 * drive->addressing:
733 * 0: 28-bit
734 * 1: 48-bit
735 * 2: 48-bit capable doing 28-bit
736 */
737static int set_lba_addressing(ide_drive_t *drive, int arg)
738{
Bartlomiej Zolnierkiewicz14979432007-05-10 00:01:10 +0200739 if (arg < 0 || arg > 2)
740 return -EINVAL;
741
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 drive->addressing = 0;
743
Bartlomiej Zolnierkiewicz238e4f12007-10-19 00:30:07 +0200744 if (drive->hwif->host_flags & IDE_HFLAG_NO_LBA48)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 return 0;
746
Bartlomiej Zolnierkiewicz942dcd82008-10-10 22:39:30 +0200747 if (ata_id_lba48_enabled(drive->id) == 0)
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200748 return -EIO;
Bartlomiej Zolnierkiewicz942dcd82008-10-10 22:39:30 +0200749
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 drive->addressing = arg;
Bartlomiej Zolnierkiewicz942dcd82008-10-10 22:39:30 +0200751
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 return 0;
753}
754
Bartlomiej Zolnierkiewicz7662d042007-05-10 00:01:10 +0200755#ifdef CONFIG_IDE_PROC_FS
Bartlomiej Zolnierkiewicz8185d5a2008-10-10 22:39:28 +0200756ide_devset_rw_nolock(acoustic, 0, 254, acoustic);
757ide_devset_rw_nolock(address, 0, 2, lba_addressing);
758ide_devset_rw_nolock(multcount, 0, 16, multcount);
759ide_devset_rw_nolock(nowerr, 0, 1, nowerr);
760ide_devset_rw_nolock(wcache, 0, 1, wcache);
761
762ide_devset_rw(bios_cyl, 0, 65535, bios_cyl);
763ide_devset_rw(bios_head, 0, 255, bios_head);
764ide_devset_rw(bios_sect, 0, 63, bios_sect);
765ide_devset_rw(failures, 0, 65535, failures);
766ide_devset_rw(lun, 0, 7, lun);
767ide_devset_rw(max_failures, 0, 65535, max_failures);
768
769static const struct ide_devset *idedisk_settings[] = {
770 &ide_devset_acoustic,
771 &ide_devset_address,
772 &ide_devset_bios_cyl,
773 &ide_devset_bios_head,
774 &ide_devset_bios_sect,
775 &ide_devset_failures,
776 &ide_devset_lun,
777 &ide_devset_max_failures,
778 &ide_devset_multcount,
779 &ide_devset_nowerr,
780 &ide_devset_wcache,
781 NULL
782};
Bartlomiej Zolnierkiewicz7662d042007-05-10 00:01:10 +0200783#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200785static void idedisk_setup(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786{
Bartlomiej Zolnierkiewicz1e874f42008-10-10 22:39:27 +0200787 struct ide_disk_obj *idkp = drive->driver_data;
Bartlomiej Zolnierkiewicz238e4f12007-10-19 00:30:07 +0200788 ide_hwif_t *hwif = drive->hwif;
Bartlomiej Zolnierkiewicz4dde4492008-10-10 22:39:19 +0200789 u16 *id = drive->id;
790 char *m = (char *)&id[ATA_ID_PROD];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 unsigned long long capacity;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792
Bartlomiej Zolnierkiewicz1e874f42008-10-10 22:39:27 +0200793 ide_proc_register_driver(drive, idkp->driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794
795 if (drive->id_read == 0)
796 return;
797
Richard Purdie98109332006-02-03 03:04:55 -0800798 if (drive->removable) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 /*
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200800 * Removable disks (eg. SYQUEST); ignore 'WD' drives
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 */
Bartlomiej Zolnierkiewicz4dde4492008-10-10 22:39:19 +0200802 if (m[0] != 'W' || m[1] != 'D')
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 drive->doorlocking = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 }
805
806 (void)set_lba_addressing(drive, 1);
807
808 if (drive->addressing == 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 int max_s = 2048;
810
811 if (max_s > hwif->rqsize)
812 max_s = hwif->rqsize;
813
814 blk_queue_max_sectors(drive->queue, max_s);
815 }
816
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200817 printk(KERN_INFO "%s: max request size: %dKiB\n", drive->name,
818 drive->queue->max_sectors / 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819
820 /* calculate drive capacity, and select LBA if possible */
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200821 init_idedisk_capacity(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822
823 /* limit drive capacity to 137GB if LBA48 cannot be used */
824 if (drive->addressing == 0 && drive->capacity64 > 1ULL << 28) {
825 printk(KERN_WARNING "%s: cannot use LBA48 - full capacity "
826 "%llu sectors (%llu MB)\n",
827 drive->name, (unsigned long long)drive->capacity64,
828 sectors_to_MB(drive->capacity64));
829 drive->capacity64 = 1ULL << 28;
830 }
831
Bartlomiej Zolnierkiewicz238e4f12007-10-19 00:30:07 +0200832 if ((hwif->host_flags & IDE_HFLAG_NO_LBA48_DMA) && drive->addressing) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 if (drive->capacity64 > 1ULL << 28) {
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200834 printk(KERN_INFO "%s: cannot use LBA48 DMA - PIO mode"
835 " will be used for accessing sectors "
836 "> %u\n", drive->name, 1 << 28);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 } else
838 drive->addressing = 0;
839 }
840
841 /*
842 * if possible, give fdisk access to more of the drive,
843 * by correcting bios_cyls:
844 */
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200845 capacity = idedisk_capacity(drive);
846
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 if (!drive->forced_geom) {
Bartlomiej Zolnierkiewicz942dcd82008-10-10 22:39:30 +0200848 if (ata_id_lba48_enabled(drive->id)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849 /* compatibility */
850 drive->bios_sect = 63;
851 drive->bios_head = 255;
852 }
853
854 if (drive->bios_sect && drive->bios_head) {
855 unsigned int cap0 = capacity; /* truncate to 32 bits */
856 unsigned int cylsz, cyl;
857
858 if (cap0 != capacity)
859 drive->bios_cyl = 65535;
860 else {
861 cylsz = drive->bios_sect * drive->bios_head;
862 cyl = cap0 / cylsz;
863 if (cyl > 65535)
864 cyl = 65535;
865 if (cyl > drive->bios_cyl)
866 drive->bios_cyl = cyl;
867 }
868 }
869 }
870 printk(KERN_INFO "%s: %llu sectors (%llu MB)",
871 drive->name, capacity, sectors_to_MB(capacity));
872
873 /* Only print cache size when it was specified */
Bartlomiej Zolnierkiewicz4dde4492008-10-10 22:39:19 +0200874 if (id[ATA_ID_BUF_SIZE])
875 printk(KERN_CONT " w/%dKiB Cache", id[ATA_ID_BUF_SIZE] / 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876
Bartlomiej Zolnierkiewicz3ab7efe2007-12-12 23:31:58 +0100877 printk(KERN_CONT ", CHS=%d/%d/%d\n",
878 drive->bios_cyl, drive->bios_head, drive->bios_sect);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 /* write cache enabled? */
Bartlomiej Zolnierkiewicz8a089c62008-10-10 22:39:20 +0200881 if ((id[ATA_ID_CSFO] & 1) || ata_id_wcache_enabled(id))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 drive->wcache = 1;
883
Bartlomiej Zolnierkiewicz8185d5a2008-10-10 22:39:28 +0200884 set_wcache(drive, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885}
886
887static void ide_cacheflush_p(ide_drive_t *drive)
888{
Bartlomiej Zolnierkiewicz4b58f172008-10-10 22:39:30 +0200889 if (!drive->wcache || ata_id_flush_enabled(drive->id) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 return;
891
892 if (do_idedisk_flushcache(drive))
893 printk(KERN_INFO "%s: wcache flush failed!\n", drive->name);
894}
895
Russell King4031bbe2006-01-06 11:41:00 +0000896static void ide_disk_remove(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897{
898 struct ide_disk_obj *idkp = drive->driver_data;
899 struct gendisk *g = idkp->disk;
900
Bartlomiej Zolnierkiewicz7662d042007-05-10 00:01:10 +0200901 ide_proc_unregister_driver(drive, idkp->driver);
Bartlomiej Zolnierkiewicz8604aff2005-05-26 14:55:34 +0200902
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 del_gendisk(g);
904
Bartlomiej Zolnierkiewiczd36fef62005-12-15 02:19:20 +0100905 ide_cacheflush_p(drive);
906
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907 ide_disk_put(idkp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908}
909
910static void ide_disk_release(struct kref *kref)
911{
912 struct ide_disk_obj *idkp = to_ide_disk(kref);
913 ide_drive_t *drive = idkp->drive;
914 struct gendisk *g = idkp->disk;
915
916 drive->driver_data = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 g->private_data = NULL;
918 put_disk(g);
919 kfree(idkp);
920}
921
Russell King4031bbe2006-01-06 11:41:00 +0000922static int ide_disk_probe(ide_drive_t *drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923
Lee Trager0d2157f2007-06-08 15:14:30 +0200924/*
925 * On HPA drives the capacity needs to be
926 * reinitilized on resume otherwise the disk
927 * can not be used and a hard reset is required
928 */
929static void ide_disk_resume(ide_drive_t *drive)
930{
Bartlomiej Zolnierkiewiczf41891c2008-10-10 22:39:20 +0200931 if (ata_id_hpa_enabled(drive->id))
Lee Trager0d2157f2007-06-08 15:14:30 +0200932 init_idedisk_capacity(drive);
933}
934
Russell King4031bbe2006-01-06 11:41:00 +0000935static void ide_device_shutdown(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937#ifdef CONFIG_ALPHA
938 /* On Alpha, halt(8) doesn't actually turn the machine off,
939 it puts you into the sort of firmware monitor. Typically,
940 it's used to boot another kernel image, so it's not much
941 different from reboot(8). Therefore, we don't need to
942 spin down the disk in this case, especially since Alpha
943 firmware doesn't handle disks in standby mode properly.
944 On the other hand, it's reasonably safe to turn the power
945 off when the shutdown process reaches the firmware prompt,
946 as the firmware initialization takes rather long time -
947 at least 10 seconds, which should be sufficient for
948 the disk to expire its write cache. */
949 if (system_state != SYSTEM_POWER_OFF) {
950#else
951 if (system_state == SYSTEM_RESTART) {
952#endif
953 ide_cacheflush_p(drive);
954 return;
955 }
956
Bartlomiej Zolnierkiewiczd12faa22008-02-26 21:50:36 +0100957 printk(KERN_INFO "Shutdown: %s\n", drive->name);
958
Russell King4031bbe2006-01-06 11:41:00 +0000959 drive->gendev.bus->suspend(&drive->gendev, PMSG_SUSPEND);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960}
961
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962static ide_driver_t idedisk_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 .gen_driver = {
Laurent Riffard4ef3b8f2005-11-18 22:15:40 +0100964 .owner = THIS_MODULE,
Bartlomiej Zolnierkiewicz8604aff2005-05-26 14:55:34 +0200965 .name = "ide-disk",
966 .bus = &ide_bus_type,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967 },
Russell King4031bbe2006-01-06 11:41:00 +0000968 .probe = ide_disk_probe,
969 .remove = ide_disk_remove,
Lee Trager0d2157f2007-06-08 15:14:30 +0200970 .resume = ide_disk_resume,
Russell King4031bbe2006-01-06 11:41:00 +0000971 .shutdown = ide_device_shutdown,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972 .version = IDEDISK_VERSION,
973 .media = ide_disk,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974 .do_request = ide_do_rw_disk,
975 .end_request = ide_end_request,
976 .error = __ide_error,
Bartlomiej Zolnierkiewicz7662d042007-05-10 00:01:10 +0200977#ifdef CONFIG_IDE_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 .proc = idedisk_proc,
Bartlomiej Zolnierkiewicz8185d5a2008-10-10 22:39:28 +0200979 .settings = idedisk_settings,
Bartlomiej Zolnierkiewicz7662d042007-05-10 00:01:10 +0200980#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981};
982
Bartlomiej Zolnierkiewicz29ec6832008-01-26 20:12:59 +0100983static int idedisk_set_doorlock(ide_drive_t *drive, int on)
984{
985 ide_task_t task;
986
987 memset(&task, 0, sizeof(task));
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200988 task.tf.command = on ? ATA_CMD_MEDIA_LOCK : ATA_CMD_MEDIA_UNLOCK;
Bartlomiej Zolnierkiewicz657cc1a2008-01-26 20:13:10 +0100989 task.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
Bartlomiej Zolnierkiewicz29ec6832008-01-26 20:12:59 +0100990
991 return ide_no_data_taskfile(drive, &task);
992}
993
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994static int idedisk_open(struct inode *inode, struct file *filp)
995{
996 struct gendisk *disk = inode->i_bdev->bd_disk;
997 struct ide_disk_obj *idkp;
998 ide_drive_t *drive;
999
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +02001000 idkp = ide_disk_get(disk);
1001 if (idkp == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 return -ENXIO;
1003
1004 drive = idkp->drive;
1005
Bartlomiej Zolnierkiewiczc94964a2007-02-17 02:40:24 +01001006 idkp->openers++;
1007
1008 if (drive->removable && idkp->openers == 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 check_disk_change(inode->i_bdev);
1010 /*
1011 * Ignore the return code from door_lock,
1012 * since the open() has already succeeded,
1013 * and the door_lock is irrelevant at this point.
1014 */
Bartlomiej Zolnierkiewicz29ec6832008-01-26 20:12:59 +01001015 if (drive->doorlocking && idedisk_set_doorlock(drive, 1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016 drive->doorlocking = 0;
1017 }
1018 return 0;
1019}
1020
1021static int idedisk_release(struct inode *inode, struct file *filp)
1022{
1023 struct gendisk *disk = inode->i_bdev->bd_disk;
1024 struct ide_disk_obj *idkp = ide_disk_g(disk);
1025 ide_drive_t *drive = idkp->drive;
1026
Bartlomiej Zolnierkiewiczc94964a2007-02-17 02:40:24 +01001027 if (idkp->openers == 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028 ide_cacheflush_p(drive);
Bartlomiej Zolnierkiewiczc94964a2007-02-17 02:40:24 +01001029
1030 if (drive->removable && idkp->openers == 1) {
Bartlomiej Zolnierkiewicz29ec6832008-01-26 20:12:59 +01001031 if (drive->doorlocking && idedisk_set_doorlock(drive, 0))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032 drive->doorlocking = 0;
1033 }
Bartlomiej Zolnierkiewiczc94964a2007-02-17 02:40:24 +01001034
1035 idkp->openers--;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036
1037 ide_disk_put(idkp);
1038
1039 return 0;
1040}
1041
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001042static int idedisk_getgeo(struct block_device *bdev, struct hd_geometry *geo)
1043{
1044 struct ide_disk_obj *idkp = ide_disk_g(bdev->bd_disk);
1045 ide_drive_t *drive = idkp->drive;
1046
1047 geo->heads = drive->bios_head;
1048 geo->sectors = drive->bios_sect;
1049 geo->cylinders = (u16)drive->bios_cyl; /* truncate */
1050 return 0;
1051}
1052
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053static int idedisk_ioctl(struct inode *inode, struct file *file,
1054 unsigned int cmd, unsigned long arg)
1055{
Bartlomiej Zolnierkiewicz14979432007-05-10 00:01:10 +02001056 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057 struct block_device *bdev = inode->i_bdev;
1058 struct ide_disk_obj *idkp = ide_disk_g(bdev->bd_disk);
Bartlomiej Zolnierkiewicz14979432007-05-10 00:01:10 +02001059 ide_drive_t *drive = idkp->drive;
Bartlomiej Zolnierkiewicz8185d5a2008-10-10 22:39:28 +02001060 int err, (*getfunc)(ide_drive_t *), (*setfunc)(ide_drive_t *, int);
Bartlomiej Zolnierkiewicz14979432007-05-10 00:01:10 +02001061
1062 switch (cmd) {
Bartlomiej Zolnierkiewicz8185d5a2008-10-10 22:39:28 +02001063 case HDIO_GET_ADDRESS: getfunc = get_lba_addressing; goto read_val;
1064 case HDIO_GET_MULTCOUNT: getfunc = get_multcount; goto read_val;
1065 case HDIO_GET_NOWERR: getfunc = get_nowerr; goto read_val;
1066 case HDIO_GET_WCACHE: getfunc = get_wcache; goto read_val;
1067 case HDIO_GET_ACOUSTIC: getfunc = get_acoustic; goto read_val;
Bartlomiej Zolnierkiewicz14979432007-05-10 00:01:10 +02001068 case HDIO_SET_ADDRESS: setfunc = set_lba_addressing; goto set_val;
1069 case HDIO_SET_MULTCOUNT: setfunc = set_multcount; goto set_val;
1070 case HDIO_SET_NOWERR: setfunc = set_nowerr; goto set_val;
Bartlomiej Zolnierkiewicz8185d5a2008-10-10 22:39:28 +02001071 case HDIO_SET_WCACHE: setfunc = set_wcache; goto set_val;
Bartlomiej Zolnierkiewicz14979432007-05-10 00:01:10 +02001072 case HDIO_SET_ACOUSTIC: setfunc = set_acoustic; goto set_val;
1073 }
1074
1075 return generic_ide_ioctl(drive, file, bdev, cmd, arg);
1076
1077read_val:
Matthias Kaehlckef9383c42007-07-09 23:17:56 +02001078 mutex_lock(&ide_setting_mtx);
Bartlomiej Zolnierkiewicz14979432007-05-10 00:01:10 +02001079 spin_lock_irqsave(&ide_lock, flags);
Bartlomiej Zolnierkiewicz8185d5a2008-10-10 22:39:28 +02001080 err = getfunc(drive);
Bartlomiej Zolnierkiewicz14979432007-05-10 00:01:10 +02001081 spin_unlock_irqrestore(&ide_lock, flags);
Matthias Kaehlckef9383c42007-07-09 23:17:56 +02001082 mutex_unlock(&ide_setting_mtx);
Bartlomiej Zolnierkiewicz14979432007-05-10 00:01:10 +02001083 return err >= 0 ? put_user(err, (long __user *)arg) : err;
1084
1085set_val:
1086 if (bdev != bdev->bd_contains)
1087 err = -EINVAL;
1088 else {
1089 if (!capable(CAP_SYS_ADMIN))
1090 err = -EACCES;
1091 else {
Matthias Kaehlckef9383c42007-07-09 23:17:56 +02001092 mutex_lock(&ide_setting_mtx);
Bartlomiej Zolnierkiewicz14979432007-05-10 00:01:10 +02001093 err = setfunc(drive, arg);
Matthias Kaehlckef9383c42007-07-09 23:17:56 +02001094 mutex_unlock(&ide_setting_mtx);
Bartlomiej Zolnierkiewicz14979432007-05-10 00:01:10 +02001095 }
1096 }
1097 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098}
1099
1100static int idedisk_media_changed(struct gendisk *disk)
1101{
1102 struct ide_disk_obj *idkp = ide_disk_g(disk);
1103 ide_drive_t *drive = idkp->drive;
1104
1105 /* do not scan partitions twice if this is a removable device */
1106 if (drive->attach) {
1107 drive->attach = 0;
1108 return 0;
1109 }
1110 /* if removable, always assume it was changed */
1111 return drive->removable;
1112}
1113
1114static int idedisk_revalidate_disk(struct gendisk *disk)
1115{
1116 struct ide_disk_obj *idkp = ide_disk_g(disk);
1117 set_capacity(disk, idedisk_capacity(idkp->drive));
1118 return 0;
1119}
1120
1121static struct block_device_operations idedisk_ops = {
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +02001122 .owner = THIS_MODULE,
1123 .open = idedisk_open,
1124 .release = idedisk_release,
1125 .ioctl = idedisk_ioctl,
1126 .getgeo = idedisk_getgeo,
1127 .media_changed = idedisk_media_changed,
1128 .revalidate_disk = idedisk_revalidate_disk
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129};
1130
1131MODULE_DESCRIPTION("ATA DISK Driver");
1132
Russell King4031bbe2006-01-06 11:41:00 +00001133static int ide_disk_probe(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134{
1135 struct ide_disk_obj *idkp;
1136 struct gendisk *g;
1137
1138 /* strstr("foo", "") is non-NULL */
1139 if (!strstr("ide-disk", drive->driver_req))
1140 goto failed;
Bartlomiej Zolnierkiewicz2a924662008-10-10 22:39:24 +02001141
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142 if (drive->media != ide_disk)
1143 goto failed;
1144
Deepak Saxenaf5e3c2f2005-11-07 01:01:25 -08001145 idkp = kzalloc(sizeof(*idkp), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146 if (!idkp)
1147 goto failed;
1148
Tejun Heo689d6fa2008-08-25 19:56:16 +09001149 g = alloc_disk_node(IDE_DISK_MINORS, hwif_to_node(drive->hwif));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150 if (!g)
1151 goto out_free_idkp;
1152
1153 ide_init_disk(g, drive);
1154
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155 kref_init(&idkp->kref);
1156
1157 idkp->drive = drive;
1158 idkp->driver = &idedisk_driver;
1159 idkp->disk = g;
1160
1161 g->private_data = &idkp->driver;
1162
1163 drive->driver_data = idkp;
1164
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 idedisk_setup(drive);
1166 if ((!drive->head || drive->head > 16) && !drive->select.b.lba) {
1167 printk(KERN_ERR "%s: INVALID GEOMETRY: %d PHYSICAL HEADS?\n",
1168 drive->name, drive->head);
1169 drive->attach = 0;
1170 } else
1171 drive->attach = 1;
Bartlomiej Zolnierkiewicz8604aff2005-05-26 14:55:34 +02001172
Tejun Heof615b482008-08-25 19:47:24 +09001173 g->minors = IDE_DISK_MINORS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174 g->driverfs_dev = &drive->gendev;
Tejun Heo689d6fa2008-08-25 19:56:16 +09001175 g->flags |= GENHD_FL_EXT_DEVT;
1176 if (drive->removable)
1177 g->flags |= GENHD_FL_REMOVABLE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178 set_capacity(g, idedisk_capacity(drive));
1179 g->fops = &idedisk_ops;
1180 add_disk(g);
1181 return 0;
1182
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183out_free_idkp:
1184 kfree(idkp);
1185failed:
Bartlomiej Zolnierkiewicz8604aff2005-05-26 14:55:34 +02001186 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187}
1188
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +02001189static void __exit idedisk_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190{
Bartlomiej Zolnierkiewicz8604aff2005-05-26 14:55:34 +02001191 driver_unregister(&idedisk_driver.gen_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192}
1193
Bartlomiej Zolnierkiewicz17514e82005-11-19 22:24:35 +01001194static int __init idedisk_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195{
Bartlomiej Zolnierkiewicz8604aff2005-05-26 14:55:34 +02001196 return driver_register(&idedisk_driver.gen_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197}
1198
Kay Sievers263756e2005-12-12 18:03:44 +01001199MODULE_ALIAS("ide:*m-disk*");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200module_init(idedisk_init);
1201module_exit(idedisk_exit);
1202MODULE_LICENSE("GPL");