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