Annotation of linux/kernel/blk_drv/hd.c, revision 1.1.1.9

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.