Import 2.3.18pre1
[davej-history.git] / drivers / block / hd.c
blob8e995be1b8220b6df3c11018a6d9203791845229
1 /*
2 * linux/drivers/block/hd.c
4 * Copyright (C) 1991, 1992 Linus Torvalds
5 */
7 /*
8 * This is the low-level hd interrupt support. It traverses the
9 * request-list, using interrupts to jump between functions. As
10 * all the functions are called within interrupts, we may not
11 * sleep. Special care is recommended.
13 * modified by Drew Eckhardt to check nr of hd's from the CMOS.
15 * Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug
16 * in the early extended-partition checks and added DM partitions
18 * IRQ-unmask, drive-id, multiple-mode, support for ">16 heads",
19 * and general streamlining by Mark Lord.
21 * Removed 99% of above. Use Mark's ide driver for those options.
22 * This is now a lightweight ST-506 driver. (Paul Gortmaker)
24 * Modified 1995 Russell King for ARM processor.
27 /* Uncomment the following if you want verbose error reports. */
28 /* #define VERBOSE_ERRORS */
30 #include <linux/errno.h>
31 #include <linux/signal.h>
32 #include <linux/sched.h>
33 #include <linux/timer.h>
34 #include <linux/fs.h>
35 #include <linux/kernel.h>
36 #include <linux/hdreg.h>
37 #include <linux/genhd.h>
38 #include <linux/malloc.h>
39 #include <linux/string.h>
40 #include <linux/ioport.h>
41 #include <linux/mc146818rtc.h> /* CMOS defines */
42 #include <linux/init.h>
44 #define REALLY_SLOW_IO
45 #include <asm/system.h>
46 #include <asm/io.h>
47 #include <asm/uaccess.h>
49 #define MAJOR_NR HD_MAJOR
50 #include <linux/blk.h>
52 #ifdef __arm__
53 #undef HD_IRQ
54 #endif
55 #include <asm/irq.h>
56 #ifdef __arm__
57 #define HD_IRQ IRQ_HARDDISK
58 #endif
60 static int revalidate_hddisk(kdev_t, int);
62 #define HD_DELAY 0
64 #define MAX_ERRORS 16 /* Max read/write errors/sector */
65 #define RESET_FREQ 8 /* Reset controller every 8th retry */
66 #define RECAL_FREQ 4 /* Recalibrate every 4th retry */
67 #define MAX_HD 2
69 #define STAT_OK (READY_STAT|SEEK_STAT)
70 #define OK_STATUS(s) (((s)&(STAT_OK|(BUSY_STAT|WRERR_STAT|ERR_STAT)))==STAT_OK)
72 static void recal_intr(void);
73 static void bad_rw_intr(void);
75 static char recalibrate[MAX_HD];
76 static char special_op[MAX_HD];
77 static int access_count[MAX_HD];
78 static char busy[MAX_HD];
79 static DECLARE_WAIT_QUEUE_HEAD(busy_wait);
81 static int reset;
82 static int hd_error;
84 #define SUBSECTOR(block) (CURRENT->current_nr_sectors > 0)
87 * This struct defines the HD's and their types.
89 struct hd_i_struct {
90 unsigned int head,sect,cyl,wpcom,lzone,ctl;
93 #ifdef HD_TYPE
94 static struct hd_i_struct hd_info[] = { HD_TYPE };
95 static int NR_HD = ((sizeof (hd_info))/(sizeof (struct hd_i_struct)));
96 #else
97 static struct hd_i_struct hd_info[MAX_HD];
98 static int NR_HD;
99 #endif
101 static struct hd_struct hd[MAX_HD<<6];
102 static int hd_sizes[MAX_HD<<6];
103 static int hd_blocksizes[MAX_HD<<6];
104 static int hd_hardsectsizes[MAX_HD<<6];
106 #if (HD_DELAY > 0)
107 unsigned long last_req;
109 unsigned long read_timer(void)
111 unsigned long t, flags;
112 int i;
114 save_flags(flags);
115 cli();
116 t = jiffies * 11932;
117 outb_p(0, 0x43);
118 i = inb_p(0x40);
119 i |= inb(0x40) << 8;
120 restore_flags(flags);
121 return(t - i);
123 #endif
125 void __init hd_setup(char *str, int *ints)
127 int hdind = 0;
129 if (ints[0] != 3)
130 return;
131 if (hd_info[0].head != 0)
132 hdind=1;
133 hd_info[hdind].head = ints[2];
134 hd_info[hdind].sect = ints[3];
135 hd_info[hdind].cyl = ints[1];
136 hd_info[hdind].wpcom = 0;
137 hd_info[hdind].lzone = ints[1];
138 hd_info[hdind].ctl = (ints[2] > 8 ? 8 : 0);
139 NR_HD = hdind+1;
142 static void dump_status (const char *msg, unsigned int stat)
144 unsigned long flags;
145 char devc;
147 devc = CURRENT ? 'a' + DEVICE_NR(CURRENT->rq_dev) : '?';
148 save_flags (flags);
149 sti();
150 #ifdef VERBOSE_ERRORS
151 printk("hd%c: %s: status=0x%02x { ", devc, msg, stat & 0xff);
152 if (stat & BUSY_STAT) printk("Busy ");
153 if (stat & READY_STAT) printk("DriveReady ");
154 if (stat & WRERR_STAT) printk("WriteFault ");
155 if (stat & SEEK_STAT) printk("SeekComplete ");
156 if (stat & DRQ_STAT) printk("DataRequest ");
157 if (stat & ECC_STAT) printk("CorrectedError ");
158 if (stat & INDEX_STAT) printk("Index ");
159 if (stat & ERR_STAT) printk("Error ");
160 printk("}\n");
161 if ((stat & ERR_STAT) == 0) {
162 hd_error = 0;
163 } else {
164 hd_error = inb(HD_ERROR);
165 printk("hd%c: %s: error=0x%02x { ", devc, msg, hd_error & 0xff);
166 if (hd_error & BBD_ERR) printk("BadSector ");
167 if (hd_error & ECC_ERR) printk("UncorrectableError ");
168 if (hd_error & ID_ERR) printk("SectorIdNotFound ");
169 if (hd_error & ABRT_ERR) printk("DriveStatusError ");
170 if (hd_error & TRK0_ERR) printk("TrackZeroNotFound ");
171 if (hd_error & MARK_ERR) printk("AddrMarkNotFound ");
172 printk("}");
173 if (hd_error & (BBD_ERR|ECC_ERR|ID_ERR|MARK_ERR)) {
174 printk(", CHS=%d/%d/%d", (inb(HD_HCYL)<<8) + inb(HD_LCYL),
175 inb(HD_CURRENT) & 0xf, inb(HD_SECTOR));
176 if (CURRENT)
177 printk(", sector=%ld", CURRENT->sector);
179 printk("\n");
181 #else
182 printk("hd%c: %s: status=0x%02x.\n", devc, msg, stat & 0xff);
183 if ((stat & ERR_STAT) == 0) {
184 hd_error = 0;
185 } else {
186 hd_error = inb(HD_ERROR);
187 printk("hd%c: %s: error=0x%02x.\n", devc, msg, hd_error & 0xff);
189 #endif /* verbose errors */
190 restore_flags (flags);
193 void check_status(void)
195 int i = inb_p(HD_STATUS);
197 if (!OK_STATUS(i)) {
198 dump_status("check_status", i);
199 bad_rw_intr();
203 static int controller_busy(void)
205 int retries = 100000;
206 unsigned char status;
208 do {
209 status = inb_p(HD_STATUS);
210 } while ((status & BUSY_STAT) && --retries);
211 return status;
214 static int status_ok(void)
216 unsigned char status = inb_p(HD_STATUS);
218 if (status & BUSY_STAT)
219 return 1; /* Ancient, but does it make sense??? */
220 if (status & WRERR_STAT)
221 return 0;
222 if (!(status & READY_STAT))
223 return 0;
224 if (!(status & SEEK_STAT))
225 return 0;
226 return 1;
229 static int controller_ready(unsigned int drive, unsigned int head)
231 int retry = 100;
233 do {
234 if (controller_busy() & BUSY_STAT)
235 return 0;
236 outb_p(0xA0 | (drive<<4) | head, HD_CURRENT);
237 if (status_ok())
238 return 1;
239 } while (--retry);
240 return 0;
243 static void hd_out(unsigned int drive,unsigned int nsect,unsigned int sect,
244 unsigned int head,unsigned int cyl,unsigned int cmd,
245 void (*intr_addr)(void))
247 unsigned short port;
249 #if (HD_DELAY > 0)
250 while (read_timer() - last_req < HD_DELAY)
251 /* nothing */;
252 #endif
253 if (reset)
254 return;
255 if (!controller_ready(drive, head)) {
256 reset = 1;
257 return;
259 SET_INTR(intr_addr);
260 outb_p(hd_info[drive].ctl,HD_CMD);
261 port=HD_DATA;
262 outb_p(hd_info[drive].wpcom>>2,++port);
263 outb_p(nsect,++port);
264 outb_p(sect,++port);
265 outb_p(cyl,++port);
266 outb_p(cyl>>8,++port);
267 outb_p(0xA0|(drive<<4)|head,++port);
268 outb_p(cmd,++port);
271 static void hd_request (void);
273 static int drive_busy(void)
275 unsigned int i;
276 unsigned char c;
278 for (i = 0; i < 500000 ; i++) {
279 c = inb_p(HD_STATUS);
280 if ((c & (BUSY_STAT | READY_STAT | SEEK_STAT)) == STAT_OK)
281 return 0;
283 dump_status("reset timed out", c);
284 return 1;
287 static void reset_controller(void)
289 int i;
291 outb_p(4,HD_CMD);
292 for(i = 0; i < 1000; i++) barrier();
293 outb_p(hd_info[0].ctl & 0x0f,HD_CMD);
294 for(i = 0; i < 1000; i++) barrier();
295 if (drive_busy())
296 printk("hd: controller still busy\n");
297 else if ((hd_error = inb(HD_ERROR)) != 1)
298 printk("hd: controller reset failed: %02x\n",hd_error);
301 static void reset_hd(void)
303 static int i;
305 repeat:
306 if (reset) {
307 reset = 0;
308 i = -1;
309 reset_controller();
310 } else {
311 check_status();
312 if (reset)
313 goto repeat;
315 if (++i < NR_HD) {
316 special_op[i] = recalibrate[i] = 1;
317 hd_out(i,hd_info[i].sect,hd_info[i].sect,hd_info[i].head-1,
318 hd_info[i].cyl,WIN_SPECIFY,&reset_hd);
319 if (reset)
320 goto repeat;
321 } else
322 hd_request();
326 * Ok, don't know what to do with the unexpected interrupts: on some machines
327 * doing a reset and a retry seems to result in an eternal loop. Right now I
328 * ignore it, and just set the timeout.
330 * On laptops (and "green" PCs), an unexpected interrupt occurs whenever the
331 * drive enters "idle", "standby", or "sleep" mode, so if the status looks
332 * "good", we just ignore the interrupt completely.
334 void unexpected_hd_interrupt(void)
336 unsigned int stat = inb_p(HD_STATUS);
338 if (stat & (BUSY_STAT|DRQ_STAT|ECC_STAT|ERR_STAT)) {
339 dump_status ("unexpected interrupt", stat);
340 SET_TIMER;
345 * bad_rw_intr() now tries to be a bit smarter and does things
346 * according to the error returned by the controller.
347 * -Mika Liljeberg (liljeber@cs.Helsinki.FI)
349 static void bad_rw_intr(void)
351 int dev;
353 if (!CURRENT)
354 return;
355 dev = DEVICE_NR(CURRENT->rq_dev);
356 if (++CURRENT->errors >= MAX_ERRORS || (hd_error & BBD_ERR)) {
357 end_request(0);
358 special_op[dev] = recalibrate[dev] = 1;
359 } else if (CURRENT->errors % RESET_FREQ == 0)
360 reset = 1;
361 else if ((hd_error & TRK0_ERR) || CURRENT->errors % RECAL_FREQ == 0)
362 special_op[dev] = recalibrate[dev] = 1;
363 /* Otherwise just retry */
366 static inline int wait_DRQ(void)
368 int retries = 100000, stat;
370 while (--retries > 0)
371 if ((stat = inb_p(HD_STATUS)) & DRQ_STAT)
372 return 0;
373 dump_status("wait_DRQ", stat);
374 return -1;
377 static void read_intr(void)
379 int i, retries = 100000;
381 do {
382 i = (unsigned) inb_p(HD_STATUS);
383 if (i & BUSY_STAT)
384 continue;
385 if (!OK_STATUS(i))
386 break;
387 if (i & DRQ_STAT)
388 goto ok_to_read;
389 } while (--retries > 0);
390 dump_status("read_intr", i);
391 bad_rw_intr();
392 hd_request();
393 return;
394 ok_to_read:
395 insw(HD_DATA,CURRENT->buffer,256);
396 CURRENT->sector++;
397 CURRENT->buffer += 512;
398 CURRENT->errors = 0;
399 i = --CURRENT->nr_sectors;
400 --CURRENT->current_nr_sectors;
401 #ifdef DEBUG
402 printk("hd%c: read: sector %ld, remaining = %ld, buffer=0x%08lx\n",
403 dev+'a', CURRENT->sector, CURRENT->nr_sectors,
404 (unsigned long) CURRENT->buffer+512));
405 #endif
406 if (CURRENT->current_nr_sectors <= 0)
407 end_request(1);
408 if (i > 0) {
409 SET_INTR(&read_intr);
410 return;
412 (void) inb_p(HD_STATUS);
413 #if (HD_DELAY > 0)
414 last_req = read_timer();
415 #endif
416 if (CURRENT)
417 hd_request();
418 return;
421 static void write_intr(void)
423 int i;
424 int retries = 100000;
426 do {
427 i = (unsigned) inb_p(HD_STATUS);
428 if (i & BUSY_STAT)
429 continue;
430 if (!OK_STATUS(i))
431 break;
432 if ((CURRENT->nr_sectors <= 1) || (i & DRQ_STAT))
433 goto ok_to_write;
434 } while (--retries > 0);
435 dump_status("write_intr", i);
436 bad_rw_intr();
437 hd_request();
438 return;
439 ok_to_write:
440 CURRENT->sector++;
441 i = --CURRENT->nr_sectors;
442 --CURRENT->current_nr_sectors;
443 CURRENT->buffer += 512;
444 if (!i || (CURRENT->bh && !SUBSECTOR(i)))
445 end_request(1);
446 if (i > 0) {
447 SET_INTR(&write_intr);
448 outsw(HD_DATA,CURRENT->buffer,256);
449 sti();
450 } else {
451 #if (HD_DELAY > 0)
452 last_req = read_timer();
453 #endif
454 hd_request();
456 return;
459 static void recal_intr(void)
461 check_status();
462 #if (HD_DELAY > 0)
463 last_req = read_timer();
464 #endif
465 hd_request();
469 * This is another of the error-routines I don't know what to do with. The
470 * best idea seems to just set reset, and start all over again.
472 static void hd_times_out(void)
474 unsigned int dev;
476 DEVICE_INTR = NULL;
477 if (!CURRENT)
478 return;
479 disable_irq(HD_IRQ);
480 sti();
481 reset = 1;
482 dev = DEVICE_NR(CURRENT->rq_dev);
483 printk("hd%c: timeout\n", dev+'a');
484 if (++CURRENT->errors >= MAX_ERRORS) {
485 #ifdef DEBUG
486 printk("hd%c: too many errors\n", dev+'a');
487 #endif
488 end_request(0);
490 cli();
491 hd_request();
492 enable_irq(HD_IRQ);
495 int do_special_op (unsigned int dev)
497 if (recalibrate[dev]) {
498 recalibrate[dev] = 0;
499 hd_out(dev,hd_info[dev].sect,0,0,0,WIN_RESTORE,&recal_intr);
500 return reset;
502 if (hd_info[dev].head > 16) {
503 printk ("hd%c: cannot handle device with more than 16 heads - giving up\n", dev+'a');
504 end_request(0);
506 special_op[dev] = 0;
507 return 1;
511 * The driver enables interrupts as much as possible. In order to do this,
512 * (a) the device-interrupt is disabled before entering hd_request(),
513 * and (b) the timeout-interrupt is disabled before the sti().
515 * Interrupts are still masked (by default) whenever we are exchanging
516 * data/cmds with a drive, because some drives seem to have very poor
517 * tolerance for latency during I/O. The IDE driver has support to unmask
518 * interrupts for non-broken hardware, so use that driver if required.
520 static void hd_request(void)
522 unsigned int dev, block, nsect, sec, track, head, cyl;
524 if (CURRENT && CURRENT->rq_status == RQ_INACTIVE) return;
525 if (DEVICE_INTR)
526 return;
527 repeat:
528 timer_active &= ~(1<<HD_TIMER);
529 sti();
530 INIT_REQUEST;
531 if (reset) {
532 cli();
533 reset_hd();
534 return;
536 dev = MINOR(CURRENT->rq_dev);
537 block = CURRENT->sector;
538 nsect = CURRENT->nr_sectors;
539 if (dev >= (NR_HD<<6) || block >= hd[dev].nr_sects || ((block+nsect) > hd[dev].nr_sects)) {
540 #ifdef DEBUG
541 if (dev >= (NR_HD<<6))
542 printk("hd: bad minor number: device=%s\n",
543 kdevname(CURRENT->rq_dev));
544 else
545 printk("hd%c: bad access: block=%d, count=%d\n",
546 (MINOR(CURRENT->rq_dev)>>6)+'a', block, nsect);
547 #endif
548 end_request(0);
549 goto repeat;
551 block += hd[dev].start_sect;
552 dev >>= 6;
553 if (special_op[dev]) {
554 if (do_special_op(dev))
555 goto repeat;
556 return;
558 sec = block % hd_info[dev].sect + 1;
559 track = block / hd_info[dev].sect;
560 head = track % hd_info[dev].head;
561 cyl = track / hd_info[dev].head;
562 #ifdef DEBUG
563 printk("hd%c: %sing: CHS=%d/%d/%d, sectors=%d, buffer=0x%08lx\n",
564 dev+'a', (CURRENT->cmd == READ)?"read":"writ",
565 cyl, head, sec, nsect, (unsigned long) CURRENT->buffer);
566 #endif
567 if (CURRENT->cmd == READ) {
568 hd_out(dev,nsect,sec,head,cyl,WIN_READ,&read_intr);
569 if (reset)
570 goto repeat;
571 return;
573 if (CURRENT->cmd == WRITE) {
574 hd_out(dev,nsect,sec,head,cyl,WIN_WRITE,&write_intr);
575 if (reset)
576 goto repeat;
577 if (wait_DRQ()) {
578 bad_rw_intr();
579 goto repeat;
581 outsw(HD_DATA,CURRENT->buffer,256);
582 return;
584 panic("unknown hd-command");
587 static void do_hd_request (void)
589 disable_irq(HD_IRQ);
590 hd_request();
591 enable_irq(HD_IRQ);
594 static int hd_ioctl(struct inode * inode, struct file * file,
595 unsigned int cmd, unsigned long arg)
597 struct hd_geometry *loc = (struct hd_geometry *) arg;
598 int dev;
600 if ((!inode) || !(inode->i_rdev))
601 return -EINVAL;
602 dev = DEVICE_NR(inode->i_rdev);
603 if (dev >= NR_HD)
604 return -EINVAL;
605 switch (cmd) {
606 case HDIO_GETGEO:
608 struct hd_geometry g;
609 if (!loc) return -EINVAL;
610 g.heads = hd_info[dev].head;
611 g.sectors = hd_info[dev].sect;
612 g.cylinders = hd_info[dev].cyl;
613 g.start = hd[MINOR(inode->i_rdev)].start_sect;
614 return copy_to_user(loc, &g, sizeof g) ? -EFAULT : 0;
617 case BLKGETSIZE: /* Return device size */
618 if (!arg) return -EINVAL;
619 return put_user(hd[MINOR(inode->i_rdev)].nr_sects,
620 (long *) arg);
622 case BLKRRPART: /* Re-read partition tables */
623 if (!capable(CAP_SYS_ADMIN))
624 return -EACCES;
625 return revalidate_hddisk(inode->i_rdev, 1);
627 case BLKROSET:
628 case BLKROGET:
629 case BLKRASET:
630 case BLKRAGET:
631 case BLKFLSBUF:
632 case BLKPG:
633 return blk_ioctl(inode->i_rdev, cmd, arg);
635 default:
636 return -EINVAL;
640 static int hd_open(struct inode * inode, struct file * filp)
642 int target;
643 target = DEVICE_NR(inode->i_rdev);
645 if (target >= NR_HD)
646 return -ENODEV;
647 while (busy[target])
648 sleep_on(&busy_wait);
649 access_count[target]++;
650 return 0;
654 * Releasing a block device means we sync() it, so that it can safely
655 * be forgotten about...
657 static int hd_release(struct inode * inode, struct file * file)
659 int target;
660 sync_dev(inode->i_rdev);
662 target = DEVICE_NR(inode->i_rdev);
663 access_count[target]--;
664 return 0;
667 static void hd_geninit(struct gendisk *);
669 static struct gendisk hd_gendisk = {
670 MAJOR_NR, /* Major number */
671 "hd", /* Major name */
672 6, /* Bits to shift to get real from partition */
673 1 << 6, /* Number of partitions per real */
674 MAX_HD, /* maximum number of real */
675 hd_geninit, /* init function */
676 hd, /* hd struct */
677 hd_sizes, /* block sizes */
678 0, /* number */
679 NULL, /* internal use, not presently used */
680 NULL /* next */
683 static void hd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
685 void (*handler)(void) = DEVICE_INTR;
687 DEVICE_INTR = NULL;
688 timer_active &= ~(1<<HD_TIMER);
689 if (!handler)
690 handler = unexpected_hd_interrupt;
691 handler();
692 sti();
696 * This is the hard disk IRQ description. The SA_INTERRUPT in sa_flags
697 * means we run the IRQ-handler with interrupts disabled: this is bad for
698 * interrupt latency, but anything else has led to problems on some
699 * machines.
701 * We enable interrupts in some of the routines after making sure it's
702 * safe.
704 static void hd_geninit(struct gendisk *ignored)
706 int drive;
708 #ifdef __i386__
709 if (!NR_HD) {
710 extern struct drive_info drive_info;
711 unsigned char *BIOS = (unsigned char *) &drive_info;
712 int cmos_disks;
714 for (drive=0 ; drive<2 ; drive++) {
715 hd_info[drive].cyl = *(unsigned short *) BIOS;
716 hd_info[drive].head = *(2+BIOS);
717 hd_info[drive].wpcom = *(unsigned short *) (5+BIOS);
718 hd_info[drive].ctl = *(8+BIOS);
719 hd_info[drive].lzone = *(unsigned short *) (12+BIOS);
720 hd_info[drive].sect = *(14+BIOS);
721 #ifdef does_not_work_for_everybody_with_scsi_but_helps_ibm_vp
722 if (hd_info[drive].cyl && NR_HD == drive)
723 NR_HD++;
724 #endif
725 BIOS += 16;
729 We query CMOS about hard disks : it could be that
730 we have a SCSI/ESDI/etc controller that is BIOS
731 compatible with ST-506, and thus showing up in our
732 BIOS table, but not register compatible, and therefore
733 not present in CMOS.
735 Furthermore, we will assume that our ST-506 drives
736 <if any> are the primary drives in the system, and
737 the ones reflected as drive 1 or 2.
739 The first drive is stored in the high nibble of CMOS
740 byte 0x12, the second in the low nibble. This will be
741 either a 4 bit drive type or 0xf indicating use byte 0x19
742 for an 8 bit type, drive 1, 0x1a for drive 2 in CMOS.
744 Needless to say, a non-zero value means we have
745 an AT controller hard disk for that drive.
750 if ((cmos_disks = CMOS_READ(0x12)) & 0xf0) {
751 if (cmos_disks & 0x0f)
752 NR_HD = 2;
753 else
754 NR_HD = 1;
757 #endif /* __i386__ */
758 #ifdef __arm__
759 if (!NR_HD) {
760 /* We don't know anything about the drive. This means
761 * that you *MUST* specify the drive parameters to the
762 * kernel yourself.
764 printk("hd: no drives specified - use hd=cyl,head,sectors"
765 " on kernel command line\n");
767 #endif
769 for (drive=0 ; drive < NR_HD ; drive++) {
770 hd[drive<<6].nr_sects = hd_info[drive].head *
771 hd_info[drive].sect * hd_info[drive].cyl;
772 printk ("hd%c: %ldMB, CHS=%d/%d/%d\n", drive+'a',
773 hd[drive<<6].nr_sects / 2048, hd_info[drive].cyl,
774 hd_info[drive].head, hd_info[drive].sect);
776 if (NR_HD) {
777 if (request_irq(HD_IRQ, hd_interrupt, SA_INTERRUPT, "hd", NULL)) {
778 printk("hd: unable to get IRQ%d for the hard disk driver\n",HD_IRQ);
779 NR_HD = 0;
780 } else {
781 request_region(HD_DATA, 8, "hd");
782 request_region(HD_CMD, 1, "hd(cmd)");
785 hd_gendisk.nr_real = NR_HD;
787 for(drive=0; drive < (MAX_HD << 6); drive++) {
788 hd_blocksizes[drive] = 1024;
789 hd_hardsectsizes[drive] = 512;
791 blksize_size[MAJOR_NR] = hd_blocksizes;
792 hardsect_size[MAJOR_NR] = hd_hardsectsizes;
795 static struct file_operations hd_fops = {
796 NULL, /* lseek - default */
797 block_read, /* read - general block-dev read */
798 block_write, /* write - general block-dev write */
799 NULL, /* readdir - bad */
800 NULL, /* poll */
801 hd_ioctl, /* ioctl */
802 NULL, /* mmap */
803 hd_open, /* open */
804 NULL, /* flush */
805 hd_release, /* release */
806 block_fsync /* fsync */
809 int __init hd_init(void)
811 if (register_blkdev(MAJOR_NR,"hd",&hd_fops)) {
812 printk("hd: unable to get major %d for hard disk\n",MAJOR_NR);
813 return -1;
815 blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
816 read_ahead[MAJOR_NR] = 8; /* 8 sector (4kB) read-ahead */
817 hd_gendisk.next = gendisk_head;
818 gendisk_head = &hd_gendisk;
819 timer_table[HD_TIMER].fn = hd_times_out;
820 return 0;
823 #define DEVICE_BUSY busy[target]
824 #define USAGE access_count[target]
825 #define CAPACITY (hd_info[target].head*hd_info[target].sect*hd_info[target].cyl)
826 /* We assume that the BIOS parameters do not change, so the disk capacity
827 will not change */
828 #undef MAYBE_REINIT
829 #define GENDISK_STRUCT hd_gendisk
832 * This routine is called to flush all partitions and partition tables
833 * for a changed disk, and then re-read the new partition table.
834 * If we are revalidating a disk because of a media change, then we
835 * enter with usage == 0. If we are using an ioctl, we automatically have
836 * usage == 1 (we need an open channel to use an ioctl :-), so this
837 * is our limit.
839 static int revalidate_hddisk(kdev_t dev, int maxusage)
841 int target;
842 struct gendisk * gdev;
843 int max_p;
844 int start;
845 int i;
846 long flags;
848 target = DEVICE_NR(dev);
849 gdev = &GENDISK_STRUCT;
851 save_flags(flags);
852 cli();
853 if (DEVICE_BUSY || USAGE > maxusage) {
854 restore_flags(flags);
855 return -EBUSY;
857 DEVICE_BUSY = 1;
858 restore_flags(flags);
860 max_p = gdev->max_p;
861 start = target << gdev->minor_shift;
863 for (i=max_p - 1; i >=0 ; i--) {
864 int minor = start + i;
865 kdev_t devi = MKDEV(MAJOR_NR, minor);
866 struct super_block *sb = get_super(devi);
868 sync_dev(devi);
869 if (sb)
870 invalidate_inodes(sb);
871 invalidate_buffers(devi);
872 gdev->part[minor].start_sect = 0;
873 gdev->part[minor].nr_sects = 0;
876 #ifdef MAYBE_REINIT
877 MAYBE_REINIT;
878 #endif
880 gdev->part[start].nr_sects = CAPACITY;
881 resetup_one_dev(gdev, target);
883 DEVICE_BUSY = 0;
884 wake_up(&busy_wait);
885 return 0;