This source file includes following definitions.
- CMOS_READ
- read_timer
- win_result
- controller_ready
- status_ok
- controller_busy
- hd_out
- drive_busy
- reset_controller
- reset_hd
- unexpected_hd_interrupt
- bad_rw_intr
- wait_DRQ
- read_intr
- write_intr
- recal_intr
- hd_times_out
- do_hd_request
- hd_ioctl
- hd_open
- hd_release
- hd_interrupt
- hd_geninit
- hd_init
- revalidate_hddisk
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 #include <linux/config.h>
20 #ifdef CONFIG_BLK_DEV_HD
21
22 #define HD_IRQ 14
23
24 #include <linux/errno.h>
25 #include <linux/signal.h>
26 #include <linux/sched.h>
27 #include <linux/timer.h>
28 #include <linux/fs.h>
29 #include <linux/kernel.h>
30 #include <linux/hdreg.h>
31 #include <linux/genhd.h>
32
33 #define REALLY_SLOW_IO
34 #include <asm/system.h>
35 #include <asm/io.h>
36 #include <asm/segment.h>
37
38 #define MAJOR_NR 3
39 #include "blk.h"
40
41 extern void resetup_one_dev(struct gendisk *, unsigned int);
42 static int revalidate_hddisk(int, int);
43
44 static inline unsigned char CMOS_READ(unsigned char addr)
45 {
46 outb_p(addr,0x70);
47 return inb_p(0x71);
48 }
49
50 #define HD_DELAY 0
51
52 #define MAX_ERRORS 16
53 #define RESET_FREQ 8
54 #define RECAL_FREQ 4
55 #define MAX_HD 2
56
57 static void recal_intr(void);
58 static void bad_rw_intr(void);
59
60 static char recalibrate[ MAX_HD ] = { 0, };
61 static int access_count[MAX_HD] = {0, };
62 static char busy[MAX_HD] = {0, };
63 static struct wait_queue * busy_wait = NULL;
64
65 static int reset = 0;
66 static int hd_error = 0;
67
68 #if (HD_DELAY > 0)
69 unsigned long last_req, read_timer();
70 #endif
71
72
73
74
75 struct hd_i_struct {
76 unsigned int head,sect,cyl,wpcom,lzone,ctl;
77 };
78 #ifdef HD_TYPE
79 struct hd_i_struct hd_info[] = { HD_TYPE };
80 static int NR_HD = ((sizeof (hd_info))/(sizeof (struct hd_i_struct)));
81 #else
82 struct hd_i_struct hd_info[] = { {0,0,0,0,0,0},{0,0,0,0,0,0} };
83 static int NR_HD = 0;
84 #endif
85
86 static struct hd_struct hd[MAX_HD<<6]={{0,0},};
87 static int hd_sizes[MAX_HD<<6] = {0, };
88
89 #define port_read(port,buf,nr) \
90 __asm__("cld;rep;insw"::"d" (port),"D" (buf),"c" (nr):"cx","di")
91
92 #define port_write(port,buf,nr) \
93 __asm__("cld;rep;outsw"::"d" (port),"S" (buf),"c" (nr):"cx","si")
94
95 #if (HD_DELAY > 0)
96 unsigned long read_timer(void)
97 {
98 unsigned long t;
99 int i;
100
101 cli();
102 outb_p(0xc2, 0x43);
103 t = jiffies * 11931 + (inb_p(0x40) & 0x80 ? 5966 : 11932);
104 i = inb_p(0x40);
105 i |= inb(0x40) << 8;
106 sti();
107 return(t - i / 2);
108 }
109 #endif
110
111 static int win_result(void)
112 {
113 int i=inb_p(HD_STATUS);
114
115 if ((i & (BUSY_STAT | READY_STAT | WRERR_STAT | SEEK_STAT | ERR_STAT))
116 == (READY_STAT | SEEK_STAT)) {
117 hd_error = 0;
118 return 0;
119 }
120 printk("HD: win_result: status = 0x%02x\n",i);
121 if (i&1) {
122 hd_error = inb(HD_ERROR);
123 printk("HD: win_result: error = 0x%02x\n",hd_error);
124 }
125 return 1;
126 }
127
128 static int controller_busy(void);
129 static int status_ok(void);
130
131 static int controller_ready(unsigned int drive, unsigned int head)
132 {
133 int retry = 100;
134
135 do {
136 if (controller_busy() & BUSY_STAT)
137 return 0;
138 outb_p(0xA0 | (drive<<4) | head, HD_CURRENT);
139 if (status_ok())
140 return 1;
141 } while (--retry);
142 return 0;
143 }
144
145 static int status_ok(void)
146 {
147 unsigned char status = inb_p(HD_STATUS);
148
149 if (status & BUSY_STAT)
150 return 1;
151 if (status & WRERR_STAT)
152 return 0;
153 if (!(status & READY_STAT))
154 return 0;
155 if (!(status & SEEK_STAT))
156 return 0;
157 return 1;
158 }
159
160 static int controller_busy(void)
161 {
162 int retries = 100000;
163 unsigned char status;
164
165 do {
166 status = inb_p(HD_STATUS);
167 } while ((status & BUSY_STAT) && --retries);
168 return status;
169 }
170
171 static void hd_out(unsigned int drive,unsigned int nsect,unsigned int sect,
172 unsigned int head,unsigned int cyl,unsigned int cmd,
173 void (*intr_addr)(void))
174 {
175 unsigned short port;
176
177 if (drive>1 || head>15)
178 panic("Trying to write bad sector");
179 #if (HD_DELAY > 0)
180 while (read_timer() - last_req < HD_DELAY)
181 ;
182 #endif
183 if (reset)
184 return;
185 if (!controller_ready(drive, head)) {
186 reset = 1;
187 return;
188 }
189 SET_INTR(intr_addr);
190 outb_p(hd_info[drive].ctl,HD_CMD);
191 port=HD_DATA;
192 outb_p(hd_info[drive].wpcom>>2,++port);
193 outb_p(nsect,++port);
194 outb_p(sect,++port);
195 outb_p(cyl,++port);
196 outb_p(cyl>>8,++port);
197 outb_p(0xA0|(drive<<4)|head,++port);
198 outb_p(cmd,++port);
199 }
200
201 static int drive_busy(void)
202 {
203 unsigned int i;
204 unsigned char c;
205
206 for (i = 0; i < 500000 ; i++) {
207 c = inb_p(HD_STATUS);
208 c &= (BUSY_STAT | READY_STAT | SEEK_STAT);
209 if (c == (READY_STAT | SEEK_STAT))
210 return 0;
211 }
212 printk("HD controller times out, status = 0x%02x\n",c);
213 return 1;
214 }
215
216 static void reset_controller(void)
217 {
218 int i;
219
220 printk("HD-controller reset\n");
221 outb(4,HD_CMD);
222 for(i = 0; i < 1000; i++) nop();
223 outb(hd_info[0].ctl & 0x0f ,HD_CMD);
224 if (drive_busy())
225 printk("HD-controller still busy\n");
226 if ((hd_error = inb(HD_ERROR)) != 1)
227 printk("HD-controller reset failed: %02x\n",hd_error);
228 }
229
230 static void reset_hd(void)
231 {
232 static int i;
233
234 repeat:
235 if (reset) {
236 reset = 0;
237 i = -1;
238 reset_controller();
239 } else if (win_result()) {
240 bad_rw_intr();
241 if (reset)
242 goto repeat;
243 }
244 i++;
245 if (i < NR_HD) {
246 hd_out(i,hd_info[i].sect,hd_info[i].sect,hd_info[i].head-1,
247 hd_info[i].cyl,WIN_SPECIFY,&reset_hd);
248 if (reset)
249 goto repeat;
250 } else
251 do_hd_request();
252 }
253
254
255
256
257
258
259 void unexpected_hd_interrupt(void)
260 {
261 sti();
262 printk("Unexpected HD interrupt\n");
263 SET_TIMER;
264 }
265
266
267
268
269
270
271 static void bad_rw_intr(void)
272 {
273 int dev;
274
275 if (!CURRENT)
276 return;
277 dev = MINOR(CURRENT->dev) >> 6;
278 if (++CURRENT->errors >= MAX_ERRORS || (hd_error & BBD_ERR)) {
279 end_request(0);
280 recalibrate[dev] = 1;
281 } else if (CURRENT->errors % RESET_FREQ == 0)
282 reset = 1;
283 else if ((hd_error & TRK0_ERR) || CURRENT->errors % RECAL_FREQ == 0)
284 recalibrate[dev] = 1;
285
286 }
287
288 static inline int wait_DRQ(void)
289 {
290 int retries = 100000;
291
292 while (--retries > 0)
293 if (inb_p(HD_STATUS) & DRQ_STAT)
294 return 0;
295 return -1;
296 }
297
298 #define STAT_MASK (BUSY_STAT | READY_STAT | WRERR_STAT | SEEK_STAT | ERR_STAT)
299 #define STAT_OK (READY_STAT | SEEK_STAT)
300
301 static void read_intr(void)
302 {
303 int i;
304 int retries = 100000;
305
306 do {
307 i = (unsigned) inb_p(HD_STATUS);
308 if ((i & STAT_MASK) != STAT_OK)
309 break;
310 if (i & DRQ_STAT)
311 goto ok_to_read;
312 } while (--retries > 0);
313 sti();
314 printk("HD: read_intr: status = 0x%02x\n",i);
315 if (i & ERR_STAT) {
316 hd_error = (unsigned) inb(HD_ERROR);
317 printk("HD: read_intr: error = 0x%02x\n",hd_error);
318 }
319 bad_rw_intr();
320 cli();
321 do_hd_request();
322 return;
323 ok_to_read:
324 port_read(HD_DATA,CURRENT->buffer,256);
325 CURRENT->errors = 0;
326 CURRENT->buffer += 512;
327 CURRENT->sector++;
328 i = --CURRENT->nr_sectors;
329 --CURRENT->current_nr_sectors;
330 #ifdef DEBUG
331 printk("hd%d : sector = %d, %d remaining to buffer = %08x\n",
332 MINOR(CURRENT->dev), CURRENT->sector, i, CURRENT->
333 buffer);
334 #endif
335 if (!i || (CURRENT->bh && !SUBSECTOR(i)))
336 end_request(1);
337 if (i > 0) {
338 SET_INTR(&read_intr);
339 sti();
340 return;
341 }
342 (void) inb_p(HD_STATUS);
343 #if (HD_DELAY > 0)
344 last_req = read_timer();
345 #endif
346 do_hd_request();
347 return;
348 }
349
350 static void write_intr(void)
351 {
352 int i;
353 int retries = 100000;
354
355 do {
356 i = (unsigned) inb_p(HD_STATUS);
357 if ((i & STAT_MASK) != STAT_OK)
358 break;
359 if ((CURRENT->nr_sectors <= 1) || (i & DRQ_STAT))
360 goto ok_to_write;
361 } while (--retries > 0);
362 sti();
363 printk("HD: write_intr: status = 0x%02x\n",i);
364 if (i & ERR_STAT) {
365 hd_error = (unsigned) inb(HD_ERROR);
366 printk("HD: write_intr: error = 0x%02x\n",hd_error);
367 }
368 bad_rw_intr();
369 cli();
370 do_hd_request();
371 return;
372 ok_to_write:
373 CURRENT->sector++;
374 i = --CURRENT->nr_sectors;
375 --CURRENT->current_nr_sectors;
376 CURRENT->buffer += 512;
377 if (!i || (CURRENT->bh && !SUBSECTOR(i)))
378 end_request(1);
379 if (i > 0) {
380 SET_INTR(&write_intr);
381 port_write(HD_DATA,CURRENT->buffer,256);
382 sti();
383 } else {
384 #if (HD_DELAY > 0)
385 last_req = read_timer();
386 #endif
387 do_hd_request();
388 }
389 return;
390 }
391
392 static void recal_intr(void)
393 {
394 if (win_result())
395 bad_rw_intr();
396 do_hd_request();
397 }
398
399
400
401
402
403 static void hd_times_out(void)
404 {
405 DEVICE_INTR = NULL;
406 sti();
407 reset = 1;
408 if (!CURRENT)
409 return;
410 printk("HD timeout\n");
411 cli();
412 if (++CURRENT->errors >= MAX_ERRORS) {
413 #ifdef DEBUG
414 printk("hd : too many errors.\n");
415 #endif
416 end_request(0);
417 }
418
419 do_hd_request();
420 }
421
422
423
424
425
426
427
428
429 static void do_hd_request(void)
430 {
431 unsigned int block,dev;
432 unsigned int sec,head,cyl,track;
433 unsigned int nsect;
434
435 if (CURRENT && CURRENT->dev < 0) return;
436
437 if (DEVICE_INTR)
438 return;
439 repeat:
440 timer_active &= ~(1<<HD_TIMER);
441 sti();
442 INIT_REQUEST;
443 dev = MINOR(CURRENT->dev);
444 block = CURRENT->sector;
445 nsect = CURRENT->nr_sectors;
446 if (dev >= (NR_HD<<6) || block >= hd[dev].nr_sects) {
447 #ifdef DEBUG
448 printk("hd%d : attempted read for sector %d past end of device at sector %d.\n",
449 block, hd[dev].nr_sects);
450 #endif
451 end_request(0);
452 goto repeat;
453 }
454 block += hd[dev].start_sect;
455 dev >>= 6;
456 sec = block % hd_info[dev].sect + 1;
457 track = block / hd_info[dev].sect;
458 head = track % hd_info[dev].head;
459 cyl = track / hd_info[dev].head;
460 #ifdef DEBUG
461 printk("hd%d : cyl = %d, head = %d, sector = %d, buffer = %08x\n",
462 dev, cyl, head, sec, CURRENT->buffer);
463 #endif
464 cli();
465 if (reset) {
466 int i;
467
468 for (i=0; i < NR_HD; i++)
469 recalibrate[i] = 1;
470 reset_hd();
471 sti();
472 return;
473 }
474 if (recalibrate[dev]) {
475 recalibrate[dev] = 0;
476 hd_out(dev,hd_info[dev].sect,0,0,0,WIN_RESTORE,&recal_intr);
477 if (reset)
478 goto repeat;
479 sti();
480 return;
481 }
482 if (CURRENT->cmd == WRITE) {
483 hd_out(dev,nsect,sec,head,cyl,WIN_WRITE,&write_intr);
484 if (reset)
485 goto repeat;
486 if (wait_DRQ()) {
487 printk("HD: do_hd_request: no DRQ\n");
488 bad_rw_intr();
489 goto repeat;
490 }
491 port_write(HD_DATA,CURRENT->buffer,256);
492 sti();
493 return;
494 }
495 if (CURRENT->cmd == READ) {
496 hd_out(dev,nsect,sec,head,cyl,WIN_READ,&read_intr);
497 if (reset)
498 goto repeat;
499 sti();
500 return;
501 }
502 panic("unknown hd-command");
503 }
504
505 static int hd_ioctl(struct inode * inode, struct file * file,
506 unsigned int cmd, unsigned int arg)
507 {
508 struct hd_geometry *loc = (void *) arg;
509 int dev, err;
510
511 if (!inode)
512 return -EINVAL;
513 dev = MINOR(inode->i_rdev) >> 6;
514 if (dev >= NR_HD)
515 return -EINVAL;
516 switch (cmd) {
517 case HDIO_GETGEO:
518 if (!loc) return -EINVAL;
519 err = verify_area(VERIFY_WRITE, loc, sizeof(*loc));
520 if (err)
521 return err;
522 put_fs_byte(hd_info[dev].head,
523 (char *) &loc->heads);
524 put_fs_byte(hd_info[dev].sect,
525 (char *) &loc->sectors);
526 put_fs_word(hd_info[dev].cyl,
527 (short *) &loc->cylinders);
528 put_fs_long(hd[MINOR(inode->i_rdev)].start_sect,
529 (long *) &loc->start);
530 return 0;
531 case BLKGETSIZE:
532 if (!arg) return -EINVAL;
533 err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));
534 if (err)
535 return err;
536 put_fs_long(hd[MINOR(inode->i_rdev)].nr_sects,
537 (long *) arg);
538 return 0;
539 case BLKRRPART:
540 return revalidate_hddisk(inode->i_rdev, 1);
541 RO_IOCTLS(inode->i_rdev,arg);
542 default:
543 return -EINVAL;
544 }
545 }
546
547 static int hd_open(struct inode * inode, struct file * filp)
548 {
549 int target;
550 target = DEVICE_NR(MINOR(inode->i_rdev));
551
552 while (busy[target])
553 sleep_on(&busy_wait);
554 access_count[target]++;
555 return 0;
556 }
557
558
559
560
561
562 static void hd_release(struct inode * inode, struct file * file)
563 {
564 int target;
565 sync_dev(inode->i_rdev);
566
567 target = DEVICE_NR(MINOR(inode->i_rdev));
568 access_count[target]--;
569
570 }
571
572 static void hd_geninit(void);
573
574 static struct gendisk hd_gendisk = {
575 MAJOR_NR,
576 "hd",
577 6,
578 1 << 6,
579 MAX_HD,
580 hd_geninit,
581 hd,
582 hd_sizes,
583 0,
584 (void *) hd_info,
585 NULL
586 };
587
588 static void hd_interrupt(int unused)
589 {
590 void (*handler)(void) = DEVICE_INTR;
591
592 DEVICE_INTR = NULL;
593 timer_active &= ~(1<<HD_TIMER);
594 if (!handler)
595 handler = unexpected_hd_interrupt;
596 handler();
597 sti();
598 }
599
600
601
602
603
604
605
606
607
608
609 static struct sigaction hd_sigaction = {
610 hd_interrupt,
611 0,
612 SA_INTERRUPT,
613 NULL
614 };
615
616 static void hd_geninit(void)
617 {
618 int drive, i;
619 #ifndef HD_TYPE
620 extern struct drive_info drive_info;
621 void *BIOS = (void *) &drive_info;
622 int cmos_disks;
623
624 for (drive=0 ; drive<2 ; drive++) {
625 hd_info[drive].cyl = *(unsigned short *) BIOS;
626 hd_info[drive].head = *(unsigned char *) (2+BIOS);
627 hd_info[drive].wpcom = *(unsigned short *) (5+BIOS);
628 hd_info[drive].ctl = *(unsigned char *) (8+BIOS);
629 hd_info[drive].lzone = *(unsigned short *) (12+BIOS);
630 hd_info[drive].sect = *(unsigned char *) (14+BIOS);
631 BIOS += 16;
632 }
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656 if ((cmos_disks = CMOS_READ(0x12)) & 0xf0)
657 if (cmos_disks & 0x0f)
658 NR_HD = 2;
659 else
660 NR_HD = 1;
661 else
662 NR_HD = 0;
663 #endif
664 i = NR_HD;
665 while (i-- > 0) {
666 hd[i<<6].nr_sects = 0;
667 if (hd_info[i].head > 16) {
668 printk("hd.c: ST-506 interface disk with more than 16 heads detected,\n");
669 printk(" probably due to non-standard sector translation. Giving up.\n");
670 printk(" (disk %d: cyl=%d, sect=%d, head=%d)\n", i,
671 hd_info[i].cyl,
672 hd_info[i].sect,
673 hd_info[i].head);
674 if (i+1 == NR_HD)
675 NR_HD--;
676 continue;
677 }
678 hd[i<<6].nr_sects = hd_info[i].head*
679 hd_info[i].sect*hd_info[i].cyl;
680 }
681 if (NR_HD) {
682 if (irqaction(HD_IRQ,&hd_sigaction)) {
683 printk("hd.c: unable to get IRQ%d for the harddisk driver\n",HD_IRQ);
684 NR_HD = 0;
685 }
686 }
687 hd_gendisk.nr_real = NR_HD;
688 }
689
690 static struct file_operations hd_fops = {
691 NULL,
692 block_read,
693 block_write,
694 NULL,
695 NULL,
696 hd_ioctl,
697 NULL,
698 hd_open,
699 hd_release
700 };
701
702 unsigned long hd_init(unsigned long mem_start, unsigned long mem_end)
703 {
704 if (register_blkdev(MAJOR_NR,"hd",&hd_fops)) {
705 printk("Unable to get major %d for harddisk\n",MAJOR_NR);
706 return mem_start;
707 }
708 blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
709 read_ahead[MAJOR_NR] = 8;
710 hd_gendisk.next = gendisk_head;
711 gendisk_head = &hd_gendisk;
712 timer_table[HD_TIMER].fn = hd_times_out;
713 return mem_start;
714 }
715
716 #define DEVICE_BUSY busy[target]
717 #define USAGE access_count[target]
718 #define CAPACITY (hd_info[target].head*hd_info[target].sect*hd_info[target].cyl)
719
720
721 #undef MAYBE_REINIT
722 #define GENDISK_STRUCT hd_gendisk
723
724
725
726
727
728
729
730
731
732 static int revalidate_hddisk(int dev, int maxusage)
733 {
734 int target, major;
735 struct gendisk * gdev;
736 int max_p;
737 int start;
738 int i;
739
740 target = DEVICE_NR(MINOR(dev));
741 gdev = &GENDISK_STRUCT;
742
743 cli();
744 if (DEVICE_BUSY || USAGE > maxusage) {
745 sti();
746 return -EBUSY;
747 };
748 DEVICE_BUSY = 1;
749 sti();
750
751 max_p = gdev->max_p;
752 start = target << gdev->minor_shift;
753 major = MAJOR_NR << 8;
754
755 for (i=max_p - 1; i >=0 ; i--) {
756 sync_dev(major | start | i);
757 invalidate_inodes(major | start | i);
758 invalidate_buffers(major | start | i);
759 gdev->part[start+i].start_sect = 0;
760 gdev->part[start+i].nr_sects = 0;
761 };
762
763 #ifdef MAYBE_REINIT
764 MAYBE_REINIT;
765 #endif
766
767 gdev->part[start].nr_sects = CAPACITY;
768 resetup_one_dev(gdev, target);
769
770 DEVICE_BUSY = 0;
771 wake_up(&busy_wait);
772 return 0;
773 }
774
775 #endif