This source file includes following definitions.
- CMOS_READ
- 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_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 #include <linux/sched.h>
21 #include <linux/timer.h>
22 #include <linux/fs.h>
23 #include <linux/kernel.h>
24 #include <linux/hdreg.h>
25 #include <asm/system.h>
26 #include <asm/io.h>
27 #include <asm/segment.h>
28
29 #define MAJOR_NR 3
30 #include "blk.h"
31
32 static inline unsigned char CMOS_READ(unsigned char addr)
33 {
34 outb_p(0x80|addr,0x70);
35 return inb_p(0x71);
36 }
37
38
39 #define MAX_ERRORS 7
40 #define MAX_HD 2
41
42 static void recal_intr(void);
43 static void bad_rw_intr(void);
44
45 static int recalibrate = 0;
46 static int reset = 1;
47
48
49
50
51 struct hd_i_struct {
52 unsigned int head,sect,cyl,wpcom,lzone,ctl;
53 };
54 #ifdef HD_TYPE
55 struct hd_i_struct hd_info[] = { HD_TYPE };
56 #define NR_HD ((sizeof (hd_info))/(sizeof (struct hd_i_struct)))
57 #else
58 struct hd_i_struct hd_info[] = { {0,0,0,0,0,0},{0,0,0,0,0,0} };
59 static int NR_HD = 0;
60 #endif
61
62 static struct hd_struct {
63 long start_sect;
64 long nr_sects;
65 } hd[MAX_HD<<6]={{0,0},};
66
67 static int hd_sizes[MAX_HD<<6] = {0, };
68
69 #define port_read(port,buf,nr) \
70 __asm__("cld;rep;insw"::"d" (port),"D" (buf),"c" (nr):"cx","di")
71
72 #define port_write(port,buf,nr) \
73 __asm__("cld;rep;outsw"::"d" (port),"S" (buf),"c" (nr):"cx","si")
74
75 extern void hd_interrupt(void);
76 extern void rd_load(void);
77
78 static unsigned int current_minor;
79
80 static void check_partition(unsigned int dev)
81 {
82 int minor, i;
83 struct buffer_head *bh;
84 struct partition *p;
85
86 if (!(bh = bread(dev,0))) {
87 printk("Unable to read partition table of device %04x\n",dev);
88 return;
89 }
90 minor = current_minor;
91 if (*(unsigned short *) (bh->b_data+510) == 0xAA55) {
92 p = 0x1BE + (void *)bh->b_data;
93 for (i=0 ; i<4 ; i++,p++) {
94 if (!(hd[i+minor].nr_sects = p->nr_sects))
95 continue;
96 hd[i+minor].start_sect = p->start_sect;
97 if ((current_minor & 0x3f) >= 60)
98 continue;
99 if (p->sys_ind == EXTENDED_PARTITION) {
100 current_minor += 4;
101 check_partition(0x0300 | (i+minor));
102 }
103 }
104
105
106
107 if (*(unsigned short *) (bh->b_data+0xfc) == 0x55AA) {
108 p = 0x1BE + (void *)bh->b_data;
109 for (i=4; i<16; i++) {
110 p--;
111 if ((current_minor & 0x3f) >= 60)
112 break;
113 if (!(hd[current_minor+4].start_sect = p->start_sect))
114 continue;
115 hd[current_minor+4].nr_sects = p->nr_sects;
116 current_minor++;
117 }
118 }
119 } else
120 printk("Bad partition table on dev %04x\n",dev);
121 brelse(bh);
122 }
123
124
125 int sys_setup(void * BIOS)
126 {
127 static int callable = 1;
128 int i,drive;
129 unsigned char cmos_disks;
130
131 if (!callable)
132 return -1;
133 callable = 0;
134 #ifndef HD_TYPE
135 for (drive=0 ; drive<2 ; drive++) {
136 hd_info[drive].cyl = *(unsigned short *) BIOS;
137 hd_info[drive].head = *(unsigned char *) (2+BIOS);
138 hd_info[drive].wpcom = *(unsigned short *) (5+BIOS);
139 hd_info[drive].ctl = *(unsigned char *) (8+BIOS);
140 hd_info[drive].lzone = *(unsigned short *) (12+BIOS);
141 hd_info[drive].sect = *(unsigned char *) (14+BIOS);
142 BIOS += 16;
143 }
144 if (hd_info[1].cyl)
145 NR_HD=2;
146 else
147 NR_HD=1;
148 #endif
149 for (i=0 ; i<NR_HD ; i++) {
150 hd[i<<6].start_sect = 0;
151 hd[i<<6].nr_sects = hd_info[i].head*
152 hd_info[i].sect*hd_info[i].cyl;
153 }
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177 if ((cmos_disks = CMOS_READ(0x12)) & 0xf0)
178 if (cmos_disks & 0x0f)
179 NR_HD = 2;
180 else
181 NR_HD = 1;
182 else
183 NR_HD = 0;
184 for (i = NR_HD ; i < 2 ; i++) {
185 hd[i<<6].start_sect = 0;
186 hd[i<<6].nr_sects = 0;
187 }
188 for (drive=0 ; drive<NR_HD ; drive++) {
189 current_minor = 1+(drive<<6);
190 check_partition(0x0300+(drive<<6));
191 }
192 for (i=0 ; i<(MAX_HD<<6) ; i++)
193 hd_sizes[i] = hd[i].nr_sects>>1 ;
194 blk_size[MAJOR_NR] = hd_sizes;
195 if (NR_HD)
196 printk("Partition table%s ok.\n\r",(NR_HD>1)?"s":"");
197 rd_load();
198 mount_root();
199 return (0);
200 }
201
202 static int controller_ready(void)
203 {
204 int retries = 100000;
205
206 while (--retries && (inb_p(HD_STATUS)&0x80))
207 ;
208 if (!retries)
209 printk("controller_ready: status = %02x\n\r",
210 (unsigned char) inb_p(HD_STATUS));
211 return (retries);
212 }
213
214 static int win_result(void)
215 {
216 int i=inb_p(HD_STATUS);
217
218 if ((i & (BUSY_STAT | READY_STAT | WRERR_STAT | SEEK_STAT | ERR_STAT))
219 == (READY_STAT | SEEK_STAT))
220 return(0);
221 if (i&1)
222 i=inb(HD_ERROR);
223 return (1);
224 }
225
226 static void hd_out(unsigned int drive,unsigned int nsect,unsigned int sect,
227 unsigned int head,unsigned int cyl,unsigned int cmd,
228 void (*intr_addr)(void))
229 {
230 unsigned short port;
231
232 if (drive>1 || head>15)
233 panic("Trying to write bad sector");
234 if (reset || !controller_ready()) {
235 reset = 1;
236 return;
237 }
238 SET_INTR(intr_addr);
239 outb_p(hd_info[drive].ctl,HD_CMD);
240 port=HD_DATA;
241 outb_p(hd_info[drive].wpcom>>2,++port);
242 outb_p(nsect,++port);
243 outb_p(sect,++port);
244 outb_p(cyl,++port);
245 outb_p(cyl>>8,++port);
246 outb_p(0xA0|(drive<<4)|head,++port);
247 outb(cmd,++port);
248 }
249
250 static int drive_busy(void)
251 {
252 unsigned int i;
253 unsigned char c;
254
255 for (i = 0; i < 50000; i++) {
256 c = inb_p(HD_STATUS);
257 c &= (BUSY_STAT | READY_STAT | SEEK_STAT);
258 if (c == (READY_STAT | SEEK_STAT))
259 return 0;
260 }
261 printk("HD controller times out, c=%02x\n\r",c);
262 return(1);
263 }
264
265 static void reset_controller(void)
266 {
267 int i;
268
269 outb(4,HD_CMD);
270 for(i = 0; i < 1000; i++) nop();
271 outb(hd_info[0].ctl & 0x0f ,HD_CMD);
272 if (drive_busy())
273 printk("HD-controller still busy\n\r");
274 if ((i = inb(HD_ERROR)) != 1)
275 printk("HD-controller reset failed: %02x\n\r",i);
276 }
277
278 static void reset_hd(void)
279 {
280 static int i;
281
282 repeat:
283 if (reset) {
284 reset = 0;
285 i = -1;
286 reset_controller();
287 } else if (win_result()) {
288 bad_rw_intr();
289 if (reset)
290 goto repeat;
291 }
292 i++;
293 if (i < NR_HD) {
294 hd_out(i,hd_info[i].sect,hd_info[i].sect,hd_info[i].head-1,
295 hd_info[i].cyl,WIN_SPECIFY,&reset_hd);
296 if (reset)
297 goto repeat;
298 } else
299 do_hd_request();
300 }
301
302 void unexpected_hd_interrupt(void)
303 {
304 printk("Unexpected HD interrupt\n\r");
305 reset = 1;
306 do_hd_request();
307 }
308
309 static void bad_rw_intr(void)
310 {
311 if (++CURRENT->errors >= MAX_ERRORS)
312 end_request(0);
313 if (CURRENT->errors > MAX_ERRORS/2)
314 reset = 1;
315 else
316 recalibrate = 1;
317 }
318
319 static void read_intr(void)
320 {
321 SET_INTR(&read_intr);
322 if (win_result()) {
323 SET_INTR(NULL);
324 bad_rw_intr();
325 do_hd_request();
326 return;
327 }
328 port_read(HD_DATA,CURRENT->buffer,256);
329 CURRENT->errors = 0;
330 CURRENT->buffer += 512;
331 CURRENT->sector++;
332 if (--CURRENT->nr_sectors)
333 return;
334 SET_INTR(NULL);
335 end_request(1);
336 do_hd_request();
337 }
338
339 static void write_intr(void)
340 {
341 if (win_result()) {
342 bad_rw_intr();
343 do_hd_request();
344 return;
345 }
346 if (--CURRENT->nr_sectors) {
347 CURRENT->sector++;
348 CURRENT->buffer += 512;
349 SET_INTR(&write_intr);
350 port_write(HD_DATA,CURRENT->buffer,256);
351 return;
352 }
353 end_request(1);
354 do_hd_request();
355 }
356
357 static void recal_intr(void)
358 {
359 if (win_result())
360 bad_rw_intr();
361 do_hd_request();
362 }
363
364 static void hd_times_out(void)
365 {
366 do_hd = NULL;
367 reset = 1;
368 if (!CURRENT)
369 return;
370 printk("HD timeout");
371 if (++CURRENT->errors >= MAX_ERRORS)
372 end_request(0);
373 do_hd_request();
374 }
375
376 void do_hd_request(void)
377 {
378 int i,r;
379 unsigned int block,dev;
380 unsigned int sec,head,cyl;
381 unsigned int nsect;
382
383 INIT_REQUEST;
384 dev = MINOR(CURRENT->dev);
385 block = CURRENT->sector;
386 nsect = CURRENT->nr_sectors;
387 if (dev >= (NR_HD<<6) || block+nsect > hd[dev].nr_sects) {
388 end_request(0);
389 goto repeat;
390 }
391 block += hd[dev].start_sect;
392 dev >>= 6;
393 sec = block % hd_info[dev].sect;
394 block /= hd_info[dev].sect;
395 head = block % hd_info[dev].head;
396 cyl = block / hd_info[dev].head;
397 sec++;
398 if (reset) {
399 recalibrate = 1;
400 reset_hd();
401 return;
402 }
403 if (recalibrate) {
404 recalibrate = 0;
405 hd_out(dev,hd_info[dev].sect,0,0,0,
406 WIN_RESTORE,&recal_intr);
407 if (reset)
408 goto repeat;
409 return;
410 }
411 if (CURRENT->cmd == WRITE) {
412 hd_out(dev,nsect,sec,head,cyl,WIN_WRITE,&write_intr);
413 if (reset)
414 goto repeat;
415 for(i=0 ; i<10000 && !(r=inb_p(HD_STATUS)&DRQ_STAT) ; i++)
416 ;
417 if (!r) {
418 bad_rw_intr();
419 goto repeat;
420 }
421 port_write(HD_DATA,CURRENT->buffer,256);
422 } else if (CURRENT->cmd == READ) {
423 hd_out(dev,nsect,sec,head,cyl,WIN_READ,&read_intr);
424 if (reset)
425 goto repeat;
426 } else
427 panic("unknown hd-command");
428 }
429
430 void hd_init(void)
431 {
432 blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
433 set_intr_gate(0x2E,&hd_interrupt);
434 outb_p(inb_p(0x21)&0xfb,0x21);
435 outb(inb_p(0xA1)&0xbf,0xA1);
436 timer_table[HD_TIMER].fn = hd_times_out;
437 }