This source file includes following definitions.
- CMOS_READ
- read_timer
- controller_ready
- win_result
- 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_release
- hd_geninit
- hd_interrupt
- hd_init
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 static inline unsigned char CMOS_READ(unsigned char addr)
42 {
43 outb_p(0x80|addr,0x70);
44 return inb_p(0x71);
45 }
46
47 #define HD_DELAY 0
48
49
50 #define MAX_ERRORS 7
51 #define MAX_HD 2
52
53 static void recal_intr(void);
54 static void bad_rw_intr(void);
55
56 static char recalibrate[ MAX_HD ] = { 0, };
57
58 static int reset = 0;
59
60 #if (HD_DELAY > 0)
61 unsigned long last_req, read_timer();
62 #endif
63
64
65
66
67 struct hd_i_struct {
68 unsigned int head,sect,cyl,wpcom,lzone,ctl;
69 };
70 #ifdef HD_TYPE
71 struct hd_i_struct hd_info[] = { HD_TYPE };
72 #define NR_HD ((sizeof (hd_info))/(sizeof (struct hd_i_struct)))
73 #else
74 struct hd_i_struct hd_info[] = { {0,0,0,0,0,0},{0,0,0,0,0,0} };
75 static int NR_HD = 0;
76 #endif
77
78 static struct hd_struct hd[MAX_HD<<6]={{0,0},};
79 static int hd_sizes[MAX_HD<<6] = {0, };
80
81 #define port_read(port,buf,nr) \
82 __asm__("cld;rep;insw"::"d" (port),"D" (buf),"c" (nr):"cx","di")
83
84 #define port_write(port,buf,nr) \
85 __asm__("cld;rep;outsw"::"d" (port),"S" (buf),"c" (nr):"cx","si")
86
87 #if (HD_DELAY > 0)
88 unsigned long read_timer(void)
89 {
90 unsigned long t;
91 int i;
92
93 cli();
94 outb_p(0xc2, 0x43);
95 t = jiffies * 11931 + (inb_p(0x40) & 0x80 ? 5966 : 11932);
96 i = inb_p(0x40);
97 i |= inb(0x40) << 8;
98 sti();
99 return(t - i / 2);
100 }
101 #endif
102
103 static int controller_ready(void)
104 {
105 int retries = 100000;
106
107 while (--retries && (inb_p(HD_STATUS)&0x80))
108 ;
109 if (!retries)
110 printk("controller_ready: status = %02x\n\r",
111 (unsigned char) inb_p(HD_STATUS));
112 return (retries);
113 }
114
115 static int win_result(void)
116 {
117 int i=inb_p(HD_STATUS);
118
119 if ((i & (BUSY_STAT | READY_STAT | WRERR_STAT | SEEK_STAT | ERR_STAT))
120 == (READY_STAT | SEEK_STAT))
121 return 0;
122 printk("HD: win_result: status = 0x%02x\n",i);
123 if (i&1) {
124 i=inb(HD_ERROR);
125 printk("HD: win_result: error = 0x%02x\n",i);
126 }
127 return 1;
128 }
129
130 static void hd_out(unsigned int drive,unsigned int nsect,unsigned int sect,
131 unsigned int head,unsigned int cyl,unsigned int cmd,
132 void (*intr_addr)(void))
133 {
134 unsigned short port;
135
136 if (drive>1 || head>15)
137 panic("Trying to write bad sector");
138 #if (HD_DELAY > 0)
139 while (read_timer() - last_req < HD_DELAY)
140 ;
141 #endif
142 if (reset || !controller_ready()) {
143 reset = 1;
144 return;
145 }
146 SET_INTR(intr_addr);
147 outb_p(hd_info[drive].ctl,HD_CMD);
148 port=HD_DATA;
149 outb_p(hd_info[drive].wpcom>>2,++port);
150 outb_p(nsect,++port);
151 outb_p(sect,++port);
152 outb_p(cyl,++port);
153 outb_p(cyl>>8,++port);
154 outb_p(0xA0|(drive<<4)|head,++port);
155 outb_p(cmd,++port);
156 }
157
158 static int drive_busy(void)
159 {
160 unsigned int i;
161 unsigned char c;
162
163 for (i = 0; i < 500000 ; i++) {
164 c = inb_p(HD_STATUS);
165 c &= (BUSY_STAT | READY_STAT | SEEK_STAT);
166 if (c == (READY_STAT | SEEK_STAT))
167 return 0;
168 }
169 printk("HD controller times out, status = 0x%02x\n\r",c);
170 return(1);
171 }
172
173 static void reset_controller(void)
174 {
175 int i;
176
177 printk("HD-controller reset\r\n");
178 outb(4,HD_CMD);
179 for(i = 0; i < 1000; i++) nop();
180 outb(hd_info[0].ctl & 0x0f ,HD_CMD);
181 if (drive_busy())
182 printk("HD-controller still busy\n\r");
183 if ((i = inb(HD_ERROR)) != 1)
184 printk("HD-controller reset failed: %02x\n\r",i);
185 }
186
187 static void reset_hd(void)
188 {
189 static int i;
190
191 repeat:
192 if (reset) {
193 reset = 0;
194 i = -1;
195 reset_controller();
196 } else if (win_result()) {
197 bad_rw_intr();
198 if (reset)
199 goto repeat;
200 }
201 i++;
202 if (i < NR_HD) {
203 hd_out(i,hd_info[i].sect,hd_info[i].sect,hd_info[i].head-1,
204 hd_info[i].cyl,WIN_SPECIFY,&reset_hd);
205 if (reset)
206 goto repeat;
207 } else
208 do_hd_request();
209 }
210
211
212
213
214
215
216 void unexpected_hd_interrupt(void)
217 {
218 sti();
219 printk("Unexpected HD interrupt\n\r");
220 SET_TIMER;
221 }
222
223 static void bad_rw_intr(void)
224 {
225 int i;
226
227 if (!CURRENT)
228 return;
229 if (++CURRENT->errors >= MAX_ERRORS)
230 end_request(0);
231 else if (CURRENT->errors > MAX_ERRORS/2)
232 reset = 1;
233 else
234 for (i=0; i < NR_HD; i++)
235 recalibrate[i] = 1;
236 }
237
238 static inline int wait_DRQ(void)
239 {
240 int retries = 100000;
241
242 while (--retries > 0)
243 if (inb_p(HD_STATUS) & DRQ_STAT)
244 return 0;
245 return -1;
246 }
247
248 #define STAT_MASK (BUSY_STAT | READY_STAT | WRERR_STAT | SEEK_STAT | ERR_STAT)
249 #define STAT_OK (READY_STAT | SEEK_STAT)
250
251 static void read_intr(void)
252 {
253 int i;
254 int retries = 100000;
255
256 do {
257 i = (unsigned) inb_p(HD_STATUS);
258 if ((i & STAT_MASK) != STAT_OK)
259 break;
260 if (i & DRQ_STAT)
261 goto ok_to_read;
262 } while (--retries > 0);
263 sti();
264 printk("HD: read_intr: status = 0x%02x\n",i);
265 if (i & ERR_STAT) {
266 i = (unsigned) inb(HD_ERROR);
267 printk("HD: read_intr: error = 0x%02x\n",i);
268 }
269 bad_rw_intr();
270 cli();
271 do_hd_request();
272 return;
273 ok_to_read:
274 port_read(HD_DATA,CURRENT->buffer,256);
275 CURRENT->errors = 0;
276 CURRENT->buffer += 512;
277 CURRENT->sector++;
278 i = --CURRENT->nr_sectors;
279 --CURRENT->current_nr_sectors;
280 #ifdef DEBUG
281 printk("hd%d : sector = %d, %d remaining to buffer = %08x\n",
282 MINOR(CURRENT->dev), CURRENT->sector, i, CURRENT->
283 buffer);
284 #endif
285 if (!i || (CURRENT->bh && !SUBSECTOR(i)))
286 end_request(1);
287 if (i > 0) {
288 SET_INTR(&read_intr);
289 sti();
290 return;
291 }
292 #if (HD_DELAY > 0)
293 last_req = read_timer();
294 #endif
295 do_hd_request();
296 return;
297 }
298
299 static void write_intr(void)
300 {
301 int i;
302 int retries = 100000;
303
304 do {
305 i = (unsigned) inb_p(HD_STATUS);
306 if ((i & STAT_MASK) != STAT_OK)
307 break;
308 if ((CURRENT->nr_sectors <= 1) || (i & DRQ_STAT))
309 goto ok_to_write;
310 } while (--retries > 0);
311 sti();
312 printk("HD: write_intr: status = 0x%02x\n",i);
313 if (i & ERR_STAT) {
314 i = (unsigned) inb(HD_ERROR);
315 printk("HD: write_intr: error = 0x%02x\n",i);
316 }
317 bad_rw_intr();
318 cli();
319 do_hd_request();
320 return;
321 ok_to_write:
322 CURRENT->sector++;
323 i = --CURRENT->nr_sectors;
324 --CURRENT->current_nr_sectors;
325 CURRENT->buffer += 512;
326 if (!i || (CURRENT->bh && !SUBSECTOR(i)))
327 end_request(1);
328 if (i > 0) {
329 SET_INTR(&write_intr);
330 port_write(HD_DATA,CURRENT->buffer,256);
331 sti();
332 } else {
333 #if (HD_DELAY > 0)
334 last_req = read_timer();
335 #endif
336 do_hd_request();
337 }
338 return;
339 }
340
341 static void recal_intr(void)
342 {
343 if (win_result())
344 bad_rw_intr();
345 do_hd_request();
346 }
347
348
349
350
351
352 static void hd_times_out(void)
353 {
354 DEVICE_INTR = NULL;
355 sti();
356 reset = 1;
357 if (!CURRENT)
358 return;
359 printk("HD timeout\n\r");
360 cli();
361 if (++CURRENT->errors >= MAX_ERRORS) {
362 #ifdef DEBUG
363 printk("hd : too many errors.\n");
364 #endif
365 end_request(0);
366 }
367
368 do_hd_request();
369 }
370
371
372
373
374
375
376
377
378 static void do_hd_request(void)
379 {
380 unsigned int block,dev;
381 unsigned int sec,head,cyl,track;
382 unsigned int nsect;
383
384 if (DEVICE_INTR)
385 return;
386 repeat:
387 timer_active &= ~(1<<HD_TIMER);
388 sti();
389 INIT_REQUEST;
390 dev = MINOR(CURRENT->dev);
391 block = CURRENT->sector;
392 nsect = CURRENT->nr_sectors;
393 if (dev >= (NR_HD<<6) || block >= hd[dev].nr_sects) {
394 #ifdef DEBUG
395 printk("hd%d : attempted read for sector %d past end of device at sector %d.\n",
396 block, hd[dev].nr_sects);
397 #endif
398 end_request(0);
399 goto repeat;
400 }
401 block += hd[dev].start_sect;
402 dev >>= 6;
403 sec = block % hd_info[dev].sect + 1;
404 track = block / hd_info[dev].sect;
405 head = track % hd_info[dev].head;
406 cyl = track / hd_info[dev].head;
407 #ifdef DEBUG
408 printk("hd%d : cyl = %d, head = %d, sector = %d, buffer = %08x\n",
409 dev, cyl, head, sec, CURRENT->buffer);
410 #endif
411 cli();
412 if (reset) {
413 int i;
414
415 for (i=0; i < NR_HD; i++)
416 recalibrate[i] = 1;
417 reset_hd();
418 sti();
419 return;
420 }
421 if (recalibrate[dev]) {
422 recalibrate[dev] = 0;
423 hd_out(dev,hd_info[dev].sect,0,0,0,WIN_RESTORE,&recal_intr);
424 if (reset)
425 goto repeat;
426 sti();
427 return;
428 }
429 if (CURRENT->cmd == WRITE) {
430 hd_out(dev,nsect,sec,head,cyl,WIN_WRITE,&write_intr);
431 if (reset)
432 goto repeat;
433 if (wait_DRQ()) {
434 printk("HD: do_hd_request: no DRQ\n");
435 bad_rw_intr();
436 goto repeat;
437 }
438 port_write(HD_DATA,CURRENT->buffer,256);
439 sti();
440 return;
441 }
442 if (CURRENT->cmd == READ) {
443 hd_out(dev,nsect,sec,head,cyl,WIN_READ,&read_intr);
444 if (reset)
445 goto repeat;
446 sti();
447 return;
448 }
449 panic("unknown hd-command");
450 }
451
452 static int hd_ioctl(struct inode * inode, struct file * file,
453 unsigned int cmd, unsigned int arg)
454 {
455 struct hd_geometry *loc = (void *) arg;
456 int dev;
457
458 if (!loc || !inode)
459 return -EINVAL;
460 dev = MINOR(inode->i_rdev) >> 6;
461 if (dev >= NR_HD)
462 return -EINVAL;
463 switch (cmd) {
464 case HDIO_REQ:
465 verify_area(loc, sizeof(*loc));
466 put_fs_byte(hd_info[dev].head,
467 (char *) &loc->heads);
468 put_fs_byte(hd_info[dev].sect,
469 (char *) &loc->sectors);
470 put_fs_word(hd_info[dev].cyl,
471 (short *) &loc->cylinders);
472 put_fs_long(hd[MINOR(inode->i_rdev)].start_sect,
473 (long *) &loc->start);
474 return 0;
475 RO_IOCTLS(inode->i_rdev,arg);
476 default:
477 return -EINVAL;
478 }
479 }
480
481
482
483
484
485 static void hd_release(struct inode * inode, struct file * file)
486 {
487 sync_dev(inode->i_rdev);
488 }
489
490 static void hd_geninit();
491
492 static struct gendisk hd_gendisk = {
493 MAJOR_NR,
494 "hd",
495 6,
496 1 << 6,
497 MAX_HD,
498 hd_geninit,
499 hd,
500 hd_sizes,
501 0,
502 (void *) hd_info,
503 NULL
504 };
505
506 static void hd_geninit(void)
507 {
508 int drive, i;
509 #ifndef HD_TYPE
510 extern struct drive_info drive_info;
511 void *BIOS = (void *) &drive_info;
512 int cmos_disks;
513
514 for (drive=0 ; drive<2 ; drive++) {
515 hd_info[drive].cyl = *(unsigned short *) BIOS;
516 hd_info[drive].head = *(unsigned char *) (2+BIOS);
517 hd_info[drive].wpcom = *(unsigned short *) (5+BIOS);
518 hd_info[drive].ctl = *(unsigned char *) (8+BIOS);
519 hd_info[drive].lzone = *(unsigned short *) (12+BIOS);
520 hd_info[drive].sect = *(unsigned char *) (14+BIOS);
521 BIOS += 16;
522 }
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546 if ((cmos_disks = CMOS_READ(0x12)) & 0xf0)
547 if (cmos_disks & 0x0f)
548 NR_HD = 2;
549 else
550 NR_HD = 1;
551 else
552 NR_HD = 0;
553 #endif
554
555 for (i = 0 ; i < NR_HD ; i++)
556 hd[i<<6].nr_sects = hd_info[i].head*
557 hd_info[i].sect*hd_info[i].cyl;
558
559 hd_gendisk.nr_real = NR_HD;
560 }
561
562 static struct file_operations hd_fops = {
563 NULL,
564 block_read,
565 block_write,
566 NULL,
567 NULL,
568 hd_ioctl,
569 NULL,
570 hd_release
571 };
572
573 static void hd_interrupt(int unused)
574 {
575 void (*handler)(void) = DEVICE_INTR;
576
577 DEVICE_INTR = NULL;
578 timer_active &= ~(1<<HD_TIMER);
579 if (!handler)
580 handler = unexpected_hd_interrupt;
581 handler();
582 sti();
583 }
584
585
586
587
588
589
590
591
592
593
594 static struct sigaction hd_sigaction = {
595 hd_interrupt,
596 0,
597 SA_INTERRUPT,
598 NULL
599 };
600
601 unsigned long hd_init(unsigned long mem_start, unsigned long mem_end)
602 {
603 blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
604 blkdev_fops[MAJOR_NR] = &hd_fops;
605 hd_gendisk.next = gendisk_head;
606 gendisk_head = &hd_gendisk;
607 if (irqaction(HD_IRQ,&hd_sigaction))
608 printk("Unable to get IRQ%d for the harddisk driver\n",HD_IRQ);
609 timer_table[HD_TIMER].fn = hd_times_out;
610 return mem_start;
611 }
612
613 #endif