⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 hd.c.txt

📁 Linux块设备驱动分析与模拟实现
💻 TXT
📖 第 1 页 / 共 2 页
字号:
  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 + -