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

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       root       14:  */
                     15: 
                     16: #include <linux/config.h>
                     17: #include <linux/sched.h>
                     18: #include <linux/fs.h>
                     19: #include <linux/kernel.h>
                     20: #include <linux/hdreg.h>
                     21: #include <asm/system.h>
                     22: #include <asm/io.h>
                     23: #include <asm/segment.h>
                     24: 
                     25: #define MAJOR_NR 3
                     26: #include "blk.h"
                     27: 
1.1.1.2 ! root       28: #define CMOS_READ(addr) ({ \
        !            29: outb_p(0x80|addr,0x70); \
        !            30: inb_p(0x71); \
        !            31: })
        !            32: 
1.1       root       33: /* Max read/write errors/sector */
1.1.1.2 ! root       34: #define MAX_ERRORS     7
1.1       root       35: #define MAX_HD         2
                     36: 
1.1.1.2 ! root       37: static void recal_intr(void);
        !            38: 
        !            39: static int recalibrate = 1;
        !            40: static int reset = 1;
        !            41: 
1.1       root       42: /*
                     43:  *  This struct defines the HD's and their types.
                     44:  */
                     45: struct hd_i_struct {
                     46:        int head,sect,cyl,wpcom,lzone,ctl;
                     47:        };
                     48: #ifdef HD_TYPE
                     49: struct hd_i_struct hd_info[] = { HD_TYPE };
                     50: #define NR_HD ((sizeof (hd_info))/(sizeof (struct hd_i_struct)))
                     51: #else
                     52: struct hd_i_struct hd_info[] = { {0,0,0,0,0,0},{0,0,0,0,0,0} };
                     53: static int NR_HD = 0;
                     54: #endif
                     55: 
                     56: static struct hd_struct {
                     57:        long start_sect;
                     58:        long nr_sects;
                     59: } hd[5*MAX_HD]={{0,0},};
                     60: 
                     61: #define port_read(port,buf,nr) \
                     62: __asm__("cld;rep;insw"::"d" (port),"D" (buf),"c" (nr):"cx","di")
                     63: 
                     64: #define port_write(port,buf,nr) \
                     65: __asm__("cld;rep;outsw"::"d" (port),"S" (buf),"c" (nr):"cx","si")
                     66: 
                     67: extern void hd_interrupt(void);
1.1.1.2 ! root       68: extern void rd_load(void);
1.1       root       69: 
                     70: /* This may be used only once, enforced by 'static int callable' */
                     71: int sys_setup(void * BIOS)
                     72: {
                     73:        static int callable = 1;
                     74:        int i,drive;
1.1.1.2 ! root       75:        unsigned char cmos_disks;
1.1       root       76:        struct partition *p;
                     77:        struct buffer_head * bh;
                     78: 
                     79:        if (!callable)
                     80:                return -1;
                     81:        callable = 0;
                     82: #ifndef HD_TYPE
                     83:        for (drive=0 ; drive<2 ; drive++) {
                     84:                hd_info[drive].cyl = *(unsigned short *) BIOS;
                     85:                hd_info[drive].head = *(unsigned char *) (2+BIOS);
                     86:                hd_info[drive].wpcom = *(unsigned short *) (5+BIOS);
                     87:                hd_info[drive].ctl = *(unsigned char *) (8+BIOS);
                     88:                hd_info[drive].lzone = *(unsigned short *) (12+BIOS);
                     89:                hd_info[drive].sect = *(unsigned char *) (14+BIOS);
                     90:                BIOS += 16;
                     91:        }
                     92:        if (hd_info[1].cyl)
                     93:                NR_HD=2;
                     94:        else
                     95:                NR_HD=1;
                     96: #endif
                     97:        for (i=0 ; i<NR_HD ; i++) {
                     98:                hd[i*5].start_sect = 0;
                     99:                hd[i*5].nr_sects = hd_info[i].head*
                    100:                                hd_info[i].sect*hd_info[i].cyl;
                    101:        }
1.1.1.2 ! root      102: 
        !           103:        /*
        !           104:                We querry CMOS about hard disks : it could be that 
        !           105:                we have a SCSI/ESDI/etc controller that is BIOS
        !           106:                compatable with ST-506, and thus showing up in our
        !           107:                BIOS table, but not register compatable, and therefore
        !           108:                not present in CMOS.
        !           109: 
        !           110:                Furthurmore, we will assume that our ST-506 drives
        !           111:                <if any> are the primary drives in the system, and 
        !           112:                the ones reflected as drive 1 or 2.
        !           113: 
        !           114:                The first drive is stored in the high nibble of CMOS
        !           115:                byte 0x12, the second in the low nibble.  This will be
        !           116:                either a 4 bit drive type or 0xf indicating use byte 0x19 
        !           117:                for an 8 bit type, drive 1, 0x1a for drive 2 in CMOS.
        !           118: 
        !           119:                Needless to say, a non-zero value means we have 
        !           120:                an AT controller hard disk for that drive.
        !           121: 
        !           122:                
        !           123:        */
        !           124: 
        !           125:        if ((cmos_disks = CMOS_READ(0x12)) & 0xf0)
        !           126:                if (cmos_disks & 0x0f)
        !           127:                        NR_HD = 2;
        !           128:                else
        !           129:                        NR_HD = 1;
        !           130:        else
        !           131:                NR_HD = 0;
        !           132:        for (i = NR_HD ; i < 2 ; i++) {
        !           133:                hd[i*5].start_sect = 0;
        !           134:                hd[i*5].nr_sects = 0;
        !           135:        }
1.1       root      136:        for (drive=0 ; drive<NR_HD ; drive++) {
                    137:                if (!(bh = bread(0x300 + drive*5,0))) {
                    138:                        printk("Unable to read partition table of drive %d\n\r",
                    139:                                drive);
                    140:                        panic("");
                    141:                }
                    142:                if (bh->b_data[510] != 0x55 || (unsigned char)
                    143:                    bh->b_data[511] != 0xAA) {
                    144:                        printk("Bad partition table on drive %d\n\r",drive);
                    145:                        panic("");
                    146:                }
                    147:                p = 0x1BE + (void *)bh->b_data;
                    148:                for (i=1;i<5;i++,p++) {
                    149:                        hd[i+5*drive].start_sect = p->start_sect;
                    150:                        hd[i+5*drive].nr_sects = p->nr_sects;
                    151:                }
                    152:                brelse(bh);
                    153:        }
1.1.1.2 ! root      154:        if (NR_HD)
        !           155:                printk("Partition table%s ok.\n\r",(NR_HD>1)?"s":"");
        !           156:        rd_load();
1.1       root      157:        mount_root();
                    158:        return (0);
                    159: }
                    160: 
                    161: static int controller_ready(void)
                    162: {
1.1.1.2 ! root      163:        int retries=10000;
1.1       root      164: 
1.1.1.2 ! root      165:        while (--retries && (inb_p(HD_STATUS)&0xc0)!=0x40);
1.1       root      166:        return (retries);
                    167: }
                    168: 
                    169: static int win_result(void)
                    170: {
1.1.1.2 ! root      171:        int i=inb_p(HD_STATUS);
1.1       root      172: 
                    173:        if ((i & (BUSY_STAT | READY_STAT | WRERR_STAT | SEEK_STAT | ERR_STAT))
                    174:                == (READY_STAT | SEEK_STAT))
                    175:                return(0); /* ok */
                    176:        if (i&1) i=inb(HD_ERROR);
                    177:        return (1);
                    178: }
                    179: 
                    180: static void hd_out(unsigned int drive,unsigned int nsect,unsigned int sect,
                    181:                unsigned int head,unsigned int cyl,unsigned int cmd,
                    182:                void (*intr_addr)(void))
                    183: {
                    184:        register int port asm("dx");
                    185: 
                    186:        if (drive>1 || head>15)
                    187:                panic("Trying to write bad sector");
                    188:        if (!controller_ready())
                    189:                panic("HD controller not ready");
                    190:        do_hd = intr_addr;
1.1.1.2 ! root      191:        outb_p(hd_info[drive].ctl,HD_CMD);
1.1       root      192:        port=HD_DATA;
                    193:        outb_p(hd_info[drive].wpcom>>2,++port);
                    194:        outb_p(nsect,++port);
                    195:        outb_p(sect,++port);
                    196:        outb_p(cyl,++port);
                    197:        outb_p(cyl>>8,++port);
                    198:        outb_p(0xA0|(drive<<4)|head,++port);
                    199:        outb(cmd,++port);
                    200: }
                    201: 
                    202: static int drive_busy(void)
                    203: {
                    204:        unsigned int i;
                    205: 
1.1.1.2 ! root      206:        for (i = 0; i < 10000; i++)
        !           207:                if (READY_STAT == (inb_p(HD_STATUS) & (BUSY_STAT|READY_STAT)))
1.1       root      208:                        break;
                    209:        i = inb(HD_STATUS);
                    210:        i &= BUSY_STAT | READY_STAT | SEEK_STAT;
                    211:        if (i == READY_STAT | SEEK_STAT)
                    212:                return(0);
                    213:        printk("HD controller times out\n\r");
                    214:        return(1);
                    215: }
                    216: 
                    217: static void reset_controller(void)
                    218: {
                    219:        int     i;
                    220: 
                    221:        outb(4,HD_CMD);
1.1.1.2 ! root      222:        for(i = 0; i < 100; i++) nop();
        !           223:        outb(hd_info[0].ctl & 0x0f ,HD_CMD);
1.1       root      224:        if (drive_busy())
                    225:                printk("HD-controller still busy\n\r");
1.1.1.2 ! root      226:        if ((i = inb(HD_ERROR)) != 1)
1.1       root      227:                printk("HD-controller reset failed: %02x\n\r",i);
                    228: }
                    229: 
                    230: static void reset_hd(int nr)
                    231: {
                    232:        reset_controller();
                    233:        hd_out(nr,hd_info[nr].sect,hd_info[nr].sect,hd_info[nr].head-1,
1.1.1.2 ! root      234:                hd_info[nr].cyl,WIN_SPECIFY,&recal_intr);
1.1       root      235: }
                    236: 
                    237: void unexpected_hd_interrupt(void)
                    238: {
                    239:        printk("Unexpected HD interrupt\n\r");
                    240: }
                    241: 
                    242: static void bad_rw_intr(void)
                    243: {
1.1.1.2 ! root      244:        if (++CURRENT->errors >= MAX_ERRORS)
1.1       root      245:                end_request(0);
1.1.1.2 ! root      246:        if (CURRENT->errors > MAX_ERRORS/2)
        !           247:                reset = 1;
1.1       root      248: }
                    249: 
                    250: static void read_intr(void)
                    251: {
                    252:        if (win_result()) {
                    253:                bad_rw_intr();
1.1.1.2 ! root      254:                do_hd_request();
1.1       root      255:                return;
                    256:        }
                    257:        port_read(HD_DATA,CURRENT->buffer,256);
                    258:        CURRENT->errors = 0;
                    259:        CURRENT->buffer += 512;
                    260:        CURRENT->sector++;
1.1.1.2 ! root      261:        if (--CURRENT->nr_sectors) {
        !           262:                do_hd = &read_intr;
1.1       root      263:                return;
1.1.1.2 ! root      264:        }
1.1       root      265:        end_request(1);
                    266:        do_hd_request();
                    267: }
                    268: 
                    269: static void write_intr(void)
                    270: {
                    271:        if (win_result()) {
                    272:                bad_rw_intr();
1.1.1.2 ! root      273:                do_hd_request();
1.1       root      274:                return;
                    275:        }
                    276:        if (--CURRENT->nr_sectors) {
                    277:                CURRENT->sector++;
                    278:                CURRENT->buffer += 512;
1.1.1.2 ! root      279:                do_hd = &write_intr;
1.1       root      280:                port_write(HD_DATA,CURRENT->buffer,256);
                    281:                return;
                    282:        }
                    283:        end_request(1);
                    284:        do_hd_request();
                    285: }
                    286: 
1.1.1.2 ! root      287: static void recal_intr(void)
        !           288: {
        !           289:        if (win_result())
        !           290:                bad_rw_intr();
        !           291:        do_hd_request();
        !           292: }
        !           293: 
1.1       root      294: void do_hd_request(void)
                    295: {
                    296:        int i,r;
                    297:        unsigned int block,dev;
                    298:        unsigned int sec,head,cyl;
                    299:        unsigned int nsect;
                    300: 
                    301:        INIT_REQUEST;
                    302:        dev = MINOR(CURRENT->dev);
                    303:        block = CURRENT->sector;
                    304:        if (dev >= 5*NR_HD || block+2 > hd[dev].nr_sects) {
                    305:                end_request(0);
                    306:                goto repeat;
                    307:        }
                    308:        block += hd[dev].start_sect;
                    309:        dev /= 5;
                    310:        __asm__("divl %4":"=a" (block),"=d" (sec):"0" (block),"1" (0),
                    311:                "r" (hd_info[dev].sect));
                    312:        __asm__("divl %4":"=a" (cyl),"=d" (head):"0" (block),"1" (0),
                    313:                "r" (hd_info[dev].head));
                    314:        sec++;
                    315:        nsect = CURRENT->nr_sectors;
1.1.1.2 ! root      316:        if (reset) {
        !           317:                reset = 0;
        !           318:                recalibrate = 1;
        !           319:                reset_hd(CURRENT_DEV);
        !           320:                return;
        !           321:        }
        !           322:        if (recalibrate) {
        !           323:                recalibrate = 0;
        !           324:                hd_out(dev,hd_info[CURRENT_DEV].sect,0,0,0,
        !           325:                        WIN_RESTORE,&recal_intr);
        !           326:                return;
        !           327:        }       
1.1       root      328:        if (CURRENT->cmd == WRITE) {
                    329:                hd_out(dev,nsect,sec,head,cyl,WIN_WRITE,&write_intr);
                    330:                for(i=0 ; i<3000 && !(r=inb_p(HD_STATUS)&DRQ_STAT) ; i++)
                    331:                        /* nothing */ ;
                    332:                if (!r) {
1.1.1.2 ! root      333:                        bad_rw_intr();
        !           334:                        goto repeat;
1.1       root      335:                }
                    336:                port_write(HD_DATA,CURRENT->buffer,256);
                    337:        } else if (CURRENT->cmd == READ) {
                    338:                hd_out(dev,nsect,sec,head,cyl,WIN_READ,&read_intr);
                    339:        } else
                    340:                panic("unknown hd-command");
                    341: }
                    342: 
                    343: void hd_init(void)
                    344: {
                    345:        blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
1.1.1.2 ! root      346:        set_intr_gate(0x2E,&hd_interrupt);
1.1       root      347:        outb_p(inb_p(0x21)&0xfb,0x21);
                    348:        outb(inb_p(0xA1)&0xbf,0xA1);
                    349: }

unix.superglobalmegacorp.com

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