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

1.1     ! root        1: #include <linux/config.h>
        !             2: #include <linux/sched.h>
        !             3: #include <linux/fs.h>
        !             4: #include <linux/kernel.h>
        !             5: #include <linux/hdreg.h>
        !             6: #include <asm/system.h>
        !             7: #include <asm/io.h>
        !             8: #include <asm/segment.h>
        !             9: 
        !            10: /*
        !            11:  * This code handles all hd-interrupts, and read/write requests to
        !            12:  * the hard-disk. It is relatively straigthforward (not obvious maybe,
        !            13:  * but interrupts never are), while still being efficient, and never
        !            14:  * disabling interrupts (except to overcome possible race-condition).
        !            15:  * The elevator block-seek algorithm doesn't need to disable interrupts
        !            16:  * due to clever programming.
        !            17:  */
        !            18: 
        !            19: /* Max read/write errors/sector */
        !            20: #define MAX_ERRORS     5
        !            21: #define MAX_HD         2
        !            22: #define NR_REQUEST     32
        !            23: 
        !            24: /*
        !            25:  *  This struct defines the HD's and their types.
        !            26:  *  Currently defined for CP3044's, ie a modified
        !            27:  *  type 17.
        !            28:  */
        !            29: static struct hd_i_struct{
        !            30:        int head,sect,cyl,wpcom,lzone,ctl;
        !            31:        } hd_info[]= { HD_TYPE };
        !            32: 
        !            33: #define NR_HD ((sizeof (hd_info))/(sizeof (struct hd_i_struct)))
        !            34: 
        !            35: static struct hd_struct {
        !            36:        long start_sect;
        !            37:        long nr_sects;
        !            38: } hd[5*MAX_HD]={{0,0},};
        !            39: 
        !            40: static struct hd_request {
        !            41:        int hd;         /* -1 if no request */
        !            42:        int nsector;
        !            43:        int sector;
        !            44:        int head;
        !            45:        int cyl;
        !            46:        int cmd;
        !            47:        int errors;
        !            48:        struct buffer_head * bh;
        !            49:        struct hd_request * next;
        !            50: } request[NR_REQUEST];
        !            51: 
        !            52: #define IN_ORDER(s1,s2) \
        !            53: ((s1)->hd<(s2)->hd || (s1)->hd==(s2)->hd && \
        !            54: ((s1)->cyl<(s2)->cyl || (s1)->cyl==(s2)->cyl && \
        !            55: ((s1)->head<(s2)->head || (s1)->head==(s2)->head && \
        !            56: ((s1)->sector<(s2)->sector))))
        !            57: 
        !            58: static struct hd_request * this_request = NULL;
        !            59: 
        !            60: static int sorting=0;
        !            61: 
        !            62: static void do_request(void);
        !            63: static void reset_controller(void);
        !            64: static void rw_abs_hd(int rw,unsigned int nr,unsigned int sec,unsigned int head,
        !            65:        unsigned int cyl,struct buffer_head * bh);
        !            66: void hd_init(void);
        !            67: 
        !            68: #define port_read(port,buf,nr) \
        !            69: __asm__("cld;rep;insw"::"d" (port),"D" (buf),"c" (nr):"cx","di")
        !            70: 
        !            71: #define port_write(port,buf,nr) \
        !            72: __asm__("cld;rep;outsw"::"d" (port),"S" (buf),"c" (nr):"cx","si")
        !            73: 
        !            74: extern void hd_interrupt(void);
        !            75: 
        !            76: static struct task_struct * wait_for_request=NULL;
        !            77: 
        !            78: static inline void lock_buffer(struct buffer_head * bh)
        !            79: {
        !            80:        if (bh->b_lock)
        !            81:                printk("hd.c: buffer multiply locked\n");
        !            82:        bh->b_lock=1;
        !            83: }
        !            84: 
        !            85: static inline void unlock_buffer(struct buffer_head * bh)
        !            86: {
        !            87:        if (!bh->b_lock)
        !            88:                printk("hd.c: free buffer being unlocked\n");
        !            89:        bh->b_lock=0;
        !            90:        wake_up(&bh->b_wait);
        !            91: }
        !            92: 
        !            93: static inline void wait_on_buffer(struct buffer_head * bh)
        !            94: {
        !            95:        cli();
        !            96:        while (bh->b_lock)
        !            97:                sleep_on(&bh->b_wait);
        !            98:        sti();
        !            99: }
        !           100: 
        !           101: void rw_hd(int rw, struct buffer_head * bh)
        !           102: {
        !           103:        unsigned int block,dev;
        !           104:        unsigned int sec,head,cyl;
        !           105: 
        !           106:        block = bh->b_blocknr << 1;
        !           107:        dev = MINOR(bh->b_dev);
        !           108:        if (dev >= 5*NR_HD || block+2 > hd[dev].nr_sects)
        !           109:                return;
        !           110:        block += hd[dev].start_sect;
        !           111:        dev /= 5;
        !           112:        __asm__("divl %4":"=a" (block),"=d" (sec):"0" (block),"1" (0),
        !           113:                "r" (hd_info[dev].sect));
        !           114:        __asm__("divl %4":"=a" (cyl),"=d" (head):"0" (block),"1" (0),
        !           115:                "r" (hd_info[dev].head));
        !           116:        rw_abs_hd(rw,dev,sec+1,head,cyl,bh);
        !           117: }
        !           118: 
        !           119: /* This may be used only once, enforced by 'static int callable' */
        !           120: int sys_setup(void)
        !           121: {
        !           122:        static int callable = 1;
        !           123:        int i,drive;
        !           124:        struct partition *p;
        !           125: 
        !           126:        if (!callable)
        !           127:                return -1;
        !           128:        callable = 0;
        !           129:        for (drive=0 ; drive<NR_HD ; drive++) {
        !           130:                rw_abs_hd(READ,drive,1,0,0,(struct buffer_head *) start_buffer);
        !           131:                if (!start_buffer->b_uptodate) {
        !           132:                        printk("Unable to read partition table of drive %d\n\r",
        !           133:                                drive);
        !           134:                        panic("");
        !           135:                }
        !           136:                if (start_buffer->b_data[510] != 0x55 || (unsigned char)
        !           137:                    start_buffer->b_data[511] != 0xAA) {
        !           138:                        printk("Bad partition table on drive %d\n\r",drive);
        !           139:                        panic("");
        !           140:                }
        !           141:                p = 0x1BE + (void *)start_buffer->b_data;
        !           142:                for (i=1;i<5;i++,p++) {
        !           143:                        hd[i+5*drive].start_sect = p->start_sect;
        !           144:                        hd[i+5*drive].nr_sects = p->nr_sects;
        !           145:                }
        !           146:        }
        !           147:        printk("Partition table%s ok.\n\r",(NR_HD>1)?"s":"");
        !           148:        mount_root();
        !           149:        return (0);
        !           150: }
        !           151: 
        !           152: /*
        !           153:  * This is the pointer to a routine to be executed at every hd-interrupt.
        !           154:  * Interesting way of doing things, but should be rather practical.
        !           155:  */
        !           156: void (*do_hd)(void) = NULL;
        !           157: 
        !           158: static int controller_ready(void)
        !           159: {
        !           160:        int retries=1000;
        !           161: 
        !           162:        while (--retries && (inb(HD_STATUS)&0xc0)!=0x40);
        !           163:        return (retries);
        !           164: }
        !           165: 
        !           166: static int win_result(void)
        !           167: {
        !           168:        int i=inb(HD_STATUS);
        !           169: 
        !           170:        if ((i & (BUSY_STAT | READY_STAT | WRERR_STAT | SEEK_STAT | ERR_STAT))
        !           171:                == (READY_STAT | SEEK_STAT))
        !           172:                return(0); /* ok */
        !           173:        if (i&1) i=inb(HD_ERROR);
        !           174:        return (1);
        !           175: }
        !           176: 
        !           177: static void hd_out(unsigned int drive,unsigned int nsect,unsigned int sect,
        !           178:                unsigned int head,unsigned int cyl,unsigned int cmd,
        !           179:                void (*intr_addr)(void))
        !           180: {
        !           181:        register int port asm("dx");
        !           182: 
        !           183:        if (drive>1 || head>15)
        !           184:                panic("Trying to write bad sector");
        !           185:        if (!controller_ready())
        !           186:                panic("HD controller not ready");
        !           187:        do_hd = intr_addr;
        !           188:        outb(_CTL,HD_CMD);
        !           189:        port=HD_DATA;
        !           190:        outb_p(_WPCOM,++port);
        !           191:        outb_p(nsect,++port);
        !           192:        outb_p(sect,++port);
        !           193:        outb_p(cyl,++port);
        !           194:        outb_p(cyl>>8,++port);
        !           195:        outb_p(0xA0|(drive<<4)|head,++port);
        !           196:        outb(cmd,++port);
        !           197: }
        !           198: 
        !           199: static int drive_busy(void)
        !           200: {
        !           201:        unsigned int i;
        !           202: 
        !           203:        for (i = 0; i < 100000; i++)
        !           204:                if (READY_STAT == (inb(HD_STATUS) & (BUSY_STAT | READY_STAT)))
        !           205:                        break;
        !           206:        i = inb(HD_STATUS);
        !           207:        i &= BUSY_STAT | READY_STAT | SEEK_STAT;
        !           208:        if (i == READY_STAT | SEEK_STAT)
        !           209:                return(0);
        !           210:        printk("HD controller times out\n\r");
        !           211:        return(1);
        !           212: }
        !           213: 
        !           214: static void reset_controller(void)
        !           215: {
        !           216:        int     i;
        !           217: 
        !           218:        outb(4,HD_CMD);
        !           219:        for(i = 0; i < 1000; i++) nop();
        !           220:        outb(0,HD_CMD);
        !           221:        for(i = 0; i < 10000 && drive_busy(); i++) /* nothing */;
        !           222:        if (drive_busy())
        !           223:                printk("HD-controller still busy\n\r");
        !           224:        if((i = inb(ERR_STAT)) != 1)
        !           225:                printk("HD-controller reset failed: %02x\n\r",i);
        !           226: }
        !           227: 
        !           228: static void reset_hd(int nr)
        !           229: {
        !           230:        reset_controller();
        !           231:        hd_out(nr,_SECT,_SECT,_HEAD-1,_CYL,WIN_SPECIFY,&do_request);
        !           232: }
        !           233: 
        !           234: void unexpected_hd_interrupt(void)
        !           235: {
        !           236:        panic("Unexpected HD interrupt\n\r");
        !           237: }
        !           238: 
        !           239: static void bad_rw_intr(void)
        !           240: {
        !           241:        int i = this_request->hd;
        !           242: 
        !           243:        if (this_request->errors++ >= MAX_ERRORS) {
        !           244:                this_request->bh->b_uptodate = 0;
        !           245:                unlock_buffer(this_request->bh);
        !           246:                wake_up(&wait_for_request);
        !           247:                this_request->hd = -1;
        !           248:                this_request=this_request->next;
        !           249:        }
        !           250:        reset_hd(i);
        !           251: }
        !           252: 
        !           253: static void read_intr(void)
        !           254: {
        !           255:        if (win_result()) {
        !           256:                bad_rw_intr();
        !           257:                return;
        !           258:        }
        !           259:        port_read(HD_DATA,this_request->bh->b_data+
        !           260:                512*(this_request->nsector&1),256);
        !           261:        this_request->errors = 0;
        !           262:        if (--this_request->nsector)
        !           263:                return;
        !           264:        this_request->bh->b_uptodate = 1;
        !           265:        this_request->bh->b_dirt = 0;
        !           266:        wake_up(&wait_for_request);
        !           267:        unlock_buffer(this_request->bh);
        !           268:        this_request->hd = -1;
        !           269:        this_request=this_request->next;
        !           270:        do_request();
        !           271: }
        !           272: 
        !           273: static void write_intr(void)
        !           274: {
        !           275:        if (win_result()) {
        !           276:                bad_rw_intr();
        !           277:                return;
        !           278:        }
        !           279:        if (--this_request->nsector) {
        !           280:                port_write(HD_DATA,this_request->bh->b_data+512,256);
        !           281:                return;
        !           282:        }
        !           283:        this_request->bh->b_uptodate = 1;
        !           284:        this_request->bh->b_dirt = 0;
        !           285:        wake_up(&wait_for_request);
        !           286:        unlock_buffer(this_request->bh);
        !           287:        this_request->hd = -1;
        !           288:        this_request=this_request->next;
        !           289:        do_request();
        !           290: }
        !           291: 
        !           292: static void do_request(void)
        !           293: {
        !           294:        int i,r;
        !           295: 
        !           296:        if (sorting)
        !           297:                return;
        !           298:        if (!this_request) {
        !           299:                do_hd=NULL;
        !           300:                return;
        !           301:        }
        !           302:        if (this_request->cmd == WIN_WRITE) {
        !           303:                hd_out(this_request->hd,this_request->nsector,this_request->
        !           304:                        sector,this_request->head,this_request->cyl,
        !           305:                        this_request->cmd,&write_intr);
        !           306:                for(i=0 ; i<3000 && !(r=inb_p(HD_STATUS)&DRQ_STAT) ; i++)
        !           307:                        /* nothing */ ;
        !           308:                if (!r) {
        !           309:                        reset_hd(this_request->hd);
        !           310:                        return;
        !           311:                }
        !           312:                port_write(HD_DATA,this_request->bh->b_data+
        !           313:                        512*(this_request->nsector&1),256);
        !           314:        } else if (this_request->cmd == WIN_READ) {
        !           315:                hd_out(this_request->hd,this_request->nsector,this_request->
        !           316:                        sector,this_request->head,this_request->cyl,
        !           317:                        this_request->cmd,&read_intr);
        !           318:        } else
        !           319:                panic("unknown hd-command");
        !           320: }
        !           321: 
        !           322: /*
        !           323:  * add-request adds a request to the linked list.
        !           324:  * It sets the 'sorting'-variable when doing something
        !           325:  * that interrupts shouldn't touch.
        !           326:  */
        !           327: static void add_request(struct hd_request * req)
        !           328: {
        !           329:        struct hd_request * tmp;
        !           330: 
        !           331:        if (req->nsector != 2)
        !           332:                panic("nsector!=2 not implemented");
        !           333: /*
        !           334:  * Not to mess up the linked lists, we never touch the two first
        !           335:  * entries (not this_request, as it is used by current interrups,
        !           336:  * and not this_request->next, as it can be assigned to this_request).
        !           337:  * This is not too high a price to pay for the ability of not
        !           338:  * disabling interrupts.
        !           339:  */
        !           340:        sorting=1;
        !           341:        if (!(tmp=this_request))
        !           342:                this_request=req;
        !           343:        else {
        !           344:                if (!(tmp->next))
        !           345:                        tmp->next=req;
        !           346:                else {
        !           347:                        tmp=tmp->next;
        !           348:                        for ( ; tmp->next ; tmp=tmp->next)
        !           349:                                if ((IN_ORDER(tmp,req) ||
        !           350:                                    !IN_ORDER(tmp,tmp->next)) &&
        !           351:                                    IN_ORDER(req,tmp->next))
        !           352:                                        break;
        !           353:                        req->next=tmp->next;
        !           354:                        tmp->next=req;
        !           355:                }
        !           356:        }
        !           357:        sorting=0;
        !           358: /*
        !           359:  * NOTE! As a result of sorting, the interrupts may have died down,
        !           360:  * as they aren't redone due to locking with sorting=1. They might
        !           361:  * also never have started, if this is the first request in the queue,
        !           362:  * so we restart them if necessary.
        !           363:  */
        !           364:        if (!do_hd)
        !           365:                do_request();
        !           366: }
        !           367: 
        !           368: void rw_abs_hd(int rw,unsigned int nr,unsigned int sec,unsigned int head,
        !           369:        unsigned int cyl,struct buffer_head * bh)
        !           370: {
        !           371:        struct hd_request * req;
        !           372: 
        !           373:        if (rw!=READ && rw!=WRITE)
        !           374:                panic("Bad hd command, must be R/W");
        !           375:        lock_buffer(bh);
        !           376: repeat:
        !           377:        for (req=0+request ; req<NR_REQUEST+request ; req++)
        !           378:                if (req->hd<0)
        !           379:                        break;
        !           380:        if (req==NR_REQUEST+request) {
        !           381:                sleep_on(&wait_for_request);
        !           382:                goto repeat;
        !           383:        }
        !           384:        req->hd=nr;
        !           385:        req->nsector=2;
        !           386:        req->sector=sec;
        !           387:        req->head=head;
        !           388:        req->cyl=cyl;
        !           389:        req->cmd = ((rw==READ)?WIN_READ:WIN_WRITE);
        !           390:        req->bh=bh;
        !           391:        req->errors=0;
        !           392:        req->next=NULL;
        !           393:        add_request(req);
        !           394:        wait_on_buffer(bh);
        !           395: }
        !           396: 
        !           397: void hd_init(void)
        !           398: {
        !           399:        int i;
        !           400: 
        !           401:        for (i=0 ; i<NR_REQUEST ; i++) {
        !           402:                request[i].hd = -1;
        !           403:                request[i].next = NULL;
        !           404:        }
        !           405:        for (i=0 ; i<NR_HD ; i++) {
        !           406:                hd[i*5].start_sect = 0;
        !           407:                hd[i*5].nr_sects = hd_info[i].head*
        !           408:                                hd_info[i].sect*hd_info[i].cyl;
        !           409:        }
        !           410:        set_trap_gate(0x2E,&hd_interrupt);
        !           411:        outb_p(inb_p(0x21)&0xfb,0x21);
        !           412:        outb(inb_p(0xA1)&0xbf,0xA1);
        !           413: }

unix.superglobalmegacorp.com

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