|
|
1.1 root 1: /*
2: * linux/kernel/hd.c
3: *
1.1.1.9 root 4: * Copyright (C) 1991, 1992 Linus Torvalds
1.1 root 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>
1.1.1.9 root 20: #ifdef CONFIG_BLK_DEV_HD
21:
22: #define HD_IRQ 14
23:
24: #include <linux/errno.h>
25: #include <linux/signal.h>
1.1 root 26: #include <linux/sched.h>
1.1.1.4 root 27: #include <linux/timer.h>
1.1 root 28: #include <linux/fs.h>
29: #include <linux/kernel.h>
30: #include <linux/hdreg.h>
1.1.1.9 root 31: #include <linux/genhd.h>
1.1.1.8 root 32:
33: #define REALLY_SLOW_IO
1.1 root 34: #include <asm/system.h>
35: #include <asm/io.h>
36: #include <asm/segment.h>
37:
38: #define MAJOR_NR 3
39: #include "blk.h"
40:
1.1.1.5 root 41: static inline unsigned char CMOS_READ(unsigned char addr)
42: {
43: outb_p(0x80|addr,0x70);
44: return inb_p(0x71);
45: }
1.1.1.2 root 46:
1.1.1.7 root 47: #define HD_DELAY 0
48:
1.1 root 49: /* Max read/write errors/sector */
1.1.1.2 root 50: #define MAX_ERRORS 7
1.1 root 51: #define MAX_HD 2
52:
1.1.1.2 root 53: static void recal_intr(void);
1.1.1.3 root 54: static void bad_rw_intr(void);
1.1.1.2 root 55:
1.1.1.10! root 56: static char recalibrate[ MAX_HD ] = { 0, };
! 57:
1.1.1.6 root 58: static int reset = 0;
1.1.1.2 root 59:
1.1.1.7 root 60: #if (HD_DELAY > 0)
61: unsigned long last_req, read_timer();
62: #endif
63:
1.1 root 64: /*
65: * This struct defines the HD's and their types.
66: */
67: struct hd_i_struct {
1.1.1.4 root 68: unsigned int head,sect,cyl,wpcom,lzone,ctl;
1.1 root 69: };
70: #ifdef HD_TYPE
71: struct hd_i_struct hd_info[] = { HD_TYPE };
72: #define NR_HD ((sizeof (hd_info))/(sizeof (struct hd_i_struct)))
73: #else
74: struct hd_i_struct hd_info[] = { {0,0,0,0,0,0},{0,0,0,0,0,0} };
75: static int NR_HD = 0;
76: #endif
77:
1.1.1.9 root 78: static struct hd_struct hd[MAX_HD<<6]={{0,0},};
1.1.1.4 root 79: static int hd_sizes[MAX_HD<<6] = {0, };
1.1.1.3 root 80:
1.1 root 81: #define port_read(port,buf,nr) \
82: __asm__("cld;rep;insw"::"d" (port),"D" (buf),"c" (nr):"cx","di")
83:
84: #define port_write(port,buf,nr) \
85: __asm__("cld;rep;outsw"::"d" (port),"S" (buf),"c" (nr):"cx","si")
86:
1.1.1.7 root 87: #if (HD_DELAY > 0)
88: unsigned long read_timer(void)
89: {
90: unsigned long t;
91: int i;
92:
93: cli();
94: outb_p(0xc2, 0x43);
95: t = jiffies * 11931 + (inb_p(0x40) & 0x80 ? 5966 : 11932);
96: i = inb_p(0x40);
97: i |= inb(0x40) << 8;
98: sti();
99: return(t - i / 2);
100: }
101: #endif
102:
1.1 root 103: static int controller_ready(void)
104: {
1.1.1.3 root 105: int retries = 100000;
1.1 root 106:
1.1.1.4 root 107: while (--retries && (inb_p(HD_STATUS)&0x80))
108: /* nothing */;
109: if (!retries)
110: printk("controller_ready: status = %02x\n\r",
111: (unsigned char) inb_p(HD_STATUS));
1.1 root 112: return (retries);
113: }
114:
115: static int win_result(void)
116: {
1.1.1.2 root 117: int i=inb_p(HD_STATUS);
1.1 root 118:
119: if ((i & (BUSY_STAT | READY_STAT | WRERR_STAT | SEEK_STAT | ERR_STAT))
120: == (READY_STAT | SEEK_STAT))
1.1.1.9 root 121: return 0; /* ok */
122: printk("HD: win_result: status = 0x%02x\n",i);
123: if (i&1) {
1.1.1.5 root 124: i=inb(HD_ERROR);
1.1.1.9 root 125: printk("HD: win_result: error = 0x%02x\n",i);
126: }
127: return 1;
1.1 root 128: }
129:
130: static void hd_out(unsigned int drive,unsigned int nsect,unsigned int sect,
131: unsigned int head,unsigned int cyl,unsigned int cmd,
132: void (*intr_addr)(void))
133: {
1.1.1.4 root 134: unsigned short port;
1.1 root 135:
136: if (drive>1 || head>15)
137: panic("Trying to write bad sector");
1.1.1.7 root 138: #if (HD_DELAY > 0)
139: while (read_timer() - last_req < HD_DELAY)
140: /* nothing */;
141: #endif
1.1.1.4 root 142: if (reset || !controller_ready()) {
143: reset = 1;
144: return;
145: }
1.1.1.3 root 146: SET_INTR(intr_addr);
1.1.1.2 root 147: outb_p(hd_info[drive].ctl,HD_CMD);
1.1 root 148: port=HD_DATA;
149: outb_p(hd_info[drive].wpcom>>2,++port);
150: outb_p(nsect,++port);
151: outb_p(sect,++port);
152: outb_p(cyl,++port);
153: outb_p(cyl>>8,++port);
154: outb_p(0xA0|(drive<<4)|head,++port);
1.1.1.7 root 155: outb_p(cmd,++port);
1.1 root 156: }
157:
158: static int drive_busy(void)
159: {
160: unsigned int i;
1.1.1.3 root 161: unsigned char c;
1.1 root 162:
1.1.1.6 root 163: for (i = 0; i < 500000 ; i++) {
1.1.1.3 root 164: c = inb_p(HD_STATUS);
165: c &= (BUSY_STAT | READY_STAT | SEEK_STAT);
166: if (c == (READY_STAT | SEEK_STAT))
167: return 0;
168: }
1.1.1.9 root 169: printk("HD controller times out, status = 0x%02x\n\r",c);
1.1 root 170: return(1);
171: }
172:
173: static void reset_controller(void)
174: {
175: int i;
176:
1.1.1.7 root 177: printk("HD-controller reset\r\n");
1.1 root 178: outb(4,HD_CMD);
1.1.1.3 root 179: for(i = 0; i < 1000; i++) nop();
1.1.1.2 root 180: outb(hd_info[0].ctl & 0x0f ,HD_CMD);
1.1 root 181: if (drive_busy())
182: printk("HD-controller still busy\n\r");
1.1.1.2 root 183: if ((i = inb(HD_ERROR)) != 1)
1.1 root 184: printk("HD-controller reset failed: %02x\n\r",i);
185: }
186:
1.1.1.3 root 187: static void reset_hd(void)
1.1 root 188: {
1.1.1.3 root 189: static int i;
190:
191: repeat:
192: if (reset) {
193: reset = 0;
194: i = -1;
195: reset_controller();
196: } else if (win_result()) {
197: bad_rw_intr();
198: if (reset)
199: goto repeat;
200: }
201: i++;
202: if (i < NR_HD) {
203: hd_out(i,hd_info[i].sect,hd_info[i].sect,hd_info[i].head-1,
204: hd_info[i].cyl,WIN_SPECIFY,&reset_hd);
1.1.1.4 root 205: if (reset)
206: goto repeat;
1.1.1.3 root 207: } else
208: do_hd_request();
1.1 root 209: }
210:
1.1.1.6 root 211: /*
212: * Ok, don't know what to do with the unexpected interrupts: on some machines
213: * doing a reset and a retry seems to result in an eternal loop. Right now I
214: * ignore it, and just set the timeout.
215: */
1.1 root 216: void unexpected_hd_interrupt(void)
217: {
1.1.1.9 root 218: sti();
1.1 root 219: printk("Unexpected HD interrupt\n\r");
1.1.1.6 root 220: SET_TIMER;
1.1 root 221: }
222:
223: static void bad_rw_intr(void)
224: {
1.1.1.10! root 225: int i;
! 226:
1.1.1.6 root 227: if (!CURRENT)
228: return;
1.1.1.2 root 229: if (++CURRENT->errors >= MAX_ERRORS)
1.1.1.8 root 230: end_request(0);
231: else if (CURRENT->errors > MAX_ERRORS/2)
1.1.1.2 root 232: reset = 1;
1.1.1.5 root 233: else
1.1.1.10! root 234: for (i=0; i < NR_HD; i++)
! 235: recalibrate[i] = 1;
1.1 root 236: }
237:
1.1.1.9 root 238: static inline int wait_DRQ(void)
239: {
240: int retries = 100000;
241:
242: while (--retries > 0)
243: if (inb_p(HD_STATUS) & DRQ_STAT)
244: return 0;
245: return -1;
246: }
247:
1.1.1.7 root 248: #define STAT_MASK (BUSY_STAT | READY_STAT | WRERR_STAT | SEEK_STAT | ERR_STAT)
249: #define STAT_OK (READY_STAT | SEEK_STAT)
250:
1.1 root 251: static void read_intr(void)
252: {
1.1.1.7 root 253: int i;
1.1.1.10! root 254: int retries = 100000;
1.1.1.7 root 255:
1.1.1.10! root 256: do {
! 257: i = (unsigned) inb_p(HD_STATUS);
! 258: if ((i & STAT_MASK) != STAT_OK)
! 259: break;
! 260: if (i & DRQ_STAT)
! 261: goto ok_to_read;
! 262: } while (--retries > 0);
! 263: sti();
! 264: printk("HD: read_intr: status = 0x%02x\n",i);
! 265: if (i & ERR_STAT) {
! 266: i = (unsigned) inb(HD_ERROR);
! 267: printk("HD: read_intr: error = 0x%02x\n",i);
1.1.1.9 root 268: }
1.1.1.10! root 269: bad_rw_intr();
! 270: cli();
! 271: do_hd_request();
! 272: return;
! 273: ok_to_read:
1.1 root 274: port_read(HD_DATA,CURRENT->buffer,256);
275: CURRENT->errors = 0;
1.1.1.8 root 276: CURRENT->buffer += 512;
1.1 root 277: CURRENT->sector++;
1.1.1.8 root 278: i = --CURRENT->nr_sectors;
1.1.1.9 root 279: --CURRENT->current_nr_sectors;
280: #ifdef DEBUG
281: printk("hd%d : sector = %d, %d remaining to buffer = %08x\n",
282: MINOR(CURRENT->dev), CURRENT->sector, i, CURRENT->
283: buffer);
284: #endif
285: if (!i || (CURRENT->bh && !SUBSECTOR(i)))
1.1.1.8 root 286: end_request(1);
287: if (i > 0) {
1.1.1.7 root 288: SET_INTR(&read_intr);
1.1.1.9 root 289: sti();
1.1 root 290: return;
1.1.1.7 root 291: }
292: #if (HD_DELAY > 0)
293: last_req = read_timer();
294: #endif
1.1 root 295: do_hd_request();
1.1.1.7 root 296: return;
1.1 root 297: }
298:
299: static void write_intr(void)
300: {
1.1.1.7 root 301: int i;
1.1.1.10! root 302: int retries = 100000;
1.1.1.7 root 303:
1.1.1.10! root 304: do {
! 305: i = (unsigned) inb_p(HD_STATUS);
! 306: if ((i & STAT_MASK) != STAT_OK)
! 307: break;
! 308: if ((CURRENT->nr_sectors <= 1) || (i & DRQ_STAT))
! 309: goto ok_to_write;
! 310: } while (--retries > 0);
! 311: sti();
! 312: printk("HD: write_intr: status = 0x%02x\n",i);
! 313: if (i & ERR_STAT) {
! 314: i = (unsigned) inb(HD_ERROR);
! 315: printk("HD: write_intr: error = 0x%02x\n",i);
1.1.1.9 root 316: }
1.1.1.10! root 317: bad_rw_intr();
! 318: cli();
! 319: do_hd_request();
! 320: return;
! 321: ok_to_write:
1.1.1.8 root 322: CURRENT->sector++;
323: i = --CURRENT->nr_sectors;
1.1.1.9 root 324: --CURRENT->current_nr_sectors;
1.1.1.8 root 325: CURRENT->buffer += 512;
1.1.1.9 root 326: if (!i || (CURRENT->bh && !SUBSECTOR(i)))
1.1.1.7 root 327: end_request(1);
1.1.1.8 root 328: if (i > 0) {
329: SET_INTR(&write_intr);
330: port_write(HD_DATA,CURRENT->buffer,256);
1.1.1.9 root 331: sti();
1.1.1.8 root 332: } else {
1.1.1.7 root 333: #if (HD_DELAY > 0)
334: last_req = read_timer();
335: #endif
1.1.1.2 root 336: do_hd_request();
1.1 root 337: }
1.1.1.7 root 338: return;
1.1 root 339: }
340:
1.1.1.2 root 341: static void recal_intr(void)
342: {
343: if (win_result())
344: bad_rw_intr();
345: do_hd_request();
346: }
347:
1.1.1.6 root 348: /*
349: * This is another of the error-routines I don't know what to do with. The
350: * best idea seems to just set reset, and start all over again.
351: */
1.1.1.4 root 352: static void hd_times_out(void)
1.1.1.9 root 353: {
354: DEVICE_INTR = NULL;
1.1.1.10! root 355: sti();
1.1.1.5 root 356: reset = 1;
1.1.1.3 root 357: if (!CURRENT)
358: return;
1.1.1.6 root 359: printk("HD timeout\n\r");
360: cli();
1.1.1.9 root 361: if (++CURRENT->errors >= MAX_ERRORS) {
362: #ifdef DEBUG
363: printk("hd : too many errors.\n");
364: #endif
1.1.1.8 root 365: end_request(0);
1.1.1.9 root 366: }
367:
1.1.1.3 root 368: do_hd_request();
369: }
370:
1.1.1.9 root 371: /*
372: * The driver has been modified to enable interrupts a bit more: in order to
373: * do this we first (a) disable the timeout-interrupt and (b) clear the
374: * device-interrupt. This way the interrupts won't mess with out code (the
375: * worst that can happen is that an unexpected HD-interrupt comes in and
376: * sets the "reset" variable and starts the timer)
377: */
1.1.1.6 root 378: static void do_hd_request(void)
1.1 root 379: {
380: unsigned int block,dev;
1.1.1.10! root 381: unsigned int sec,head,cyl,track;
1.1 root 382: unsigned int nsect;
383:
1.1.1.10! root 384: if (DEVICE_INTR)
! 385: return;
1.1.1.9 root 386: repeat:
387: timer_active &= ~(1<<HD_TIMER);
388: sti();
1.1 root 389: INIT_REQUEST;
390: dev = MINOR(CURRENT->dev);
391: block = CURRENT->sector;
1.1.1.5 root 392: nsect = CURRENT->nr_sectors;
1.1.1.8 root 393: if (dev >= (NR_HD<<6) || block >= hd[dev].nr_sects) {
1.1.1.9 root 394: #ifdef DEBUG
395: printk("hd%d : attempted read for sector %d past end of device at sector %d.\n",
396: block, hd[dev].nr_sects);
397: #endif
1.1 root 398: end_request(0);
399: goto repeat;
400: }
401: block += hd[dev].start_sect;
1.1.1.4 root 402: dev >>= 6;
1.1.1.10! root 403: sec = block % hd_info[dev].sect + 1;
! 404: track = block / hd_info[dev].sect;
! 405: head = track % hd_info[dev].head;
! 406: cyl = track / hd_info[dev].head;
1.1.1.9 root 407: #ifdef DEBUG
408: printk("hd%d : cyl = %d, head = %d, sector = %d, buffer = %08x\n",
409: dev, cyl, head, sec, CURRENT->buffer);
410: #endif
411: cli();
1.1.1.2 root 412: if (reset) {
1.1.1.10! root 413: int i;
! 414:
! 415: for (i=0; i < NR_HD; i++)
! 416: recalibrate[i] = 1;
1.1.1.3 root 417: reset_hd();
1.1.1.9 root 418: sti();
1.1.1.2 root 419: return;
420: }
1.1.1.10! root 421: if (recalibrate[dev]) {
! 422: recalibrate[dev] = 0;
1.1.1.7 root 423: hd_out(dev,hd_info[dev].sect,0,0,0,WIN_RESTORE,&recal_intr);
1.1.1.4 root 424: if (reset)
425: goto repeat;
1.1.1.9 root 426: sti();
1.1.1.2 root 427: return;
428: }
1.1 root 429: if (CURRENT->cmd == WRITE) {
430: hd_out(dev,nsect,sec,head,cyl,WIN_WRITE,&write_intr);
1.1.1.4 root 431: if (reset)
432: goto repeat;
1.1.1.9 root 433: if (wait_DRQ()) {
434: printk("HD: do_hd_request: no DRQ\n");
1.1.1.2 root 435: bad_rw_intr();
436: goto repeat;
1.1 root 437: }
438: port_write(HD_DATA,CURRENT->buffer,256);
1.1.1.9 root 439: sti();
1.1.1.10! root 440: return;
! 441: }
! 442: if (CURRENT->cmd == READ) {
1.1 root 443: hd_out(dev,nsect,sec,head,cyl,WIN_READ,&read_intr);
1.1.1.4 root 444: if (reset)
445: goto repeat;
1.1.1.9 root 446: sti();
1.1.1.10! root 447: return;
! 448: }
! 449: panic("unknown hd-command");
1.1 root 450: }
451:
1.1.1.7 root 452: static int hd_ioctl(struct inode * inode, struct file * file,
453: unsigned int cmd, unsigned int arg)
1.1.1.6 root 454: {
455: struct hd_geometry *loc = (void *) arg;
1.1.1.7 root 456: int dev;
1.1.1.6 root 457:
1.1.1.7 root 458: if (!loc || !inode)
1.1.1.6 root 459: return -EINVAL;
1.1.1.7 root 460: dev = MINOR(inode->i_rdev) >> 6;
1.1.1.6 root 461: if (dev >= NR_HD)
462: return -EINVAL;
463: switch (cmd) {
464: case HDIO_REQ:
1.1.1.7 root 465: verify_area(loc, sizeof(*loc));
1.1.1.6 root 466: put_fs_byte(hd_info[dev].head,
467: (char *) &loc->heads);
468: put_fs_byte(hd_info[dev].sect,
469: (char *) &loc->sectors);
470: put_fs_word(hd_info[dev].cyl,
471: (short *) &loc->cylinders);
1.1.1.9 root 472: put_fs_long(hd[MINOR(inode->i_rdev)].start_sect,
473: (long *) &loc->start);
1.1.1.6 root 474: return 0;
1.1.1.9 root 475: RO_IOCTLS(inode->i_rdev,arg);
1.1.1.6 root 476: default:
477: return -EINVAL;
478: }
479: }
1.1.1.7 root 480:
481: /*
482: * Releasing a block device means we sync() it, so that it can safely
483: * be forgotten about...
484: */
485: static void hd_release(struct inode * inode, struct file * file)
486: {
487: sync_dev(inode->i_rdev);
488: }
489:
1.1.1.9 root 490: static void hd_geninit();
491:
492: static struct gendisk hd_gendisk = {
493: MAJOR_NR, /* Major number */
494: "hd", /* Major name */
495: 6, /* Bits to shift to get real from partition */
496: 1 << 6, /* Number of partitions per real */
497: MAX_HD, /* maximum number of real */
498: hd_geninit, /* init function */
499: hd, /* hd struct */
500: hd_sizes, /* block sizes */
501: 0, /* number */
502: (void *) hd_info, /* internal */
503: NULL /* next */
504: };
505:
506: static void hd_geninit(void)
507: {
1.1.1.10! root 508: int drive, i;
1.1.1.9 root 509: #ifndef HD_TYPE
510: extern struct drive_info drive_info;
511: void *BIOS = (void *) &drive_info;
1.1.1.10! root 512: int cmos_disks;
1.1.1.9 root 513:
514: for (drive=0 ; drive<2 ; drive++) {
515: hd_info[drive].cyl = *(unsigned short *) BIOS;
516: hd_info[drive].head = *(unsigned char *) (2+BIOS);
517: hd_info[drive].wpcom = *(unsigned short *) (5+BIOS);
518: hd_info[drive].ctl = *(unsigned char *) (8+BIOS);
519: hd_info[drive].lzone = *(unsigned short *) (12+BIOS);
520: hd_info[drive].sect = *(unsigned char *) (14+BIOS);
521: BIOS += 16;
522: }
523:
524: /*
525: We querry CMOS about hard disks : it could be that
526: we have a SCSI/ESDI/etc controller that is BIOS
527: compatable with ST-506, and thus showing up in our
528: BIOS table, but not register compatable, and therefore
529: not present in CMOS.
530:
531: Furthurmore, we will assume that our ST-506 drives
532: <if any> are the primary drives in the system, and
533: the ones reflected as drive 1 or 2.
534:
535: The first drive is stored in the high nibble of CMOS
536: byte 0x12, the second in the low nibble. This will be
537: either a 4 bit drive type or 0xf indicating use byte 0x19
538: for an 8 bit type, drive 1, 0x1a for drive 2 in CMOS.
539:
540: Needless to say, a non-zero value means we have
541: an AT controller hard disk for that drive.
542:
543:
544: */
545:
546: if ((cmos_disks = CMOS_READ(0x12)) & 0xf0)
547: if (cmos_disks & 0x0f)
548: NR_HD = 2;
549: else
550: NR_HD = 1;
551: else
552: NR_HD = 0;
553: #endif
554:
555: for (i = 0 ; i < NR_HD ; i++)
556: hd[i<<6].nr_sects = hd_info[i].head*
557: hd_info[i].sect*hd_info[i].cyl;
558:
559: hd_gendisk.nr_real = NR_HD;
560: }
561:
1.1.1.7 root 562: static struct file_operations hd_fops = {
563: NULL, /* lseek - default */
564: block_read, /* read - general block-dev read */
565: block_write, /* write - general block-dev write */
566: NULL, /* readdir - bad */
567: NULL, /* select */
568: hd_ioctl, /* ioctl */
569: NULL, /* no special open code */
570: hd_release /* release */
571: };
572:
1.1.1.9 root 573: static void hd_interrupt(int unused)
574: {
575: void (*handler)(void) = DEVICE_INTR;
576:
577: DEVICE_INTR = NULL;
578: timer_active &= ~(1<<HD_TIMER);
579: if (!handler)
580: handler = unexpected_hd_interrupt;
581: handler();
582: sti();
583: }
584:
585: /*
1.1.1.10! root 586: * This is the harddisk IRQ description. The SA_INTERRUPT in sa_flags
1.1.1.9 root 587: * means we run the IRQ-handler with interrupts disabled: this is bad for
588: * interrupt latency, but anything else has led to problems on some
589: * machines...
590: *
591: * We enable interrupts in some of the routines after making sure it's
592: * safe.
593: */
594: static struct sigaction hd_sigaction = {
595: hd_interrupt,
596: 0,
597: SA_INTERRUPT,
598: NULL
599: };
600:
1.1.1.10! root 601: unsigned long hd_init(unsigned long mem_start, unsigned long mem_end)
1.1.1.7 root 602: {
603: blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
604: blkdev_fops[MAJOR_NR] = &hd_fops;
1.1.1.9 root 605: hd_gendisk.next = gendisk_head;
606: gendisk_head = &hd_gendisk;
607: if (irqaction(HD_IRQ,&hd_sigaction))
608: printk("Unable to get IRQ%d for the harddisk driver\n",HD_IRQ);
1.1.1.7 root 609: timer_table[HD_TIMER].fn = hd_times_out;
1.1.1.10! root 610: return mem_start;
1.1.1.7 root 611: }
1.1.1.9 root 612:
613: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.