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
255 i = (unsigned) inb_p(HD_STATUS);
256 if ((i & STAT_MASK) != STAT_OK) {
257 printk("HD: read_intr: status = 0x%02x\n",i);
258 goto bad_read;
259 }
260 if (wait_DRQ()) {
261 printk("HD: read_intr: no DRQ\n");
262 goto bad_read;
263 }
264 port_read(HD_DATA,CURRENT->buffer,256);
265 i = (unsigned) inb_p(HD_STATUS);
266 if (!(i & BUSY_STAT))
267 if ((i & STAT_MASK) != STAT_OK) {
268 printk("HD: read_intr: second status = 0x%02x\n",i);
269 goto bad_read;
270 }
271 CURRENT->errors = 0;
272 CURRENT->buffer += 512;
273 CURRENT->sector++;
274 i = --CURRENT->nr_sectors;
275 --CURRENT->current_nr_sectors;
276 #ifdef DEBUG
277 printk("hd%d : sector = %d, %d remaining to buffer = %08x\n",
278 MINOR(CURRENT->dev), CURRENT->sector, i, CURRENT->
279 buffer);
280 #endif
281 if (!i || (CURRENT->bh && !SUBSECTOR(i)))
282 end_request(1);
283 if (i > 0) {
284 SET_INTR(&read_intr);
285 sti();
286 return;
287 }
288 #if (HD_DELAY > 0)
289 last_req = read_timer();
290 #endif
291 do_hd_request();
292 return;
293 bad_read:
294 if (i & ERR_STAT) {
295 i = (unsigned) inb(HD_ERROR);
296 printk("HD: read_intr: error = 0x%02x\n",i);
297 }
298 bad_rw_intr();
299 do_hd_request();
300 return;
301 }
302
303 static void write_intr(void)
304 {
305 int i;
306
307 i = (unsigned) inb_p(HD_STATUS);
308 if ((i & STAT_MASK) != STAT_OK) {
309 printk("HD: write_intr: status = 0x%02x\n",i);
310 goto bad_write;
311 }
312 if (CURRENT->nr_sectors > 1 && wait_DRQ()) {
313 printk("HD: write_intr: no DRQ\n");
314 goto bad_write;
315 }
316 CURRENT->sector++;
317 i = --CURRENT->nr_sectors;
318 --CURRENT->current_nr_sectors;
319 CURRENT->buffer += 512;
320 if (!i || (CURRENT->bh && !SUBSECTOR(i)))
321 end_request(1);
322 if (i > 0) {
323 SET_INTR(&write_intr);
324 port_write(HD_DATA,CURRENT->buffer,256);
325 sti();
326 } else {
327 #if (HD_DELAY > 0)
328 last_req = read_timer();
329 #endif
330 do_hd_request();
331 }
332 return;
333 bad_write:
334 sti();
335 if (i & ERR_STAT) {
336 i = (unsigned) inb(HD_ERROR);
337 printk("HD: write_intr: error = 0x%02x\n",i);
338 }
339 bad_rw_intr();
340 cli();
341 do_hd_request();
342 return;
343 }
344
345 static void recal_intr(void)
346 {
347 if (win_result())
348 bad_rw_intr();
349 do_hd_request();
350 }
351
352
353
354
355
356 static void hd_times_out(void)
357 {
358 DEVICE_INTR = NULL;
359 sti();
360 reset = 1;
361 if (!CURRENT)
362 return;
363 printk("HD timeout\n\r");
364 cli();
365 if (++CURRENT->errors >= MAX_ERRORS) {
366 #ifdef DEBUG
367 printk("hd : too many errors.\n");
368 #endif
369 end_request(0);
370 }
371
372 do_hd_request();
373 }
374
375
376
377
378
379
380
381
382 static void do_hd_request(void)
383 {
384 unsigned int block,dev;
385 unsigned int sec,head,cyl,track;
386 unsigned int nsect;
387
388 if (DEVICE_INTR)
389 return;
390 repeat:
391 timer_active &= ~(1<<HD_TIMER);
392 sti();
393 INIT_REQUEST;
394 dev = MINOR(CURRENT->dev);
395 block = CURRENT->sector;
396 nsect = CURRENT->nr_sectors;
397 if (dev >= (NR_HD<<6) || block >= hd[dev].nr_sects) {
398 #ifdef DEBUG
399 printk("hd%d : attempted read for sector %d past end of device at sector %d.\n",
400 block, hd[dev].nr_sects);
401 #endif
402 end_request(0);
403 goto repeat;
404 }
405 block += hd[dev].start_sect;
406 dev >>= 6;
407 sec = block % hd_info[dev].sect + 1;
408 track = block / hd_info[dev].sect;
409 head = track % hd_info[dev].head;
410 cyl = track / hd_info[dev].head;
411 #ifdef DEBUG
412 printk("hd%d : cyl = %d, head = %d, sector = %d, buffer = %08x\n",
413 dev, cyl, head, sec, CURRENT->buffer);
414 #endif
415 cli();
416 if (reset) {
417 int i;
418
419 for (i=0; i < NR_HD; i++)
420 recalibrate[i] = 1;
421 reset_hd();
422 sti();
423 return;
424 }
425 if (recalibrate[dev]) {
426 recalibrate[dev] = 0;
427 hd_out(dev,hd_info[dev].sect,0,0,0,WIN_RESTORE,&recal_intr);
428 if (reset)
429 goto repeat;
430 sti();
431 return;
432 }
433 if (CURRENT->cmd == WRITE) {
434 hd_out(dev,nsect,sec,head,cyl,WIN_WRITE,&write_intr);
435 if (reset)
436 goto repeat;
437 if (wait_DRQ()) {
438 printk("HD: do_hd_request: no DRQ\n");
439 bad_rw_intr();
440 goto repeat;
441 }
442 port_write(HD_DATA,CURRENT->buffer,256);
443 sti();
444 return;
445 }
446 if (CURRENT->cmd == READ) {
447 hd_out(dev,nsect,sec,head,cyl,WIN_READ,&read_intr);
448 if (reset)
449 goto repeat;
450 sti();
451 return;
452 }
453 panic("unknown hd-command");
454 }
455
456 static int hd_ioctl(struct inode * inode, struct file * file,
457 unsigned int cmd, unsigned int arg)
458 {
459 struct hd_geometry *loc = (void *) arg;
460 int dev;
461
462 if (!loc || !inode)
463 return -EINVAL;
464 dev = MINOR(inode->i_rdev) >> 6;
465 if (dev >= NR_HD)
466 return -EINVAL;
467 switch (cmd) {
468 case HDIO_REQ:
469 verify_area(loc, sizeof(*loc));
470 put_fs_byte(hd_info[dev].head,
471 (char *) &loc->heads);
472 put_fs_byte(hd_info[dev].sect,
473 (char *) &loc->sectors);
474 put_fs_word(hd_info[dev].cyl,
475 (short *) &loc->cylinders);
476 put_fs_long(hd[MINOR(inode->i_rdev)].start_sect,
477 (long *) &loc->start);
478 return 0;
479 RO_IOCTLS(inode->i_rdev,arg);
480 default:
481 return -EINVAL;
482 }
483 }
484
485
486
487
488
489 static void hd_release(struct inode * inode, struct file * file)
490 {
491 sync_dev(inode->i_rdev);
492 }
493
494 static void hd_geninit();
495
496 static struct gendisk hd_gendisk = {
497 MAJOR_NR,
498 "hd",
499 6,
500 1 << 6,
501 MAX_HD,
502 hd_geninit,
503 hd,
504 hd_sizes,
505 0,
506 (void *) hd_info,
507 NULL
508 };
509
510 static void hd_geninit(void)
511 {
512 int drive, i;
513 #ifndef HD_TYPE
514 extern struct drive_info drive_info;
515 void *BIOS = (void *) &drive_info;
516 int cmos_disks;
517
518 for (drive=0 ; drive<2 ; drive++) {
519 hd_info[drive].cyl = *(unsigned short *) BIOS;
520 hd_info[drive].head = *(unsigned char *) (2+BIOS);
521 hd_info[drive].wpcom = *(unsigned short *) (5+BIOS);
522 hd_info[drive].ctl = *(unsigned char *) (8+BIOS);
523 hd_info[drive].lzone = *(unsigned short *) (12+BIOS);
524 hd_info[drive].sect = *(unsigned char *) (14+BIOS);
525 BIOS += 16;
526 }
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550 if ((cmos_disks = CMOS_READ(0x12)) & 0xf0)
551 if (cmos_disks & 0x0f)
552 NR_HD = 2;
553 else
554 NR_HD = 1;
555 else
556 NR_HD = 0;
557 #endif
558
559 for (i = 0 ; i < NR_HD ; i++)
560 hd[i<<6].nr_sects = hd_info[i].head*
561 hd_info[i].sect*hd_info[i].cyl;
562
563 hd_gendisk.nr_real = NR_HD;
564 }
565
566 static struct file_operations hd_fops = {
567 NULL,
568 block_read,
569 block_write,
570 NULL,
571 NULL,
572 hd_ioctl,
573 NULL,
574 hd_release
575 };
576
577 static void hd_interrupt(int unused)
578 {
579 void (*handler)(void) = DEVICE_INTR;
580
581 DEVICE_INTR = NULL;
582 timer_active &= ~(1<<HD_TIMER);
583 if (!handler)
584 handler = unexpected_hd_interrupt;
585 handler();
586 sti();
587 }
588
589
590
591
592
593
594
595
596
597
598 static struct sigaction hd_sigaction = {
599 hd_interrupt,
600 0,
601 SA_INTERRUPT,
602 NULL
603 };
604
605 unsigned long hd_init(unsigned long mem_start, unsigned long mem_end)
606 {
607 blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
608 blkdev_fops[MAJOR_NR] = &hd_fops;
609 hd_gendisk.next = gendisk_head;
610 gendisk_head = &hd_gendisk;
611 if (irqaction(HD_IRQ,&hd_sigaction))
612 printk("Unable to get IRQ%d for the harddisk driver\n",HD_IRQ);
613 timer_table[HD_TIMER].fn = hd_times_out;
614 return mem_start;
615 }
616
617 #endif