blob: c35de54dfc228b0de5aadb338daed99e9cf34b83 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Bartlomiej Zolnierkiewicz59bca8c2008-02-01 23:09:33 +01002 * Copyright (C) 1994-1998 Linus Torvalds & authors (see below)
3 * Copyright (C) 1998-2002 Linux ATA Development
4 * Andre Hedrick <andre@linux-ide.org>
5 * Copyright (C) 2003 Red Hat <alan@redhat.com>
6 * Copyright (C) 2003-2005, 2007 Bartlomiej Zolnierkiewicz
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 */
8
9/*
10 * Mostly written by Mark Lord <mlord@pobox.com>
11 * and Gadi Oxman <gadio@netvision.net.il>
12 * and Andre Hedrick <andre@linux-ide.org>
13 *
14 * This is the IDE/ATA disk driver, as evolved from hd.c and ide.c.
Linus Torvalds1da177e2005-04-16 15:20:36 -070015 */
16
17#define IDEDISK_VERSION "1.18"
18
Linus Torvalds1da177e2005-04-16 15:20:36 -070019#include <linux/module.h>
20#include <linux/types.h>
21#include <linux/string.h>
22#include <linux/kernel.h>
23#include <linux/timer.h>
24#include <linux/mm.h>
25#include <linux/interrupt.h>
26#include <linux/major.h>
27#include <linux/errno.h>
28#include <linux/genhd.h>
29#include <linux/slab.h>
30#include <linux/delay.h>
Arjan van de Vencf8b8972006-03-23 03:00:45 -080031#include <linux/mutex.h>
Richard Purdie2bfb6462006-03-31 02:31:16 -080032#include <linux/leds.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#include <linux/ide.h>
Bartlomiej Zolnierkiewicz3ceca722008-10-10 22:39:27 +020034#include <linux/hdreg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070035
36#include <asm/byteorder.h>
37#include <asm/irq.h>
38#include <asm/uaccess.h>
39#include <asm/io.h>
40#include <asm/div64.h>
41
Tejun Heo870d6652008-08-25 19:47:25 +090042#if !defined(CONFIG_DEBUG_BLOCK_EXT_DEVT)
Tejun Heo689d6fa2008-08-25 19:56:16 +090043#define IDE_DISK_MINORS (1 << PARTN_BITS)
Tejun Heo870d6652008-08-25 19:47:25 +090044#else
Tejun Heo3e1a7ff2008-08-25 19:56:17 +090045#define IDE_DISK_MINORS 0
Tejun Heo870d6652008-08-25 19:47:25 +090046#endif
47
Linus Torvalds1da177e2005-04-16 15:20:36 -070048struct ide_disk_obj {
49 ide_drive_t *drive;
50 ide_driver_t *driver;
51 struct gendisk *disk;
52 struct kref kref;
Bartlomiej Zolnierkiewiczc94964a2007-02-17 02:40:24 +010053 unsigned int openers; /* protected by BKL for now */
Linus Torvalds1da177e2005-04-16 15:20:36 -070054};
55
Arjan van de Vencf8b8972006-03-23 03:00:45 -080056static DEFINE_MUTEX(idedisk_ref_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -070057
58#define to_ide_disk(obj) container_of(obj, struct ide_disk_obj, kref)
59
60#define ide_disk_g(disk) \
61 container_of((disk)->private_data, struct ide_disk_obj, driver)
62
Bartlomiej Zolnierkiewicz08da5912008-07-24 22:53:15 +020063static void ide_disk_release(struct kref *);
64
Linus Torvalds1da177e2005-04-16 15:20:36 -070065static struct ide_disk_obj *ide_disk_get(struct gendisk *disk)
66{
67 struct ide_disk_obj *idkp = NULL;
68
Arjan van de Vencf8b8972006-03-23 03:00:45 -080069 mutex_lock(&idedisk_ref_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -070070 idkp = ide_disk_g(disk);
Bartlomiej Zolnierkiewicz08da5912008-07-24 22:53:15 +020071 if (idkp) {
Bartlomiej Zolnierkiewiczd3e33ff2008-08-05 18:16:59 +020072 if (ide_device_get(idkp->drive))
Bartlomiej Zolnierkiewicz08da5912008-07-24 22:53:15 +020073 idkp = NULL;
Bartlomiej Zolnierkiewiczd3e33ff2008-08-05 18:16:59 +020074 else
75 kref_get(&idkp->kref);
Bartlomiej Zolnierkiewicz08da5912008-07-24 22:53:15 +020076 }
Arjan van de Vencf8b8972006-03-23 03:00:45 -080077 mutex_unlock(&idedisk_ref_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -070078 return idkp;
79}
80
Linus Torvalds1da177e2005-04-16 15:20:36 -070081static void ide_disk_put(struct ide_disk_obj *idkp)
82{
Bartlomiej Zolnierkiewiczd3e33ff2008-08-05 18:16:59 +020083 ide_drive_t *drive = idkp->drive;
84
Arjan van de Vencf8b8972006-03-23 03:00:45 -080085 mutex_lock(&idedisk_ref_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -070086 kref_put(&idkp->kref, ide_disk_release);
Bartlomiej Zolnierkiewiczd3e33ff2008-08-05 18:16:59 +020087 ide_device_put(drive);
Arjan van de Vencf8b8972006-03-23 03:00:45 -080088 mutex_unlock(&idedisk_ref_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -070089}
90
Bartlomiej Zolnierkiewiczba76ae32008-01-25 22:17:16 +010091static const u8 ide_rw_cmds[] = {
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +020092 ATA_CMD_READ_MULTI,
93 ATA_CMD_WRITE_MULTI,
94 ATA_CMD_READ_MULTI_EXT,
95 ATA_CMD_WRITE_MULTI_EXT,
96 ATA_CMD_PIO_READ,
97 ATA_CMD_PIO_WRITE,
98 ATA_CMD_PIO_READ_EXT,
99 ATA_CMD_PIO_WRITE_EXT,
100 ATA_CMD_READ,
101 ATA_CMD_WRITE,
102 ATA_CMD_READ_EXT,
103 ATA_CMD_WRITE_EXT,
Bartlomiej Zolnierkiewiczba76ae32008-01-25 22:17:16 +0100104};
105
106static const u8 ide_data_phases[] = {
107 TASKFILE_MULTI_IN,
108 TASKFILE_MULTI_OUT,
109 TASKFILE_IN,
110 TASKFILE_OUT,
111 TASKFILE_IN_DMA,
112 TASKFILE_OUT_DMA,
113};
114
115static void ide_tf_set_cmd(ide_drive_t *drive, ide_task_t *task, u8 dma)
116{
117 u8 index, lba48, write;
118
119 lba48 = (task->tf_flags & IDE_TFLAG_LBA48) ? 2 : 0;
120 write = (task->tf_flags & IDE_TFLAG_WRITE) ? 1 : 0;
121
122 if (dma)
Bartlomiej Zolnierkiewiczba4b2e62008-07-23 19:55:55 +0200123 index = 8;
Bartlomiej Zolnierkiewiczba76ae32008-01-25 22:17:16 +0100124 else
125 index = drive->mult_count ? 0 : 4;
126
127 task->tf.command = ide_rw_cmds[index + lba48 + write];
128
129 if (dma)
130 index = 8; /* fixup index */
131
132 task->data_phase = ide_data_phases[index / 2 + write];
133}
134
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135/*
136 * __ide_do_rw_disk() issues READ and WRITE commands to a disk,
137 * using LBA if supported, or CHS otherwise, to address sectors.
138 */
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200139static ide_startstop_t __ide_do_rw_disk(ide_drive_t *drive, struct request *rq,
140 sector_t block)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141{
142 ide_hwif_t *hwif = HWIF(drive);
Bartlomiej Zolnierkiewicz790d1232008-01-25 22:17:12 +0100143 u16 nsectors = (u16)rq->nr_sectors;
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200144 u8 lba48 = !!(drive->dev_flags & IDE_DFLAG_LBA48);
145 u8 dma = !!(drive->dev_flags & IDE_DFLAG_USING_DMA);
Bartlomiej Zolnierkiewicz9e422372008-01-25 22:17:07 +0100146 ide_task_t task;
147 struct ide_taskfile *tf = &task.tf;
Bartlomiej Zolnierkiewiczf6e29e32008-01-25 22:17:16 +0100148 ide_startstop_t rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149
Bartlomiej Zolnierkiewicz238e4f12007-10-19 00:30:07 +0200150 if ((hwif->host_flags & IDE_HFLAG_NO_LBA48_DMA) && lba48 && dma) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151 if (block + rq->nr_sectors > 1ULL << 28)
152 dma = 0;
153 else
154 lba48 = 0;
155 }
156
157 if (!dma) {
158 ide_init_sg_cmd(drive, rq);
159 ide_map_sg(drive, rq);
160 }
161
Bartlomiej Zolnierkiewicz9e422372008-01-25 22:17:07 +0100162 memset(&task, 0, sizeof(task));
Bartlomiej Zolnierkiewicz9a410e72008-07-15 21:21:48 +0200163 task.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
Bartlomiej Zolnierkiewicz2bd06b22008-01-25 22:17:06 +0100164
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 if (drive->select.b.lba) {
166 if (lba48) {
Michael Richardsonc2f83112006-02-07 12:58:33 -0800167 pr_debug("%s: LBA=0x%012llx\n", drive->name,
168 (unsigned long long)block);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169
Bartlomiej Zolnierkiewicz790d1232008-01-25 22:17:12 +0100170 tf->hob_nsect = (nsectors >> 8) & 0xff;
Bartlomiej Zolnierkiewicz2bd06b22008-01-25 22:17:06 +0100171 tf->hob_lbal = (u8)(block >> 24);
172 if (sizeof(block) != 4) {
173 tf->hob_lbam = (u8)((u64)block >> 32);
174 tf->hob_lbah = (u8)((u64)block >> 40);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175 }
Bartlomiej Zolnierkiewicz2bd06b22008-01-25 22:17:06 +0100176
Bartlomiej Zolnierkiewicz790d1232008-01-25 22:17:12 +0100177 tf->nsect = nsectors & 0xff;
Bartlomiej Zolnierkiewicz2bd06b22008-01-25 22:17:06 +0100178 tf->lbal = (u8) block;
179 tf->lbam = (u8)(block >> 8);
180 tf->lbah = (u8)(block >> 16);
Bartlomiej Zolnierkiewicz6dd9b832008-01-26 20:13:03 +0100181
Bartlomiej Zolnierkiewicz657cc1a2008-01-26 20:13:10 +0100182 task.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_HOB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183 } else {
Bartlomiej Zolnierkiewicz790d1232008-01-25 22:17:12 +0100184 tf->nsect = nsectors & 0xff;
Bartlomiej Zolnierkiewicz2bd06b22008-01-25 22:17:06 +0100185 tf->lbal = block;
186 tf->lbam = block >>= 8;
187 tf->lbah = block >>= 8;
188 tf->device = (block >> 8) & 0xf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189 }
190 } else {
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200191 unsigned int sect, head, cyl, track;
192
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193 track = (int)block / drive->sect;
194 sect = (int)block % drive->sect + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195 head = track % drive->head;
196 cyl = track / drive->head;
197
198 pr_debug("%s: CHS=%u/%u/%u\n", drive->name, cyl, head, sect);
199
Bartlomiej Zolnierkiewicz790d1232008-01-25 22:17:12 +0100200 tf->nsect = nsectors & 0xff;
Bartlomiej Zolnierkiewicz2bd06b22008-01-25 22:17:06 +0100201 tf->lbal = sect;
202 tf->lbam = cyl;
203 tf->lbah = cyl >> 8;
204 tf->device = head;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205 }
206
Bartlomiej Zolnierkiewiczba76ae32008-01-25 22:17:16 +0100207 if (rq_data_dir(rq))
208 task.tf_flags |= IDE_TFLAG_WRITE;
209
210 ide_tf_set_cmd(drive, &task, dma);
Bartlomiej Zolnierkiewiczf6e29e32008-01-25 22:17:16 +0100211 if (!dma)
212 hwif->data_phase = task.data_phase;
213 task.rq = rq;
Bartlomiej Zolnierkiewiczba76ae32008-01-25 22:17:16 +0100214
Bartlomiej Zolnierkiewiczf6e29e32008-01-25 22:17:16 +0100215 rc = do_rw_taskfile(drive, &task);
Bartlomiej Zolnierkiewicz2bd06b22008-01-25 22:17:06 +0100216
Bartlomiej Zolnierkiewiczf6e29e32008-01-25 22:17:16 +0100217 if (rc == ide_stopped && dma) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218 /* fallback to PIO */
Bartlomiej Zolnierkiewiczf6e29e32008-01-25 22:17:16 +0100219 task.tf_flags |= IDE_TFLAG_DMA_PIO_FALLBACK;
Bartlomiej Zolnierkiewiczba76ae32008-01-25 22:17:16 +0100220 ide_tf_set_cmd(drive, &task, 0);
Bartlomiej Zolnierkiewiczf6e29e32008-01-25 22:17:16 +0100221 hwif->data_phase = task.data_phase;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 ide_init_sg_cmd(drive, rq);
Bartlomiej Zolnierkiewiczf6e29e32008-01-25 22:17:16 +0100223 rc = do_rw_taskfile(drive, &task);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 }
225
Bartlomiej Zolnierkiewiczf6e29e32008-01-25 22:17:16 +0100226 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227}
228
229/*
230 * 268435455 == 137439 MB or 28bit limit
231 * 320173056 == 163929 MB or 48bit addressing
232 * 1073741822 == 549756 MB or 48bit addressing fake drive
233 */
234
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200235static ide_startstop_t ide_do_rw_disk(ide_drive_t *drive, struct request *rq,
236 sector_t block)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237{
238 ide_hwif_t *hwif = HWIF(drive);
239
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200240 BUG_ON(drive->dev_flags & IDE_DFLAG_BLOCKED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241
242 if (!blk_fs_request(rq)) {
243 blk_dump_rq_flags(rq, "ide_do_rw_disk - bad command");
244 ide_end_request(drive, 0, 0);
245 return ide_stopped;
246 }
247
Richard Purdie2bfb6462006-03-31 02:31:16 -0800248 ledtrig_ide_activity();
249
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250 pr_debug("%s: %sing: block=%llu, sectors=%lu, buffer=0x%08lx\n",
251 drive->name, rq_data_dir(rq) == READ ? "read" : "writ",
Michael Richardsonc2f83112006-02-07 12:58:33 -0800252 (unsigned long long)block, rq->nr_sectors,
253 (unsigned long)rq->buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254
255 if (hwif->rw_disk)
256 hwif->rw_disk(drive, rq);
257
258 return __ide_do_rw_disk(drive, rq, block);
259}
260
261/*
262 * Queries for true maximum capacity of the drive.
263 * Returns maximum LBA address (> 0) of the drive, 0 if failed.
264 */
Bartlomiej Zolnierkiewicz7a3b7512008-01-25 22:17:06 +0100265static u64 idedisk_read_native_max_address(ide_drive_t *drive, int lba48)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266{
267 ide_task_t args;
Bartlomiej Zolnierkiewicz650d8412008-01-25 22:17:06 +0100268 struct ide_taskfile *tf = &args.tf;
Bartlomiej Zolnierkiewicz7a3b7512008-01-25 22:17:06 +0100269 u64 addr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270
271 /* Create IDE/ATA command request structure */
272 memset(&args, 0, sizeof(ide_task_t));
Bartlomiej Zolnierkiewicz7a3b7512008-01-25 22:17:06 +0100273 if (lba48)
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200274 tf->command = ATA_CMD_READ_NATIVE_MAX_EXT;
Bartlomiej Zolnierkiewicz7a3b7512008-01-25 22:17:06 +0100275 else
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200276 tf->command = ATA_CMD_READ_NATIVE_MAX;
Bartlomiej Zolnierkiewicz650d8412008-01-25 22:17:06 +0100277 tf->device = ATA_LBA;
Bartlomiej Zolnierkiewicz657cc1a2008-01-26 20:13:10 +0100278 args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
Bartlomiej Zolnierkiewicza3bbb9d2008-01-25 22:17:10 +0100279 if (lba48)
Bartlomiej Zolnierkiewicz657cc1a2008-01-26 20:13:10 +0100280 args.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_HOB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281 /* submit command request */
Bartlomiej Zolnierkiewicz9a3c49b2008-01-25 22:17:07 +0100282 ide_no_data_taskfile(drive, &args);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283
284 /* if OK, compute maximum address value */
Bartlomiej Zolnierkiewicza5016332008-01-25 22:17:17 +0100285 if ((tf->status & 0x01) == 0)
286 addr = ide_get_lba_addr(tf, lba48) + 1;
Bartlomiej Zolnierkiewicz650d8412008-01-25 22:17:06 +0100287
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 return addr;
289}
290
291/*
292 * Sets maximum virtual LBA address of the drive.
293 * Returns new maximum virtual LBA address (> 0) or 0 on failure.
294 */
Bartlomiej Zolnierkiewicz7a3b7512008-01-25 22:17:06 +0100295static u64 idedisk_set_max_address(ide_drive_t *drive, u64 addr_req, int lba48)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296{
297 ide_task_t args;
Bartlomiej Zolnierkiewicz650d8412008-01-25 22:17:06 +0100298 struct ide_taskfile *tf = &args.tf;
Bartlomiej Zolnierkiewicz7a3b7512008-01-25 22:17:06 +0100299 u64 addr_set = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300
301 addr_req--;
302 /* Create IDE/ATA command request structure */
303 memset(&args, 0, sizeof(ide_task_t));
Bartlomiej Zolnierkiewicz650d8412008-01-25 22:17:06 +0100304 tf->lbal = (addr_req >> 0) & 0xff;
305 tf->lbam = (addr_req >>= 8) & 0xff;
306 tf->lbah = (addr_req >>= 8) & 0xff;
Bartlomiej Zolnierkiewicz7a3b7512008-01-25 22:17:06 +0100307 if (lba48) {
308 tf->hob_lbal = (addr_req >>= 8) & 0xff;
309 tf->hob_lbam = (addr_req >>= 8) & 0xff;
310 tf->hob_lbah = (addr_req >>= 8) & 0xff;
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200311 tf->command = ATA_CMD_SET_MAX_EXT;
Bartlomiej Zolnierkiewicz7a3b7512008-01-25 22:17:06 +0100312 } else {
313 tf->device = (addr_req >>= 8) & 0x0f;
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200314 tf->command = ATA_CMD_SET_MAX;
Bartlomiej Zolnierkiewicz7a3b7512008-01-25 22:17:06 +0100315 }
316 tf->device |= ATA_LBA;
Bartlomiej Zolnierkiewicz657cc1a2008-01-26 20:13:10 +0100317 args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
Bartlomiej Zolnierkiewicza3bbb9d2008-01-25 22:17:10 +0100318 if (lba48)
Bartlomiej Zolnierkiewicz657cc1a2008-01-26 20:13:10 +0100319 args.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_HOB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320 /* submit command request */
Bartlomiej Zolnierkiewicz9a3c49b2008-01-25 22:17:07 +0100321 ide_no_data_taskfile(drive, &args);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322 /* if OK, compute maximum address value */
Bartlomiej Zolnierkiewicza5016332008-01-25 22:17:17 +0100323 if ((tf->status & 0x01) == 0)
324 addr_set = ide_get_lba_addr(tf, lba48) + 1;
Bartlomiej Zolnierkiewicz650d8412008-01-25 22:17:06 +0100325
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326 return addr_set;
327}
328
329static unsigned long long sectors_to_MB(unsigned long long n)
330{
331 n <<= 9; /* make it bytes */
332 do_div(n, 1000000); /* make it MB */
333 return n;
334}
335
336/*
Bartlomiej Zolnierkiewiczb0244a02007-08-20 22:42:57 +0200337 * Some disks report total number of sectors instead of
338 * maximum sector address. We list them here.
339 */
340static const struct drive_list_entry hpa_list[] = {
341 { "ST340823A", NULL },
Jorge Juan Chico7062cdc2007-09-17 12:35:30 +0200342 { "ST320413A", NULL },
Mikko Rapelib152fcd2008-02-19 01:41:25 +0100343 { "ST310211A", NULL },
Bartlomiej Zolnierkiewiczb0244a02007-08-20 22:42:57 +0200344 { NULL, NULL }
345};
346
Arjan van de Ven858119e2006-01-14 13:20:43 -0800347static void idedisk_check_hpa(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348{
349 unsigned long long capacity, set_max;
Bartlomiej Zolnierkiewicz942dcd82008-10-10 22:39:30 +0200350 int lba48 = ata_id_lba48_enabled(drive->id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351
352 capacity = drive->capacity64;
Bartlomiej Zolnierkiewicz7a3b7512008-01-25 22:17:06 +0100353
354 set_max = idedisk_read_native_max_address(drive, lba48);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355
Bartlomiej Zolnierkiewiczb0244a02007-08-20 22:42:57 +0200356 if (ide_in_drive_list(drive->id, hpa_list)) {
357 /*
358 * Since we are inclusive wrt to firmware revisions do this
359 * extra check and apply the workaround only when needed.
360 */
361 if (set_max == capacity + 1)
362 set_max--;
363 }
364
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 if (set_max <= capacity)
366 return;
367
368 printk(KERN_INFO "%s: Host Protected Area detected.\n"
369 "\tcurrent capacity is %llu sectors (%llu MB)\n"
370 "\tnative capacity is %llu sectors (%llu MB)\n",
371 drive->name,
372 capacity, sectors_to_MB(capacity),
373 set_max, sectors_to_MB(set_max));
374
Bartlomiej Zolnierkiewicz7a3b7512008-01-25 22:17:06 +0100375 set_max = idedisk_set_max_address(drive, set_max, lba48);
376
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 if (set_max) {
378 drive->capacity64 = set_max;
379 printk(KERN_INFO "%s: Host Protected Area disabled.\n",
380 drive->name);
381 }
382}
383
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200384static void init_idedisk_capacity(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385{
Bartlomiej Zolnierkiewicz4dde4492008-10-10 22:39:19 +0200386 u16 *id = drive->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 /*
388 * If this drive supports the Host Protected Area feature set,
389 * then we may need to change our opinion about the drive's capacity.
390 */
Bartlomiej Zolnierkiewiczf41891c2008-10-10 22:39:20 +0200391 int hpa = ata_id_hpa_enabled(id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392
Bartlomiej Zolnierkiewicz942dcd82008-10-10 22:39:30 +0200393 if (ata_id_lba48_enabled(id)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 /* drive speaks 48-bit LBA */
395 drive->select.b.lba = 1;
Bartlomiej Zolnierkiewicz48fb2682008-10-10 22:39:19 +0200396 drive->capacity64 = ata_id_u64(id, ATA_ID_LBA_CAPACITY_2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 if (hpa)
398 idedisk_check_hpa(drive);
Bartlomiej Zolnierkiewicza02227c2008-10-10 22:39:31 +0200399 } else if (ata_id_has_lba(id) && ata_id_is_lba_capacity_ok(id)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 /* drive speaks 28-bit LBA */
401 drive->select.b.lba = 1;
Bartlomiej Zolnierkiewicz48fb2682008-10-10 22:39:19 +0200402 drive->capacity64 = ata_id_u32(id, ATA_ID_LBA_CAPACITY);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 if (hpa)
404 idedisk_check_hpa(drive);
405 } else {
406 /* drive speaks boring old 28-bit CHS */
407 drive->capacity64 = drive->cyl * drive->head * drive->sect;
408 }
409}
410
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200411static sector_t idedisk_capacity(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412{
Bartlomiej Zolnierkiewicz3c619ff2008-10-10 22:39:22 +0200413 return drive->capacity64;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414}
415
Bartlomiej Zolnierkiewiczecfd80e2007-05-10 00:01:09 +0200416#ifdef CONFIG_IDE_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417static int smart_enable(ide_drive_t *drive)
418{
419 ide_task_t args;
Bartlomiej Zolnierkiewicz650d8412008-01-25 22:17:06 +0100420 struct ide_taskfile *tf = &args.tf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421
422 memset(&args, 0, sizeof(ide_task_t));
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200423 tf->feature = ATA_SMART_ENABLE;
424 tf->lbam = ATA_SMART_LBAM_PASS;
425 tf->lbah = ATA_SMART_LBAH_PASS;
426 tf->command = ATA_CMD_SMART;
Bartlomiej Zolnierkiewicz657cc1a2008-01-26 20:13:10 +0100427 args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
Bartlomiej Zolnierkiewicz9a3c49b2008-01-25 22:17:07 +0100428 return ide_no_data_taskfile(drive, &args);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429}
430
Bartlomiej Zolnierkiewicz43e7c0c2007-10-20 00:32:37 +0200431static int get_smart_data(ide_drive_t *drive, u8 *buf, u8 sub_cmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432{
433 ide_task_t args;
Bartlomiej Zolnierkiewicz650d8412008-01-25 22:17:06 +0100434 struct ide_taskfile *tf = &args.tf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435
436 memset(&args, 0, sizeof(ide_task_t));
Bartlomiej Zolnierkiewicz650d8412008-01-25 22:17:06 +0100437 tf->feature = sub_cmd;
438 tf->nsect = 0x01;
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200439 tf->lbam = ATA_SMART_LBAM_PASS;
440 tf->lbah = ATA_SMART_LBAH_PASS;
441 tf->command = ATA_CMD_SMART;
Bartlomiej Zolnierkiewicz657cc1a2008-01-26 20:13:10 +0100442 args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
Bartlomiej Zolnierkiewiczac026ff2008-01-25 22:17:14 +0100443 args.data_phase = TASKFILE_IN;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 (void) smart_enable(drive);
Bartlomiej Zolnierkiewiczac026ff2008-01-25 22:17:14 +0100445 return ide_raw_taskfile(drive, &args, buf, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446}
447
448static int proc_idedisk_read_cache
449 (char *page, char **start, off_t off, int count, int *eof, void *data)
450{
451 ide_drive_t *drive = (ide_drive_t *) data;
452 char *out = page;
453 int len;
454
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200455 if (drive->dev_flags & IDE_DFLAG_ID_READ)
Bartlomiej Zolnierkiewicz4dde4492008-10-10 22:39:19 +0200456 len = sprintf(out, "%i\n", drive->id[ATA_ID_BUF_SIZE] / 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 else
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200458 len = sprintf(out, "(none)\n");
459
460 PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461}
462
463static int proc_idedisk_read_capacity
464 (char *page, char **start, off_t off, int count, int *eof, void *data)
465{
466 ide_drive_t*drive = (ide_drive_t *)data;
467 int len;
468
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200469 len = sprintf(page, "%llu\n", (long long)idedisk_capacity(drive));
470
471 PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472}
473
Bartlomiej Zolnierkiewicz799ee572008-04-26 17:36:37 +0200474static int proc_idedisk_read_smart(char *page, char **start, off_t off,
475 int count, int *eof, void *data, u8 sub_cmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476{
477 ide_drive_t *drive = (ide_drive_t *)data;
478 int len = 0, i = 0;
479
Bartlomiej Zolnierkiewicz799ee572008-04-26 17:36:37 +0200480 if (get_smart_data(drive, page, sub_cmd) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 unsigned short *val = (unsigned short *) page;
Bartlomiej Zolnierkiewicz151a6702008-10-10 22:39:28 +0200482 char *out = (char *)val + SECTOR_SIZE;
483
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 page = out;
485 do {
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200486 out += sprintf(out, "%04x%c", le16_to_cpu(*val),
487 (++i & 7) ? ' ' : '\n');
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 val += 1;
Bartlomiej Zolnierkiewicz151a6702008-10-10 22:39:28 +0200489 } while (i < SECTOR_SIZE / 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 len = out - page;
491 }
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200492
493 PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494}
495
Bartlomiej Zolnierkiewicz799ee572008-04-26 17:36:37 +0200496static int proc_idedisk_read_sv
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 (char *page, char **start, off_t off, int count, int *eof, void *data)
498{
Bartlomiej Zolnierkiewicz799ee572008-04-26 17:36:37 +0200499 return proc_idedisk_read_smart(page, start, off, count, eof, data,
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200500 ATA_SMART_READ_VALUES);
Bartlomiej Zolnierkiewicz799ee572008-04-26 17:36:37 +0200501}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502
Bartlomiej Zolnierkiewicz799ee572008-04-26 17:36:37 +0200503static int proc_idedisk_read_st
504 (char *page, char **start, off_t off, int count, int *eof, void *data)
505{
506 return proc_idedisk_read_smart(page, start, off, count, eof, data,
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200507 ATA_SMART_READ_THRESHOLDS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508}
509
510static ide_proc_entry_t idedisk_proc[] = {
Bartlomiej Zolnierkiewicz799ee572008-04-26 17:36:37 +0200511 { "cache", S_IFREG|S_IRUGO, proc_idedisk_read_cache, NULL },
512 { "capacity", S_IFREG|S_IRUGO, proc_idedisk_read_capacity, NULL },
513 { "geometry", S_IFREG|S_IRUGO, proc_ide_read_geometry, NULL },
514 { "smart_values", S_IFREG|S_IRUSR, proc_idedisk_read_sv, NULL },
515 { "smart_thresholds", S_IFREG|S_IRUSR, proc_idedisk_read_st, NULL },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516 { NULL, 0, NULL, NULL }
517};
Bartlomiej Zolnierkiewiczecfd80e2007-05-10 00:01:09 +0200518#endif /* CONFIG_IDE_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519
Jens Axboe165125e2007-07-24 09:28:11 +0200520static void idedisk_prepare_flush(struct request_queue *q, struct request *rq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521{
522 ide_drive_t *drive = q->queuedata;
Bartlomiej Zolnierkiewicz395d8ef2008-02-11 00:32:14 +0100523 ide_task_t *task = kmalloc(sizeof(*task), GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524
Bartlomiej Zolnierkiewicz395d8ef2008-02-11 00:32:14 +0100525 /* FIXME: map struct ide_taskfile on rq->cmd[] */
526 BUG_ON(task == NULL);
527
528 memset(task, 0, sizeof(*task));
Bartlomiej Zolnierkiewiczff2779b2008-10-10 22:39:31 +0200529 if (ata_id_flush_ext_enabled(drive->id) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 (drive->capacity64 >= (1UL << 28)))
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200531 task->tf.command = ATA_CMD_FLUSH_EXT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532 else
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200533 task->tf.command = ATA_CMD_FLUSH;
Bartlomiej Zolnierkiewicz395d8ef2008-02-11 00:32:14 +0100534 task->tf_flags = IDE_TFLAG_OUT_TF | IDE_TFLAG_OUT_DEVICE |
535 IDE_TFLAG_DYN;
536 task->data_phase = TASKFILE_NO_DATA;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537
Bartlomiej Zolnierkiewicz813a0eb2008-01-25 22:17:10 +0100538 rq->cmd_type = REQ_TYPE_ATA_TASKFILE;
Jens Axboe4aff5e22006-08-10 08:44:47 +0200539 rq->cmd_flags |= REQ_SOFTBARRIER;
Bartlomiej Zolnierkiewicz395d8ef2008-02-11 00:32:14 +0100540 rq->special = task;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541}
542
Bartlomiej Zolnierkiewicz8185d5a2008-10-10 22:39:28 +0200543ide_devset_get(multcount, mult_count);
544
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545/*
546 * This is tightly woven into the driver->do_special can not touch.
547 * DON'T do it again until a total personality rewrite is committed.
548 */
549static int set_multcount(ide_drive_t *drive, int arg)
550{
FUJITA Tomonoridd470872008-07-15 21:21:43 +0200551 struct request *rq;
552 int error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553
Bartlomiej Zolnierkiewicz48fb2682008-10-10 22:39:19 +0200554 if (arg < 0 || arg > (drive->id[ATA_ID_MAX_MULTSECT] & 0xff))
Bartlomiej Zolnierkiewicz14979432007-05-10 00:01:10 +0200555 return -EINVAL;
556
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 if (drive->special.b.set_multmode)
558 return -EBUSY;
Bartlomiej Zolnierkiewicz852738f2008-01-26 20:13:12 +0100559
FUJITA Tomonoridd470872008-07-15 21:21:43 +0200560 rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
561 rq->cmd_type = REQ_TYPE_ATA_TASKFILE;
Bartlomiej Zolnierkiewicz852738f2008-01-26 20:13:12 +0100562
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563 drive->mult_req = arg;
564 drive->special.b.set_multmode = 1;
FUJITA Tomonoridd470872008-07-15 21:21:43 +0200565 error = blk_execute_rq(drive->queue, NULL, rq, 0);
566 blk_put_request(rq);
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200567
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568 return (drive->mult_count == arg) ? 0 : -EIO;
569}
570
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200571ide_devset_get_flag(nowerr, IDE_DFLAG_NOWERR);
Bartlomiej Zolnierkiewicz8185d5a2008-10-10 22:39:28 +0200572
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573static int set_nowerr(ide_drive_t *drive, int arg)
574{
Bartlomiej Zolnierkiewicz14979432007-05-10 00:01:10 +0200575 if (arg < 0 || arg > 1)
576 return -EINVAL;
577
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200578 if (arg)
579 drive->dev_flags |= IDE_DFLAG_NOWERR;
580 else
581 drive->dev_flags &= ~IDE_DFLAG_NOWERR;
582
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 drive->bad_wstat = arg ? BAD_R_STAT : BAD_W_STAT;
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200584
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585 return 0;
586}
587
Bartlomiej Zolnierkiewiczbe3c0962008-10-13 21:39:36 +0200588static int ide_do_setfeature(ide_drive_t *drive, u8 feature, u8 nsect)
589{
590 ide_task_t task;
591
592 memset(&task, 0, sizeof(task));
593 task.tf.feature = feature;
594 task.tf.nsect = nsect;
595 task.tf.command = ATA_CMD_SET_FEATURES;
596 task.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
597
598 return ide_no_data_taskfile(drive, &task);
599}
600
Tejun Heo3e087b52006-01-06 09:57:31 +0100601static void update_ordered(ide_drive_t *drive)
602{
Bartlomiej Zolnierkiewicz4dde4492008-10-10 22:39:19 +0200603 u16 *id = drive->id;
Tejun Heo3e087b52006-01-06 09:57:31 +0100604 unsigned ordered = QUEUE_ORDERED_NONE;
605 prepare_flush_fn *prep_fn = NULL;
Tejun Heo3e087b52006-01-06 09:57:31 +0100606
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200607 if (drive->dev_flags & IDE_DFLAG_WCACHE) {
Tejun Heo3e087b52006-01-06 09:57:31 +0100608 unsigned long long capacity;
609 int barrier;
610 /*
611 * We must avoid issuing commands a drive does not
612 * understand or we may crash it. We check flush cache
613 * is supported. We also check we have the LBA48 flush
614 * cache if the drive capacity is too large. By this
615 * time we have trimmed the drive capacity if LBA48 is
616 * not available so we don't need to recheck that.
617 */
618 capacity = idedisk_capacity(drive);
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200619 barrier = ata_id_flush_enabled(id) &&
620 (drive->dev_flags & IDE_DFLAG_NOFLUSH) == 0 &&
621 ((drive->dev_flags & IDE_DFLAG_LBA48) == 0 ||
622 capacity <= (1ULL << 28) ||
Bartlomiej Zolnierkiewiczff2779b2008-10-10 22:39:31 +0200623 ata_id_flush_ext_enabled(id));
Tejun Heo3e087b52006-01-06 09:57:31 +0100624
625 printk(KERN_INFO "%s: cache flushes %ssupported\n",
Jean Delvaref7ad8362006-02-03 03:04:57 -0800626 drive->name, barrier ? "" : "not ");
Tejun Heo3e087b52006-01-06 09:57:31 +0100627
628 if (barrier) {
629 ordered = QUEUE_ORDERED_DRAIN_FLUSH;
630 prep_fn = idedisk_prepare_flush;
Tejun Heo3e087b52006-01-06 09:57:31 +0100631 }
632 } else
633 ordered = QUEUE_ORDERED_DRAIN;
634
635 blk_queue_ordered(drive->queue, ordered, prep_fn);
Tejun Heo3e087b52006-01-06 09:57:31 +0100636}
637
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200638ide_devset_get_flag(wcache, IDE_DFLAG_WCACHE);
Bartlomiej Zolnierkiewicz8185d5a2008-10-10 22:39:28 +0200639
640static int set_wcache(ide_drive_t *drive, int arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641{
Tejun Heo3e087b52006-01-06 09:57:31 +0100642 int err = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643
Bartlomiej Zolnierkiewicz14979432007-05-10 00:01:10 +0200644 if (arg < 0 || arg > 1)
645 return -EINVAL;
646
Bartlomiej Zolnierkiewicz4b58f172008-10-10 22:39:30 +0200647 if (ata_id_flush_enabled(drive->id)) {
Bartlomiej Zolnierkiewiczbe3c0962008-10-13 21:39:36 +0200648 err = ide_do_setfeature(drive,
649 arg ? SETFEATURES_WC_ON : SETFEATURES_WC_OFF, 0);
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200650 if (err == 0) {
651 if (arg)
652 drive->dev_flags |= IDE_DFLAG_WCACHE;
653 else
654 drive->dev_flags &= ~IDE_DFLAG_WCACHE;
655 }
Tejun Heo3e087b52006-01-06 09:57:31 +0100656 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657
Tejun Heo3e087b52006-01-06 09:57:31 +0100658 update_ordered(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659
Tejun Heo3e087b52006-01-06 09:57:31 +0100660 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661}
662
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200663static int do_idedisk_flushcache(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664{
665 ide_task_t args;
666
667 memset(&args, 0, sizeof(ide_task_t));
Bartlomiej Zolnierkiewiczff2779b2008-10-10 22:39:31 +0200668 if (ata_id_flush_ext_enabled(drive->id))
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200669 args.tf.command = ATA_CMD_FLUSH_EXT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 else
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200671 args.tf.command = ATA_CMD_FLUSH;
Bartlomiej Zolnierkiewicz657cc1a2008-01-26 20:13:10 +0100672 args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
Bartlomiej Zolnierkiewicz9a3c49b2008-01-25 22:17:07 +0100673 return ide_no_data_taskfile(drive, &args);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674}
675
Bartlomiej Zolnierkiewicz8185d5a2008-10-10 22:39:28 +0200676ide_devset_get(acoustic, acoustic);
677
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200678static int set_acoustic(ide_drive_t *drive, int arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679{
Bartlomiej Zolnierkiewicz14979432007-05-10 00:01:10 +0200680 if (arg < 0 || arg > 254)
681 return -EINVAL;
682
Bartlomiej Zolnierkiewiczbe3c0962008-10-13 21:39:36 +0200683 ide_do_setfeature(drive,
684 arg ? SETFEATURES_AAM_ON : SETFEATURES_AAM_OFF, arg);
685
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 drive->acoustic = arg;
Bartlomiej Zolnierkiewiczbe3c0962008-10-13 21:39:36 +0200687
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 return 0;
689}
690
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200691ide_devset_get_flag(addressing, IDE_DFLAG_LBA48);
Bartlomiej Zolnierkiewicz8185d5a2008-10-10 22:39:28 +0200692
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693/*
694 * drive->addressing:
695 * 0: 28-bit
696 * 1: 48-bit
697 * 2: 48-bit capable doing 28-bit
698 */
Bartlomiej Zolnierkiewiczaa7687732008-10-10 22:39:33 +0200699static int set_addressing(ide_drive_t *drive, int arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700{
Bartlomiej Zolnierkiewicz14979432007-05-10 00:01:10 +0200701 if (arg < 0 || arg > 2)
702 return -EINVAL;
703
Bartlomiej Zolnierkiewicz35c13752008-10-13 21:39:36 +0200704 if (arg && ((drive->hwif->host_flags & IDE_HFLAG_NO_LBA48) ||
705 ata_id_lba48_enabled(drive->id) == 0))
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200706 return -EIO;
Bartlomiej Zolnierkiewicz942dcd82008-10-10 22:39:30 +0200707
Bartlomiej Zolnierkiewicz35c13752008-10-13 21:39:36 +0200708 if (arg == 2)
709 arg = 0;
710
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200711 if (arg)
712 drive->dev_flags |= IDE_DFLAG_LBA48;
713 else
714 drive->dev_flags &= ~IDE_DFLAG_LBA48;
Bartlomiej Zolnierkiewicz942dcd82008-10-10 22:39:30 +0200715
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 return 0;
717}
718
Elias Oltmanns92f1f8f2008-10-10 22:39:40 +0200719ide_devset_rw(acoustic, acoustic);
720ide_devset_rw(address, addressing);
721ide_devset_rw(multcount, multcount);
722ide_devset_rw(wcache, wcache);
723
724ide_devset_rw_sync(nowerr, nowerr);
725
Bartlomiej Zolnierkiewicz7662d042007-05-10 00:01:10 +0200726#ifdef CONFIG_IDE_PROC_FS
Elias Oltmanns92f1f8f2008-10-10 22:39:40 +0200727ide_devset_rw_field(bios_cyl, bios_cyl);
728ide_devset_rw_field(bios_head, bios_head);
729ide_devset_rw_field(bios_sect, bios_sect);
730ide_devset_rw_field(failures, failures);
731ide_devset_rw_field(lun, lun);
732ide_devset_rw_field(max_failures, max_failures);
Bartlomiej Zolnierkiewicz8185d5a2008-10-10 22:39:28 +0200733
Elias Oltmanns92f1f8f2008-10-10 22:39:40 +0200734static const struct ide_proc_devset idedisk_settings[] = {
735 IDE_PROC_DEVSET(acoustic, 0, 254),
736 IDE_PROC_DEVSET(address, 0, 2),
737 IDE_PROC_DEVSET(bios_cyl, 0, 65535),
738 IDE_PROC_DEVSET(bios_head, 0, 255),
739 IDE_PROC_DEVSET(bios_sect, 0, 63),
740 IDE_PROC_DEVSET(failures, 0, 65535),
741 IDE_PROC_DEVSET(lun, 0, 7),
742 IDE_PROC_DEVSET(max_failures, 0, 65535),
743 IDE_PROC_DEVSET(multcount, 0, 16),
744 IDE_PROC_DEVSET(nowerr, 0, 1),
745 IDE_PROC_DEVSET(wcache, 0, 1),
746 { 0 },
Bartlomiej Zolnierkiewicz8185d5a2008-10-10 22:39:28 +0200747};
Bartlomiej Zolnierkiewicz7662d042007-05-10 00:01:10 +0200748#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200750static void idedisk_setup(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751{
Bartlomiej Zolnierkiewicz1e874f42008-10-10 22:39:27 +0200752 struct ide_disk_obj *idkp = drive->driver_data;
Bartlomiej Zolnierkiewicz238e4f12007-10-19 00:30:07 +0200753 ide_hwif_t *hwif = drive->hwif;
Bartlomiej Zolnierkiewicz4dde4492008-10-10 22:39:19 +0200754 u16 *id = drive->id;
755 char *m = (char *)&id[ATA_ID_PROD];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 unsigned long long capacity;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757
Bartlomiej Zolnierkiewicz1e874f42008-10-10 22:39:27 +0200758 ide_proc_register_driver(drive, idkp->driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200760 if ((drive->dev_flags & IDE_DFLAG_ID_READ) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 return;
762
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200763 if (drive->dev_flags & IDE_DFLAG_REMOVABLE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 /*
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200765 * Removable disks (eg. SYQUEST); ignore 'WD' drives
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 */
Bartlomiej Zolnierkiewicz4dde4492008-10-10 22:39:19 +0200767 if (m[0] != 'W' || m[1] != 'D')
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200768 drive->dev_flags |= IDE_DFLAG_DOORLOCKING;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769 }
770
Bartlomiej Zolnierkiewiczaa7687732008-10-10 22:39:33 +0200771 (void)set_addressing(drive, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200773 if (drive->dev_flags & IDE_DFLAG_LBA48) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 int max_s = 2048;
775
776 if (max_s > hwif->rqsize)
777 max_s = hwif->rqsize;
778
779 blk_queue_max_sectors(drive->queue, max_s);
780 }
781
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200782 printk(KERN_INFO "%s: max request size: %dKiB\n", drive->name,
783 drive->queue->max_sectors / 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784
785 /* calculate drive capacity, and select LBA if possible */
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200786 init_idedisk_capacity(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787
788 /* limit drive capacity to 137GB if LBA48 cannot be used */
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200789 if ((drive->dev_flags & IDE_DFLAG_LBA48) == 0 &&
790 drive->capacity64 > 1ULL << 28) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 printk(KERN_WARNING "%s: cannot use LBA48 - full capacity "
792 "%llu sectors (%llu MB)\n",
793 drive->name, (unsigned long long)drive->capacity64,
794 sectors_to_MB(drive->capacity64));
795 drive->capacity64 = 1ULL << 28;
796 }
797
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200798 if ((hwif->host_flags & IDE_HFLAG_NO_LBA48_DMA) &&
799 (drive->dev_flags & IDE_DFLAG_LBA48)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800 if (drive->capacity64 > 1ULL << 28) {
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200801 printk(KERN_INFO "%s: cannot use LBA48 DMA - PIO mode"
802 " will be used for accessing sectors "
803 "> %u\n", drive->name, 1 << 28);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 } else
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200805 drive->dev_flags &= ~IDE_DFLAG_LBA48;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 }
807
808 /*
809 * if possible, give fdisk access to more of the drive,
810 * by correcting bios_cyls:
811 */
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200812 capacity = idedisk_capacity(drive);
813
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200814 if ((drive->dev_flags & IDE_DFLAG_FORCED_GEOM) == 0) {
Bartlomiej Zolnierkiewicz942dcd82008-10-10 22:39:30 +0200815 if (ata_id_lba48_enabled(drive->id)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 /* compatibility */
817 drive->bios_sect = 63;
818 drive->bios_head = 255;
819 }
820
821 if (drive->bios_sect && drive->bios_head) {
822 unsigned int cap0 = capacity; /* truncate to 32 bits */
823 unsigned int cylsz, cyl;
824
825 if (cap0 != capacity)
826 drive->bios_cyl = 65535;
827 else {
828 cylsz = drive->bios_sect * drive->bios_head;
829 cyl = cap0 / cylsz;
830 if (cyl > 65535)
831 cyl = 65535;
832 if (cyl > drive->bios_cyl)
833 drive->bios_cyl = cyl;
834 }
835 }
836 }
837 printk(KERN_INFO "%s: %llu sectors (%llu MB)",
838 drive->name, capacity, sectors_to_MB(capacity));
839
840 /* Only print cache size when it was specified */
Bartlomiej Zolnierkiewicz4dde4492008-10-10 22:39:19 +0200841 if (id[ATA_ID_BUF_SIZE])
842 printk(KERN_CONT " w/%dKiB Cache", id[ATA_ID_BUF_SIZE] / 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843
Bartlomiej Zolnierkiewicz3ab7efe2007-12-12 23:31:58 +0100844 printk(KERN_CONT ", CHS=%d/%d/%d\n",
845 drive->bios_cyl, drive->bios_head, drive->bios_sect);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 /* write cache enabled? */
Bartlomiej Zolnierkiewicz8a089c62008-10-10 22:39:20 +0200848 if ((id[ATA_ID_CSFO] & 1) || ata_id_wcache_enabled(id))
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200849 drive->dev_flags |= IDE_DFLAG_WCACHE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850
Bartlomiej Zolnierkiewicz8185d5a2008-10-10 22:39:28 +0200851 set_wcache(drive, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852}
853
854static void ide_cacheflush_p(ide_drive_t *drive)
855{
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200856 if (ata_id_flush_enabled(drive->id) == 0 ||
857 (drive->dev_flags & IDE_DFLAG_WCACHE) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 return;
859
860 if (do_idedisk_flushcache(drive))
861 printk(KERN_INFO "%s: wcache flush failed!\n", drive->name);
862}
863
Russell King4031bbe2006-01-06 11:41:00 +0000864static void ide_disk_remove(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865{
866 struct ide_disk_obj *idkp = drive->driver_data;
867 struct gendisk *g = idkp->disk;
868
Bartlomiej Zolnierkiewicz7662d042007-05-10 00:01:10 +0200869 ide_proc_unregister_driver(drive, idkp->driver);
Bartlomiej Zolnierkiewicz8604aff2005-05-26 14:55:34 +0200870
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 del_gendisk(g);
872
Bartlomiej Zolnierkiewiczd36fef62005-12-15 02:19:20 +0100873 ide_cacheflush_p(drive);
874
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 ide_disk_put(idkp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876}
877
878static void ide_disk_release(struct kref *kref)
879{
880 struct ide_disk_obj *idkp = to_ide_disk(kref);
881 ide_drive_t *drive = idkp->drive;
882 struct gendisk *g = idkp->disk;
883
884 drive->driver_data = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 g->private_data = NULL;
886 put_disk(g);
887 kfree(idkp);
888}
889
Russell King4031bbe2006-01-06 11:41:00 +0000890static int ide_disk_probe(ide_drive_t *drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891
Lee Trager0d2157f2007-06-08 15:14:30 +0200892/*
893 * On HPA drives the capacity needs to be
894 * reinitilized on resume otherwise the disk
895 * can not be used and a hard reset is required
896 */
897static void ide_disk_resume(ide_drive_t *drive)
898{
Bartlomiej Zolnierkiewiczf41891c2008-10-10 22:39:20 +0200899 if (ata_id_hpa_enabled(drive->id))
Lee Trager0d2157f2007-06-08 15:14:30 +0200900 init_idedisk_capacity(drive);
901}
902
Russell King4031bbe2006-01-06 11:41:00 +0000903static void ide_device_shutdown(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905#ifdef CONFIG_ALPHA
906 /* On Alpha, halt(8) doesn't actually turn the machine off,
907 it puts you into the sort of firmware monitor. Typically,
908 it's used to boot another kernel image, so it's not much
909 different from reboot(8). Therefore, we don't need to
910 spin down the disk in this case, especially since Alpha
911 firmware doesn't handle disks in standby mode properly.
912 On the other hand, it's reasonably safe to turn the power
913 off when the shutdown process reaches the firmware prompt,
914 as the firmware initialization takes rather long time -
915 at least 10 seconds, which should be sufficient for
916 the disk to expire its write cache. */
917 if (system_state != SYSTEM_POWER_OFF) {
918#else
919 if (system_state == SYSTEM_RESTART) {
920#endif
921 ide_cacheflush_p(drive);
922 return;
923 }
924
Bartlomiej Zolnierkiewiczd12faa22008-02-26 21:50:36 +0100925 printk(KERN_INFO "Shutdown: %s\n", drive->name);
926
Russell King4031bbe2006-01-06 11:41:00 +0000927 drive->gendev.bus->suspend(&drive->gendev, PMSG_SUSPEND);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928}
929
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930static ide_driver_t idedisk_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931 .gen_driver = {
Laurent Riffard4ef3b8f2005-11-18 22:15:40 +0100932 .owner = THIS_MODULE,
Bartlomiej Zolnierkiewicz8604aff2005-05-26 14:55:34 +0200933 .name = "ide-disk",
934 .bus = &ide_bus_type,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 },
Russell King4031bbe2006-01-06 11:41:00 +0000936 .probe = ide_disk_probe,
937 .remove = ide_disk_remove,
Lee Trager0d2157f2007-06-08 15:14:30 +0200938 .resume = ide_disk_resume,
Russell King4031bbe2006-01-06 11:41:00 +0000939 .shutdown = ide_device_shutdown,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 .version = IDEDISK_VERSION,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941 .do_request = ide_do_rw_disk,
942 .end_request = ide_end_request,
943 .error = __ide_error,
Bartlomiej Zolnierkiewicz7662d042007-05-10 00:01:10 +0200944#ifdef CONFIG_IDE_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945 .proc = idedisk_proc,
Bartlomiej Zolnierkiewicz8185d5a2008-10-10 22:39:28 +0200946 .settings = idedisk_settings,
Bartlomiej Zolnierkiewicz7662d042007-05-10 00:01:10 +0200947#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948};
949
Bartlomiej Zolnierkiewicz29ec6832008-01-26 20:12:59 +0100950static int idedisk_set_doorlock(ide_drive_t *drive, int on)
951{
952 ide_task_t task;
953
954 memset(&task, 0, sizeof(task));
Bartlomiej Zolnierkiewiczaaaade32008-10-10 22:39:21 +0200955 task.tf.command = on ? ATA_CMD_MEDIA_LOCK : ATA_CMD_MEDIA_UNLOCK;
Bartlomiej Zolnierkiewicz657cc1a2008-01-26 20:13:10 +0100956 task.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
Bartlomiej Zolnierkiewicz29ec6832008-01-26 20:12:59 +0100957
958 return ide_no_data_taskfile(drive, &task);
959}
960
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961static int idedisk_open(struct inode *inode, struct file *filp)
962{
963 struct gendisk *disk = inode->i_bdev->bd_disk;
964 struct ide_disk_obj *idkp;
965 ide_drive_t *drive;
966
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +0200967 idkp = ide_disk_get(disk);
968 if (idkp == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969 return -ENXIO;
970
971 drive = idkp->drive;
972
Bartlomiej Zolnierkiewiczc94964a2007-02-17 02:40:24 +0100973 idkp->openers++;
974
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200975 if ((drive->dev_flags & IDE_DFLAG_REMOVABLE) && idkp->openers == 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 check_disk_change(inode->i_bdev);
977 /*
978 * Ignore the return code from door_lock,
979 * since the open() has already succeeded,
980 * and the door_lock is irrelevant at this point.
981 */
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200982 if ((drive->dev_flags & IDE_DFLAG_DOORLOCKING) &&
983 idedisk_set_doorlock(drive, 1))
984 drive->dev_flags &= ~IDE_DFLAG_DOORLOCKING;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985 }
986 return 0;
987}
988
989static int idedisk_release(struct inode *inode, struct file *filp)
990{
991 struct gendisk *disk = inode->i_bdev->bd_disk;
992 struct ide_disk_obj *idkp = ide_disk_g(disk);
993 ide_drive_t *drive = idkp->drive;
994
Bartlomiej Zolnierkiewiczc94964a2007-02-17 02:40:24 +0100995 if (idkp->openers == 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 ide_cacheflush_p(drive);
Bartlomiej Zolnierkiewiczc94964a2007-02-17 02:40:24 +0100997
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200998 if ((drive->dev_flags & IDE_DFLAG_REMOVABLE) && idkp->openers == 1) {
999 if ((drive->dev_flags & IDE_DFLAG_DOORLOCKING) &&
1000 idedisk_set_doorlock(drive, 0))
1001 drive->dev_flags &= ~IDE_DFLAG_DOORLOCKING;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 }
Bartlomiej Zolnierkiewiczc94964a2007-02-17 02:40:24 +01001003
1004 idkp->openers--;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005
1006 ide_disk_put(idkp);
1007
1008 return 0;
1009}
1010
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001011static int idedisk_getgeo(struct block_device *bdev, struct hd_geometry *geo)
1012{
1013 struct ide_disk_obj *idkp = ide_disk_g(bdev->bd_disk);
1014 ide_drive_t *drive = idkp->drive;
1015
1016 geo->heads = drive->bios_head;
1017 geo->sectors = drive->bios_sect;
1018 geo->cylinders = (u16)drive->bios_cyl; /* truncate */
1019 return 0;
1020}
1021
Bartlomiej Zolnierkiewiczaa7687732008-10-10 22:39:33 +02001022static const struct ide_ioctl_devset ide_disk_ioctl_settings[] = {
Elias Oltmanns92f1f8f2008-10-10 22:39:40 +02001023{ HDIO_GET_ADDRESS, HDIO_SET_ADDRESS, &ide_devset_address },
1024{ HDIO_GET_MULTCOUNT, HDIO_SET_MULTCOUNT, &ide_devset_multcount },
1025{ HDIO_GET_NOWERR, HDIO_SET_NOWERR, &ide_devset_nowerr },
1026{ HDIO_GET_WCACHE, HDIO_SET_WCACHE, &ide_devset_wcache },
1027{ HDIO_GET_ACOUSTIC, HDIO_SET_ACOUSTIC, &ide_devset_acoustic },
Bartlomiej Zolnierkiewiczaa7687732008-10-10 22:39:33 +02001028{ 0 }
1029};
1030
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031static int idedisk_ioctl(struct inode *inode, struct file *file,
1032 unsigned int cmd, unsigned long arg)
1033{
1034 struct block_device *bdev = inode->i_bdev;
1035 struct ide_disk_obj *idkp = ide_disk_g(bdev->bd_disk);
Bartlomiej Zolnierkiewicz14979432007-05-10 00:01:10 +02001036 ide_drive_t *drive = idkp->drive;
Bartlomiej Zolnierkiewiczaa7687732008-10-10 22:39:33 +02001037 int err;
Bartlomiej Zolnierkiewicz14979432007-05-10 00:01:10 +02001038
Bartlomiej Zolnierkiewiczaa7687732008-10-10 22:39:33 +02001039 err = ide_setting_ioctl(drive, bdev, cmd, arg, ide_disk_ioctl_settings);
1040 if (err != -EOPNOTSUPP)
1041 return err;
Bartlomiej Zolnierkiewicz14979432007-05-10 00:01:10 +02001042
1043 return generic_ide_ioctl(drive, file, bdev, cmd, arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044}
1045
1046static int idedisk_media_changed(struct gendisk *disk)
1047{
1048 struct ide_disk_obj *idkp = ide_disk_g(disk);
1049 ide_drive_t *drive = idkp->drive;
1050
1051 /* do not scan partitions twice if this is a removable device */
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +02001052 if (drive->dev_flags & IDE_DFLAG_ATTACH) {
1053 drive->dev_flags &= ~IDE_DFLAG_ATTACH;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054 return 0;
1055 }
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +02001056
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057 /* if removable, always assume it was changed */
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +02001058 return !!(drive->dev_flags & IDE_DFLAG_REMOVABLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059}
1060
1061static int idedisk_revalidate_disk(struct gendisk *disk)
1062{
1063 struct ide_disk_obj *idkp = ide_disk_g(disk);
1064 set_capacity(disk, idedisk_capacity(idkp->drive));
1065 return 0;
1066}
1067
1068static struct block_device_operations idedisk_ops = {
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +02001069 .owner = THIS_MODULE,
1070 .open = idedisk_open,
1071 .release = idedisk_release,
1072 .ioctl = idedisk_ioctl,
1073 .getgeo = idedisk_getgeo,
1074 .media_changed = idedisk_media_changed,
1075 .revalidate_disk = idedisk_revalidate_disk
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076};
1077
1078MODULE_DESCRIPTION("ATA DISK Driver");
1079
Russell King4031bbe2006-01-06 11:41:00 +00001080static int ide_disk_probe(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081{
1082 struct ide_disk_obj *idkp;
1083 struct gendisk *g;
1084
1085 /* strstr("foo", "") is non-NULL */
1086 if (!strstr("ide-disk", drive->driver_req))
1087 goto failed;
Bartlomiej Zolnierkiewicz2a924662008-10-10 22:39:24 +02001088
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089 if (drive->media != ide_disk)
1090 goto failed;
1091
Deepak Saxenaf5e3c2f2005-11-07 01:01:25 -08001092 idkp = kzalloc(sizeof(*idkp), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093 if (!idkp)
1094 goto failed;
1095
Tejun Heo689d6fa2008-08-25 19:56:16 +09001096 g = alloc_disk_node(IDE_DISK_MINORS, hwif_to_node(drive->hwif));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097 if (!g)
1098 goto out_free_idkp;
1099
1100 ide_init_disk(g, drive);
1101
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102 kref_init(&idkp->kref);
1103
1104 idkp->drive = drive;
1105 idkp->driver = &idedisk_driver;
1106 idkp->disk = g;
1107
1108 g->private_data = &idkp->driver;
1109
1110 drive->driver_data = idkp;
1111
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 idedisk_setup(drive);
1113 if ((!drive->head || drive->head > 16) && !drive->select.b.lba) {
1114 printk(KERN_ERR "%s: INVALID GEOMETRY: %d PHYSICAL HEADS?\n",
1115 drive->name, drive->head);
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +02001116 drive->dev_flags &= ~IDE_DFLAG_ATTACH;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 } else
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +02001118 drive->dev_flags |= IDE_DFLAG_ATTACH;
Bartlomiej Zolnierkiewicz8604aff2005-05-26 14:55:34 +02001119
Tejun Heof615b482008-08-25 19:47:24 +09001120 g->minors = IDE_DISK_MINORS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 g->driverfs_dev = &drive->gendev;
Tejun Heo689d6fa2008-08-25 19:56:16 +09001122 g->flags |= GENHD_FL_EXT_DEVT;
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +02001123 if (drive->dev_flags & IDE_DFLAG_REMOVABLE)
1124 g->flags = GENHD_FL_REMOVABLE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125 set_capacity(g, idedisk_capacity(drive));
1126 g->fops = &idedisk_ops;
1127 add_disk(g);
1128 return 0;
1129
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130out_free_idkp:
1131 kfree(idkp);
1132failed:
Bartlomiej Zolnierkiewicz8604aff2005-05-26 14:55:34 +02001133 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134}
1135
Bartlomiej Zolnierkiewicz98416542008-04-26 17:36:37 +02001136static void __exit idedisk_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137{
Bartlomiej Zolnierkiewicz8604aff2005-05-26 14:55:34 +02001138 driver_unregister(&idedisk_driver.gen_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139}
1140
Bartlomiej Zolnierkiewicz17514e82005-11-19 22:24:35 +01001141static int __init idedisk_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142{
Bartlomiej Zolnierkiewicz8604aff2005-05-26 14:55:34 +02001143 return driver_register(&idedisk_driver.gen_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144}
1145
Kay Sievers263756e2005-12-12 18:03:44 +01001146MODULE_ALIAS("ide:*m-disk*");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147module_init(idedisk_init);
1148module_exit(idedisk_exit);
1149MODULE_LICENSE("GPL");