|
|
1.1 root 1: /*
2: * linux/kernel/hd.c
3: *
4: * (C) 1991 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:
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: /* Max read/write errors/sector */
27: #define MAX_ERRORS 5
28: #define MAX_HD 2
29:
30: /*
31: * This struct defines the HD's and their types.
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: /* This may be used only once, enforced by 'static int callable' */
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); /* ok */
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++) /* nothing */;
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: /* nothing */ ;
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.