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

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

unix.superglobalmegacorp.com

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