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