aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block
diff options
context:
space:
mode:
authorAdrian Bunk <bunk@kernel.org>2008-07-16 14:33:47 -0400
committerBartlomiej Zolnierkiewicz <bzolnier@gmail.com>2008-07-16 14:33:47 -0400
commit453ea3ed0b3e8ad67d4ee9d2fccf3d95a3e1f709 (patch)
tree359db77d614ee17d948a9e9fc318174c12e96377 /drivers/block
parent01c22bfc30a3f40fed08cfd2779348edcb6c5e53 (diff)
move ide/legacy/hd.c to drivers/block/
This patch moves hd.c to drivers/block/ Signed-off-by: Adrian Bunk <bunk@kernel.org> Cc: rmk@arm.linux.org.uk Cc: Alan Cox <alan@lxorguk.ukuu.org.uk> Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
Diffstat (limited to 'drivers/block')
-rw-r--r--drivers/block/Kconfig24
-rw-r--r--drivers/block/Makefile1
-rw-r--r--drivers/block/hd.c815
3 files changed, 840 insertions, 0 deletions
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
index 0d1d2133d9bc..c3909743c484 100644
--- a/drivers/block/Kconfig
+++ b/drivers/block/Kconfig
@@ -433,4 +433,28 @@ config VIRTIO_BLK
433 This is the virtual block driver for virtio. It can be used with 433 This is the virtual block driver for virtio. It can be used with
434 lguest or QEMU based VMMs (like KVM or Xen). Say Y or M. 434 lguest or QEMU based VMMs (like KVM or Xen). Say Y or M.
435 435
436config BLK_DEV_HD
437 bool "Old hard disk (MFM/RLL/IDE) driver"
438 depends on HAVE_IDE
439 depends on !ARM || ARCH_RPC || ARCH_SHARK || BROKEN
440 help
441 There are two drivers for MFM/RLL/IDE hard disks. Most people use
442 the newer enhanced driver, but this old one is still around for two
443 reasons. Some older systems have strange timing problems and seem to
444 work only with the old driver (which itself does not work with some
445 newer systems). The other reason is that the old driver is smaller,
446 since it lacks the enhanced functionality of the new one. This makes
447 it a good choice for systems with very tight memory restrictions, or
448 for systems with only older MFM/RLL/ESDI drives. Choosing the old
449 driver can save 13 KB or so of kernel memory.
450
451 If you want to use this driver together with the new one you have
452 to use "hda=noprobe hdb=noprobe" kernel parameters to prevent the new
453 driver from probing the primary interface.
454
455 If you are unsure, then just choose the Enhanced IDE/MFM/RLL driver
456 instead of this one. For more detailed information, read the
457 Disk-HOWTO, available from
458 <http://www.tldp.org/docs.html#howto>.
459
436endif # BLK_DEV 460endif # BLK_DEV
diff --git a/drivers/block/Makefile b/drivers/block/Makefile
index 5e584306be99..204332b29578 100644
--- a/drivers/block/Makefile
+++ b/drivers/block/Makefile
@@ -29,5 +29,6 @@ obj-$(CONFIG_VIRTIO_BLK) += virtio_blk.o
29obj-$(CONFIG_VIODASD) += viodasd.o 29obj-$(CONFIG_VIODASD) += viodasd.o
30obj-$(CONFIG_BLK_DEV_SX8) += sx8.o 30obj-$(CONFIG_BLK_DEV_SX8) += sx8.o
31obj-$(CONFIG_BLK_DEV_UB) += ub.o 31obj-$(CONFIG_BLK_DEV_UB) += ub.o
32obj-$(CONFIG_BLK_DEV_HD) += hd.o
32 33
33obj-$(CONFIG_XEN_BLKDEV_FRONTEND) += xen-blkfront.o 34obj-$(CONFIG_XEN_BLKDEV_FRONTEND) += xen-blkfront.o
diff --git a/drivers/block/hd.c b/drivers/block/hd.c
new file mode 100644
index 000000000000..00b695652b2a
--- /dev/null
+++ b/drivers/block/hd.c
@@ -0,0 +1,815 @@
1/*
2 * Copyright (C) 1991, 1992 Linus Torvalds
3 *
4 * This is the low-level hd interrupt support. It traverses the
5 * request-list, using interrupts to jump between functions. As
6 * all the functions are called within interrupts, we may not
7 * sleep. Special care is recommended.
8 *
9 * modified by Drew Eckhardt to check nr of hd's from the CMOS.
10 *
11 * Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug
12 * in the early extended-partition checks and added DM partitions
13 *
14 * IRQ-unmask, drive-id, multiple-mode, support for ">16 heads",
15 * and general streamlining by Mark Lord.
16 *
17 * Removed 99% of above. Use Mark's ide driver for those options.
18 * This is now a lightweight ST-506 driver. (Paul Gortmaker)
19 *
20 * Modified 1995 Russell King for ARM processor.
21 *
22 * Bugfix: max_sectors must be <= 255 or the wheels tend to come
23 * off in a hurry once you queue things up - Paul G. 02/2001
24 */
25
26/* Uncomment the following if you want verbose error reports. */
27/* #define VERBOSE_ERRORS */
28
29#include <linux/blkdev.h>
30#include <linux/errno.h>
31#include <linux/signal.h>
32#include <linux/interrupt.h>
33#include <linux/timer.h>
34#include <linux/fs.h>
35#include <linux/kernel.h>
36#include <linux/genhd.h>
37#include <linux/slab.h>
38#include <linux/string.h>
39#include <linux/ioport.h>
40#include <linux/mc146818rtc.h> /* CMOS defines */
41#include <linux/init.h>
42#include <linux/blkpg.h>
43#include <linux/hdreg.h>
44
45#define REALLY_SLOW_IO
46#include <asm/system.h>
47#include <asm/io.h>
48#include <asm/uaccess.h>
49
50#ifdef __arm__
51#undef HD_IRQ
52#endif
53#include <asm/irq.h>
54#ifdef __arm__
55#define HD_IRQ IRQ_HARDDISK
56#endif
57
58/* Hd controller regster ports */
59
60#define HD_DATA 0x1f0 /* _CTL when writing */
61#define HD_ERROR 0x1f1 /* see err-bits */
62#define HD_NSECTOR 0x1f2 /* nr of sectors to read/write */
63#define HD_SECTOR 0x1f3 /* starting sector */
64#define HD_LCYL 0x1f4 /* starting cylinder */
65#define HD_HCYL 0x1f5 /* high byte of starting cyl */
66#define HD_CURRENT 0x1f6 /* 101dhhhh , d=drive, hhhh=head */
67#define HD_STATUS 0x1f7 /* see status-bits */
68#define HD_FEATURE HD_ERROR /* same io address, read=error, write=feature */
69#define HD_PRECOMP HD_FEATURE /* obsolete use of this port - predates IDE */
70#define HD_COMMAND HD_STATUS /* same io address, read=status, write=cmd */
71
72#define HD_CMD 0x3f6 /* used for resets */
73#define HD_ALTSTATUS 0x3f6 /* same as HD_STATUS but doesn't clear irq */
74
75/* Bits of HD_STATUS */
76#define ERR_STAT 0x01
77#define INDEX_STAT 0x02
78#define ECC_STAT 0x04 /* Corrected error */
79#define DRQ_STAT 0x08
80#define SEEK_STAT 0x10
81#define SERVICE_STAT SEEK_STAT
82#define WRERR_STAT 0x20
83#define READY_STAT 0x40
84#define BUSY_STAT 0x80
85
86/* Bits for HD_ERROR */
87#define MARK_ERR 0x01 /* Bad address mark */
88#define TRK0_ERR 0x02 /* couldn't find track 0 */
89#define ABRT_ERR 0x04 /* Command aborted */
90#define MCR_ERR 0x08 /* media change request */
91#define ID_ERR 0x10 /* ID field not found */
92#define MC_ERR 0x20 /* media changed */
93#define ECC_ERR 0x40 /* Uncorrectable ECC error */
94#define BBD_ERR 0x80 /* pre-EIDE meaning: block marked bad */
95#define ICRC_ERR 0x80 /* new meaning: CRC error during transfer */
96
97static DEFINE_SPINLOCK(hd_lock);
98static struct request_queue *hd_queue;
99
100#define MAJOR_NR HD_MAJOR
101#define QUEUE (hd_queue)
102#define CURRENT elv_next_request(hd_queue)
103
104#define TIMEOUT_VALUE (6*HZ)
105#define HD_DELAY 0
106
107#define MAX_ERRORS 16 /* Max read/write errors/sector */
108#define RESET_FREQ 8 /* Reset controller every 8th retry */
109#define RECAL_FREQ 4 /* Recalibrate every 4th retry */
110#define MAX_HD 2
111
112#define STAT_OK (READY_STAT|SEEK_STAT)
113#define OK_STATUS(s) (((s)&(STAT_OK|(BUSY_STAT|WRERR_STAT|ERR_STAT)))==STAT_OK)
114
115static void recal_intr(void);
116static void bad_rw_intr(void);
117
118static int reset;
119static int hd_error;
120
121/*
122 * This struct defines the HD's and their types.
123 */
124struct hd_i_struct {
125 unsigned int head, sect, cyl, wpcom, lzone, ctl;
126 int unit;
127 int recalibrate;
128 int special_op;
129};
130
131#ifdef HD_TYPE
132static struct hd_i_struct hd_info[] = { HD_TYPE };
133static int NR_HD = ARRAY_SIZE(hd_info);
134#else
135static struct hd_i_struct hd_info[MAX_HD];
136static int NR_HD;
137#endif
138
139static struct gendisk *hd_gendisk[MAX_HD];
140
141static struct timer_list device_timer;
142
143#define TIMEOUT_VALUE (6*HZ)
144
145#define SET_TIMER \
146 do { \
147 mod_timer(&device_timer, jiffies + TIMEOUT_VALUE); \
148 } while (0)
149
150static void (*do_hd)(void) = NULL;
151#define SET_HANDLER(x) \
152if ((do_hd = (x)) != NULL) \
153 SET_TIMER; \
154else \
155 del_timer(&device_timer);
156
157
158#if (HD_DELAY > 0)
159
160#include <asm/i8253.h>
161
162unsigned long last_req;
163
164unsigned long read_timer(void)
165{
166 unsigned long t, flags;
167 int i;
168
169 spin_lock_irqsave(&i8253_lock, flags);
170 t = jiffies * 11932;
171 outb_p(0, 0x43);
172 i = inb_p(0x40);
173 i |= inb(0x40) << 8;
174 spin_unlock_irqrestore(&i8253_lock, flags);
175 return(t - i);
176}
177#endif
178
179static void __init hd_setup(char *str, int *ints)
180{
181 int hdind = 0;
182
183 if (ints[0] != 3)
184 return;
185 if (hd_info[0].head != 0)
186 hdind = 1;
187 hd_info[hdind].head = ints[2];
188 hd_info[hdind].sect = ints[3];
189 hd_info[hdind].cyl = ints[1];
190 hd_info[hdind].wpcom = 0;
191 hd_info[hdind].lzone = ints[1];
192 hd_info[hdind].ctl = (ints[2] > 8 ? 8 : 0);
193 NR_HD = hdind+1;
194}
195
196static void dump_status(const char *msg, unsigned int stat)
197{
198 char *name = "hd?";
199 if (CURRENT)
200 name = CURRENT->rq_disk->disk_name;
201
202#ifdef VERBOSE_ERRORS
203 printk("%s: %s: status=0x%02x { ", name, msg, stat & 0xff);
204 if (stat & BUSY_STAT) printk("Busy ");
205 if (stat & READY_STAT) printk("DriveReady ");
206 if (stat & WRERR_STAT) printk("WriteFault ");
207 if (stat & SEEK_STAT) printk("SeekComplete ");
208 if (stat & DRQ_STAT) printk("DataRequest ");
209 if (stat & ECC_STAT) printk("CorrectedError ");
210 if (stat & INDEX_STAT) printk("Index ");
211 if (stat & ERR_STAT) printk("Error ");
212 printk("}\n");
213 if ((stat & ERR_STAT) == 0) {
214 hd_error = 0;
215 } else {
216 hd_error = inb(HD_ERROR);
217 printk("%s: %s: error=0x%02x { ", name, msg, hd_error & 0xff);
218 if (hd_error & BBD_ERR) printk("BadSector ");
219 if (hd_error & ECC_ERR) printk("UncorrectableError ");
220 if (hd_error & ID_ERR) printk("SectorIdNotFound ");
221 if (hd_error & ABRT_ERR) printk("DriveStatusError ");
222 if (hd_error & TRK0_ERR) printk("TrackZeroNotFound ");
223 if (hd_error & MARK_ERR) printk("AddrMarkNotFound ");
224 printk("}");
225 if (hd_error & (BBD_ERR|ECC_ERR|ID_ERR|MARK_ERR)) {
226 printk(", CHS=%d/%d/%d", (inb(HD_HCYL)<<8) + inb(HD_LCYL),
227 inb(HD_CURRENT) & 0xf, inb(HD_SECTOR));
228 if (CURRENT)
229 printk(", sector=%ld", CURRENT->sector);
230 }
231 printk("\n");
232 }
233#else
234 printk("%s: %s: status=0x%02x.\n", name, msg, stat & 0xff);
235 if ((stat & ERR_STAT) == 0) {
236 hd_error = 0;
237 } else {
238 hd_error = inb(HD_ERROR);
239 printk("%s: %s: error=0x%02x.\n", name, msg, hd_error & 0xff);
240 }
241#endif
242}
243
244static void check_status(void)
245{
246 int i = inb_p(HD_STATUS);
247
248 if (!OK_STATUS(i)) {
249 dump_status("check_status", i);
250 bad_rw_intr();
251 }
252}
253
254static int controller_busy(void)
255{
256 int retries = 100000;
257 unsigned char status;
258
259 do {
260 status = inb_p(HD_STATUS);
261 } while ((status & BUSY_STAT) && --retries);
262 return status;
263}
264
265static int status_ok(void)
266{
267 unsigned char status = inb_p(HD_STATUS);
268
269 if (status & BUSY_STAT)
270 return 1; /* Ancient, but does it make sense??? */
271 if (status & WRERR_STAT)
272 return 0;
273 if (!(status & READY_STAT))
274 return 0;
275 if (!(status & SEEK_STAT))
276 return 0;
277 return 1;
278}
279
280static int controller_ready(unsigned int drive, unsigned int head)
281{
282 int retry = 100;
283
284 do {
285 if (controller_busy() & BUSY_STAT)
286 return 0;
287 outb_p(0xA0 | (drive<<4) | head, HD_CURRENT);
288 if (status_ok())
289 return 1;
290 } while (--retry);
291 return 0;
292}
293
294static void hd_out(struct hd_i_struct *disk,
295 unsigned int nsect,
296 unsigned int sect,
297 unsigned int head,
298 unsigned int cyl,
299 unsigned int cmd,
300 void (*intr_addr)(void))
301{
302 unsigned short port;
303
304#if (HD_DELAY > 0)
305 while (read_timer() - last_req < HD_DELAY)
306 /* nothing */;
307#endif
308 if (reset)
309 return;
310 if (!controller_ready(disk->unit, head)) {
311 reset = 1;
312 return;
313 }
314 SET_HANDLER(intr_addr);
315 outb_p(disk->ctl, HD_CMD);
316 port = HD_DATA;
317 outb_p(disk->wpcom >> 2, ++port);
318 outb_p(nsect, ++port);
319 outb_p(sect, ++port);
320 outb_p(cyl, ++port);
321 outb_p(cyl >> 8, ++port);
322 outb_p(0xA0 | (disk->unit << 4) | head, ++port);
323 outb_p(cmd, ++port);
324}
325
326static void hd_request (void);
327
328static int drive_busy(void)
329{
330 unsigned int i;
331 unsigned char c;
332
333 for (i = 0; i < 500000 ; i++) {
334 c = inb_p(HD_STATUS);
335 if ((c & (BUSY_STAT | READY_STAT | SEEK_STAT)) == STAT_OK)
336 return 0;
337 }
338 dump_status("reset timed out", c);
339 return 1;
340}
341
342static void reset_controller(void)
343{
344 int i;
345
346 outb_p(4, HD_CMD);
347 for (i = 0; i < 1000; i++) barrier();
348 outb_p(hd_info[0].ctl & 0x0f, HD_CMD);
349 for (i = 0; i < 1000; i++) barrier();
350 if (drive_busy())
351 printk("hd: controller still busy\n");
352 else if ((hd_error = inb(HD_ERROR)) != 1)
353 printk("hd: controller reset failed: %02x\n", hd_error);
354}
355
356static void reset_hd(void)
357{
358 static int i;
359
360repeat:
361 if (reset) {
362 reset = 0;
363 i = -1;
364 reset_controller();
365 } else {
366 check_status();
367 if (reset)
368 goto repeat;
369 }
370 if (++i < NR_HD) {
371 struct hd_i_struct *disk = &hd_info[i];
372 disk->special_op = disk->recalibrate = 1;
373 hd_out(disk, disk->sect, disk->sect, disk->head-1,
374 disk->cyl, WIN_SPECIFY, &reset_hd);
375 if (reset)
376 goto repeat;
377 } else
378 hd_request();
379}
380
381/*
382 * Ok, don't know what to do with the unexpected interrupts: on some machines
383 * doing a reset and a retry seems to result in an eternal loop. Right now I
384 * ignore it, and just set the timeout.
385 *
386 * On laptops (and "green" PCs), an unexpected interrupt occurs whenever the
387 * drive enters "idle", "standby", or "sleep" mode, so if the status looks
388 * "good", we just ignore the interrupt completely.
389 */
390static void unexpected_hd_interrupt(void)
391{
392 unsigned int stat = inb_p(HD_STATUS);
393
394 if (stat & (BUSY_STAT|DRQ_STAT|ECC_STAT|ERR_STAT)) {
395 dump_status("unexpected interrupt", stat);
396 SET_TIMER;
397 }
398}
399
400/*
401 * bad_rw_intr() now tries to be a bit smarter and does things
402 * according to the error returned by the controller.
403 * -Mika Liljeberg (liljeber@cs.Helsinki.FI)
404 */
405static void bad_rw_intr(void)
406{
407 struct request *req = CURRENT;
408 if (req != NULL) {
409 struct hd_i_struct *disk = req->rq_disk->private_data;
410 if (++req->errors >= MAX_ERRORS || (hd_error & BBD_ERR)) {
411 end_request(req, 0);
412 disk->special_op = disk->recalibrate = 1;
413 } else if (req->errors % RESET_FREQ == 0)
414 reset = 1;
415 else if ((hd_error & TRK0_ERR) || req->errors % RECAL_FREQ == 0)
416 disk->special_op = disk->recalibrate = 1;
417 /* Otherwise just retry */
418 }
419}
420
421static inline int wait_DRQ(void)
422{
423 int retries;
424 int stat;
425
426 for (retries = 0; retries < 100000; retries++) {
427 stat = inb_p(HD_STATUS);
428 if (stat & DRQ_STAT)
429 return 0;
430 }
431 dump_status("wait_DRQ", stat);
432 return -1;
433}
434
435static void read_intr(void)
436{
437 struct request *req;
438 int i, retries = 100000;
439
440 do {
441 i = (unsigned) inb_p(HD_STATUS);
442 if (i & BUSY_STAT)
443 continue;
444 if (!OK_STATUS(i))
445 break;
446 if (i & DRQ_STAT)
447 goto ok_to_read;
448 } while (--retries > 0);
449 dump_status("read_intr", i);
450 bad_rw_intr();
451 hd_request();
452 return;
453ok_to_read:
454 req = CURRENT;
455 insw(HD_DATA, req->buffer, 256);
456 req->sector++;
457 req->buffer += 512;
458 req->errors = 0;
459 i = --req->nr_sectors;
460 --req->current_nr_sectors;
461#ifdef DEBUG
462 printk("%s: read: sector %ld, remaining = %ld, buffer=%p\n",
463 req->rq_disk->disk_name, req->sector, req->nr_sectors,
464 req->buffer+512);
465#endif
466 if (req->current_nr_sectors <= 0)
467 end_request(req, 1);
468 if (i > 0) {
469 SET_HANDLER(&read_intr);
470 return;
471 }
472 (void) inb_p(HD_STATUS);
473#if (HD_DELAY > 0)
474 last_req = read_timer();
475#endif
476 if (elv_next_request(QUEUE))
477 hd_request();
478 return;
479}
480
481static void write_intr(void)
482{
483 struct request *req = CURRENT;
484 int i;
485 int retries = 100000;
486
487 do {
488 i = (unsigned) inb_p(HD_STATUS);
489 if (i & BUSY_STAT)
490 continue;
491 if (!OK_STATUS(i))
492 break;
493 if ((req->nr_sectors <= 1) || (i & DRQ_STAT))
494 goto ok_to_write;
495 } while (--retries > 0);
496 dump_status("write_intr", i);
497 bad_rw_intr();
498 hd_request();
499 return;
500ok_to_write:
501 req->sector++;
502 i = --req->nr_sectors;
503 --req->current_nr_sectors;
504 req->buffer += 512;
505 if (!i || (req->bio && req->current_nr_sectors <= 0))
506 end_request(req, 1);
507 if (i > 0) {
508 SET_HANDLER(&write_intr);
509 outsw(HD_DATA, req->buffer, 256);
510 local_irq_enable();
511 } else {
512#if (HD_DELAY > 0)
513 last_req = read_timer();
514#endif
515 hd_request();
516 }
517 return;
518}
519
520static void recal_intr(void)
521{
522 check_status();
523#if (HD_DELAY > 0)
524 last_req = read_timer();
525#endif
526 hd_request();
527}
528
529/*
530 * This is another of the error-routines I don't know what to do with. The
531 * best idea seems to just set reset, and start all over again.
532 */
533static void hd_times_out(unsigned long dummy)
534{
535 char *name;
536
537 do_hd = NULL;
538
539 if (!CURRENT)
540 return;
541
542 disable_irq(HD_IRQ);
543 local_irq_enable();
544 reset = 1;
545 name = CURRENT->rq_disk->disk_name;
546 printk("%s: timeout\n", name);
547 if (++CURRENT->errors >= MAX_ERRORS) {
548#ifdef DEBUG
549 printk("%s: too many errors\n", name);
550#endif
551 end_request(CURRENT, 0);
552 }
553 local_irq_disable();
554 hd_request();
555 enable_irq(HD_IRQ);
556}
557
558static int do_special_op(struct hd_i_struct *disk, struct request *req)
559{
560 if (disk->recalibrate) {
561 disk->recalibrate = 0;
562 hd_out(disk, disk->sect, 0, 0, 0, WIN_RESTORE, &recal_intr);
563 return reset;
564 }
565 if (disk->head > 16) {
566 printk("%s: cannot handle device with more than 16 heads - giving up\n", req->rq_disk->disk_name);
567 end_request(req, 0);
568 }
569 disk->special_op = 0;
570 return 1;
571}
572
573/*
574 * The driver enables interrupts as much as possible. In order to do this,
575 * (a) the device-interrupt is disabled before entering hd_request(),
576 * and (b) the timeout-interrupt is disabled before the sti().
577 *
578 * Interrupts are still masked (by default) whenever we are exchanging
579 * data/cmds with a drive, because some drives seem to have very poor
580 * tolerance for latency during I/O. The IDE driver has support to unmask
581 * interrupts for non-broken hardware, so use that driver if required.
582 */
583static void hd_request(void)
584{
585 unsigned int block, nsect, sec, track, head, cyl;
586 struct hd_i_struct *disk;
587 struct request *req;
588
589 if (do_hd)
590 return;
591repeat:
592 del_timer(&device_timer);
593 local_irq_enable();
594
595 req = CURRENT;
596 if (!req) {
597 do_hd = NULL;
598 return;
599 }
600
601 if (reset) {
602 local_irq_disable();
603 reset_hd();
604 return;
605 }
606 disk = req->rq_disk->private_data;
607 block = req->sector;
608 nsect = req->nr_sectors;
609 if (block >= get_capacity(req->rq_disk) ||
610 ((block+nsect) > get_capacity(req->rq_disk))) {
611 printk("%s: bad access: block=%d, count=%d\n",
612 req->rq_disk->disk_name, block, nsect);
613 end_request(req, 0);
614 goto repeat;
615 }
616
617 if (disk->special_op) {
618 if (do_special_op(disk, req))
619 goto repeat;
620 return;
621 }
622 sec = block % disk->sect + 1;
623 track = block / disk->sect;
624 head = track % disk->head;
625 cyl = track / disk->head;
626#ifdef DEBUG
627 printk("%s: %sing: CHS=%d/%d/%d, sectors=%d, buffer=%p\n",
628 req->rq_disk->disk_name,
629 req_data_dir(req) == READ ? "read" : "writ",
630 cyl, head, sec, nsect, req->buffer);
631#endif
632 if (blk_fs_request(req)) {
633 switch (rq_data_dir(req)) {
634 case READ:
635 hd_out(disk, nsect, sec, head, cyl, WIN_READ,
636 &read_intr);
637 if (reset)
638 goto repeat;
639 break;
640 case WRITE:
641 hd_out(disk, nsect, sec, head, cyl, WIN_WRITE,
642 &write_intr);
643 if (reset)
644 goto repeat;
645 if (wait_DRQ()) {
646 bad_rw_intr();
647 goto repeat;
648 }
649 outsw(HD_DATA, req->buffer, 256);
650 break;
651 default:
652 printk("unknown hd-command\n");
653 end_request(req, 0);
654 break;
655 }
656 }
657}
658
659static void do_hd_request(struct request_queue *q)
660{
661 disable_irq(HD_IRQ);
662 hd_request();
663 enable_irq(HD_IRQ);
664}
665
666static int hd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
667{
668 struct hd_i_struct *disk = bdev->bd_disk->private_data;
669
670 geo->heads = disk->head;
671 geo->sectors = disk->sect;
672 geo->cylinders = disk->cyl;
673 return 0;
674}
675
676/*
677 * Releasing a block device means we sync() it, so that it can safely
678 * be forgotten about...
679 */
680
681static irqreturn_t hd_interrupt(int irq, void *dev_id)
682{
683 void (*handler)(void) = do_hd;
684
685 do_hd = NULL;
686 del_timer(&device_timer);
687 if (!handler)
688 handler = unexpected_hd_interrupt;
689 handler();
690 local_irq_enable();
691 return IRQ_HANDLED;
692}
693
694static struct block_device_operations hd_fops = {
695 .getgeo = hd_getgeo,
696};
697
698/*
699 * This is the hard disk IRQ description. The IRQF_DISABLED in sa_flags
700 * means we run the IRQ-handler with interrupts disabled: this is bad for
701 * interrupt latency, but anything else has led to problems on some
702 * machines.
703 *
704 * We enable interrupts in some of the routines after making sure it's
705 * safe.
706 */
707
708static int __init hd_init(void)
709{
710 int drive;
711
712 if (register_blkdev(MAJOR_NR, "hd"))
713 return -1;
714
715 hd_queue = blk_init_queue(do_hd_request, &hd_lock);
716 if (!hd_queue) {
717 unregister_blkdev(MAJOR_NR, "hd");
718 return -ENOMEM;
719 }
720
721 blk_queue_max_sectors(hd_queue, 255);
722 init_timer(&device_timer);
723 device_timer.function = hd_times_out;
724 blk_queue_hardsect_size(hd_queue, 512);
725
726 if (!NR_HD) {
727 /*
728 * We don't know anything about the drive. This means
729 * that you *MUST* specify the drive parameters to the
730 * kernel yourself.
731 *
732 * If we were on an i386, we used to read this info from
733 * the BIOS or CMOS. This doesn't work all that well,
734 * since this assumes that this is a primary or secondary
735 * drive, and if we're using this legacy driver, it's
736 * probably an auxilliary controller added to recover
737 * legacy data off an ST-506 drive. Either way, it's
738 * definitely safest to have the user explicitly specify
739 * the information.
740 */
741 printk("hd: no drives specified - use hd=cyl,head,sectors"
742 " on kernel command line\n");
743 goto out;
744 }
745
746 for (drive = 0 ; drive < NR_HD ; drive++) {
747 struct gendisk *disk = alloc_disk(64);
748 struct hd_i_struct *p = &hd_info[drive];
749 if (!disk)
750 goto Enomem;
751 disk->major = MAJOR_NR;
752 disk->first_minor = drive << 6;
753 disk->fops = &hd_fops;
754 sprintf(disk->disk_name, "hd%c", 'a'+drive);
755 disk->private_data = p;
756 set_capacity(disk, p->head * p->sect * p->cyl);
757 disk->queue = hd_queue;
758 p->unit = drive;
759 hd_gendisk[drive] = disk;
760 printk("%s: %luMB, CHS=%d/%d/%d\n",
761 disk->disk_name, (unsigned long)get_capacity(disk)/2048,
762 p->cyl, p->head, p->sect);
763 }
764
765 if (request_irq(HD_IRQ, hd_interrupt, IRQF_DISABLED, "hd", NULL)) {
766 printk("hd: unable to get IRQ%d for the hard disk driver\n",
767 HD_IRQ);
768 goto out1;
769 }
770 if (!request_region(HD_DATA, 8, "hd")) {
771 printk(KERN_WARNING "hd: port 0x%x busy\n", HD_DATA);
772 goto out2;
773 }
774 if (!request_region(HD_CMD, 1, "hd(cmd)")) {
775 printk(KERN_WARNING "hd: port 0x%x busy\n", HD_CMD);
776 goto out3;
777 }
778
779 /* Let them fly */
780 for (drive = 0; drive < NR_HD; drive++)
781 add_disk(hd_gendisk[drive]);
782
783 return 0;
784
785out3:
786 release_region(HD_DATA, 8);
787out2:
788 free_irq(HD_IRQ, NULL);
789out1:
790 for (drive = 0; drive < NR_HD; drive++)
791 put_disk(hd_gendisk[drive]);
792 NR_HD = 0;
793out:
794 del_timer(&device_timer);
795 unregister_blkdev(MAJOR_NR, "hd");
796 blk_cleanup_queue(hd_queue);
797 return -1;
798Enomem:
799 while (drive--)
800 put_disk(hd_gendisk[drive]);
801 goto out;
802}
803
804static int __init parse_hd_setup(char *line)
805{
806 int ints[6];
807
808 (void) get_options(line, ARRAY_SIZE(ints), ints);
809 hd_setup(NULL, ints);
810
811 return 1;
812}
813__setup("hd=", parse_hd_setup);
814
815late_initcall(hd_init);