Annotation of Net2/arch/i386/stand/wd.c, revision 1.1.1.3

1.1       root        1: /*-
                      2:  * Copyright (c) 1990 The Regents of the University of California.
                      3:  * All rights reserved.
                      4:  *
                      5:  * This code is derived from software contributed to Berkeley by
                      6:  * William Jolitz.
                      7:  *
                      8:  * Redistribution and use in source and binary forms, with or without
                      9:  * modification, are permitted provided that the following conditions
                     10:  * are met:
                     11:  * 1. Redistributions of source code must retain the above copyright
                     12:  *    notice, this list of conditions and the following disclaimer.
                     13:  * 2. Redistributions in binary form must reproduce the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer in the
                     15:  *    documentation and/or other materials provided with the distribution.
                     16:  * 3. All advertising materials mentioning features or use of this software
                     17:  *    must display the following acknowledgement:
                     18:  *     This product includes software developed by the University of
                     19:  *     California, Berkeley and its contributors.
                     20:  * 4. Neither the name of the University nor the names of its contributors
                     21:  *    may be used to endorse or promote products derived from this software
                     22:  *    without specific prior written permission.
                     23:  *
                     24:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     25:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     26:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     27:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     28:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     29:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     30:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     31:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     32:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     33:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     34:  * SUCH DAMAGE.
                     35:  *
                     36:  *     @(#)wd.c        7.3 (Berkeley) 5/4/91
                     37:  */
                     38: 
                     39: /*  device driver for winchester disk  */
                     40: 
                     41: #include "param.h"
                     42: #include "dkbad.h"
                     43: #include "disklabel.h"
                     44: #include "i386/isa/isa.h"
                     45: #include "i386/isa/wdreg.h"
                     46: #include "saio.h"
                     47: 
1.1.1.3 ! root       48: #define SMALL
        !            49: #define        NWD             1       /* number of hard disk units supported, max 2 */
1.1       root       50: #define        RETRIES         5       /* number of retries before giving up */
                     51: 
                     52: int noretries, wdquiet;
1.1.1.3 ! root       53: /* #define WDDEBUG*/
1.1       root       54: 
                     55: #ifdef SMALL
                     56: extern struct disklabel disklabel;
                     57: #else
                     58: struct disklabel wdsizes[NWD];
                     59: #endif
                     60: 
                     61: extern cyloffset ;             /* bootstrap's idea of cylinder for disklabel */
                     62: 
                     63: /*
                     64:  * Record for the bad block forwarding code.
                     65:  * This is initialized to be empty until the bad-sector table
                     66:  * is read from the disk.
                     67:  */
                     68: #define TRKSEC(trk,sec)        ((trk << 8) + sec)
                     69: 
                     70: struct dkbad   dkbad[NWD];
                     71: static wdcport;
                     72: 
                     73: wdopen(io)
                     74:        register struct iob *io;
                     75: {
                     76:         register struct disklabel *dd;
                     77: 
                     78: #ifdef WDDEBUG
                     79:        printf("wdopen ");
                     80: #endif
                     81: #ifdef SMALL
                     82:         dd = &disklabel;
                     83: #else
                     84:         dd = &wdsizes[io->i_unit];
                     85:        if (io->i_part > 8)
                     86:                 _stop("Invalid partition number");
                     87:        if(io->i_ctlr > 1)
                     88:                 _stop("Invalid controller number");
                     89: #endif
                     90:         if (wdinit(io))
                     91:                 _stop("wd initialization error");
                     92:        io->i_boff = dd->d_partitions[io->i_part].p_offset ;
1.1.1.3 ! root       93: /*printf("boff %d ", io->i_boff);*/
1.1       root       94:        return(0);
                     95: }
                     96: 
                     97: wdstrategy(io,func)
                     98:        register struct iob *io;
                     99: {
                    100:        register int iosize;    /* number of sectors to do IO for this loop */
                    101:        register daddr_t sector;
                    102:        int nblocks, cyloff;
                    103:        int unit, partition;
                    104:        char *address;
                    105:        register struct disklabel *dd;
                    106: 
                    107:        unit = io->i_unit;
                    108:        partition = io->i_part;
                    109: #ifdef WDDEBUG
                    110:        printf("wdstrat %d %d ", unit, partition);
                    111: #endif
                    112: #ifdef SMALL
                    113:        dd = &disklabel;
                    114: #else
                    115:        dd = &wdsizes[unit];
                    116: #endif
                    117:         iosize = io->i_cc / dd->d_secsize;
                    118:        /*
                    119:         * Convert PGSIZE "blocks" to sectors.
                    120:         * Note: doing the conversions this way limits the partition size
                    121:         * to about 8 million sectors (1-8 Gb).
                    122:         */
1.1.1.3 ! root      123: /*printf("bn%d ", io->i_bn);*/
1.1       root      124:        sector = (unsigned long) io->i_bn * DEV_BSIZE / dd->d_secsize;
                    125:        nblocks = dd->d_partitions[partition].p_size;
                    126: #ifndef SMALL
                    127:         if (iosize < 0 || sector + iosize > nblocks || sector < 0) {
                    128: #ifdef WDDEBUG
                    129:                printf("bn = %d; sectors = %d; partition = %d; fssize = %d\n",
                    130:                        io->i_bn, iosize, partition, nblocks);
                    131: #endif
                    132:                 printf("wdstrategy - I/O out of filesystem boundaries\n");
                    133:                return(-1);
                    134:        }
                    135:        if (io->i_bn * DEV_BSIZE % dd->d_secsize) {
                    136:                printf("wdstrategy - transfer starts in midsector\n");
                    137:                return(-1);
                    138:        }
                    139:         if (io->i_cc % dd->d_secsize) {
                    140:                printf("wd: transfer of partial sector\n");
                    141:                return(-1);
                    142:        }
                    143: #endif
1.1.1.3 ! root      144:        sector += io->i_boff;
1.1       root      145: 
                    146:        address = io->i_ma;
                    147:         while (iosize > 0) {
                    148:                 if (wdio(func, unit, sector, address))
                    149:                         return(-1);
                    150:                iosize--;
                    151:                sector++;
                    152:                 address += dd->d_secsize;
                    153:         }
                    154:         return(io->i_cc);
                    155: }
                    156: 
                    157: /* 
                    158:  * Routine to do a one-sector I/O operation, and wait for it
                    159:  * to complete.
                    160:  */
                    161: wdio(func, unit, blknm, addr)
                    162:         short *addr;
                    163: {
                    164:        struct disklabel *dd;
                    165:        register wdc = wdcport;
                    166:        struct bt_bad *bt_ptr;
                    167:         int    i;
                    168:        int retries = 0;
                    169:         long    cylin, head, sector;
                    170:         u_char opcode, erro;
                    171: 
                    172: #ifdef SMALL
                    173:        dd = &disklabel;
                    174: #else
                    175:        dd = &wdsizes[unit];
                    176: #endif
                    177:         if (func == F_WRITE)
                    178:                 opcode = WDCC_WRITE;
                    179:         else
                    180:                 opcode = WDCC_READ;
                    181: 
                    182:         /* Calculate data for output.           */
                    183:         cylin = blknm / dd->d_secpercyl;
                    184:         head = (blknm % dd->d_secpercyl) / dd->d_nsectors;
                    185:         sector = blknm % dd->d_nsectors;
                    186: 
                    187:        /* 
                    188:         * See if the current block is in the bad block list.
                    189:         */
                    190:        if (blknm > BBSIZE/DEV_BSIZE)   /* should be BBSIZE */
                    191:            for (bt_ptr = dkbad[unit].bt_bad; bt_ptr->bt_cyl != -1; bt_ptr++) {
                    192:                if (bt_ptr->bt_cyl > cylin)
                    193:                        /* Sorted list, and we passed our cylinder. quit. */
                    194:                        break;
                    195:                if (bt_ptr->bt_cyl == cylin &&
                    196:                        bt_ptr->bt_trksec == (head << 8) + sector) {
                    197:                        /*
                    198:                         * Found bad block.  Calculate new block addr.
                    199:                         * This starts at the end of the disk (skip the
                    200:                         * last track which is used for the bad block list),
                    201:                         * and works backwards to the front of the disk.
                    202:                         */
                    203: #ifdef WDDEBUG
                    204:                            printf("--- badblock code -> Old = %d; ",
                    205:                                blknm);
                    206: #endif
1.1.1.3 ! root      207:                            printf("--- badblock code -> Old = %d; ",
        !           208:                                blknm);
1.1       root      209:                        blknm = dd->d_secperunit - dd->d_nsectors
                    210:                                - (bt_ptr - dkbad[unit].bt_bad) - 1;
                    211:                        cylin = blknm / dd->d_secpercyl;
                    212:                        head = (blknm % dd->d_secpercyl) / dd->d_nsectors;
                    213:                        sector = blknm % dd->d_nsectors;
                    214: #ifdef WDDEBUG
                    215:                            printf("new = %d\n", blknm);
                    216: #endif
                    217:                        break;
                    218:                }
                    219:        }
                    220: 
                    221:         sector += 1;
                    222: retry:
                    223: #ifdef WDDEBUG
                    224:        printf("sec %d sdh %x cylin %d ", sector,
                    225:                WDSD_IBM | (unit<<4) | (head & 0xf), cylin);
                    226: #endif
1.1.1.3 ! root      227: /*printf("c %d h %d s %d ", cylin, head, sector);*/
1.1       root      228:        outb(wdc+wd_precomp, 0xff);
                    229:        outb(wdc+wd_seccnt, 1);
                    230:        outb(wdc+wd_sector, sector);
                    231:        outb(wdc+wd_cyl_lo, cylin);
                    232:        outb(wdc+wd_cyl_hi, cylin >> 8);
                    233: 
                    234:        /* Set up the SDH register (select drive).     */
                    235:        outb(wdc+wd_sdh, WDSD_IBM | (unit<<4) | (head & 0xf));
                    236:        while ((inb(wdc+wd_status) & WDCS_READY) == 0) ;
                    237: 
                    238:        outb(wdc+wd_command, opcode);
                    239:        while (opcode == WDCC_READ && (inb(wdc+wd_status) & WDCS_BUSY))
                    240:                ;
                    241:        /* Did we get an error?         */
                    242:        if (opcode == WDCC_READ && (inb(wdc+wd_status) & WDCS_ERR))
                    243:                goto error;
                    244: 
                    245:        /* Ready to remove data?        */
                    246:        while ((inb(wdc+wd_status) & WDCS_DRQ) == 0) ;
                    247: 
                    248:        if (opcode == WDCC_READ)
                    249:                insw(wdc+wd_data,addr,256);
                    250:        else    outsw(wdc+wd_data,addr,256);
                    251: 
                    252:        /* Check data request (should be done).         */
                    253:        if (inb(wdc+wd_status) & WDCS_DRQ) goto error;
                    254: 
                    255:        while (opcode == WDCC_WRITE && (inb(wdc+wd_status) & WDCS_BUSY)) ;
                    256: 
                    257:        if (inb(wdc+wd_status) & WDCS_ERR) goto error;
                    258: 
                    259: #ifdef WDDEBUG
1.1.1.2   root      260: printf("addr %x",addr);
1.1       root      261: #endif
                    262:         return (0);
                    263: error:
                    264:        erro = inb(wdc+wd_error);
                    265:        if (++retries < RETRIES)
                    266:                goto retry;
                    267:        if (!wdquiet)
                    268:            printf("wd%d: hard %s error: sector %d status %b error %b\n", unit,
                    269:                opcode == WDCC_READ? "read" : "write", blknm, 
                    270:                inb(wdc+wd_status), WDCS_BITS, erro, WDERR_BITS);
                    271:        return (-1);
                    272: }
                    273: 
                    274: wdinit(io)
                    275:        struct iob *io;
                    276: {
                    277:        register wdc;
                    278:        struct disklabel *dd;
                    279:         unsigned int   unit;
                    280:        struct dkbad *db;
                    281:        int i, errcnt = 0;
                    282:        char buf[512];
                    283:        static open[NWD];
                    284: 
                    285:        unit = io->i_unit;
                    286:        if (open[unit]) return(0);
                    287: 
                    288:        wdcport = io->i_ctlr ? IO_WD2 : IO_WD1;
                    289:        wdc = wdcport;
                    290: 
                    291: #ifdef SMALL
                    292:        dd = &disklabel;
                    293: #else
                    294:        dd = &wdsizes[unit];
1.1.1.3 ! root      295: #endif
        !           296: 
        !           297:        /* reset controller */
        !           298:        outb(wdc+wd_ctlr,6);
        !           299:        DELAY(1000);
        !           300:        outb(wdc+wd_ctlr,2);
        !           301:        DELAY(1000);
        !           302:        while(inb(wdc+wd_altsts) & WDCS_BUSY);
        !           303:        outb(wdc+wd_ctlr,8);
1.1       root      304: 
                    305:        /* set SDH, step rate, do restore to recalibrate drive */
1.1.1.3 ! root      306: tryagainrecal:
1.1       root      307:        outb(wdc+wd_sdh, WDSD_IBM | (unit << 4));
                    308:        wdwait();
                    309:        outb(wdc+wd_command, WDCC_RESTORE | WD_STEP);
                    310:        wdwait();
                    311:        if ((i = inb(wdc+wd_status)) & WDCS_ERR) {
                    312:                printf("wd%d: recal status %b error %b\n",
                    313:                        unit, i, WDCS_BITS, inb(wdc+wd_error), WDERR_BITS);
                    314:                if (++errcnt < 10)
                    315:                        goto tryagainrecal;
                    316:                return(-1);
                    317:        }
                    318: 
1.1.1.3 ! root      319: #ifndef SMALL
1.1       root      320:        /*
                    321:         * Some controllers require this (after a recal they
                    322:         * revert to a logical translation mode to compensate for
                    323:         * dos limitation on 10-bit cylinders -- *shudder* -wfj)
1.1.1.3 ! root      324:         * note: heads *must* be fewer than or equal to 8 to
1.1       root      325:         * compensate for some IDE drives that latch this for all time.
                    326:         */
                    327:        outb(wdc+wd_sdh, WDSD_IBM | (unit << 4) + 8 -1);
                    328:        outb(wdc+wd_seccnt, 35 );
                    329:        outb(wdc+wd_cyl_lo, 1224);
                    330:        outb(wdc+wd_cyl_hi, 1224/256);
                    331:        outb(wdc+wd_command, 0x91);
                    332:        while (inb(wdc+wd_status) & WDCS_BUSY) ;
                    333: 
                    334:        errcnt = 0;
                    335: retry:
                    336:        /*
                    337:         * Read in LABELSECTOR to get the pack label and geometry.
                    338:         */
                    339:        outb(wdc+wd_precomp, 0xff);     /* sometimes this is head bit 3 */
                    340:        outb(wdc+wd_seccnt, 1);
                    341:        outb(wdc+wd_sector, LABELSECTOR + 1);
                    342:        outb(wdc+wd_cyl_lo, (cyloffset & 0xff));
                    343:        outb(wdc+wd_cyl_hi, (cyloffset >> 8));
                    344:        outb(wdc+wd_sdh, WDSD_IBM | (unit << 4));
                    345:        wdwait();
                    346:        outb(wdc+wd_command, WDCC_READ);
                    347:        wdwait();
                    348:        if ((i = inb(wdc+wd_status)) & WDCS_ERR) {
                    349:                int err;
                    350: 
                    351:                err = inb(wdc+wd_error);
                    352:                if (++errcnt < RETRIES)
                    353:                        goto retry;
                    354:                if (!wdquiet)
                    355:                    printf("wd%d: reading label, status %b error %b\n",
                    356:                        unit, i, WDCS_BITS, err, WDERR_BITS);
                    357:                return(-1);
                    358:        }
                    359: 
                    360:        /* Ready to remove data?        */
                    361:        while ((inb(wdc+wd_status) & WDCS_DRQ) == 0) ;
                    362: 
                    363:        i = insw(wdc+wd_data, buf, 256);
                    364: 
                    365: #ifdef WDDEBUG
                    366:        printf("magic %x,insw %x, %x\n",
                    367:        ((struct disklabel *) (buf + LABELOFFSET))->d_magic, i, buf);
                    368: #endif
                    369:        if (((struct disklabel *) (buf + LABELOFFSET))->d_magic == DISKMAGIC) {
                    370:                *dd = * (struct disklabel *) (buf + LABELOFFSET);
                    371:                open[unit] = 1;
                    372:        } else {
                    373:                if (!wdquiet)
                    374:                        printf("wd%d: bad disk label\n", unit);
                    375:                if (io->i_flgs & F_FILE) return(-1);
                    376:                dkbad[unit].bt_bad[0].bt_cyl = -1;
                    377:                dd->d_secpercyl = 1999999 ; dd->d_nsectors = 17 ;
                    378:                dd->d_secsize = 512;
                    379:                outb(wdc+wd_precomp, 0xff);     /* force head 3 bit off */
                    380:                return (0) ;
                    381:        }
                    382: #ifdef WDDEBUG
                    383:        printf("magic %x sect %d\n", dd->d_magic, dd->d_nsectors);
                    384: #endif
1.1.1.3 ! root      385: #endif !SMALL
1.1       root      386: 
1.1.1.3 ! root      387: /*printf("C%dH%dS%d ", dd->d_ncylinders, dd->d_ntracks, dd->d_nsectors);*/
1.1       root      388: 
                    389:        /* now that we know the disk geometry, tell the controller */
1.1.1.3 ! root      390:        outb(wdc+wd_cyl_lo, dd->d_ncylinders+1);
        !           391:        outb(wdc+wd_cyl_hi, (dd->d_ncylinders+1)>>8);
1.1       root      392:        outb(wdc+wd_sdh, WDSD_IBM | (unit << 4) + dd->d_ntracks-1);
                    393:        outb(wdc+wd_seccnt, dd->d_nsectors);
                    394:        outb(wdc+wd_command, 0x91);
                    395:        while (inb(wdc+wd_status) & WDCS_BUSY) ;
                    396: 
                    397:        dkbad[unit].bt_bad[0].bt_cyl = -1;
                    398: 
1.1.1.3 ! root      399:        if (dd->d_flags & D_BADSECT) {
1.1       root      400:        /*
                    401:         * Read bad sector table into memory.
                    402:         */
                    403:        i = 0;
                    404:        do {
                    405:                int blknm = dd->d_secperunit - dd->d_nsectors + i;
                    406:                errcnt = wdio(F_READ, unit, blknm, buf);
                    407:        } while (errcnt && (i += 2) < 10 && i < dd->d_nsectors);
                    408:        db = (struct dkbad *)(buf);
                    409: #define DKBAD_MAGIC 0x4321
                    410:        if (errcnt == 0 && db->bt_mbz == 0 && db->bt_flag == DKBAD_MAGIC)
                    411:                dkbad[unit] = *db;
                    412:        else {
                    413:                if (!wdquiet)
                    414:                        printf("wd%d: error in bad-sector file\n", unit);
                    415:                dkbad[unit].bt_bad[0].bt_cyl = -1;
                    416:        }
1.1.1.3 ! root      417:        }
1.1       root      418:        return(0);
                    419: }
                    420: 
                    421: wdwait()
                    422: {
                    423:        register wdc = wdcport;
                    424:        register i = 0;
                    425:        
                    426:        while (inb(wdc+wd_status) & WDCS_BUSY)
                    427:                ;
                    428:        while ((inb(wdc+wd_status) & WDCS_READY) == 0)
                    429:                if (i++ > 100000)
                    430:                        return(-1);
                    431:        return(0);
                    432: }

unix.superglobalmegacorp.com

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