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

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

unix.superglobalmegacorp.com

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