📄 hd.c.txt
字号:
1 /*
2 * linux/kernel/hd.c
3 *
4 * Copyright (C) 1991, 1992 Linus Torvalds
5 */
6
7 /*
8 * This is the low-level hd interrupt support. It traverses the
9 * request-list, using interrupts to jump between functions. As
10 * all the functions are called within interrupts, we may not
11 * sleep. Special care is recommended.
12 *
13 * modified by Drew Eckhardt to check nr of hd's from the CMOS.
14 *
15 * Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug
16 * in the early extended-partition checks and added DM partitions
17 */
18
19
20 #include <linux/errno.h>
21 #include <linux/signal.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 <linux/genhd.h>
28 #include <linux/config.h>
29
30 #define REALLY_SLOW_IO
31 #include <asm/system.h>
32 #include <asm/io.h>
33 #include <asm/segment.h>
34
35 #define MAJOR_NR HD_MAJOR
36 #include "blk.h"
37
38 #define HD_IRQ 14
39
40 static int revalidate_hddisk(int, int);
41
42 static inline unsigned char CMOS_READ(unsigned char addr)
43 {
44 outb_p(addr,0x70);
45 return inb_p(0x71);
46 }
47
48 #define HD_DELAY 0
49
50 #define MAX_ERRORS 16 /* Max read/write errors/sector */
51 #define RESET_FREQ 8 /* Reset controller every 8th retry */
52 #define RECAL_FREQ 4 /* Recalibrate every 4th retry */
53 #define MAX_HD 2
54
55 static void recal_intr(void);
56 static void bad_rw_intr(void);
57
58 static char recalibrate[ MAX_HD ] = { 0, };
59 static int access_count[MAX_HD] = {0, };
60 static char busy[MAX_HD] = {0, };
61 static struct wait_queue * busy_wait = NULL;
62
63 static int reset = 0;
64 static int hd_error = 0;
65
66 #if (HD_DELAY > 0)
67 unsigned long last_req, read_timer();
68 #endif
69
70 /*
71 * This struct defines the HD's and their types.
72 */
73 struct hd_i_struct {
74 unsigned int head,sect,cyl,wpcom,lzone,ctl;
75 };
76 #ifdef HD_TYPE
77 struct hd_i_struct hd_info[] = { HD_TYPE };
78 static int NR_HD = ((sizeof (hd_info))/(sizeof (struct hd_i_struct)));
79 #else
80 struct hd_i_struct hd_info[] = { {0,0,0,0,0,0},{0,0,0,0,0,0} };
81 static int NR_HD = 0;
82 #endif
83
84 static struct hd_struct hd[MAX_HD<<6]={{0,0},};
85 static int hd_sizes[MAX_HD<<6] = {0, };
86 static int hd_blocksizes[MAX_HD<<6] = {0, };
87
88 #if (HD_DELAY > 0)
89 unsigned long read_timer(void)
90 {
91 unsigned long t;
92 int i;
93
94 cli();
95 t = jiffies * 11932;
96 outb_p(0, 0x43);
97 i = inb_p(0x40);
98 i |= inb(0x40) << 8;
99 sti();
100 return(t - i);
101 }
102 #endif
103
104 void hd_setup(char *str, int *ints)
105 {
106 int hdind = 0;
107
108 if (ints[0] != 3)
109 return;
110 if (hd_info[0].head != 0)
111 hdind=1;
112 hd_info[hdind].head = ints[2];
113 hd_info[hdind].sect = ints[3];
114 hd_info[hdind].cyl = ints[1];
115 hd_info[hdind].wpcom = 0;
116 hd_info[hdind].lzone = ints[1];
117 hd_info[hdind].ctl = (ints[2] > 8 ? 8 : 0);
118 NR_HD = hdind+1;
119 }
120
121 static int win_result(void)
122 {
123 int i=inb_p(HD_STATUS);
124
125 if ((i & (BUSY_STAT | READY_STAT | WRERR_STAT | SEEK_STAT | ERR_STAT))
126 == (READY_STAT | SEEK_STAT)) {
127 hd_error = 0;
128 return 0; /* ok */
129 }
130 printk("HD: win_result: status = 0x%02x\n",i);
131 if (i&1) {
132 hd_error = inb(HD_ERROR);
133 printk("HD: win_result: error = 0x%02x\n",hd_error);
134 }
135 return 1;
136 }
137
138 static int controller_busy(void);
139 static int status_ok(void);
140
141 static int controller_ready(unsigned int drive, unsigned int head)
142 {
143 int retry = 100;
144
145 do {
146 if (controller_busy() & BUSY_STAT)
147 return 0;
148 outb_p(0xA0 | (drive<<4) | head, HD_CURRENT);
149 if (status_ok())
150 return 1;
151 } while (--retry);
152 return 0;
153 }
154
155 static int status_ok(void)
156 {
157 unsigned char status = inb_p(HD_STATUS);
158
159 if (status & BUSY_STAT)
160 return 1;
161 if (status & WRERR_STAT)
162 return 0;
163 if (!(status & READY_STAT))
164 return 0;
165 if (!(status & SEEK_STAT))
166 return 0;
167 return 1;
168 }
169
170 static int controller_busy(void)
171 {
172 int retries = 100000;
173 unsigned char status;
174
175 do {
176 status = inb_p(HD_STATUS);
177 } while ((status & BUSY_STAT) && --retries);
178 return status;
179 }
180
181 static void hd_out(unsigned int drive,unsigned int nsect,unsigned int sect,
182 unsigned int head,unsigned int cyl,unsigned int cmd,
183 void (*intr_addr)(void))
184 {
185 unsigned short port;
186
187 if (drive>1 || head>15)
188 panic("Trying to write bad sector");
189 #if (HD_DELAY > 0)
190 while (read_timer() - last_req < HD_DELAY)
191 /* nothing */;
192 #endif
193 if (reset)
194 return;
195 if (!controller_ready(drive, head)) {
196 reset = 1;
197 return;
198 }
199 SET_INTR(intr_addr);
200 outb_p(hd_info[drive].ctl,HD_CMD);
201 port=HD_DATA;
202 outb_p(hd_info[drive].wpcom>>2,++port);
203 outb_p(nsect,++port);
204 outb_p(sect,++port);
205 outb_p(cyl,++port);
206 outb_p(cyl>>8,++port);
207 outb_p(0xA0|(drive<<4)|head,++port);
208 outb_p(cmd,++port);
209 }
210
211 static int drive_busy(void)
212 {
213 unsigned int i;
214 unsigned char c;
215
216 for (i = 0; i < 500000 ; i++) {
217 c = inb_p(HD_STATUS);
218 c &= (BUSY_STAT | READY_STAT | SEEK_STAT);
219 if (c == (READY_STAT | SEEK_STAT))
220 return 0;
221 }
222 printk("HD controller times out, status = 0x%02x\n",c);
223 return 1;
224 }
225
226 static void reset_controller(void)
227 {
228 int i;
229
230 printk(KERN_DEBUG "HD-controller reset\n");
231 outb_p(4,HD_CMD);
232 for(i = 0; i < 1000; i++) nop();
233 outb(hd_info[0].ctl & 0x0f ,HD_CMD);
234 if (drive_busy())
235 printk("HD-controller still busy\n");
236 if ((hd_error = inb(HD_ERROR)) != 1)
237 printk("HD-controller reset failed: %02x\n",hd_error);
238 }
239
240 static void reset_hd(void)
241 {
242 static int i;
243
244 repeat:
245 if (reset) {
246 reset = 0;
247 i = -1;
248 reset_controller();
249 } else if (win_result()) {
250 bad_rw_intr();
251 if (reset)
252 goto repeat;
253 }
254 i++;
255 if (i < NR_HD) {
256 hd_out(i,hd_info[i].sect,hd_info[i].sect,hd_info[i].head-1,
257 hd_info[i].cyl,WIN_SPECIFY,&reset_hd);
258 if (reset)
259 goto repeat;
260 } else
261 do_hd_request();
262 }
263
264 /*
265 * Ok, don't know what to do with the unexpected interrupts: on some machines
266 * doing a reset and a retry seems to result in an eternal loop. Right now I
267 * ignore it, and just set the timeout.
268 */
269 void unexpected_hd_interrupt(void)
270 {
271 sti();
272 printk(KERN_DEBUG "Unexpected HD interrupt\n");
273 SET_TIMER;
274 }
275
276 /*
277 * bad_rw_intr() now tries to be a bit smarter and does things
278 * according to the error returned by the controller.
279 * -Mika Liljeberg (liljeber@cs.Helsinki.FI)
280 */
281 static void bad_rw_intr(void)
282 {
283 int dev;
284
285 if (!CURRENT)
286 return;
287 dev = MINOR(CURRENT->dev) >> 6;
288 if (++CURRENT->errors >= MAX_ERRORS || (hd_error & BBD_ERR)) {
289 end_request(0);
290 recalibrate[dev] = 1;
291 } else if (CURRENT->errors % RESET_FREQ == 0)
292 reset = 1;
293 else if ((hd_error & TRK0_ERR) || CURRENT->errors % RECAL_FREQ == 0)
294 recalibrate[dev] = 1;
295 /* Otherwise just retry */
296 }
297
298 static inline int wait_DRQ(void)
299 {
300 int retries = 100000;
301
302 while (--retries > 0)
303 if (inb_p(HD_STATUS) & DRQ_STAT)
304 return 0;
305 return -1;
306 }
307
308 #define STAT_MASK (BUSY_STAT | READY_STAT | WRERR_STAT | SEEK_STAT | ERR_STAT)
309 #define STAT_OK (READY_STAT | SEEK_STAT)
310
311 static void read_intr(void)
312 {
313 int i;
314 int retries = 100000;
315
316 do {
317 i = (unsigned) inb_p(HD_STATUS);
318 if (i & BUSY_STAT)
319 continue;
320 if ((i & STAT_MASK) != STAT_OK)
321 break;
322 if (i & DRQ_STAT)
323 goto ok_to_read;
324 } while (--retries > 0);
325 sti();
326 printk("HD: read_intr: status = 0x%02x\n",i);
327 if (i & ERR_STAT) {
328 hd_error = (unsigned) inb(HD_ERROR);
329 printk("HD: read_intr: error = 0x%02x\n",hd_error);
330 }
331 bad_rw_intr();
332 cli();
333 do_hd_request();
334 return;
335 ok_to_read:
336 insw(HD_DATA,CURRENT->buffer,256);
337 CURRENT->errors = 0;
338 CURRENT->buffer += 512;
339 CURRENT->sector++;
340 i = --CURRENT->nr_sectors;
341 --CURRENT->current_nr_sectors;
342 #ifdef DEBUG
343 printk("hd%d : sector = %d, %d remaining to buffer = %08x\n",
344 MINOR(CURRENT->dev), CURRENT->sector, i, CURRENT->
345 buffer);
346 #endif
347 if (!i || (CURRENT->bh && !SUBSECTOR(i)))
348 end_request(1);
349 if (i > 0) {
350 SET_INTR(&read_intr);
351 sti();
352 return;
353 }
354 (void) inb_p(HD_STATUS);
355 #if (HD_DELAY > 0)
356 last_req = read_timer();
357 #endif
358 do_hd_request();
359 return;
360 }
361
362 static void write_intr(void)
363 {
364 int i;
365 int retries = 100000;
366
367 do {
368 i = (unsigned) inb_p(HD_STATUS);
369 if (i & BUSY_STAT)
370 continue;
371 if ((i & STAT_MASK) != STAT_OK)
372 break;
373 if ((CURRENT->nr_sectors <= 1) || (i & DRQ_STAT))
374 goto ok_to_write;
375 } while (--retries > 0);
376 sti();
377 printk("HD: write_intr: status = 0x%02x\n",i);
378 if (i & ERR_STAT) {
379 hd_error = (unsigned) inb(HD_ERROR);
380 printk("HD: write_intr: error = 0x%02x\n",hd_error);
381 }
382 bad_rw_intr();
383 cli();
384 do_hd_request();
385 return;
386 ok_to_write:
387 CURRENT->sector++;
388 i = --CURRENT->nr_sectors;
389 --CURRENT->current_nr_sectors;
390 CURRENT->buffer += 512;
391 if (!i || (CURRENT->bh && !SUBSECTOR(i)))
392 end_request(1);
393 if (i > 0) {
394 SET_INTR(&write_intr);
395 outsw(HD_DATA,CURRENT->buffer,256);
396 sti();
397 } else {
398 #if (HD_DELAY > 0)
399 last_req = read_timer();
400 #endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -