Annotation of linux/kernel/hd.c, revision 1.1.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.