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