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