|
|
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:
1.1.1.6 ! root 19: #include <errno.h>
! 20:
1.1 root 21: #include <linux/config.h>
22: #include <linux/sched.h>
1.1.1.4 root 23: #include <linux/timer.h>
1.1 root 24: #include <linux/fs.h>
25: #include <linux/kernel.h>
26: #include <linux/hdreg.h>
27: #include <asm/system.h>
28: #include <asm/io.h>
29: #include <asm/segment.h>
30:
31: #define MAJOR_NR 3
32: #include "blk.h"
33:
1.1.1.5 root 34: static inline unsigned char CMOS_READ(unsigned char addr)
35: {
36: outb_p(0x80|addr,0x70);
37: return inb_p(0x71);
38: }
1.1.1.2 root 39:
1.1 root 40: /* Max read/write errors/sector */
1.1.1.2 root 41: #define MAX_ERRORS 7
1.1 root 42: #define MAX_HD 2
43:
1.1.1.2 root 44: static void recal_intr(void);
1.1.1.3 root 45: static void bad_rw_intr(void);
1.1.1.2 root 46:
1.1.1.3 root 47: static int recalibrate = 0;
1.1.1.6 ! root 48: static int reset = 0;
1.1.1.2 root 49:
1.1 root 50: /*
51: * This struct defines the HD's and their types.
52: */
53: struct hd_i_struct {
1.1.1.4 root 54: unsigned int head,sect,cyl,wpcom,lzone,ctl;
1.1 root 55: };
56: #ifdef HD_TYPE
57: struct hd_i_struct hd_info[] = { HD_TYPE };
58: #define NR_HD ((sizeof (hd_info))/(sizeof (struct hd_i_struct)))
59: #else
60: struct hd_i_struct hd_info[] = { {0,0,0,0,0,0},{0,0,0,0,0,0} };
61: static int NR_HD = 0;
62: #endif
63:
64: static struct hd_struct {
65: long start_sect;
66: long nr_sects;
1.1.1.4 root 67: } hd[MAX_HD<<6]={{0,0},};
1.1 root 68:
1.1.1.4 root 69: static int hd_sizes[MAX_HD<<6] = {0, };
1.1.1.3 root 70:
1.1 root 71: #define port_read(port,buf,nr) \
72: __asm__("cld;rep;insw"::"d" (port),"D" (buf),"c" (nr):"cx","di")
73:
74: #define port_write(port,buf,nr) \
75: __asm__("cld;rep;outsw"::"d" (port),"S" (buf),"c" (nr):"cx","si")
76:
77: extern void hd_interrupt(void);
1.1.1.2 root 78: extern void rd_load(void);
1.1 root 79:
1.1.1.4 root 80: static unsigned int current_minor;
81:
1.1.1.6 ! root 82: /*
! 83: * Create devices for each logical partition in an extended partition.
! 84: * The logical partitions form a linked list, with each entry being
! 85: * a partition table with two entries. The first entry
! 86: * is the real data partition (with a start relative to the partition
! 87: * table start). The second is a pointer to the next logical partition
! 88: * (with a start relative to the entire extended partition).
! 89: * We do not create a Linux partition for the partition tables, but
! 90: * only for the actual data partitions.
! 91: */
! 92: static void extended_partition(unsigned int dev)
! 93: {
! 94: struct buffer_head *bh;
! 95: struct partition *p;
! 96: unsigned long first_sector, this_sector;
! 97:
! 98: first_sector = hd[MINOR(dev)].start_sect;
! 99: this_sector = first_sector;
! 100:
! 101: while (1) {
! 102: if ((current_minor & 0x3f) >= 60)
! 103: return;
! 104: if (!(bh = bread(dev,0))) {
! 105: printk("Unable to read partition table of device %04x\n",dev);
! 106: return;
! 107: }
! 108: /*
! 109: * This block is from a device that we're about to stomp on.
! 110: * So make sure nobody thinks this block is usable.
! 111: */
! 112: bh->b_dirt=0;
! 113: bh->b_uptodate=0;
! 114: if (*(unsigned short *) (bh->b_data+510) == 0xAA55) {
! 115: p = 0x1BE + (void *)bh->b_data;
! 116: /*
! 117: * Process the first entry, which should be the real
! 118: * data partition.
! 119: */
! 120: if (p->sys_ind == EXTENDED_PARTITION ||
! 121: !(hd[current_minor].nr_sects = p->nr_sects))
! 122: goto done; /* shouldn't happen */
! 123: hd[current_minor].start_sect = this_sector + p->start_sect;
! 124: printk(" Logical part %d start %d size %d end %d\n\r",
! 125: current_minor, hd[current_minor].start_sect,
! 126: hd[current_minor].nr_sects,
! 127: hd[current_minor].start_sect +
! 128: hd[current_minor].nr_sects);
! 129: current_minor++;
! 130: p++;
! 131: /*
! 132: * Process the second entry, which should be a link
! 133: * to the next logical partition. Create a minor
! 134: * for this just long enough to get the next partition
! 135: * table. The minor will be reused for the real
! 136: * data partition.
! 137: */
! 138: if (p->sys_ind != EXTENDED_PARTITION ||
! 139: !(hd[current_minor].nr_sects = p->nr_sects))
! 140: goto done; /* no more logicals in this partition */
! 141: hd[current_minor].start_sect = first_sector + p->start_sect;
! 142: this_sector = first_sector + p->start_sect;
! 143: dev = 0x0300 | current_minor;
! 144: brelse(bh);
! 145: } else
! 146: goto done;
! 147: }
! 148: done:
! 149: brelse(bh);
! 150: }
! 151:
1.1.1.4 root 152: static void check_partition(unsigned int dev)
153: {
1.1.1.6 ! root 154: int i, minor = current_minor;
1.1.1.4 root 155: struct buffer_head *bh;
156: struct partition *p;
1.1.1.6 ! root 157: unsigned long first_sector;
1.1.1.4 root 158:
1.1.1.6 ! root 159: first_sector = hd[MINOR(dev)].start_sect;
1.1.1.4 root 160: if (!(bh = bread(dev,0))) {
161: printk("Unable to read partition table of device %04x\n",dev);
162: return;
163: }
1.1.1.6 ! root 164: printk("Drive %d:\n\r",minor >> 6);
! 165: current_minor += 4; /* first "extra" minor */
1.1.1.4 root 166: if (*(unsigned short *) (bh->b_data+510) == 0xAA55) {
167: p = 0x1BE + (void *)bh->b_data;
1.1.1.6 ! root 168: for (i=1 ; i<=4 ; minor++,i++,p++) {
! 169: if (!(hd[minor].nr_sects = p->nr_sects))
1.1.1.5 root 170: continue;
1.1.1.6 ! root 171: hd[minor].start_sect = first_sector + p->start_sect;
! 172: printk(" part %d start %d size %d end %d \n\r", i,
! 173: hd[minor].start_sect, hd[minor].nr_sects,
! 174: hd[minor].start_sect + hd[minor].nr_sects);
1.1.1.5 root 175: if ((current_minor & 0x3f) >= 60)
176: continue;
177: if (p->sys_ind == EXTENDED_PARTITION) {
1.1.1.6 ! root 178: extended_partition(0x0300 | minor);
1.1.1.5 root 179: }
1.1.1.4 root 180: }
1.1.1.5 root 181: /*
182: * check for Disk Manager partition table
183: */
184: if (*(unsigned short *) (bh->b_data+0xfc) == 0x55AA) {
185: p = 0x1BE + (void *)bh->b_data;
1.1.1.6 ! root 186: for (i = 4 ; i < 16 ; i++, current_minor++) {
1.1.1.5 root 187: p--;
188: if ((current_minor & 0x3f) >= 60)
189: break;
1.1.1.6 ! root 190: if (!(p->start_sect && p->nr_sects))
1.1.1.5 root 191: continue;
1.1.1.6 ! root 192: hd[current_minor].start_sect = p->start_sect;
! 193: hd[current_minor].nr_sects = p->nr_sects;
! 194: printk(" DM part %d start %d size %d end %d\n\r",
! 195: current_minor,
! 196: hd[current_minor].start_sect,
! 197: hd[current_minor].nr_sects,
! 198: hd[current_minor].start_sect +
! 199: hd[current_minor].nr_sects);
1.1.1.5 root 200: }
1.1.1.4 root 201: }
202: } else
203: printk("Bad partition table on dev %04x\n",dev);
204: brelse(bh);
205: }
206:
1.1 root 207: /* This may be used only once, enforced by 'static int callable' */
208: int sys_setup(void * BIOS)
209: {
210: static int callable = 1;
211: int i,drive;
1.1.1.2 root 212: unsigned char cmos_disks;
1.1 root 213:
214: if (!callable)
215: return -1;
216: callable = 0;
217: #ifndef HD_TYPE
218: for (drive=0 ; drive<2 ; drive++) {
219: hd_info[drive].cyl = *(unsigned short *) BIOS;
220: hd_info[drive].head = *(unsigned char *) (2+BIOS);
221: hd_info[drive].wpcom = *(unsigned short *) (5+BIOS);
222: hd_info[drive].ctl = *(unsigned char *) (8+BIOS);
223: hd_info[drive].lzone = *(unsigned short *) (12+BIOS);
224: hd_info[drive].sect = *(unsigned char *) (14+BIOS);
225: BIOS += 16;
226: }
1.1.1.2 root 227:
228: /*
229: We querry CMOS about hard disks : it could be that
230: we have a SCSI/ESDI/etc controller that is BIOS
231: compatable with ST-506, and thus showing up in our
232: BIOS table, but not register compatable, and therefore
233: not present in CMOS.
234:
235: Furthurmore, we will assume that our ST-506 drives
236: <if any> are the primary drives in the system, and
237: the ones reflected as drive 1 or 2.
238:
239: The first drive is stored in the high nibble of CMOS
240: byte 0x12, the second in the low nibble. This will be
241: either a 4 bit drive type or 0xf indicating use byte 0x19
242: for an 8 bit type, drive 1, 0x1a for drive 2 in CMOS.
243:
244: Needless to say, a non-zero value means we have
245: an AT controller hard disk for that drive.
246:
247:
248: */
249:
250: if ((cmos_disks = CMOS_READ(0x12)) & 0xf0)
251: if (cmos_disks & 0x0f)
252: NR_HD = 2;
253: else
254: NR_HD = 1;
255: else
256: NR_HD = 0;
1.1.1.6 ! root 257: #endif
! 258: for (i = 0 ; i < (MAX_HD<<6) ; i++) {
! 259: hd[i].start_sect = 0;
! 260: hd[i].nr_sects = 0;
1.1.1.2 root 261: }
1.1.1.6 ! root 262: for (i = 0 ; i < NR_HD ; i++)
! 263: hd[i<<6].nr_sects = hd_info[i].head*
! 264: hd_info[i].sect*hd_info[i].cyl;
1.1 root 265: for (drive=0 ; drive<NR_HD ; drive++) {
1.1.1.4 root 266: current_minor = 1+(drive<<6);
267: check_partition(0x0300+(drive<<6));
1.1 root 268: }
1.1.1.4 root 269: for (i=0 ; i<(MAX_HD<<6) ; i++)
1.1.1.3 root 270: hd_sizes[i] = hd[i].nr_sects>>1 ;
271: blk_size[MAJOR_NR] = hd_sizes;
1.1.1.2 root 272: if (NR_HD)
273: printk("Partition table%s ok.\n\r",(NR_HD>1)?"s":"");
274: rd_load();
1.1 root 275: mount_root();
276: return (0);
277: }
278:
279: static int controller_ready(void)
280: {
1.1.1.3 root 281: int retries = 100000;
1.1 root 282:
1.1.1.4 root 283: while (--retries && (inb_p(HD_STATUS)&0x80))
284: /* nothing */;
285: if (!retries)
286: printk("controller_ready: status = %02x\n\r",
287: (unsigned char) inb_p(HD_STATUS));
1.1 root 288: return (retries);
289: }
290:
291: static int win_result(void)
292: {
1.1.1.2 root 293: int i=inb_p(HD_STATUS);
1.1 root 294:
295: if ((i & (BUSY_STAT | READY_STAT | WRERR_STAT | SEEK_STAT | ERR_STAT))
296: == (READY_STAT | SEEK_STAT))
297: return(0); /* ok */
1.1.1.5 root 298: if (i&1)
299: i=inb(HD_ERROR);
1.1 root 300: return (1);
301: }
302:
303: static void hd_out(unsigned int drive,unsigned int nsect,unsigned int sect,
304: unsigned int head,unsigned int cyl,unsigned int cmd,
305: void (*intr_addr)(void))
306: {
1.1.1.4 root 307: unsigned short port;
1.1 root 308:
309: if (drive>1 || head>15)
310: panic("Trying to write bad sector");
1.1.1.4 root 311: if (reset || !controller_ready()) {
312: reset = 1;
313: return;
314: }
1.1.1.3 root 315: SET_INTR(intr_addr);
1.1.1.2 root 316: outb_p(hd_info[drive].ctl,HD_CMD);
1.1 root 317: port=HD_DATA;
318: outb_p(hd_info[drive].wpcom>>2,++port);
319: outb_p(nsect,++port);
320: outb_p(sect,++port);
321: outb_p(cyl,++port);
322: outb_p(cyl>>8,++port);
323: outb_p(0xA0|(drive<<4)|head,++port);
324: outb(cmd,++port);
325: }
326:
327: static int drive_busy(void)
328: {
329: unsigned int i;
1.1.1.3 root 330: unsigned char c;
1.1 root 331:
1.1.1.6 ! root 332: for (i = 0; i < 500000 ; i++) {
1.1.1.3 root 333: c = inb_p(HD_STATUS);
334: c &= (BUSY_STAT | READY_STAT | SEEK_STAT);
335: if (c == (READY_STAT | SEEK_STAT))
336: return 0;
337: }
1.1.1.4 root 338: printk("HD controller times out, c=%02x\n\r",c);
1.1 root 339: return(1);
340: }
341:
342: static void reset_controller(void)
343: {
344: int i;
345:
346: outb(4,HD_CMD);
1.1.1.3 root 347: for(i = 0; i < 1000; i++) nop();
1.1.1.2 root 348: outb(hd_info[0].ctl & 0x0f ,HD_CMD);
1.1 root 349: if (drive_busy())
350: printk("HD-controller still busy\n\r");
1.1.1.2 root 351: if ((i = inb(HD_ERROR)) != 1)
1.1 root 352: printk("HD-controller reset failed: %02x\n\r",i);
353: }
354:
1.1.1.3 root 355: static void reset_hd(void)
1.1 root 356: {
1.1.1.3 root 357: static int i;
358:
359: repeat:
360: if (reset) {
361: reset = 0;
362: i = -1;
363: reset_controller();
364: } else if (win_result()) {
365: bad_rw_intr();
366: if (reset)
367: goto repeat;
368: }
369: i++;
370: if (i < NR_HD) {
371: hd_out(i,hd_info[i].sect,hd_info[i].sect,hd_info[i].head-1,
372: hd_info[i].cyl,WIN_SPECIFY,&reset_hd);
1.1.1.4 root 373: if (reset)
374: goto repeat;
1.1.1.3 root 375: } else
376: do_hd_request();
1.1 root 377: }
378:
1.1.1.6 ! root 379: /*
! 380: * Ok, don't know what to do with the unexpected interrupts: on some machines
! 381: * doing a reset and a retry seems to result in an eternal loop. Right now I
! 382: * ignore it, and just set the timeout.
! 383: */
1.1 root 384: void unexpected_hd_interrupt(void)
385: {
386: printk("Unexpected HD interrupt\n\r");
1.1.1.6 ! root 387: SET_TIMER;
! 388: #if 0
1.1.1.3 root 389: reset = 1;
390: do_hd_request();
1.1.1.6 ! root 391: #endif
1.1 root 392: }
393:
394: static void bad_rw_intr(void)
395: {
1.1.1.6 ! root 396: if (!CURRENT)
! 397: return;
1.1.1.2 root 398: if (++CURRENT->errors >= MAX_ERRORS)
1.1 root 399: end_request(0);
1.1.1.2 root 400: if (CURRENT->errors > MAX_ERRORS/2)
401: reset = 1;
1.1.1.5 root 402: else
403: recalibrate = 1;
1.1 root 404: }
405:
406: static void read_intr(void)
407: {
1.1.1.5 root 408: SET_INTR(&read_intr);
1.1 root 409: if (win_result()) {
1.1.1.5 root 410: SET_INTR(NULL);
1.1 root 411: bad_rw_intr();
1.1.1.2 root 412: do_hd_request();
1.1 root 413: return;
414: }
415: port_read(HD_DATA,CURRENT->buffer,256);
416: CURRENT->errors = 0;
417: CURRENT->buffer += 512;
418: CURRENT->sector++;
1.1.1.5 root 419: if (--CURRENT->nr_sectors)
1.1 root 420: return;
1.1.1.5 root 421: SET_INTR(NULL);
1.1 root 422: end_request(1);
423: do_hd_request();
424: }
425:
426: static void write_intr(void)
427: {
428: if (win_result()) {
429: bad_rw_intr();
1.1.1.2 root 430: do_hd_request();
1.1 root 431: return;
432: }
433: if (--CURRENT->nr_sectors) {
434: CURRENT->sector++;
435: CURRENT->buffer += 512;
1.1.1.3 root 436: SET_INTR(&write_intr);
1.1 root 437: port_write(HD_DATA,CURRENT->buffer,256);
438: return;
439: }
440: end_request(1);
441: do_hd_request();
442: }
443:
1.1.1.2 root 444: static void recal_intr(void)
445: {
446: if (win_result())
447: bad_rw_intr();
448: do_hd_request();
449: }
450:
1.1.1.6 ! root 451: /*
! 452: * This is another of the error-routines I don't know what to do with. The
! 453: * best idea seems to just set reset, and start all over again.
! 454: */
1.1.1.4 root 455: static void hd_times_out(void)
1.1.1.5 root 456: {
457: do_hd = NULL;
458: reset = 1;
1.1.1.3 root 459: if (!CURRENT)
460: return;
1.1.1.6 ! root 461: printk("HD timeout\n\r");
! 462: cli();
1.1.1.3 root 463: if (++CURRENT->errors >= MAX_ERRORS)
464: end_request(0);
465: do_hd_request();
466: }
467:
1.1.1.6 ! root 468: static void do_hd_request(void)
1.1 root 469: {
470: int i,r;
471: unsigned int block,dev;
472: unsigned int sec,head,cyl;
473: unsigned int nsect;
474:
475: INIT_REQUEST;
476: dev = MINOR(CURRENT->dev);
477: block = CURRENT->sector;
1.1.1.5 root 478: nsect = CURRENT->nr_sectors;
479: if (dev >= (NR_HD<<6) || block+nsect > hd[dev].nr_sects) {
1.1 root 480: end_request(0);
481: goto repeat;
482: }
483: block += hd[dev].start_sect;
1.1.1.4 root 484: dev >>= 6;
485: sec = block % hd_info[dev].sect;
486: block /= hd_info[dev].sect;
487: head = block % hd_info[dev].head;
488: cyl = block / hd_info[dev].head;
1.1 root 489: sec++;
1.1.1.2 root 490: if (reset) {
491: recalibrate = 1;
1.1.1.3 root 492: reset_hd();
1.1.1.2 root 493: return;
494: }
495: if (recalibrate) {
496: recalibrate = 0;
1.1.1.5 root 497: hd_out(dev,hd_info[dev].sect,0,0,0,
1.1.1.2 root 498: WIN_RESTORE,&recal_intr);
1.1.1.4 root 499: if (reset)
500: goto repeat;
1.1.1.2 root 501: return;
502: }
1.1 root 503: if (CURRENT->cmd == WRITE) {
504: hd_out(dev,nsect,sec,head,cyl,WIN_WRITE,&write_intr);
1.1.1.4 root 505: if (reset)
506: goto repeat;
1.1.1.3 root 507: for(i=0 ; i<10000 && !(r=inb_p(HD_STATUS)&DRQ_STAT) ; i++)
1.1 root 508: /* nothing */ ;
509: if (!r) {
1.1.1.2 root 510: bad_rw_intr();
511: goto repeat;
1.1 root 512: }
513: port_write(HD_DATA,CURRENT->buffer,256);
514: } else if (CURRENT->cmd == READ) {
515: hd_out(dev,nsect,sec,head,cyl,WIN_READ,&read_intr);
1.1.1.4 root 516: if (reset)
517: goto repeat;
1.1 root 518: } else
519: panic("unknown hd-command");
520: }
521:
522: void hd_init(void)
523: {
524: blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
1.1.1.5 root 525: set_intr_gate(0x2E,&hd_interrupt);
1.1 root 526: outb_p(inb_p(0x21)&0xfb,0x21);
527: outb(inb_p(0xA1)&0xbf,0xA1);
1.1.1.4 root 528: timer_table[HD_TIMER].fn = hd_times_out;
1.1 root 529: }
1.1.1.6 ! root 530:
! 531: int hd_ioctl(int dev, int cmd, int arg)
! 532: {
! 533: struct hd_geometry *loc = (void *) arg;
! 534:
! 535: if (!loc)
! 536: return -EINVAL;
! 537: dev = MINOR(dev) >> 6;
! 538: if (dev >= NR_HD)
! 539: return -EINVAL;
! 540:
! 541: switch (cmd) {
! 542: case HDIO_REQ:
! 543: put_fs_byte(hd_info[dev].head,
! 544: (char *) &loc->heads);
! 545: put_fs_byte(hd_info[dev].sect,
! 546: (char *) &loc->sectors);
! 547: put_fs_word(hd_info[dev].cyl,
! 548: (short *) &loc->cylinders);
! 549: return 0;
! 550: default:
! 551: return -EINVAL;
! 552: }
! 553: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.