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

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

unix.superglobalmegacorp.com

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