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

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

unix.superglobalmegacorp.com

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