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