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

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);
1.1.1.2 ! root      195:        outb_p(0xB0|(drive<<4)|head,++port);
1.1       root      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");
1.1.1.2 ! root      224:        if((i = inb(HD_STATUS)) & ERR_STAT)
1.1       root      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:        }
1.1.1.2 ! root      259:        
        !           260:        if (this_request->nsector==2){
        !           261:                this_request->nsector--;
        !           262:                port_read(HD_DATA,this_request->bh->b_data,256);
        !           263:        }
        !           264:        else{
        !           265:                port_read(HD_DATA,this_request->bh->b_data+512,256);
1.1       root      266:                return;
1.1.1.2 ! root      267:        }
        !           268: 
        !           269:        this_request->errors = 0;
        !           270: 
1.1       root      271:        this_request->bh->b_uptodate = 1;
                    272:        this_request->bh->b_dirt = 0;
                    273:        wake_up(&wait_for_request);
                    274:        unlock_buffer(this_request->bh);
                    275:        this_request->hd = -1;
                    276:        this_request=this_request->next;
                    277:        do_request();
                    278: }
                    279: 
                    280: static void write_intr(void)
                    281: {
                    282:        if (win_result()) {
                    283:                bad_rw_intr();
                    284:                return;
                    285:        }
                    286:        if (--this_request->nsector) {
                    287:                port_write(HD_DATA,this_request->bh->b_data+512,256);
                    288:                return;
                    289:        }
                    290:        this_request->bh->b_uptodate = 1;
                    291:        this_request->bh->b_dirt = 0;
                    292:        wake_up(&wait_for_request);
                    293:        unlock_buffer(this_request->bh);
                    294:        this_request->hd = -1;
                    295:        this_request=this_request->next;
                    296:        do_request();
                    297: }
                    298: 
                    299: static void do_request(void)
                    300: {
                    301:        int i,r;
                    302: 
                    303:        if (sorting)
                    304:                return;
                    305:        if (!this_request) {
                    306:                do_hd=NULL;
                    307:                return;
                    308:        }
                    309:        if (this_request->cmd == WIN_WRITE) {
                    310:                hd_out(this_request->hd,this_request->nsector,this_request->
                    311:                        sector,this_request->head,this_request->cyl,
                    312:                        this_request->cmd,&write_intr);
                    313:                for(i=0 ; i<3000 && !(r=inb_p(HD_STATUS)&DRQ_STAT) ; i++)
                    314:                        /* nothing */ ;
                    315:                if (!r) {
                    316:                        reset_hd(this_request->hd);
                    317:                        return;
                    318:                }
                    319:                port_write(HD_DATA,this_request->bh->b_data+
                    320:                        512*(this_request->nsector&1),256);
                    321:        } else if (this_request->cmd == WIN_READ) {
                    322:                hd_out(this_request->hd,this_request->nsector,this_request->
                    323:                        sector,this_request->head,this_request->cyl,
                    324:                        this_request->cmd,&read_intr);
                    325:        } else
                    326:                panic("unknown hd-command");
                    327: }
                    328: 
                    329: /*
                    330:  * add-request adds a request to the linked list.
                    331:  * It sets the 'sorting'-variable when doing something
                    332:  * that interrupts shouldn't touch.
                    333:  */
                    334: static void add_request(struct hd_request * req)
                    335: {
                    336:        struct hd_request * tmp;
                    337: 
                    338:        if (req->nsector != 2)
                    339:                panic("nsector!=2 not implemented");
                    340: /*
                    341:  * Not to mess up the linked lists, we never touch the two first
                    342:  * entries (not this_request, as it is used by current interrups,
                    343:  * and not this_request->next, as it can be assigned to this_request).
                    344:  * This is not too high a price to pay for the ability of not
                    345:  * disabling interrupts.
                    346:  */
                    347:        sorting=1;
                    348:        if (!(tmp=this_request))
                    349:                this_request=req;
                    350:        else {
                    351:                if (!(tmp->next))
                    352:                        tmp->next=req;
                    353:                else {
                    354:                        tmp=tmp->next;
                    355:                        for ( ; tmp->next ; tmp=tmp->next)
                    356:                                if ((IN_ORDER(tmp,req) ||
                    357:                                    !IN_ORDER(tmp,tmp->next)) &&
                    358:                                    IN_ORDER(req,tmp->next))
                    359:                                        break;
                    360:                        req->next=tmp->next;
                    361:                        tmp->next=req;
                    362:                }
                    363:        }
                    364:        sorting=0;
                    365: /*
                    366:  * NOTE! As a result of sorting, the interrupts may have died down,
                    367:  * as they aren't redone due to locking with sorting=1. They might
                    368:  * also never have started, if this is the first request in the queue,
                    369:  * so we restart them if necessary.
                    370:  */
                    371:        if (!do_hd)
                    372:                do_request();
                    373: }
                    374: 
                    375: void rw_abs_hd(int rw,unsigned int nr,unsigned int sec,unsigned int head,
                    376:        unsigned int cyl,struct buffer_head * bh)
                    377: {
                    378:        struct hd_request * req;
                    379: 
                    380:        if (rw!=READ && rw!=WRITE)
                    381:                panic("Bad hd command, must be R/W");
                    382:        lock_buffer(bh);
                    383: repeat:
                    384:        for (req=0+request ; req<NR_REQUEST+request ; req++)
                    385:                if (req->hd<0)
                    386:                        break;
                    387:        if (req==NR_REQUEST+request) {
                    388:                sleep_on(&wait_for_request);
                    389:                goto repeat;
                    390:        }
                    391:        req->hd=nr;
                    392:        req->nsector=2;
                    393:        req->sector=sec;
                    394:        req->head=head;
                    395:        req->cyl=cyl;
                    396:        req->cmd = ((rw==READ)?WIN_READ:WIN_WRITE);
                    397:        req->bh=bh;
                    398:        req->errors=0;
                    399:        req->next=NULL;
                    400:        add_request(req);
                    401:        wait_on_buffer(bh);
                    402: }
                    403: 
                    404: void hd_init(void)
                    405: {
                    406:        int i;
                    407: 
                    408:        for (i=0 ; i<NR_REQUEST ; i++) {
                    409:                request[i].hd = -1;
                    410:                request[i].next = NULL;
                    411:        }
                    412:        for (i=0 ; i<NR_HD ; i++) {
                    413:                hd[i*5].start_sect = 0;
                    414:                hd[i*5].nr_sects = hd_info[i].head*
                    415:                                hd_info[i].sect*hd_info[i].cyl;
                    416:        }
                    417:        set_trap_gate(0x2E,&hd_interrupt);
                    418:        outb_p(inb_p(0x21)&0xfb,0x21);
                    419:        outb(inb_p(0xA1)&0xbf,0xA1);
                    420: }

unix.superglobalmegacorp.com

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