|
|
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.
1.1.1.2 ! root 12: *
! 13: * modified by Drew Eckhardt to check nr of hd's from the CMOS.
1.1 root 14: */
15:
16: #include <linux/config.h>
17: #include <linux/sched.h>
18: #include <linux/fs.h>
19: #include <linux/kernel.h>
20: #include <linux/hdreg.h>
21: #include <asm/system.h>
22: #include <asm/io.h>
23: #include <asm/segment.h>
24:
25: #define MAJOR_NR 3
26: #include "blk.h"
27:
1.1.1.2 ! root 28: #define CMOS_READ(addr) ({ \
! 29: outb_p(0x80|addr,0x70); \
! 30: inb_p(0x71); \
! 31: })
! 32:
1.1 root 33: /* Max read/write errors/sector */
1.1.1.2 ! root 34: #define MAX_ERRORS 7
1.1 root 35: #define MAX_HD 2
36:
1.1.1.2 ! root 37: static void recal_intr(void);
! 38:
! 39: static int recalibrate = 1;
! 40: static int reset = 1;
! 41:
1.1 root 42: /*
43: * This struct defines the HD's and their types.
44: */
45: struct hd_i_struct {
46: int head,sect,cyl,wpcom,lzone,ctl;
47: };
48: #ifdef HD_TYPE
49: struct hd_i_struct hd_info[] = { HD_TYPE };
50: #define NR_HD ((sizeof (hd_info))/(sizeof (struct hd_i_struct)))
51: #else
52: struct hd_i_struct hd_info[] = { {0,0,0,0,0,0},{0,0,0,0,0,0} };
53: static int NR_HD = 0;
54: #endif
55:
56: static struct hd_struct {
57: long start_sect;
58: long nr_sects;
59: } hd[5*MAX_HD]={{0,0},};
60:
61: #define port_read(port,buf,nr) \
62: __asm__("cld;rep;insw"::"d" (port),"D" (buf),"c" (nr):"cx","di")
63:
64: #define port_write(port,buf,nr) \
65: __asm__("cld;rep;outsw"::"d" (port),"S" (buf),"c" (nr):"cx","si")
66:
67: extern void hd_interrupt(void);
1.1.1.2 ! root 68: extern void rd_load(void);
1.1 root 69:
70: /* This may be used only once, enforced by 'static int callable' */
71: int sys_setup(void * BIOS)
72: {
73: static int callable = 1;
74: int i,drive;
1.1.1.2 ! root 75: unsigned char cmos_disks;
1.1 root 76: struct partition *p;
77: struct buffer_head * bh;
78:
79: if (!callable)
80: return -1;
81: callable = 0;
82: #ifndef HD_TYPE
83: for (drive=0 ; drive<2 ; drive++) {
84: hd_info[drive].cyl = *(unsigned short *) BIOS;
85: hd_info[drive].head = *(unsigned char *) (2+BIOS);
86: hd_info[drive].wpcom = *(unsigned short *) (5+BIOS);
87: hd_info[drive].ctl = *(unsigned char *) (8+BIOS);
88: hd_info[drive].lzone = *(unsigned short *) (12+BIOS);
89: hd_info[drive].sect = *(unsigned char *) (14+BIOS);
90: BIOS += 16;
91: }
92: if (hd_info[1].cyl)
93: NR_HD=2;
94: else
95: NR_HD=1;
96: #endif
97: for (i=0 ; i<NR_HD ; i++) {
98: hd[i*5].start_sect = 0;
99: hd[i*5].nr_sects = hd_info[i].head*
100: hd_info[i].sect*hd_info[i].cyl;
101: }
1.1.1.2 ! root 102:
! 103: /*
! 104: We querry CMOS about hard disks : it could be that
! 105: we have a SCSI/ESDI/etc controller that is BIOS
! 106: compatable with ST-506, and thus showing up in our
! 107: BIOS table, but not register compatable, and therefore
! 108: not present in CMOS.
! 109:
! 110: Furthurmore, we will assume that our ST-506 drives
! 111: <if any> are the primary drives in the system, and
! 112: the ones reflected as drive 1 or 2.
! 113:
! 114: The first drive is stored in the high nibble of CMOS
! 115: byte 0x12, the second in the low nibble. This will be
! 116: either a 4 bit drive type or 0xf indicating use byte 0x19
! 117: for an 8 bit type, drive 1, 0x1a for drive 2 in CMOS.
! 118:
! 119: Needless to say, a non-zero value means we have
! 120: an AT controller hard disk for that drive.
! 121:
! 122:
! 123: */
! 124:
! 125: if ((cmos_disks = CMOS_READ(0x12)) & 0xf0)
! 126: if (cmos_disks & 0x0f)
! 127: NR_HD = 2;
! 128: else
! 129: NR_HD = 1;
! 130: else
! 131: NR_HD = 0;
! 132: for (i = NR_HD ; i < 2 ; i++) {
! 133: hd[i*5].start_sect = 0;
! 134: hd[i*5].nr_sects = 0;
! 135: }
1.1 root 136: for (drive=0 ; drive<NR_HD ; drive++) {
137: if (!(bh = bread(0x300 + drive*5,0))) {
138: printk("Unable to read partition table of drive %d\n\r",
139: drive);
140: panic("");
141: }
142: if (bh->b_data[510] != 0x55 || (unsigned char)
143: bh->b_data[511] != 0xAA) {
144: printk("Bad partition table on drive %d\n\r",drive);
145: panic("");
146: }
147: p = 0x1BE + (void *)bh->b_data;
148: for (i=1;i<5;i++,p++) {
149: hd[i+5*drive].start_sect = p->start_sect;
150: hd[i+5*drive].nr_sects = p->nr_sects;
151: }
152: brelse(bh);
153: }
1.1.1.2 ! root 154: if (NR_HD)
! 155: printk("Partition table%s ok.\n\r",(NR_HD>1)?"s":"");
! 156: rd_load();
1.1 root 157: mount_root();
158: return (0);
159: }
160:
161: static int controller_ready(void)
162: {
1.1.1.2 ! root 163: int retries=10000;
1.1 root 164:
1.1.1.2 ! root 165: while (--retries && (inb_p(HD_STATUS)&0xc0)!=0x40);
1.1 root 166: return (retries);
167: }
168:
169: static int win_result(void)
170: {
1.1.1.2 ! root 171: int i=inb_p(HD_STATUS);
1.1 root 172:
173: if ((i & (BUSY_STAT | READY_STAT | WRERR_STAT | SEEK_STAT | ERR_STAT))
174: == (READY_STAT | SEEK_STAT))
175: return(0); /* ok */
176: if (i&1) i=inb(HD_ERROR);
177: return (1);
178: }
179:
180: static void hd_out(unsigned int drive,unsigned int nsect,unsigned int sect,
181: unsigned int head,unsigned int cyl,unsigned int cmd,
182: void (*intr_addr)(void))
183: {
184: register int port asm("dx");
185:
186: if (drive>1 || head>15)
187: panic("Trying to write bad sector");
188: if (!controller_ready())
189: panic("HD controller not ready");
190: do_hd = intr_addr;
1.1.1.2 ! root 191: outb_p(hd_info[drive].ctl,HD_CMD);
1.1 root 192: port=HD_DATA;
193: outb_p(hd_info[drive].wpcom>>2,++port);
194: outb_p(nsect,++port);
195: outb_p(sect,++port);
196: outb_p(cyl,++port);
197: outb_p(cyl>>8,++port);
198: outb_p(0xA0|(drive<<4)|head,++port);
199: outb(cmd,++port);
200: }
201:
202: static int drive_busy(void)
203: {
204: unsigned int i;
205:
1.1.1.2 ! root 206: for (i = 0; i < 10000; i++)
! 207: if (READY_STAT == (inb_p(HD_STATUS) & (BUSY_STAT|READY_STAT)))
1.1 root 208: break;
209: i = inb(HD_STATUS);
210: i &= BUSY_STAT | READY_STAT | SEEK_STAT;
211: if (i == READY_STAT | SEEK_STAT)
212: return(0);
213: printk("HD controller times out\n\r");
214: return(1);
215: }
216:
217: static void reset_controller(void)
218: {
219: int i;
220:
221: outb(4,HD_CMD);
1.1.1.2 ! root 222: for(i = 0; i < 100; i++) nop();
! 223: outb(hd_info[0].ctl & 0x0f ,HD_CMD);
1.1 root 224: if (drive_busy())
225: printk("HD-controller still busy\n\r");
1.1.1.2 ! root 226: if ((i = inb(HD_ERROR)) != 1)
1.1 root 227: printk("HD-controller reset failed: %02x\n\r",i);
228: }
229:
230: static void reset_hd(int nr)
231: {
232: reset_controller();
233: hd_out(nr,hd_info[nr].sect,hd_info[nr].sect,hd_info[nr].head-1,
1.1.1.2 ! root 234: hd_info[nr].cyl,WIN_SPECIFY,&recal_intr);
1.1 root 235: }
236:
237: void unexpected_hd_interrupt(void)
238: {
239: printk("Unexpected HD interrupt\n\r");
240: }
241:
242: static void bad_rw_intr(void)
243: {
1.1.1.2 ! root 244: if (++CURRENT->errors >= MAX_ERRORS)
1.1 root 245: end_request(0);
1.1.1.2 ! root 246: if (CURRENT->errors > MAX_ERRORS/2)
! 247: reset = 1;
1.1 root 248: }
249:
250: static void read_intr(void)
251: {
252: if (win_result()) {
253: bad_rw_intr();
1.1.1.2 ! root 254: do_hd_request();
1.1 root 255: return;
256: }
257: port_read(HD_DATA,CURRENT->buffer,256);
258: CURRENT->errors = 0;
259: CURRENT->buffer += 512;
260: CURRENT->sector++;
1.1.1.2 ! root 261: if (--CURRENT->nr_sectors) {
! 262: do_hd = &read_intr;
1.1 root 263: return;
1.1.1.2 ! root 264: }
1.1 root 265: end_request(1);
266: do_hd_request();
267: }
268:
269: static void write_intr(void)
270: {
271: if (win_result()) {
272: bad_rw_intr();
1.1.1.2 ! root 273: do_hd_request();
1.1 root 274: return;
275: }
276: if (--CURRENT->nr_sectors) {
277: CURRENT->sector++;
278: CURRENT->buffer += 512;
1.1.1.2 ! root 279: do_hd = &write_intr;
1.1 root 280: port_write(HD_DATA,CURRENT->buffer,256);
281: return;
282: }
283: end_request(1);
284: do_hd_request();
285: }
286:
1.1.1.2 ! root 287: static void recal_intr(void)
! 288: {
! 289: if (win_result())
! 290: bad_rw_intr();
! 291: do_hd_request();
! 292: }
! 293:
1.1 root 294: void do_hd_request(void)
295: {
296: int i,r;
297: unsigned int block,dev;
298: unsigned int sec,head,cyl;
299: unsigned int nsect;
300:
301: INIT_REQUEST;
302: dev = MINOR(CURRENT->dev);
303: block = CURRENT->sector;
304: if (dev >= 5*NR_HD || block+2 > hd[dev].nr_sects) {
305: end_request(0);
306: goto repeat;
307: }
308: block += hd[dev].start_sect;
309: dev /= 5;
310: __asm__("divl %4":"=a" (block),"=d" (sec):"0" (block),"1" (0),
311: "r" (hd_info[dev].sect));
312: __asm__("divl %4":"=a" (cyl),"=d" (head):"0" (block),"1" (0),
313: "r" (hd_info[dev].head));
314: sec++;
315: nsect = CURRENT->nr_sectors;
1.1.1.2 ! root 316: if (reset) {
! 317: reset = 0;
! 318: recalibrate = 1;
! 319: reset_hd(CURRENT_DEV);
! 320: return;
! 321: }
! 322: if (recalibrate) {
! 323: recalibrate = 0;
! 324: hd_out(dev,hd_info[CURRENT_DEV].sect,0,0,0,
! 325: WIN_RESTORE,&recal_intr);
! 326: return;
! 327: }
1.1 root 328: if (CURRENT->cmd == WRITE) {
329: hd_out(dev,nsect,sec,head,cyl,WIN_WRITE,&write_intr);
330: for(i=0 ; i<3000 && !(r=inb_p(HD_STATUS)&DRQ_STAT) ; i++)
331: /* nothing */ ;
332: if (!r) {
1.1.1.2 ! root 333: bad_rw_intr();
! 334: goto repeat;
1.1 root 335: }
336: port_write(HD_DATA,CURRENT->buffer,256);
337: } else if (CURRENT->cmd == READ) {
338: hd_out(dev,nsect,sec,head,cyl,WIN_READ,&read_intr);
339: } else
340: panic("unknown hd-command");
341: }
342:
343: void hd_init(void)
344: {
345: blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
1.1.1.2 ! root 346: set_intr_gate(0x2E,&hd_interrupt);
1.1 root 347: outb_p(inb_p(0x21)&0xfb,0x21);
348: outb(inb_p(0xA1)&0xbf,0xA1);
349: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.