This source file includes following definitions.
- sys_setup
- controller_ready
- win_result
- hd_out
- drive_busy
- reset_controller
- redo_hd_request
- reset_hd
- unexpected_hd_interrupt
- bad_rw_intr
- read_intr
- write_intr
- do_hd_request
- hd_init
1
2
3
4
5
6
7
8
9
10
11
12
13
14 #include <linux/config.h>
15 #include <linux/sched.h>
16 #include <linux/fs.h>
17 #include <linux/kernel.h>
18 #include <linux/hdreg.h>
19 #include <asm/system.h>
20 #include <asm/io.h>
21 #include <asm/segment.h>
22
23 #define MAJOR_NR 3
24 #include "blk.h"
25
26
27 #define MAX_ERRORS 5
28 #define MAX_HD 2
29
30
31
32
33 struct hd_i_struct {
34 int head,sect,cyl,wpcom,lzone,ctl;
35 };
36 #ifdef HD_TYPE
37 struct hd_i_struct hd_info[] = { HD_TYPE };
38 #define NR_HD ((sizeof (hd_info))/(sizeof (struct hd_i_struct)))
39 #else
40 struct hd_i_struct hd_info[] = { {0,0,0,0,0,0},{0,0,0,0,0,0} };
41 static int NR_HD = 0;
42 #endif
43
44 static struct hd_struct {
45 long start_sect;
46 long nr_sects;
47 } hd[5*MAX_HD]={{0,0},};
48
49 #define port_read(port,buf,nr) \
50 __asm__("cld;rep;insw"::"d" (port),"D" (buf),"c" (nr):"cx","di")
51
52 #define port_write(port,buf,nr) \
53 __asm__("cld;rep;outsw"::"d" (port),"S" (buf),"c" (nr):"cx","si")
54
55 extern void hd_interrupt(void);
56
57
58 int sys_setup(void * BIOS)
59 {
60 static int callable = 1;
61 int i,drive;
62 struct partition *p;
63 struct buffer_head * bh;
64
65 if (!callable)
66 return -1;
67 callable = 0;
68 #ifndef HD_TYPE
69 for (drive=0 ; drive<2 ; drive++) {
70 hd_info[drive].cyl = *(unsigned short *) BIOS;
71 hd_info[drive].head = *(unsigned char *) (2+BIOS);
72 hd_info[drive].wpcom = *(unsigned short *) (5+BIOS);
73 hd_info[drive].ctl = *(unsigned char *) (8+BIOS);
74 hd_info[drive].lzone = *(unsigned short *) (12+BIOS);
75 hd_info[drive].sect = *(unsigned char *) (14+BIOS);
76 BIOS += 16;
77 }
78 if (hd_info[1].cyl)
79 NR_HD=2;
80 else
81 NR_HD=1;
82 #endif
83 for (i=0 ; i<NR_HD ; i++) {
84 hd[i*5].start_sect = 0;
85 hd[i*5].nr_sects = hd_info[i].head*
86 hd_info[i].sect*hd_info[i].cyl;
87 }
88 for (drive=0 ; drive<NR_HD ; drive++) {
89 if (!(bh = bread(0x300 + drive*5,0))) {
90 printk("Unable to read partition table of drive %d\n\r",
91 drive);
92 panic("");
93 }
94 if (bh->b_data[510] != 0x55 || (unsigned char)
95 bh->b_data[511] != 0xAA) {
96 printk("Bad partition table on drive %d\n\r",drive);
97 panic("");
98 }
99 p = 0x1BE + (void *)bh->b_data;
100 for (i=1;i<5;i++,p++) {
101 hd[i+5*drive].start_sect = p->start_sect;
102 hd[i+5*drive].nr_sects = p->nr_sects;
103 }
104 brelse(bh);
105 }
106 printk("Partition table%s ok.\n\r",(NR_HD>1)?"s":"");
107 mount_root();
108 return (0);
109 }
110
111 static int controller_ready(void)
112 {
113 int retries=1000;
114
115 while (--retries && (inb(HD_STATUS)&0xc0)!=0x40);
116 return (retries);
117 }
118
119 static int win_result(void)
120 {
121 int i=inb(HD_STATUS);
122
123 if ((i & (BUSY_STAT | READY_STAT | WRERR_STAT | SEEK_STAT | ERR_STAT))
124 == (READY_STAT | SEEK_STAT))
125 return(0);
126 if (i&1) i=inb(HD_ERROR);
127 return (1);
128 }
129
130 static void hd_out(unsigned int drive,unsigned int nsect,unsigned int sect,
131 unsigned int head,unsigned int cyl,unsigned int cmd,
132 void (*intr_addr)(void))
133 {
134 register int port asm("dx");
135
136 if (drive>1 || head>15)
137 panic("Trying to write bad sector");
138 if (!controller_ready())
139 panic("HD controller not ready");
140 do_hd = intr_addr;
141 outb(hd_info[drive].ctl,HD_CMD);
142 port=HD_DATA;
143 outb_p(hd_info[drive].wpcom>>2,++port);
144 outb_p(nsect,++port);
145 outb_p(sect,++port);
146 outb_p(cyl,++port);
147 outb_p(cyl>>8,++port);
148 outb_p(0xA0|(drive<<4)|head,++port);
149 outb(cmd,++port);
150 }
151
152 static int drive_busy(void)
153 {
154 unsigned int i;
155
156 for (i = 0; i < 100000; i++)
157 if (READY_STAT == (inb(HD_STATUS) & (BUSY_STAT | READY_STAT)))
158 break;
159 i = inb(HD_STATUS);
160 i &= BUSY_STAT | READY_STAT | SEEK_STAT;
161 if (i == READY_STAT | SEEK_STAT)
162 return(0);
163 printk("HD controller times out\n\r");
164 return(1);
165 }
166
167 static void reset_controller(void)
168 {
169 int i;
170
171 outb(4,HD_CMD);
172 for(i = 0; i < 1000; i++) nop();
173 outb(0,HD_CMD);
174 for(i = 0; i < 10000 && drive_busy(); i++) ;
175 if (drive_busy())
176 printk("HD-controller still busy\n\r");
177 if((i = inb(ERR_STAT)) != 1)
178 printk("HD-controller reset failed: %02x\n\r",i);
179 }
180
181 static void redo_hd_request(void)
182 {
183 do_hd = NULL;
184 do_hd_request();
185 }
186
187 static void reset_hd(int nr)
188 {
189 reset_controller();
190 hd_out(nr,hd_info[nr].sect,hd_info[nr].sect,hd_info[nr].head-1,
191 hd_info[nr].cyl,WIN_SPECIFY,&redo_hd_request);
192 }
193
194 void unexpected_hd_interrupt(void)
195 {
196 printk("Unexpected HD interrupt\n\r");
197 }
198
199 static void bad_rw_intr(void)
200 {
201 int i = CURRENT_DEV;
202
203 if (CURRENT->errors++ >= MAX_ERRORS)
204 end_request(0);
205 reset_hd(i);
206 }
207
208 static void read_intr(void)
209 {
210 if (win_result()) {
211 bad_rw_intr();
212 return;
213 }
214 port_read(HD_DATA,CURRENT->buffer,256);
215 CURRENT->errors = 0;
216 CURRENT->buffer += 512;
217 CURRENT->sector++;
218 if (--CURRENT->nr_sectors)
219 return;
220 end_request(1);
221 do_hd_request();
222 }
223
224 static void write_intr(void)
225 {
226 if (win_result()) {
227 bad_rw_intr();
228 return;
229 }
230 if (--CURRENT->nr_sectors) {
231 CURRENT->sector++;
232 CURRENT->buffer += 512;
233 port_write(HD_DATA,CURRENT->buffer,256);
234 return;
235 }
236 end_request(1);
237 do_hd_request();
238 }
239
240 void do_hd_request(void)
241 {
242 int i,r;
243 unsigned int block,dev;
244 unsigned int sec,head,cyl;
245 unsigned int nsect;
246
247 INIT_REQUEST;
248 dev = MINOR(CURRENT->dev);
249 block = CURRENT->sector;
250 if (dev >= 5*NR_HD || block+2 > hd[dev].nr_sects) {
251 end_request(0);
252 goto repeat;
253 }
254 block += hd[dev].start_sect;
255 dev /= 5;
256 __asm__("divl %4":"=a" (block),"=d" (sec):"0" (block),"1" (0),
257 "r" (hd_info[dev].sect));
258 __asm__("divl %4":"=a" (cyl),"=d" (head):"0" (block),"1" (0),
259 "r" (hd_info[dev].head));
260 sec++;
261 nsect = CURRENT->nr_sectors;
262 if (CURRENT->cmd == WRITE) {
263 hd_out(dev,nsect,sec,head,cyl,WIN_WRITE,&write_intr);
264 for(i=0 ; i<3000 && !(r=inb_p(HD_STATUS)&DRQ_STAT) ; i++)
265 ;
266 if (!r) {
267 reset_hd(CURRENT_DEV);
268 return;
269 }
270 port_write(HD_DATA,CURRENT->buffer,256);
271 } else if (CURRENT->cmd == READ) {
272 hd_out(dev,nsect,sec,head,cyl,WIN_READ,&read_intr);
273 } else
274 panic("unknown hd-command");
275 }
276
277 void hd_init(void)
278 {
279 blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
280 set_trap_gate(0x2E,&hd_interrupt);
281 outb_p(inb_p(0x21)&0xfb,0x21);
282 outb(inb_p(0xA1)&0xbf,0xA1);
283 }