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

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

unix.superglobalmegacorp.com

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