blob: 995d448109eb40e6902c2bf4c2d3f7f2b6d8afc4 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Bartlomiej Zolnierkiewicz59bca8c2008-02-01 23:09:33 +01002 * Copyright (C) 1994-1998 Linus Torvalds & authors (see below)
3 * Copyright (C) 1998-2002 Linux ATA Development
4 * Andre Hedrick <andre@linux-ide.org>
5 * Copyright (C) 2003 Red Hat <alan@redhat.com>
6 * Copyright (C) 2003-2005, 2007 Bartlomiej Zolnierkiewicz
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 */
8
9/*
10 * Mostly written by Mark Lord <mlord@pobox.com>
11 * and Gadi Oxman <gadio@netvision.net.il>
12 * and Andre Hedrick <andre@linux-ide.org>
13 *
14 * This is the IDE/ATA disk driver, as evolved from hd.c and ide.c.
Linus Torvalds1da177e2005-04-16 15:20:36 -070015 */
16
17#define IDEDISK_VERSION "1.18"
18
Linus Torvalds1da177e2005-04-16 15:20:36 -070019#include <linux/module.h>
20#include <linux/types.h>
21#include <linux/string.h>
22#include <linux/kernel.h>
23#include <linux/timer.h>
24#include <linux/mm.h>
25#include <linux/interrupt.h>
26#include <linux/major.h>
27#include <linux/errno.h>
28#include <linux/genhd.h>
29#include <linux/slab.h>
30#include <linux/delay.h>
Arjan van de Vencf8b8972006-03-23 03:00:45 -080031#include <linux/mutex.h>
Richard Purdie2bfb6462006-03-31 02:31:16 -080032#include <linux/leds.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#include <linux/ide.h>
Bartlomiej Zolnierkiewicz3ceca722008-10-10 22:39:27 +020034#include <linux/hdreg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070035
36#include <asm/byteorder.h>
37#include <asm/irq.h>
38#include <asm/uaccess.h>
39#include <asm/io.h>
40#include <asm/div64.h>
41
Tejun Heo870d6652008-08-25 19:47:25 +090042#if !defined(CONFIG_DEBUG_BLOCK_EXT_DEVT)
Tejun Heo689d6fa2008-08-25 19:56:16 +090043#define IDE_DISK_MINORS (1 << PARTN_BITS)
Tejun Heo870d6652008-08-25 19:47:25 +090044#else
Tejun Heo3e1a7ff2008-08-25 19:56:17 +090045#define IDE_DISK_MINORS 0
Tejun Heo870d6652008-08-25 19:47:25 +090046#endif
47
Bartlomiej Zolnierkiewiczf8790482008-10-13 21:39:45 +020048#include "ide-disk.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070049
Arjan van de Vencf8b8972006-03-23 03:00:45 -080050static DEFINE_MUTEX(idedisk_ref_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -070051
52#define to_ide_disk(obj) container_of(obj, struct ide_disk_obj, kref)
53
Bartlomiej Zolnierkiewicz08da5912008-07-24 22:53:15 +020054static void ide_disk_release(struct kref *);
55
Linus Torvalds1da177e2005-04-16 15:20:36 -070056static struct ide_disk_obj *ide_disk_get(struct gendisk *disk)
57{
58 struct ide_disk_obj *idkp = NULL;
59
Arjan van de Vencf8b8972006-03-23 03:00:45 -080060 mutex_lock(&idedisk_ref_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -070061 idkp = ide_disk_g(disk);
Bartlomiej Zolnierkiewicz08da5912008-07-24 22:53:15 +020062 if (idkp) {
Bartlomiej Zolnierkiewiczd3e33ff2008-08-05 18:16:59 +020063 if (ide_device_get(idkp->drive))
Bartlomiej Zolnierkiewicz08da5912008-07-24 22:53:15 +020064 idkp = NULL;
Bartlomiej Zolnierkiewiczd3e33ff2008-08-05 18:16:59 +020065 else
66 kref_get(&idkp->kref);
Bartlomiej Zolnierkiewicz08da5912008-07-24 22:53:15 +020067 }
Arjan van de Vencf8b8972006-03-23 03:00:45 -080068 mutex_unlock(&idedisk_ref_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -070069 return idkp;
70}
71
Linus Torvalds1da177e2005-04-16 15:20:36 -070072static void ide_disk_put(struct ide_disk_obj *idkp)
73{
Bartlomiej Zolnierkiewiczd3e33ff2008-08-05 18:16:59 +020074 ide_drive_t *drive = idkp->drive;
75
Arjan van de Vencf8b8972006-03-23 03:00:45 -080076 mutex_lock(&idedisk_ref_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -070077 kref_put(&idkp->kref, ide_disk_release);
Bartlomiej Zolnierkiewiczd3e33ff2008-08-05 18:16:59 +020078 ide_device_put(drive);
Arjan van de Vencf8b8972006-03-23 03:00:45 -080079 mutex_unlock(&idedisk_ref_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -070080}
81
Bartlomiej Zolnierkiewiczba76ae32008-01-25 22:17:16 +010082static const u8 ide_rw_cmds[] = {
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +020083 ATA_CMD_READ_MULTI,
84 ATA_CMD_WRITE_MULTI,
85 ATA_CMD_READ_MULTI_EXT,
86 ATA_CMD_WRITE_MULTI_EXT,
87 ATA_CMD_PIO_READ,
88 ATA_CMD_PIO_WRITE,
89 ATA_CMD_PIO_READ_EXT,
90 ATA_CMD_PIO_WRITE_EXT,
91 ATA_CMD_READ,
92 ATA_CMD_WRITE,
93 ATA_CMD_READ_EXT,
94 ATA_CMD_WRITE_EXT,
Bartlomiej Zolnierkiewiczba76ae32008-01-25 22:17:16 +010095};
96
97static const u8 ide_data_phases[] = {
98 TASKFILE_MULTI_IN,
99 TASKFILE_MULTI_OUT,
100 TASKFILE_IN,
101 TASKFILE_OUT,
102 TASKFILE_IN_DMA,
103 TASKFILE_OUT_DMA,
104};
105
106static void ide_tf_set_cmd(ide_drive_t *drive, ide_task_t *task, u8 dma)
107{
108 u8 index, lba48, write;
109
110 lba48 = (task->tf_flags & IDE_TFLAG_LBA48) ? 2 : 0;
111 write = (task->tf_flags & IDE_TFLAG_WRITE) ? 1 : 0;
112
113 if (dma)
Bartlomiej Zolnierkiewiczba4b2e62008-07-23 19:55:55 +0200114 index = 8;
Bartlomiej Zolnierkiewiczba76ae32008-01-25 22:17:16 +0100115 else
116 index = drive->mult_count ? 0 : 4;
117
118 task->tf.command = ide_rw_cmds[index + lba48 + write];
119
120 if (dma)
121 index = 8; /* fixup index */
122
123 task->data_phase = ide_data_phases[index / 2 + write];
124}
125
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126/*
127 * __ide_do_rw_disk() issues READ and WRITE commands to a disk,
128 * using LBA if supported, or CHS otherwise, to address sectors.
129 */
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200130static ide_startstop_t __ide_do_rw_disk(ide_drive_t *drive, struct request *rq,
131 sector_t block)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132{
133 ide_hwif_t *hwif = HWIF(drive);
Bartlomiej Zolnierkiewicz790d1232008-01-25 22:17:12 +0100134 u16 nsectors = (u16)rq->nr_sectors;
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200135 u8 lba48 = !!(drive->dev_flags & IDE_DFLAG_LBA48);
136 u8 dma = !!(drive->dev_flags & IDE_DFLAG_USING_DMA);
Bartlomiej Zolnierkiewicz9e422372008-01-25 22:17:07 +0100137 ide_task_t task;
138 struct ide_taskfile *tf = &task.tf;
Bartlomiej Zolnierkiewiczf6e29e32008-01-25 22:17:16 +0100139 ide_startstop_t rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140
Bartlomiej Zolnierkiewicz238e4f12007-10-19 00:30:07 +0200141 if ((hwif->host_flags & IDE_HFLAG_NO_LBA48_DMA) && lba48 && dma) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142 if (block + rq->nr_sectors > 1ULL << 28)
143 dma = 0;
144 else
145 lba48 = 0;
146 }
147
148 if (!dma) {
149 ide_init_sg_cmd(drive, rq);
150 ide_map_sg(drive, rq);
151 }
152
Bartlomiej Zolnierkiewicz9e422372008-01-25 22:17:07 +0100153 memset(&task, 0, sizeof(task));
Bartlomiej Zolnierkiewicz9a410e72008-07-15 21:21:48 +0200154 task.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
Bartlomiej Zolnierkiewicz2bd06b22008-01-25 22:17:06 +0100155
Bartlomiej Zolnierkiewiczd1d76712008-10-13 21:39:38 +0200156 if (drive->dev_flags & IDE_DFLAG_LBA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157 if (lba48) {
Michael Richardsonc2f83112006-02-07 12:58:33 -0800158 pr_debug("%s: LBA=0x%012llx\n", drive->name,
159 (unsigned long long)block);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160
Bartlomiej Zolnierkiewicz790d1232008-01-25 22:17:12 +0100161 tf->hob_nsect = (nsectors >> 8) & 0xff;
Bartlomiej Zolnierkiewicz2bd06b22008-01-25 22:17:06 +0100162 tf->hob_lbal = (u8)(block >> 24);
163 if (sizeof(block) != 4) {
164 tf->hob_lbam = (u8)((u64)block >> 32);
165 tf->hob_lbah = (u8)((u64)block >> 40);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166 }
Bartlomiej Zolnierkiewicz2bd06b22008-01-25 22:17:06 +0100167
Bartlomiej Zolnierkiewicz790d1232008-01-25 22:17:12 +0100168 tf->nsect = nsectors & 0xff;
Bartlomiej Zolnierkiewicz2bd06b22008-01-25 22:17:06 +0100169 tf->lbal = (u8) block;
170 tf->lbam = (u8)(block >> 8);
171 tf->lbah = (u8)(block >> 16);
Bartlomiej Zolnierkiewicz6dd9b832008-01-26 20:13:03 +0100172
Bartlomiej Zolnierkiewicz657cc1a2008-01-26 20:13:10 +0100173 task.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_HOB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174 } else {
Bartlomiej Zolnierkiewicz790d1232008-01-25 22:17:12 +0100175 tf->nsect = nsectors & 0xff;
Bartlomiej Zolnierkiewicz2bd06b22008-01-25 22:17:06 +0100176 tf->lbal = block;
177 tf->lbam = block >>= 8;
178 tf->lbah = block >>= 8;
179 tf->device = (block >> 8) & 0xf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180 }
Bartlomiej Zolnierkiewiczd1d76712008-10-13 21:39:38 +0200181
182 tf->device |= ATA_LBA;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183 } else {
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200184 unsigned int sect, head, cyl, track;
185
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186 track = (int)block / drive->sect;
187 sect = (int)block % drive->sect + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188 head = track % drive->head;
189 cyl = track / drive->head;
190
191 pr_debug("%s: CHS=%u/%u/%u\n", drive->name, cyl, head, sect);
192
Bartlomiej Zolnierkiewicz790d1232008-01-25 22:17:12 +0100193 tf->nsect = nsectors & 0xff;
Bartlomiej Zolnierkiewicz2bd06b22008-01-25 22:17:06 +0100194 tf->lbal = sect;
195 tf->lbam = cyl;
196 tf->lbah = cyl >> 8;
197 tf->device = head;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198 }
199
Bartlomiej Zolnierkiewiczba76ae32008-01-25 22:17:16 +0100200 if (rq_data_dir(rq))
201 task.tf_flags |= IDE_TFLAG_WRITE;
202
203 ide_tf_set_cmd(drive, &task, dma);
Bartlomiej Zolnierkiewiczf6e29e32008-01-25 22:17:16 +0100204 if (!dma)
205 hwif->data_phase = task.data_phase;
206 task.rq = rq;
Bartlomiej Zolnierkiewiczba76ae32008-01-25 22:17:16 +0100207
Bartlomiej Zolnierkiewiczf6e29e32008-01-25 22:17:16 +0100208 rc = do_rw_taskfile(drive, &task);
Bartlomiej Zolnierkiewicz2bd06b22008-01-25 22:17:06 +0100209
Bartlomiej Zolnierkiewiczf6e29e32008-01-25 22:17:16 +0100210 if (rc == ide_stopped && dma) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211 /* fallback to PIO */
Bartlomiej Zolnierkiewiczf6e29e32008-01-25 22:17:16 +0100212 task.tf_flags |= IDE_TFLAG_DMA_PIO_FALLBACK;
Bartlomiej Zolnierkiewiczba76ae32008-01-25 22:17:16 +0100213 ide_tf_set_cmd(drive, &task, 0);
Bartlomiej Zolnierkiewiczf6e29e32008-01-25 22:17:16 +0100214 hwif->data_phase = task.data_phase;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 ide_init_sg_cmd(drive, rq);
Bartlomiej Zolnierkiewiczf6e29e32008-01-25 22:17:16 +0100216 rc = do_rw_taskfile(drive, &task);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217 }
218
Bartlomiej Zolnierkiewiczf6e29e32008-01-25 22:17:16 +0100219 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220}
221
222/*
223 * 268435455 == 137439 MB or 28bit limit
224 * 320173056 == 163929 MB or 48bit addressing
225 * 1073741822 == 549756 MB or 48bit addressing fake drive
226 */
227
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200228static ide_startstop_t ide_do_rw_disk(ide_drive_t *drive, struct request *rq,
229 sector_t block)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230{
231 ide_hwif_t *hwif = HWIF(drive);
232
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200233 BUG_ON(drive->dev_flags & IDE_DFLAG_BLOCKED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234
235 if (!blk_fs_request(rq)) {
236 blk_dump_rq_flags(rq, "ide_do_rw_disk - bad command");
237 ide_end_request(drive, 0, 0);
238 return ide_stopped;
239 }
240
Richard Purdie2bfb6462006-03-31 02:31:16 -0800241 ledtrig_ide_activity();
242
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243 pr_debug("%s: %sing: block=%llu, sectors=%lu, buffer=0x%08lx\n",
244 drive->name, rq_data_dir(rq) == READ ? "read" : "writ",
Michael Richardsonc2f83112006-02-07 12:58:33 -0800245 (unsigned long long)block, rq->nr_sectors,
246 (unsigned long)rq->buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247
248 if (hwif->rw_disk)
249 hwif->rw_disk(drive, rq);
250
251 return __ide_do_rw_disk(drive, rq, block);
252}
253
254/*
255 * Queries for true maximum capacity of the drive.
256 * Returns maximum LBA address (> 0) of the drive, 0 if failed.
257 */
Bartlomiej Zolnierkiewicz7a3b7512008-01-25 22:17:06 +0100258static u64 idedisk_read_native_max_address(ide_drive_t *drive, int lba48)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259{
260 ide_task_t args;
Bartlomiej Zolnierkiewicz650d8412008-01-25 22:17:06 +0100261 struct ide_taskfile *tf = &args.tf;
Bartlomiej Zolnierkiewicz7a3b7512008-01-25 22:17:06 +0100262 u64 addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263
264 /* Create IDE/ATA command request structure */
265 memset(&args, 0, sizeof(ide_task_t));
Bartlomiej Zolnierkiewicz7a3b7512008-01-25 22:17:06 +0100266 if (lba48)
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200267 tf->command = ATA_CMD_READ_NATIVE_MAX_EXT;
Bartlomiej Zolnierkiewicz7a3b7512008-01-25 22:17:06 +0100268 else
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200269 tf->command = ATA_CMD_READ_NATIVE_MAX;
Bartlomiej Zolnierkiewicz650d8412008-01-25 22:17:06 +0100270 tf->device = ATA_LBA;
Bartlomiej Zolnierkiewicz657cc1a2008-01-26 20:13:10 +0100271 args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
Bartlomiej Zolnierkiewicza3bbb9d2008-01-25 22:17:10 +0100272 if (lba48)
Bartlomiej Zolnierkiewicz657cc1a2008-01-26 20:13:10 +0100273 args.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_HOB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274 /* submit command request */
Bartlomiej Zolnierkiewicz9a3c49b2008-01-25 22:17:07 +0100275 ide_no_data_taskfile(drive, &args);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276
277 /* if OK, compute maximum address value */
Bartlomiej Zolnierkiewicza5016332008-01-25 22:17:17 +0100278 if ((tf->status & 0x01) == 0)
279 addr = ide_get_lba_addr(tf, lba48) + 1;
Bartlomiej Zolnierkiewicz650d8412008-01-25 22:17:06 +0100280
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281 return addr;
282}
283
284/*
285 * Sets maximum virtual LBA address of the drive.
286 * Returns new maximum virtual LBA address (> 0) or 0 on failure.
287 */
Bartlomiej Zolnierkiewicz7a3b7512008-01-25 22:17:06 +0100288static u64 idedisk_set_max_address(ide_drive_t *drive, u64 addr_req, int lba48)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289{
290 ide_task_t args;
Bartlomiej Zolnierkiewicz650d8412008-01-25 22:17:06 +0100291 struct ide_taskfile *tf = &args.tf;
Bartlomiej Zolnierkiewicz7a3b7512008-01-25 22:17:06 +0100292 u64 addr_set = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293
294 addr_req--;
295 /* Create IDE/ATA command request structure */
296 memset(&args, 0, sizeof(ide_task_t));
Bartlomiej Zolnierkiewicz650d8412008-01-25 22:17:06 +0100297 tf->lbal = (addr_req >> 0) & 0xff;
298 tf->lbam = (addr_req >>= 8) & 0xff;
299 tf->lbah = (addr_req >>= 8) & 0xff;
Bartlomiej Zolnierkiewicz7a3b7512008-01-25 22:17:06 +0100300 if (lba48) {
301 tf->hob_lbal = (addr_req >>= 8) & 0xff;
302 tf->hob_lbam = (addr_req >>= 8) & 0xff;
303 tf->hob_lbah = (addr_req >>= 8) & 0xff;
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200304 tf->command = ATA_CMD_SET_MAX_EXT;
Bartlomiej Zolnierkiewicz7a3b7512008-01-25 22:17:06 +0100305 } else {
306 tf->device = (addr_req >>= 8) & 0x0f;
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200307 tf->command = ATA_CMD_SET_MAX;
Bartlomiej Zolnierkiewicz7a3b7512008-01-25 22:17:06 +0100308 }
309 tf->device |= ATA_LBA;
Bartlomiej Zolnierkiewicz657cc1a2008-01-26 20:13:10 +0100310 args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
Bartlomiej Zolnierkiewicza3bbb9d2008-01-25 22:17:10 +0100311 if (lba48)
Bartlomiej Zolnierkiewicz657cc1a2008-01-26 20:13:10 +0100312 args.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_HOB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313 /* submit command request */
Bartlomiej Zolnierkiewicz9a3c49b2008-01-25 22:17:07 +0100314 ide_no_data_taskfile(drive, &args);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 /* if OK, compute maximum address value */
Bartlomiej Zolnierkiewicza5016332008-01-25 22:17:17 +0100316 if ((tf->status & 0x01) == 0)
317 addr_set = ide_get_lba_addr(tf, lba48) + 1;
Bartlomiej Zolnierkiewicz650d8412008-01-25 22:17:06 +0100318
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 return addr_set;
320}
321
322static unsigned long long sectors_to_MB(unsigned long long n)
323{
324 n <<= 9; /* make it bytes */
325 do_div(n, 1000000); /* make it MB */
326 return n;
327}
328
329/*
Bartlomiej Zolnierkiewiczb0244a02007-08-20 22:42:57 +0200330 * Some disks report total number of sectors instead of
331 * maximum sector address. We list them here.
332 */
333static const struct drive_list_entry hpa_list[] = {
334 { "ST340823A", NULL },
Jorge Juan Chico7062cdc2007-09-17 12:35:30 +0200335 { "ST320413A", NULL },
Mikko Rapelib152fcd2008-02-19 01:41:25 +0100336 { "ST310211A", NULL },
Bartlomiej Zolnierkiewiczb0244a02007-08-20 22:42:57 +0200337 { NULL, NULL }
338};
339
Arjan van de Ven858119e2006-01-14 13:20:43 -0800340static void idedisk_check_hpa(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341{
342 unsigned long long capacity, set_max;
Bartlomiej Zolnierkiewicz942dcd82008-10-10 22:39:30 +0200343 int lba48 = ata_id_lba48_enabled(drive->id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344
345 capacity = drive->capacity64;
Bartlomiej Zolnierkiewicz7a3b7512008-01-25 22:17:06 +0100346
347 set_max = idedisk_read_native_max_address(drive, lba48);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348
Bartlomiej Zolnierkiewiczb0244a02007-08-20 22:42:57 +0200349 if (ide_in_drive_list(drive->id, hpa_list)) {
350 /*
351 * Since we are inclusive wrt to firmware revisions do this
352 * extra check and apply the workaround only when needed.
353 */
354 if (set_max == capacity + 1)
355 set_max--;
356 }
357
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 if (set_max <= capacity)
359 return;
360
361 printk(KERN_INFO "%s: Host Protected Area detected.\n"
362 "\tcurrent capacity is %llu sectors (%llu MB)\n"
363 "\tnative capacity is %llu sectors (%llu MB)\n",
364 drive->name,
365 capacity, sectors_to_MB(capacity),
366 set_max, sectors_to_MB(set_max));
367
Bartlomiej Zolnierkiewicz7a3b7512008-01-25 22:17:06 +0100368 set_max = idedisk_set_max_address(drive, set_max, lba48);
369
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 if (set_max) {
371 drive->capacity64 = set_max;
372 printk(KERN_INFO "%s: Host Protected Area disabled.\n",
373 drive->name);
374 }
375}
376
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200377static void init_idedisk_capacity(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378{
Bartlomiej Zolnierkiewicz4dde4492008-10-10 22:39:19 +0200379 u16 *id = drive->id;
Bartlomiej Zolnierkiewiczd1d76712008-10-13 21:39:38 +0200380 int lba;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381
Bartlomiej Zolnierkiewicz942dcd82008-10-10 22:39:30 +0200382 if (ata_id_lba48_enabled(id)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 /* drive speaks 48-bit LBA */
Bartlomiej Zolnierkiewiczd1d76712008-10-13 21:39:38 +0200384 lba = 1;
Bartlomiej Zolnierkiewicz48fb2682008-10-10 22:39:19 +0200385 drive->capacity64 = ata_id_u64(id, ATA_ID_LBA_CAPACITY_2);
Bartlomiej Zolnierkiewicza02227c2008-10-10 22:39:31 +0200386 } else if (ata_id_has_lba(id) && ata_id_is_lba_capacity_ok(id)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 /* drive speaks 28-bit LBA */
Bartlomiej Zolnierkiewiczd1d76712008-10-13 21:39:38 +0200388 lba = 1;
Bartlomiej Zolnierkiewicz48fb2682008-10-10 22:39:19 +0200389 drive->capacity64 = ata_id_u32(id, ATA_ID_LBA_CAPACITY);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 } else {
391 /* drive speaks boring old 28-bit CHS */
Bartlomiej Zolnierkiewiczd1d76712008-10-13 21:39:38 +0200392 lba = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 drive->capacity64 = drive->cyl * drive->head * drive->sect;
394 }
Bartlomiej Zolnierkiewiczd1d76712008-10-13 21:39:38 +0200395
396 if (lba) {
397 drive->dev_flags |= IDE_DFLAG_LBA;
398
399 /*
400 * If this device supports the Host Protected Area feature set,
401 * then we may need to change our opinion about its capacity.
402 */
403 if (ata_id_hpa_enabled(id))
404 idedisk_check_hpa(drive);
405 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406}
407
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200408static sector_t idedisk_capacity(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409{
Bartlomiej Zolnierkiewicz3c619ff2008-10-10 22:39:22 +0200410 return drive->capacity64;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411}
412
Bartlomiej Zolnierkiewiczecfd80e2007-05-10 00:01:09 +0200413#ifdef CONFIG_IDE_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414static int smart_enable(ide_drive_t *drive)
415{
416 ide_task_t args;
Bartlomiej Zolnierkiewicz650d8412008-01-25 22:17:06 +0100417 struct ide_taskfile *tf = &args.tf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418
419 memset(&args, 0, sizeof(ide_task_t));
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200420 tf->feature = ATA_SMART_ENABLE;
421 tf->lbam = ATA_SMART_LBAM_PASS;
422 tf->lbah = ATA_SMART_LBAH_PASS;
423 tf->command = ATA_CMD_SMART;
Bartlomiej Zolnierkiewicz657cc1a2008-01-26 20:13:10 +0100424 args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
Bartlomiej Zolnierkiewicz9a3c49b2008-01-25 22:17:07 +0100425 return ide_no_data_taskfile(drive, &args);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426}
427
Bartlomiej Zolnierkiewicz43e7c0c2007-10-20 00:32:37 +0200428static int get_smart_data(ide_drive_t *drive, u8 *buf, u8 sub_cmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429{
430 ide_task_t args;
Bartlomiej Zolnierkiewicz650d8412008-01-25 22:17:06 +0100431 struct ide_taskfile *tf = &args.tf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432
433 memset(&args, 0, sizeof(ide_task_t));
Bartlomiej Zolnierkiewicz650d8412008-01-25 22:17:06 +0100434 tf->feature = sub_cmd;
435 tf->nsect = 0x01;
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200436 tf->lbam = ATA_SMART_LBAM_PASS;
437 tf->lbah = ATA_SMART_LBAH_PASS;
438 tf->command = ATA_CMD_SMART;
Bartlomiej Zolnierkiewicz657cc1a2008-01-26 20:13:10 +0100439 args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
Bartlomiej Zolnierkiewiczac026ff2008-01-25 22:17:14 +0100440 args.data_phase = TASKFILE_IN;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 (void) smart_enable(drive);
Bartlomiej Zolnierkiewiczac026ff2008-01-25 22:17:14 +0100442 return ide_raw_taskfile(drive, &args, buf, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443}
444
445static int proc_idedisk_read_cache
446 (char *page, char **start, off_t off, int count, int *eof, void *data)
447{
448 ide_drive_t *drive = (ide_drive_t *) data;
449 char *out = page;
450 int len;
451
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200452 if (drive->dev_flags & IDE_DFLAG_ID_READ)
Bartlomiej Zolnierkiewicz4dde4492008-10-10 22:39:19 +0200453 len = sprintf(out, "%i\n", drive->id[ATA_ID_BUF_SIZE] / 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 else
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200455 len = sprintf(out, "(none)\n");
456
457 PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458}
459
460static int proc_idedisk_read_capacity
461 (char *page, char **start, off_t off, int count, int *eof, void *data)
462{
463 ide_drive_t*drive = (ide_drive_t *)data;
464 int len;
465
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200466 len = sprintf(page, "%llu\n", (long long)idedisk_capacity(drive));
467
468 PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469}
470
Bartlomiej Zolnierkiewicz799ee572008-04-26 17:36:37 +0200471static int proc_idedisk_read_smart(char *page, char **start, off_t off,
472 int count, int *eof, void *data, u8 sub_cmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473{
474 ide_drive_t *drive = (ide_drive_t *)data;
475 int len = 0, i = 0;
476
Bartlomiej Zolnierkiewicz799ee572008-04-26 17:36:37 +0200477 if (get_smart_data(drive, page, sub_cmd) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 unsigned short *val = (unsigned short *) page;
Bartlomiej Zolnierkiewicz151a6702008-10-10 22:39:28 +0200479 char *out = (char *)val + SECTOR_SIZE;
480
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 page = out;
482 do {
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200483 out += sprintf(out, "%04x%c", le16_to_cpu(*val),
484 (++i & 7) ? ' ' : '\n');
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 val += 1;
Bartlomiej Zolnierkiewicz151a6702008-10-10 22:39:28 +0200486 } while (i < SECTOR_SIZE / 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487 len = out - page;
488 }
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200489
490 PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491}
492
Bartlomiej Zolnierkiewicz799ee572008-04-26 17:36:37 +0200493static int proc_idedisk_read_sv
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 (char *page, char **start, off_t off, int count, int *eof, void *data)
495{
Bartlomiej Zolnierkiewicz799ee572008-04-26 17:36:37 +0200496 return proc_idedisk_read_smart(page, start, off, count, eof, data,
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200497 ATA_SMART_READ_VALUES);
Bartlomiej Zolnierkiewicz799ee572008-04-26 17:36:37 +0200498}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499
Bartlomiej Zolnierkiewicz799ee572008-04-26 17:36:37 +0200500static int proc_idedisk_read_st
501 (char *page, char **start, off_t off, int count, int *eof, void *data)
502{
503 return proc_idedisk_read_smart(page, start, off, count, eof, data,
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200504 ATA_SMART_READ_THRESHOLDS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505}
506
507static ide_proc_entry_t idedisk_proc[] = {
Bartlomiej Zolnierkiewicz799ee572008-04-26 17:36:37 +0200508 { "cache", S_IFREG|S_IRUGO, proc_idedisk_read_cache, NULL },
509 { "capacity", S_IFREG|S_IRUGO, proc_idedisk_read_capacity, NULL },
510 { "geometry", S_IFREG|S_IRUGO, proc_ide_read_geometry, NULL },
511 { "smart_values", S_IFREG|S_IRUSR, proc_idedisk_read_sv, NULL },
512 { "smart_thresholds", S_IFREG|S_IRUSR, proc_idedisk_read_st, NULL },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 { NULL, 0, NULL, NULL }
514};
Bartlomiej Zolnierkiewiczecfd80e2007-05-10 00:01:09 +0200515#endif /* CONFIG_IDE_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516
Jens Axboe165125e2007-07-24 09:28:11 +0200517static void idedisk_prepare_flush(struct request_queue *q, struct request *rq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518{
519 ide_drive_t *drive = q->queuedata;
Bartlomiej Zolnierkiewicz395d8ef2008-02-11 00:32:14 +0100520 ide_task_t *task = kmalloc(sizeof(*task), GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521
Bartlomiej Zolnierkiewicz395d8ef2008-02-11 00:32:14 +0100522 /* FIXME: map struct ide_taskfile on rq->cmd[] */
523 BUG_ON(task == NULL);
524
525 memset(task, 0, sizeof(*task));
Bartlomiej Zolnierkiewiczff2779b2008-10-10 22:39:31 +0200526 if (ata_id_flush_ext_enabled(drive->id) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 (drive->capacity64 >= (1UL << 28)))
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200528 task->tf.command = ATA_CMD_FLUSH_EXT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 else
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200530 task->tf.command = ATA_CMD_FLUSH;
Bartlomiej Zolnierkiewicz395d8ef2008-02-11 00:32:14 +0100531 task->tf_flags = IDE_TFLAG_OUT_TF | IDE_TFLAG_OUT_DEVICE |
532 IDE_TFLAG_DYN;
533 task->data_phase = TASKFILE_NO_DATA;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534
Bartlomiej Zolnierkiewicz813a0eb2008-01-25 22:17:10 +0100535 rq->cmd_type = REQ_TYPE_ATA_TASKFILE;
Jens Axboe4aff5e22006-08-10 08:44:47 +0200536 rq->cmd_flags |= REQ_SOFTBARRIER;
Bartlomiej Zolnierkiewicz395d8ef2008-02-11 00:32:14 +0100537 rq->special = task;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538}
539
Bartlomiej Zolnierkiewicz8185d5a2008-10-10 22:39:28 +0200540ide_devset_get(multcount, mult_count);
541
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542/*
543 * This is tightly woven into the driver->do_special can not touch.
544 * DON'T do it again until a total personality rewrite is committed.
545 */
546static int set_multcount(ide_drive_t *drive, int arg)
547{
FUJITA Tomonoridd470872008-07-15 21:21:43 +0200548 struct request *rq;
549 int error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550
Bartlomiej Zolnierkiewicz48fb2682008-10-10 22:39:19 +0200551 if (arg < 0 || arg > (drive->id[ATA_ID_MAX_MULTSECT] & 0xff))
Bartlomiej Zolnierkiewicz14979432007-05-10 00:01:10 +0200552 return -EINVAL;
553
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554 if (drive->special.b.set_multmode)
555 return -EBUSY;
Bartlomiej Zolnierkiewicz852738f2008-01-26 20:13:12 +0100556
FUJITA Tomonoridd470872008-07-15 21:21:43 +0200557 rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
558 rq->cmd_type = REQ_TYPE_ATA_TASKFILE;
Bartlomiej Zolnierkiewicz852738f2008-01-26 20:13:12 +0100559
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 drive->mult_req = arg;
561 drive->special.b.set_multmode = 1;
FUJITA Tomonoridd470872008-07-15 21:21:43 +0200562 error = blk_execute_rq(drive->queue, NULL, rq, 0);
563 blk_put_request(rq);
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200564
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 return (drive->mult_count == arg) ? 0 : -EIO;
566}
567
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200568ide_devset_get_flag(nowerr, IDE_DFLAG_NOWERR);
Bartlomiej Zolnierkiewicz8185d5a2008-10-10 22:39:28 +0200569
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570static int set_nowerr(ide_drive_t *drive, int arg)
571{
Bartlomiej Zolnierkiewicz14979432007-05-10 00:01:10 +0200572 if (arg < 0 || arg > 1)
573 return -EINVAL;
574
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200575 if (arg)
576 drive->dev_flags |= IDE_DFLAG_NOWERR;
577 else
578 drive->dev_flags &= ~IDE_DFLAG_NOWERR;
579
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 drive->bad_wstat = arg ? BAD_R_STAT : BAD_W_STAT;
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200581
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 return 0;
583}
584
Bartlomiej Zolnierkiewiczbe3c0962008-10-13 21:39:36 +0200585static int ide_do_setfeature(ide_drive_t *drive, u8 feature, u8 nsect)
586{
587 ide_task_t task;
588
589 memset(&task, 0, sizeof(task));
590 task.tf.feature = feature;
591 task.tf.nsect = nsect;
592 task.tf.command = ATA_CMD_SET_FEATURES;
593 task.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
594
595 return ide_no_data_taskfile(drive, &task);
596}
597
Tejun Heo3e087b52006-01-06 09:57:31 +0100598static void update_ordered(ide_drive_t *drive)
599{
Bartlomiej Zolnierkiewicz4dde4492008-10-10 22:39:19 +0200600 u16 *id = drive->id;
Tejun Heo3e087b52006-01-06 09:57:31 +0100601 unsigned ordered = QUEUE_ORDERED_NONE;
602 prepare_flush_fn *prep_fn = NULL;
Tejun Heo3e087b52006-01-06 09:57:31 +0100603
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200604 if (drive->dev_flags & IDE_DFLAG_WCACHE) {
Tejun Heo3e087b52006-01-06 09:57:31 +0100605 unsigned long long capacity;
606 int barrier;
607 /*
608 * We must avoid issuing commands a drive does not
609 * understand or we may crash it. We check flush cache
610 * is supported. We also check we have the LBA48 flush
611 * cache if the drive capacity is too large. By this
612 * time we have trimmed the drive capacity if LBA48 is
613 * not available so we don't need to recheck that.
614 */
615 capacity = idedisk_capacity(drive);
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200616 barrier = ata_id_flush_enabled(id) &&
617 (drive->dev_flags & IDE_DFLAG_NOFLUSH) == 0 &&
618 ((drive->dev_flags & IDE_DFLAG_LBA48) == 0 ||
619 capacity <= (1ULL << 28) ||
Bartlomiej Zolnierkiewiczff2779b2008-10-10 22:39:31 +0200620 ata_id_flush_ext_enabled(id));
Tejun Heo3e087b52006-01-06 09:57:31 +0100621
622 printk(KERN_INFO "%s: cache flushes %ssupported\n",
Jean Delvaref7ad8362006-02-03 03:04:57 -0800623 drive->name, barrier ? "" : "not ");
Tejun Heo3e087b52006-01-06 09:57:31 +0100624
625 if (barrier) {
626 ordered = QUEUE_ORDERED_DRAIN_FLUSH;
627 prep_fn = idedisk_prepare_flush;
Tejun Heo3e087b52006-01-06 09:57:31 +0100628 }
629 } else
630 ordered = QUEUE_ORDERED_DRAIN;
631
632 blk_queue_ordered(drive->queue, ordered, prep_fn);
Tejun Heo3e087b52006-01-06 09:57:31 +0100633}
634
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200635ide_devset_get_flag(wcache, IDE_DFLAG_WCACHE);
Bartlomiej Zolnierkiewicz8185d5a2008-10-10 22:39:28 +0200636
637static int set_wcache(ide_drive_t *drive, int arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638{
Tejun Heo3e087b52006-01-06 09:57:31 +0100639 int err = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640
Bartlomiej Zolnierkiewicz14979432007-05-10 00:01:10 +0200641 if (arg < 0 || arg > 1)
642 return -EINVAL;
643
Bartlomiej Zolnierkiewicz4b58f172008-10-10 22:39:30 +0200644 if (ata_id_flush_enabled(drive->id)) {
Bartlomiej Zolnierkiewiczbe3c0962008-10-13 21:39:36 +0200645 err = ide_do_setfeature(drive,
646 arg ? SETFEATURES_WC_ON : SETFEATURES_WC_OFF, 0);
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200647 if (err == 0) {
648 if (arg)
649 drive->dev_flags |= IDE_DFLAG_WCACHE;
650 else
651 drive->dev_flags &= ~IDE_DFLAG_WCACHE;
652 }
Tejun Heo3e087b52006-01-06 09:57:31 +0100653 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654
Tejun Heo3e087b52006-01-06 09:57:31 +0100655 update_ordered(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656
Tejun Heo3e087b52006-01-06 09:57:31 +0100657 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658}
659
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200660static int do_idedisk_flushcache(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661{
662 ide_task_t args;
663
664 memset(&args, 0, sizeof(ide_task_t));
Bartlomiej Zolnierkiewiczff2779b2008-10-10 22:39:31 +0200665 if (ata_id_flush_ext_enabled(drive->id))
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200666 args.tf.command = ATA_CMD_FLUSH_EXT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 else
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200668 args.tf.command = ATA_CMD_FLUSH;
Bartlomiej Zolnierkiewicz657cc1a2008-01-26 20:13:10 +0100669 args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
Bartlomiej Zolnierkiewicz9a3c49b2008-01-25 22:17:07 +0100670 return ide_no_data_taskfile(drive, &args);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671}
672
Bartlomiej Zolnierkiewicz8185d5a2008-10-10 22:39:28 +0200673ide_devset_get(acoustic, acoustic);
674
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200675static int set_acoustic(ide_drive_t *drive, int arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676{
Bartlomiej Zolnierkiewicz14979432007-05-10 00:01:10 +0200677 if (arg < 0 || arg > 254)
678 return -EINVAL;
679
Bartlomiej Zolnierkiewiczbe3c0962008-10-13 21:39:36 +0200680 ide_do_setfeature(drive,
681 arg ? SETFEATURES_AAM_ON : SETFEATURES_AAM_OFF, arg);
682
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 drive->acoustic = arg;
Bartlomiej Zolnierkiewiczbe3c0962008-10-13 21:39:36 +0200684
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 return 0;
686}
687
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200688ide_devset_get_flag(addressing, IDE_DFLAG_LBA48);
Bartlomiej Zolnierkiewicz8185d5a2008-10-10 22:39:28 +0200689
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690/*
691 * drive->addressing:
692 * 0: 28-bit
693 * 1: 48-bit
694 * 2: 48-bit capable doing 28-bit
695 */
Bartlomiej Zolnierkiewiczaa7687732008-10-10 22:39:33 +0200696static int set_addressing(ide_drive_t *drive, int arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697{
Bartlomiej Zolnierkiewicz14979432007-05-10 00:01:10 +0200698 if (arg < 0 || arg > 2)
699 return -EINVAL;
700
Bartlomiej Zolnierkiewicz35c13752008-10-13 21:39:36 +0200701 if (arg && ((drive->hwif->host_flags & IDE_HFLAG_NO_LBA48) ||
702 ata_id_lba48_enabled(drive->id) == 0))
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200703 return -EIO;
Bartlomiej Zolnierkiewicz942dcd82008-10-10 22:39:30 +0200704
Bartlomiej Zolnierkiewicz35c13752008-10-13 21:39:36 +0200705 if (arg == 2)
706 arg = 0;
707
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200708 if (arg)
709 drive->dev_flags |= IDE_DFLAG_LBA48;
710 else
711 drive->dev_flags &= ~IDE_DFLAG_LBA48;
Bartlomiej Zolnierkiewicz942dcd82008-10-10 22:39:30 +0200712
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 return 0;
714}
715
Bartlomiej Zolnierkiewiczf8790482008-10-13 21:39:45 +0200716ide_ext_devset_rw(acoustic, acoustic);
717ide_ext_devset_rw(address, addressing);
718ide_ext_devset_rw(multcount, multcount);
719ide_ext_devset_rw(wcache, wcache);
Elias Oltmanns92f1f8f2008-10-10 22:39:40 +0200720
Bartlomiej Zolnierkiewiczf8790482008-10-13 21:39:45 +0200721ide_ext_devset_rw_sync(nowerr, nowerr);
Elias Oltmanns92f1f8f2008-10-10 22:39:40 +0200722
Bartlomiej Zolnierkiewicz7662d042007-05-10 00:01:10 +0200723#ifdef CONFIG_IDE_PROC_FS
Elias Oltmanns92f1f8f2008-10-10 22:39:40 +0200724ide_devset_rw_field(bios_cyl, bios_cyl);
725ide_devset_rw_field(bios_head, bios_head);
726ide_devset_rw_field(bios_sect, bios_sect);
727ide_devset_rw_field(failures, failures);
728ide_devset_rw_field(lun, lun);
729ide_devset_rw_field(max_failures, max_failures);
Bartlomiej Zolnierkiewicz8185d5a2008-10-10 22:39:28 +0200730
Elias Oltmanns92f1f8f2008-10-10 22:39:40 +0200731static const struct ide_proc_devset idedisk_settings[] = {
732 IDE_PROC_DEVSET(acoustic, 0, 254),
733 IDE_PROC_DEVSET(address, 0, 2),
734 IDE_PROC_DEVSET(bios_cyl, 0, 65535),
735 IDE_PROC_DEVSET(bios_head, 0, 255),
736 IDE_PROC_DEVSET(bios_sect, 0, 63),
737 IDE_PROC_DEVSET(failures, 0, 65535),
738 IDE_PROC_DEVSET(lun, 0, 7),
739 IDE_PROC_DEVSET(max_failures, 0, 65535),
740 IDE_PROC_DEVSET(multcount, 0, 16),
741 IDE_PROC_DEVSET(nowerr, 0, 1),
742 IDE_PROC_DEVSET(wcache, 0, 1),
743 { 0 },
Bartlomiej Zolnierkiewicz8185d5a2008-10-10 22:39:28 +0200744};
Bartlomiej Zolnierkiewicz7662d042007-05-10 00:01:10 +0200745#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200747static void idedisk_setup(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748{
Bartlomiej Zolnierkiewicz1e874f42008-10-10 22:39:27 +0200749 struct ide_disk_obj *idkp = drive->driver_data;
Bartlomiej Zolnierkiewicz238e4f12007-10-19 00:30:07 +0200750 ide_hwif_t *hwif = drive->hwif;
Bartlomiej Zolnierkiewicz4dde4492008-10-10 22:39:19 +0200751 u16 *id = drive->id;
752 char *m = (char *)&id[ATA_ID_PROD];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 unsigned long long capacity;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754
Bartlomiej Zolnierkiewicz1e874f42008-10-10 22:39:27 +0200755 ide_proc_register_driver(drive, idkp->driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200757 if ((drive->dev_flags & IDE_DFLAG_ID_READ) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758 return;
759
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200760 if (drive->dev_flags & IDE_DFLAG_REMOVABLE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 /*
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200762 * Removable disks (eg. SYQUEST); ignore 'WD' drives
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 */
Bartlomiej Zolnierkiewicz4dde4492008-10-10 22:39:19 +0200764 if (m[0] != 'W' || m[1] != 'D')
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200765 drive->dev_flags |= IDE_DFLAG_DOORLOCKING;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 }
767
Bartlomiej Zolnierkiewiczaa7687732008-10-10 22:39:33 +0200768 (void)set_addressing(drive, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200770 if (drive->dev_flags & IDE_DFLAG_LBA48) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 int max_s = 2048;
772
773 if (max_s > hwif->rqsize)
774 max_s = hwif->rqsize;
775
776 blk_queue_max_sectors(drive->queue, max_s);
777 }
778
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200779 printk(KERN_INFO "%s: max request size: %dKiB\n", drive->name,
780 drive->queue->max_sectors / 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781
782 /* calculate drive capacity, and select LBA if possible */
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200783 init_idedisk_capacity(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784
785 /* limit drive capacity to 137GB if LBA48 cannot be used */
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200786 if ((drive->dev_flags & IDE_DFLAG_LBA48) == 0 &&
787 drive->capacity64 > 1ULL << 28) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 printk(KERN_WARNING "%s: cannot use LBA48 - full capacity "
789 "%llu sectors (%llu MB)\n",
790 drive->name, (unsigned long long)drive->capacity64,
791 sectors_to_MB(drive->capacity64));
792 drive->capacity64 = 1ULL << 28;
793 }
794
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200795 if ((hwif->host_flags & IDE_HFLAG_NO_LBA48_DMA) &&
796 (drive->dev_flags & IDE_DFLAG_LBA48)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797 if (drive->capacity64 > 1ULL << 28) {
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200798 printk(KERN_INFO "%s: cannot use LBA48 DMA - PIO mode"
799 " will be used for accessing sectors "
800 "> %u\n", drive->name, 1 << 28);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 } else
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200802 drive->dev_flags &= ~IDE_DFLAG_LBA48;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 }
804
805 /*
806 * if possible, give fdisk access to more of the drive,
807 * by correcting bios_cyls:
808 */
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200809 capacity = idedisk_capacity(drive);
810
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200811 if ((drive->dev_flags & IDE_DFLAG_FORCED_GEOM) == 0) {
Bartlomiej Zolnierkiewicz942dcd82008-10-10 22:39:30 +0200812 if (ata_id_lba48_enabled(drive->id)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 /* compatibility */
814 drive->bios_sect = 63;
815 drive->bios_head = 255;
816 }
817
818 if (drive->bios_sect && drive->bios_head) {
819 unsigned int cap0 = capacity; /* truncate to 32 bits */
820 unsigned int cylsz, cyl;
821
822 if (cap0 != capacity)
823 drive->bios_cyl = 65535;
824 else {
825 cylsz = drive->bios_sect * drive->bios_head;
826 cyl = cap0 / cylsz;
827 if (cyl > 65535)
828 cyl = 65535;
829 if (cyl > drive->bios_cyl)
830 drive->bios_cyl = cyl;
831 }
832 }
833 }
834 printk(KERN_INFO "%s: %llu sectors (%llu MB)",
835 drive->name, capacity, sectors_to_MB(capacity));
836
837 /* Only print cache size when it was specified */
Bartlomiej Zolnierkiewicz4dde4492008-10-10 22:39:19 +0200838 if (id[ATA_ID_BUF_SIZE])
839 printk(KERN_CONT " w/%dKiB Cache", id[ATA_ID_BUF_SIZE] / 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840
Bartlomiej Zolnierkiewicz3ab7efe2007-12-12 23:31:58 +0100841 printk(KERN_CONT ", CHS=%d/%d/%d\n",
842 drive->bios_cyl, drive->bios_head, drive->bios_sect);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844 /* write cache enabled? */
Bartlomiej Zolnierkiewicz8a089c62008-10-10 22:39:20 +0200845 if ((id[ATA_ID_CSFO] & 1) || ata_id_wcache_enabled(id))
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200846 drive->dev_flags |= IDE_DFLAG_WCACHE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847
Bartlomiej Zolnierkiewicz8185d5a2008-10-10 22:39:28 +0200848 set_wcache(drive, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849}
850
851static void ide_cacheflush_p(ide_drive_t *drive)
852{
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200853 if (ata_id_flush_enabled(drive->id) == 0 ||
854 (drive->dev_flags & IDE_DFLAG_WCACHE) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 return;
856
857 if (do_idedisk_flushcache(drive))
858 printk(KERN_INFO "%s: wcache flush failed!\n", drive->name);
859}
860
Russell King4031bbe2006-01-06 11:41:00 +0000861static void ide_disk_remove(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862{
863 struct ide_disk_obj *idkp = drive->driver_data;
864 struct gendisk *g = idkp->disk;
865
Bartlomiej Zolnierkiewicz7662d042007-05-10 00:01:10 +0200866 ide_proc_unregister_driver(drive, idkp->driver);
Bartlomiej Zolnierkiewicz8604aff2005-05-26 14:55:34 +0200867
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 del_gendisk(g);
869
Bartlomiej Zolnierkiewiczd36fef62005-12-15 02:19:20 +0100870 ide_cacheflush_p(drive);
871
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872 ide_disk_put(idkp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873}
874
875static void ide_disk_release(struct kref *kref)
876{
877 struct ide_disk_obj *idkp = to_ide_disk(kref);
878 ide_drive_t *drive = idkp->drive;
879 struct gendisk *g = idkp->disk;
880
881 drive->driver_data = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 g->private_data = NULL;
883 put_disk(g);
884 kfree(idkp);
885}
886
Russell King4031bbe2006-01-06 11:41:00 +0000887static int ide_disk_probe(ide_drive_t *drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888
Lee Trager0d2157f2007-06-08 15:14:30 +0200889/*
890 * On HPA drives the capacity needs to be
891 * reinitilized on resume otherwise the disk
892 * can not be used and a hard reset is required
893 */
894static void ide_disk_resume(ide_drive_t *drive)
895{
Bartlomiej Zolnierkiewiczf41891c2008-10-10 22:39:20 +0200896 if (ata_id_hpa_enabled(drive->id))
Lee Trager0d2157f2007-06-08 15:14:30 +0200897 init_idedisk_capacity(drive);
898}
899
Russell King4031bbe2006-01-06 11:41:00 +0000900static void ide_device_shutdown(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902#ifdef CONFIG_ALPHA
903 /* On Alpha, halt(8) doesn't actually turn the machine off,
904 it puts you into the sort of firmware monitor. Typically,
905 it's used to boot another kernel image, so it's not much
906 different from reboot(8). Therefore, we don't need to
907 spin down the disk in this case, especially since Alpha
908 firmware doesn't handle disks in standby mode properly.
909 On the other hand, it's reasonably safe to turn the power
910 off when the shutdown process reaches the firmware prompt,
911 as the firmware initialization takes rather long time -
912 at least 10 seconds, which should be sufficient for
913 the disk to expire its write cache. */
914 if (system_state != SYSTEM_POWER_OFF) {
915#else
916 if (system_state == SYSTEM_RESTART) {
917#endif
918 ide_cacheflush_p(drive);
919 return;
920 }
921
Bartlomiej Zolnierkiewiczd12faa22008-02-26 21:50:36 +0100922 printk(KERN_INFO "Shutdown: %s\n", drive->name);
923
Russell King4031bbe2006-01-06 11:41:00 +0000924 drive->gendev.bus->suspend(&drive->gendev, PMSG_SUSPEND);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925}
926
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927static ide_driver_t idedisk_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928 .gen_driver = {
Laurent Riffard4ef3b8f2005-11-18 22:15:40 +0100929 .owner = THIS_MODULE,
Bartlomiej Zolnierkiewicz8604aff2005-05-26 14:55:34 +0200930 .name = "ide-disk",
931 .bus = &ide_bus_type,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932 },
Russell King4031bbe2006-01-06 11:41:00 +0000933 .probe = ide_disk_probe,
934 .remove = ide_disk_remove,
Lee Trager0d2157f2007-06-08 15:14:30 +0200935 .resume = ide_disk_resume,
Russell King4031bbe2006-01-06 11:41:00 +0000936 .shutdown = ide_device_shutdown,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937 .version = IDEDISK_VERSION,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938 .do_request = ide_do_rw_disk,
939 .end_request = ide_end_request,
940 .error = __ide_error,
Bartlomiej Zolnierkiewicz7662d042007-05-10 00:01:10 +0200941#ifdef CONFIG_IDE_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942 .proc = idedisk_proc,
Bartlomiej Zolnierkiewicz8185d5a2008-10-10 22:39:28 +0200943 .settings = idedisk_settings,
Bartlomiej Zolnierkiewicz7662d042007-05-10 00:01:10 +0200944#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945};
946
Bartlomiej Zolnierkiewicz29ec6832008-01-26 20:12:59 +0100947static int idedisk_set_doorlock(ide_drive_t *drive, int on)
948{
949 ide_task_t task;
950
951 memset(&task, 0, sizeof(task));
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200952 task.tf.command = on ? ATA_CMD_MEDIA_LOCK : ATA_CMD_MEDIA_UNLOCK;
Bartlomiej Zolnierkiewicz657cc1a2008-01-26 20:13:10 +0100953 task.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
Bartlomiej Zolnierkiewicz29ec6832008-01-26 20:12:59 +0100954
955 return ide_no_data_taskfile(drive, &task);
956}
957
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958static int idedisk_open(struct inode *inode, struct file *filp)
959{
960 struct gendisk *disk = inode->i_bdev->bd_disk;
961 struct ide_disk_obj *idkp;
962 ide_drive_t *drive;
963
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200964 idkp = ide_disk_get(disk);
965 if (idkp == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966 return -ENXIO;
967
968 drive = idkp->drive;
969
Bartlomiej Zolnierkiewiczc94964a2007-02-17 02:40:24 +0100970 idkp->openers++;
971
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200972 if ((drive->dev_flags & IDE_DFLAG_REMOVABLE) && idkp->openers == 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973 check_disk_change(inode->i_bdev);
974 /*
975 * Ignore the return code from door_lock,
976 * since the open() has already succeeded,
977 * and the door_lock is irrelevant at this point.
978 */
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200979 if ((drive->dev_flags & IDE_DFLAG_DOORLOCKING) &&
980 idedisk_set_doorlock(drive, 1))
981 drive->dev_flags &= ~IDE_DFLAG_DOORLOCKING;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 }
983 return 0;
984}
985
986static int idedisk_release(struct inode *inode, struct file *filp)
987{
988 struct gendisk *disk = inode->i_bdev->bd_disk;
989 struct ide_disk_obj *idkp = ide_disk_g(disk);
990 ide_drive_t *drive = idkp->drive;
991
Bartlomiej Zolnierkiewiczc94964a2007-02-17 02:40:24 +0100992 if (idkp->openers == 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993 ide_cacheflush_p(drive);
Bartlomiej Zolnierkiewiczc94964a2007-02-17 02:40:24 +0100994
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200995 if ((drive->dev_flags & IDE_DFLAG_REMOVABLE) && idkp->openers == 1) {
996 if ((drive->dev_flags & IDE_DFLAG_DOORLOCKING) &&
997 idedisk_set_doorlock(drive, 0))
998 drive->dev_flags &= ~IDE_DFLAG_DOORLOCKING;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999 }
Bartlomiej Zolnierkiewiczc94964a2007-02-17 02:40:24 +01001000
1001 idkp->openers--;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002
1003 ide_disk_put(idkp);
1004
1005 return 0;
1006}
1007
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001008static int idedisk_getgeo(struct block_device *bdev, struct hd_geometry *geo)
1009{
1010 struct ide_disk_obj *idkp = ide_disk_g(bdev->bd_disk);
1011 ide_drive_t *drive = idkp->drive;
1012
1013 geo->heads = drive->bios_head;
1014 geo->sectors = drive->bios_sect;
1015 geo->cylinders = (u16)drive->bios_cyl; /* truncate */
1016 return 0;
1017}
1018
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019static int idedisk_media_changed(struct gendisk *disk)
1020{
1021 struct ide_disk_obj *idkp = ide_disk_g(disk);
1022 ide_drive_t *drive = idkp->drive;
1023
1024 /* do not scan partitions twice if this is a removable device */
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +02001025 if (drive->dev_flags & IDE_DFLAG_ATTACH) {
1026 drive->dev_flags &= ~IDE_DFLAG_ATTACH;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027 return 0;
1028 }
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +02001029
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030 /* if removable, always assume it was changed */
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +02001031 return !!(drive->dev_flags & IDE_DFLAG_REMOVABLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032}
1033
1034static int idedisk_revalidate_disk(struct gendisk *disk)
1035{
1036 struct ide_disk_obj *idkp = ide_disk_g(disk);
1037 set_capacity(disk, idedisk_capacity(idkp->drive));
1038 return 0;
1039}
1040
1041static struct block_device_operations idedisk_ops = {
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +02001042 .owner = THIS_MODULE,
1043 .open = idedisk_open,
1044 .release = idedisk_release,
Bartlomiej Zolnierkiewiczf8790482008-10-13 21:39:45 +02001045 .ioctl = ide_disk_ioctl,
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +02001046 .getgeo = idedisk_getgeo,
1047 .media_changed = idedisk_media_changed,
1048 .revalidate_disk = idedisk_revalidate_disk
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049};
1050
1051MODULE_DESCRIPTION("ATA DISK Driver");
1052
Russell King4031bbe2006-01-06 11:41:00 +00001053static int ide_disk_probe(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054{
1055 struct ide_disk_obj *idkp;
1056 struct gendisk *g;
1057
1058 /* strstr("foo", "") is non-NULL */
1059 if (!strstr("ide-disk", drive->driver_req))
1060 goto failed;
Bartlomiej Zolnierkiewicz2a924662008-10-10 22:39:24 +02001061
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 if (drive->media != ide_disk)
1063 goto failed;
1064
Deepak Saxenaf5e3c2f2005-11-07 01:01:25 -08001065 idkp = kzalloc(sizeof(*idkp), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066 if (!idkp)
1067 goto failed;
1068
Tejun Heo689d6fa2008-08-25 19:56:16 +09001069 g = alloc_disk_node(IDE_DISK_MINORS, hwif_to_node(drive->hwif));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070 if (!g)
1071 goto out_free_idkp;
1072
1073 ide_init_disk(g, drive);
1074
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075 kref_init(&idkp->kref);
1076
1077 idkp->drive = drive;
1078 idkp->driver = &idedisk_driver;
1079 idkp->disk = g;
1080
1081 g->private_data = &idkp->driver;
1082
1083 drive->driver_data = idkp;
1084
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085 idedisk_setup(drive);
Bartlomiej Zolnierkiewiczd1d76712008-10-13 21:39:38 +02001086 if ((drive->dev_flags & IDE_DFLAG_LBA) == 0 &&
1087 (drive->head == 0 || drive->head > 16)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088 printk(KERN_ERR "%s: INVALID GEOMETRY: %d PHYSICAL HEADS?\n",
1089 drive->name, drive->head);
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +02001090 drive->dev_flags &= ~IDE_DFLAG_ATTACH;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091 } else
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +02001092 drive->dev_flags |= IDE_DFLAG_ATTACH;
Bartlomiej Zolnierkiewicz8604aff2005-05-26 14:55:34 +02001093
Tejun Heof615b482008-08-25 19:47:24 +09001094 g->minors = IDE_DISK_MINORS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 g->driverfs_dev = &drive->gendev;
Tejun Heo689d6fa2008-08-25 19:56:16 +09001096 g->flags |= GENHD_FL_EXT_DEVT;
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +02001097 if (drive->dev_flags & IDE_DFLAG_REMOVABLE)
1098 g->flags = GENHD_FL_REMOVABLE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099 set_capacity(g, idedisk_capacity(drive));
1100 g->fops = &idedisk_ops;
1101 add_disk(g);
1102 return 0;
1103
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104out_free_idkp:
1105 kfree(idkp);
1106failed:
Bartlomiej Zolnierkiewicz8604aff2005-05-26 14:55:34 +02001107 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108}
1109
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +02001110static void __exit idedisk_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111{
Bartlomiej Zolnierkiewicz8604aff2005-05-26 14:55:34 +02001112 driver_unregister(&idedisk_driver.gen_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113}
1114
Bartlomiej Zolnierkiewicz17514e82005-11-19 22:24:35 +01001115static int __init idedisk_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116{
Bartlomiej Zolnierkiewicz8604aff2005-05-26 14:55:34 +02001117 return driver_register(&idedisk_driver.gen_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118}
1119
Kay Sievers263756e2005-12-12 18:03:44 +01001120MODULE_ALIAS("ide:*m-disk*");
Bartlomiej Zolnierkiewiczf8790482008-10-13 21:39:45 +02001121MODULE_ALIAS("ide-disk");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122module_init(idedisk_init);
1123module_exit(idedisk_exit);
1124MODULE_LICENSE("GPL");