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

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

unix.superglobalmegacorp.com

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