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

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.
        !            12:  */
        !            13: 
        !            14: #include <linux/config.h>
        !            15: #include <linux/sched.h>
        !            16: #include <linux/fs.h>
        !            17: #include <linux/kernel.h>
        !            18: #include <linux/hdreg.h>
        !            19: #include <asm/system.h>
        !            20: #include <asm/io.h>
        !            21: #include <asm/segment.h>
        !            22: 
        !            23: #define MAJOR_NR 3
        !            24: #include "blk.h"
        !            25: 
        !            26: /* Max read/write errors/sector */
        !            27: #define MAX_ERRORS     5
        !            28: #define MAX_HD         2
        !            29: 
        !            30: /*
        !            31:  *  This struct defines the HD's and their types.
        !            32:  */
        !            33: struct hd_i_struct {
        !            34:        int head,sect,cyl,wpcom,lzone,ctl;
        !            35:        };
        !            36: #ifdef HD_TYPE
        !            37: struct hd_i_struct hd_info[] = { HD_TYPE };
        !            38: #define NR_HD ((sizeof (hd_info))/(sizeof (struct hd_i_struct)))
        !            39: #else
        !            40: struct hd_i_struct hd_info[] = { {0,0,0,0,0,0},{0,0,0,0,0,0} };
        !            41: static int NR_HD = 0;
        !            42: #endif
        !            43: 
        !            44: static struct hd_struct {
        !            45:        long start_sect;
        !            46:        long nr_sects;
        !            47: } hd[5*MAX_HD]={{0,0},};
        !            48: 
        !            49: #define port_read(port,buf,nr) \
        !            50: __asm__("cld;rep;insw"::"d" (port),"D" (buf),"c" (nr):"cx","di")
        !            51: 
        !            52: #define port_write(port,buf,nr) \
        !            53: __asm__("cld;rep;outsw"::"d" (port),"S" (buf),"c" (nr):"cx","si")
        !            54: 
        !            55: extern void hd_interrupt(void);
        !            56: 
        !            57: /* This may be used only once, enforced by 'static int callable' */
        !            58: int sys_setup(void * BIOS)
        !            59: {
        !            60:        static int callable = 1;
        !            61:        int i,drive;
        !            62:        struct partition *p;
        !            63:        struct buffer_head * bh;
        !            64: 
        !            65:        if (!callable)
        !            66:                return -1;
        !            67:        callable = 0;
        !            68: #ifndef HD_TYPE
        !            69:        for (drive=0 ; drive<2 ; drive++) {
        !            70:                hd_info[drive].cyl = *(unsigned short *) BIOS;
        !            71:                hd_info[drive].head = *(unsigned char *) (2+BIOS);
        !            72:                hd_info[drive].wpcom = *(unsigned short *) (5+BIOS);
        !            73:                hd_info[drive].ctl = *(unsigned char *) (8+BIOS);
        !            74:                hd_info[drive].lzone = *(unsigned short *) (12+BIOS);
        !            75:                hd_info[drive].sect = *(unsigned char *) (14+BIOS);
        !            76:                BIOS += 16;
        !            77:        }
        !            78:        if (hd_info[1].cyl)
        !            79:                NR_HD=2;
        !            80:        else
        !            81:                NR_HD=1;
        !            82: #endif
        !            83:        for (i=0 ; i<NR_HD ; i++) {
        !            84:                hd[i*5].start_sect = 0;
        !            85:                hd[i*5].nr_sects = hd_info[i].head*
        !            86:                                hd_info[i].sect*hd_info[i].cyl;
        !            87:        }
        !            88:        for (drive=0 ; drive<NR_HD ; drive++) {
        !            89:                if (!(bh = bread(0x300 + drive*5,0))) {
        !            90:                        printk("Unable to read partition table of drive %d\n\r",
        !            91:                                drive);
        !            92:                        panic("");
        !            93:                }
        !            94:                if (bh->b_data[510] != 0x55 || (unsigned char)
        !            95:                    bh->b_data[511] != 0xAA) {
        !            96:                        printk("Bad partition table on drive %d\n\r",drive);
        !            97:                        panic("");
        !            98:                }
        !            99:                p = 0x1BE + (void *)bh->b_data;
        !           100:                for (i=1;i<5;i++,p++) {
        !           101:                        hd[i+5*drive].start_sect = p->start_sect;
        !           102:                        hd[i+5*drive].nr_sects = p->nr_sects;
        !           103:                }
        !           104:                brelse(bh);
        !           105:        }
        !           106:        printk("Partition table%s ok.\n\r",(NR_HD>1)?"s":"");
        !           107:        mount_root();
        !           108:        return (0);
        !           109: }
        !           110: 
        !           111: static int controller_ready(void)
        !           112: {
        !           113:        int retries=1000;
        !           114: 
        !           115:        while (--retries && (inb(HD_STATUS)&0xc0)!=0x40);
        !           116:        return (retries);
        !           117: }
        !           118: 
        !           119: static int win_result(void)
        !           120: {
        !           121:        int i=inb(HD_STATUS);
        !           122: 
        !           123:        if ((i & (BUSY_STAT | READY_STAT | WRERR_STAT | SEEK_STAT | ERR_STAT))
        !           124:                == (READY_STAT | SEEK_STAT))
        !           125:                return(0); /* ok */
        !           126:        if (i&1) i=inb(HD_ERROR);
        !           127:        return (1);
        !           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: {
        !           134:        register int port asm("dx");
        !           135: 
        !           136:        if (drive>1 || head>15)
        !           137:                panic("Trying to write bad sector");
        !           138:        if (!controller_ready())
        !           139:                panic("HD controller not ready");
        !           140:        do_hd = intr_addr;
        !           141:        outb(hd_info[drive].ctl,HD_CMD);
        !           142:        port=HD_DATA;
        !           143:        outb_p(hd_info[drive].wpcom>>2,++port);
        !           144:        outb_p(nsect,++port);
        !           145:        outb_p(sect,++port);
        !           146:        outb_p(cyl,++port);
        !           147:        outb_p(cyl>>8,++port);
        !           148:        outb_p(0xA0|(drive<<4)|head,++port);
        !           149:        outb(cmd,++port);
        !           150: }
        !           151: 
        !           152: static int drive_busy(void)
        !           153: {
        !           154:        unsigned int i;
        !           155: 
        !           156:        for (i = 0; i < 100000; i++)
        !           157:                if (READY_STAT == (inb(HD_STATUS) & (BUSY_STAT | READY_STAT)))
        !           158:                        break;
        !           159:        i = inb(HD_STATUS);
        !           160:        i &= BUSY_STAT | READY_STAT | SEEK_STAT;
        !           161:        if (i == READY_STAT | SEEK_STAT)
        !           162:                return(0);
        !           163:        printk("HD controller times out\n\r");
        !           164:        return(1);
        !           165: }
        !           166: 
        !           167: static void reset_controller(void)
        !           168: {
        !           169:        int     i;
        !           170: 
        !           171:        outb(4,HD_CMD);
        !           172:        for(i = 0; i < 1000; i++) nop();
        !           173:        outb(0,HD_CMD);
        !           174:        for(i = 0; i < 10000 && drive_busy(); i++) /* nothing */;
        !           175:        if (drive_busy())
        !           176:                printk("HD-controller still busy\n\r");
        !           177:        if((i = inb(ERR_STAT)) != 1)
        !           178:                printk("HD-controller reset failed: %02x\n\r",i);
        !           179: }
        !           180: 
        !           181: static void redo_hd_request(void)
        !           182: {
        !           183:        do_hd = NULL;
        !           184:        do_hd_request();
        !           185: }
        !           186: 
        !           187: static void reset_hd(int nr)
        !           188: {
        !           189:        reset_controller();
        !           190:        hd_out(nr,hd_info[nr].sect,hd_info[nr].sect,hd_info[nr].head-1,
        !           191:                hd_info[nr].cyl,WIN_SPECIFY,&redo_hd_request);
        !           192: }
        !           193: 
        !           194: void unexpected_hd_interrupt(void)
        !           195: {
        !           196:        printk("Unexpected HD interrupt\n\r");
        !           197: }
        !           198: 
        !           199: static void bad_rw_intr(void)
        !           200: {
        !           201:        int i = CURRENT_DEV;
        !           202: 
        !           203:        if (CURRENT->errors++ >= MAX_ERRORS)
        !           204:                end_request(0);
        !           205:        reset_hd(i);
        !           206: }
        !           207: 
        !           208: static void read_intr(void)
        !           209: {
        !           210:        if (win_result()) {
        !           211:                bad_rw_intr();
        !           212:                return;
        !           213:        }
        !           214:        port_read(HD_DATA,CURRENT->buffer,256);
        !           215:        CURRENT->errors = 0;
        !           216:        CURRENT->buffer += 512;
        !           217:        CURRENT->sector++;
        !           218:        if (--CURRENT->nr_sectors)
        !           219:                return;
        !           220:        end_request(1);
        !           221:        do_hd_request();
        !           222: }
        !           223: 
        !           224: static void write_intr(void)
        !           225: {
        !           226:        if (win_result()) {
        !           227:                bad_rw_intr();
        !           228:                return;
        !           229:        }
        !           230:        if (--CURRENT->nr_sectors) {
        !           231:                CURRENT->sector++;
        !           232:                CURRENT->buffer += 512;
        !           233:                port_write(HD_DATA,CURRENT->buffer,256);
        !           234:                return;
        !           235:        }
        !           236:        end_request(1);
        !           237:        do_hd_request();
        !           238: }
        !           239: 
        !           240: void do_hd_request(void)
        !           241: {
        !           242:        int i,r;
        !           243:        unsigned int block,dev;
        !           244:        unsigned int sec,head,cyl;
        !           245:        unsigned int nsect;
        !           246: 
        !           247:        INIT_REQUEST;
        !           248:        dev = MINOR(CURRENT->dev);
        !           249:        block = CURRENT->sector;
        !           250:        if (dev >= 5*NR_HD || block+2 > hd[dev].nr_sects) {
        !           251:                end_request(0);
        !           252:                goto repeat;
        !           253:        }
        !           254:        block += hd[dev].start_sect;
        !           255:        dev /= 5;
        !           256:        __asm__("divl %4":"=a" (block),"=d" (sec):"0" (block),"1" (0),
        !           257:                "r" (hd_info[dev].sect));
        !           258:        __asm__("divl %4":"=a" (cyl),"=d" (head):"0" (block),"1" (0),
        !           259:                "r" (hd_info[dev].head));
        !           260:        sec++;
        !           261:        nsect = CURRENT->nr_sectors;
        !           262:        if (CURRENT->cmd == WRITE) {
        !           263:                hd_out(dev,nsect,sec,head,cyl,WIN_WRITE,&write_intr);
        !           264:                for(i=0 ; i<3000 && !(r=inb_p(HD_STATUS)&DRQ_STAT) ; i++)
        !           265:                        /* nothing */ ;
        !           266:                if (!r) {
        !           267:                        reset_hd(CURRENT_DEV);
        !           268:                        return;
        !           269:                }
        !           270:                port_write(HD_DATA,CURRENT->buffer,256);
        !           271:        } else if (CURRENT->cmd == READ) {
        !           272:                hd_out(dev,nsect,sec,head,cyl,WIN_READ,&read_intr);
        !           273:        } else
        !           274:                panic("unknown hd-command");
        !           275: }
        !           276: 
        !           277: void hd_init(void)
        !           278: {
        !           279:        blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
        !           280:        set_trap_gate(0x2E,&hd_interrupt);
        !           281:        outb_p(inb_p(0x21)&0xfb,0x21);
        !           282:        outb(inb_p(0xA1)&0xbf,0xA1);
        !           283: }

unix.superglobalmegacorp.com

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