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

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
1.1.1.4 ! root       37:  *
        !            38:  * PATCHES MAGIC                LEVEL   PATCH THAT GOT US HERE
        !            39:  * --------------------         -----   ----------------------
        !            40:  * CURRENT PATCH LEVEL:         1       00049
        !            41:  * --------------------         -----   ----------------------
        !            42:  *
        !            43:  * 06 Sep 92   Robert D. Thrush        Fix for HD not booting after install
1.1       root       44:  */
                     45: 
                     46: /*  device driver for winchester disk  */
                     47: 
                     48: #include "param.h"
                     49: #include "dkbad.h"
                     50: #include "disklabel.h"
                     51: #include "i386/isa/isa.h"
                     52: #include "i386/isa/wdreg.h"
                     53: #include "saio.h"
                     54: 
1.1.1.3   root       55: #define SMALL
                     56: #define        NWD             1       /* number of hard disk units supported, max 2 */
1.1       root       57: #define        RETRIES         5       /* number of retries before giving up */
                     58: 
                     59: int noretries, wdquiet;
1.1.1.3   root       60: /* #define WDDEBUG*/
1.1       root       61: 
                     62: #ifdef SMALL
                     63: extern struct disklabel disklabel;
                     64: #else
                     65: struct disklabel wdsizes[NWD];
                     66: #endif
                     67: 
                     68: extern cyloffset ;             /* bootstrap's idea of cylinder for disklabel */
                     69: 
                     70: /*
                     71:  * Record for the bad block forwarding code.
                     72:  * This is initialized to be empty until the bad-sector table
                     73:  * is read from the disk.
                     74:  */
                     75: #define TRKSEC(trk,sec)        ((trk << 8) + sec)
                     76: 
                     77: struct dkbad   dkbad[NWD];
                     78: static wdcport;
                     79: 
                     80: wdopen(io)
                     81:        register struct iob *io;
                     82: {
                     83:         register struct disklabel *dd;
                     84: 
                     85: #ifdef WDDEBUG
                     86:        printf("wdopen ");
                     87: #endif
                     88: #ifdef SMALL
                     89:         dd = &disklabel;
                     90: #else
                     91:         dd = &wdsizes[io->i_unit];
                     92:        if (io->i_part > 8)
                     93:                 _stop("Invalid partition number");
                     94:        if(io->i_ctlr > 1)
                     95:                 _stop("Invalid controller number");
                     96: #endif
                     97:         if (wdinit(io))
                     98:                 _stop("wd initialization error");
                     99:        io->i_boff = dd->d_partitions[io->i_part].p_offset ;
1.1.1.3   root      100: /*printf("boff %d ", io->i_boff);*/
1.1       root      101:        return(0);
                    102: }
                    103: 
                    104: wdstrategy(io,func)
                    105:        register struct iob *io;
                    106: {
                    107:        register int iosize;    /* number of sectors to do IO for this loop */
                    108:        register daddr_t sector;
                    109:        int nblocks, cyloff;
                    110:        int unit, partition;
                    111:        char *address;
                    112:        register struct disklabel *dd;
                    113: 
                    114:        unit = io->i_unit;
                    115:        partition = io->i_part;
                    116: #ifdef WDDEBUG
                    117:        printf("wdstrat %d %d ", unit, partition);
                    118: #endif
                    119: #ifdef SMALL
                    120:        dd = &disklabel;
                    121: #else
                    122:        dd = &wdsizes[unit];
                    123: #endif
                    124:         iosize = io->i_cc / dd->d_secsize;
                    125:        /*
                    126:         * Convert PGSIZE "blocks" to sectors.
                    127:         * Note: doing the conversions this way limits the partition size
                    128:         * to about 8 million sectors (1-8 Gb).
                    129:         */
1.1.1.3   root      130: /*printf("bn%d ", io->i_bn);*/
1.1       root      131:        sector = (unsigned long) io->i_bn * DEV_BSIZE / dd->d_secsize;
                    132:        nblocks = dd->d_partitions[partition].p_size;
                    133: #ifndef SMALL
                    134:         if (iosize < 0 || sector + iosize > nblocks || sector < 0) {
                    135: #ifdef WDDEBUG
                    136:                printf("bn = %d; sectors = %d; partition = %d; fssize = %d\n",
                    137:                        io->i_bn, iosize, partition, nblocks);
                    138: #endif
                    139:                 printf("wdstrategy - I/O out of filesystem boundaries\n");
                    140:                return(-1);
                    141:        }
                    142:        if (io->i_bn * DEV_BSIZE % dd->d_secsize) {
                    143:                printf("wdstrategy - transfer starts in midsector\n");
                    144:                return(-1);
                    145:        }
                    146:         if (io->i_cc % dd->d_secsize) {
                    147:                printf("wd: transfer of partial sector\n");
                    148:                return(-1);
                    149:        }
                    150: #endif
1.1.1.3   root      151:        sector += io->i_boff;
1.1       root      152: 
                    153:        address = io->i_ma;
                    154:         while (iosize > 0) {
                    155:                 if (wdio(func, unit, sector, address))
                    156:                         return(-1);
                    157:                iosize--;
                    158:                sector++;
                    159:                 address += dd->d_secsize;
                    160:         }
                    161:         return(io->i_cc);
                    162: }
                    163: 
                    164: /* 
                    165:  * Routine to do a one-sector I/O operation, and wait for it
                    166:  * to complete.
                    167:  */
                    168: wdio(func, unit, blknm, addr)
                    169:         short *addr;
                    170: {
                    171:        struct disklabel *dd;
                    172:        register wdc = wdcport;
                    173:        struct bt_bad *bt_ptr;
                    174:         int    i;
                    175:        int retries = 0;
                    176:         long    cylin, head, sector;
                    177:         u_char opcode, erro;
                    178: 
                    179: #ifdef SMALL
                    180:        dd = &disklabel;
                    181: #else
                    182:        dd = &wdsizes[unit];
                    183: #endif
                    184:         if (func == F_WRITE)
                    185:                 opcode = WDCC_WRITE;
                    186:         else
                    187:                 opcode = WDCC_READ;
                    188: 
                    189:         /* Calculate data for output.           */
                    190:         cylin = blknm / dd->d_secpercyl;
                    191:         head = (blknm % dd->d_secpercyl) / dd->d_nsectors;
                    192:         sector = blknm % dd->d_nsectors;
                    193: 
                    194:        /* 
                    195:         * See if the current block is in the bad block list.
                    196:         */
                    197:        if (blknm > BBSIZE/DEV_BSIZE)   /* should be BBSIZE */
                    198:            for (bt_ptr = dkbad[unit].bt_bad; bt_ptr->bt_cyl != -1; bt_ptr++) {
                    199:                if (bt_ptr->bt_cyl > cylin)
                    200:                        /* Sorted list, and we passed our cylinder. quit. */
                    201:                        break;
                    202:                if (bt_ptr->bt_cyl == cylin &&
                    203:                        bt_ptr->bt_trksec == (head << 8) + sector) {
                    204:                        /*
                    205:                         * Found bad block.  Calculate new block addr.
                    206:                         * This starts at the end of the disk (skip the
                    207:                         * last track which is used for the bad block list),
                    208:                         * and works backwards to the front of the disk.
                    209:                         */
                    210: #ifdef WDDEBUG
                    211:                            printf("--- badblock code -> Old = %d; ",
                    212:                                blknm);
                    213: #endif
1.1.1.3   root      214:                            printf("--- badblock code -> Old = %d; ",
                    215:                                blknm);
1.1       root      216:                        blknm = dd->d_secperunit - dd->d_nsectors
                    217:                                - (bt_ptr - dkbad[unit].bt_bad) - 1;
                    218:                        cylin = blknm / dd->d_secpercyl;
                    219:                        head = (blknm % dd->d_secpercyl) / dd->d_nsectors;
                    220:                        sector = blknm % dd->d_nsectors;
                    221: #ifdef WDDEBUG
                    222:                            printf("new = %d\n", blknm);
                    223: #endif
                    224:                        break;
                    225:                }
                    226:        }
                    227: 
                    228:         sector += 1;
                    229: retry:
                    230: #ifdef WDDEBUG
                    231:        printf("sec %d sdh %x cylin %d ", sector,
                    232:                WDSD_IBM | (unit<<4) | (head & 0xf), cylin);
                    233: #endif
1.1.1.3   root      234: /*printf("c %d h %d s %d ", cylin, head, sector);*/
1.1       root      235:        outb(wdc+wd_precomp, 0xff);
                    236:        outb(wdc+wd_seccnt, 1);
                    237:        outb(wdc+wd_sector, sector);
                    238:        outb(wdc+wd_cyl_lo, cylin);
                    239:        outb(wdc+wd_cyl_hi, cylin >> 8);
                    240: 
                    241:        /* Set up the SDH register (select drive).     */
                    242:        outb(wdc+wd_sdh, WDSD_IBM | (unit<<4) | (head & 0xf));
                    243:        while ((inb(wdc+wd_status) & WDCS_READY) == 0) ;
                    244: 
                    245:        outb(wdc+wd_command, opcode);
                    246:        while (opcode == WDCC_READ && (inb(wdc+wd_status) & WDCS_BUSY))
                    247:                ;
                    248:        /* Did we get an error?         */
                    249:        if (opcode == WDCC_READ && (inb(wdc+wd_status) & WDCS_ERR))
                    250:                goto error;
                    251: 
                    252:        /* Ready to remove data?        */
                    253:        while ((inb(wdc+wd_status) & WDCS_DRQ) == 0) ;
                    254: 
                    255:        if (opcode == WDCC_READ)
                    256:                insw(wdc+wd_data,addr,256);
                    257:        else    outsw(wdc+wd_data,addr,256);
                    258: 
                    259:        /* Check data request (should be done).         */
                    260:        if (inb(wdc+wd_status) & WDCS_DRQ) goto error;
                    261: 
                    262:        while (opcode == WDCC_WRITE && (inb(wdc+wd_status) & WDCS_BUSY)) ;
                    263: 
                    264:        if (inb(wdc+wd_status) & WDCS_ERR) goto error;
                    265: 
                    266: #ifdef WDDEBUG
1.1.1.2   root      267: printf("addr %x",addr);
1.1       root      268: #endif
                    269:         return (0);
                    270: error:
                    271:        erro = inb(wdc+wd_error);
                    272:        if (++retries < RETRIES)
                    273:                goto retry;
                    274:        if (!wdquiet)
                    275:            printf("wd%d: hard %s error: sector %d status %b error %b\n", unit,
                    276:                opcode == WDCC_READ? "read" : "write", blknm, 
                    277:                inb(wdc+wd_status), WDCS_BITS, erro, WDERR_BITS);
                    278:        return (-1);
                    279: }
                    280: 
                    281: wdinit(io)
                    282:        struct iob *io;
                    283: {
                    284:        register wdc;
                    285:        struct disklabel *dd;
                    286:         unsigned int   unit;
                    287:        struct dkbad *db;
                    288:        int i, errcnt = 0;
                    289:        char buf[512];
                    290:        static open[NWD];
                    291: 
                    292:        unit = io->i_unit;
                    293:        if (open[unit]) return(0);
                    294: 
                    295:        wdcport = io->i_ctlr ? IO_WD2 : IO_WD1;
                    296:        wdc = wdcport;
                    297: 
                    298: #ifdef SMALL
                    299:        dd = &disklabel;
                    300: #else
                    301:        dd = &wdsizes[unit];
1.1.1.3   root      302: #endif
                    303: 
                    304:        /* reset controller */
                    305:        outb(wdc+wd_ctlr,6);
                    306:        DELAY(1000);
                    307:        outb(wdc+wd_ctlr,2);
                    308:        DELAY(1000);
1.1.1.4 ! root      309:        while(inb(wdc+wd_status) & WDCS_BUSY);          /* 06 Sep 92*/
1.1.1.3   root      310:        outb(wdc+wd_ctlr,8);
1.1       root      311: 
                    312:        /* set SDH, step rate, do restore to recalibrate drive */
1.1.1.3   root      313: tryagainrecal:
1.1       root      314:        outb(wdc+wd_sdh, WDSD_IBM | (unit << 4));
                    315:        wdwait();
                    316:        outb(wdc+wd_command, WDCC_RESTORE | WD_STEP);
                    317:        wdwait();
                    318:        if ((i = inb(wdc+wd_status)) & WDCS_ERR) {
                    319:                printf("wd%d: recal status %b error %b\n",
                    320:                        unit, i, WDCS_BITS, inb(wdc+wd_error), WDERR_BITS);
                    321:                if (++errcnt < 10)
                    322:                        goto tryagainrecal;
                    323:                return(-1);
                    324:        }
                    325: 
1.1.1.3   root      326: #ifndef SMALL
1.1       root      327:        /*
                    328:         * Some controllers require this (after a recal they
                    329:         * revert to a logical translation mode to compensate for
                    330:         * dos limitation on 10-bit cylinders -- *shudder* -wfj)
1.1.1.3   root      331:         * note: heads *must* be fewer than or equal to 8 to
1.1       root      332:         * compensate for some IDE drives that latch this for all time.
                    333:         */
                    334:        outb(wdc+wd_sdh, WDSD_IBM | (unit << 4) + 8 -1);
                    335:        outb(wdc+wd_seccnt, 35 );
                    336:        outb(wdc+wd_cyl_lo, 1224);
                    337:        outb(wdc+wd_cyl_hi, 1224/256);
                    338:        outb(wdc+wd_command, 0x91);
                    339:        while (inb(wdc+wd_status) & WDCS_BUSY) ;
                    340: 
                    341:        errcnt = 0;
                    342: retry:
                    343:        /*
                    344:         * Read in LABELSECTOR to get the pack label and geometry.
                    345:         */
                    346:        outb(wdc+wd_precomp, 0xff);     /* sometimes this is head bit 3 */
                    347:        outb(wdc+wd_seccnt, 1);
                    348:        outb(wdc+wd_sector, LABELSECTOR + 1);
                    349:        outb(wdc+wd_cyl_lo, (cyloffset & 0xff));
                    350:        outb(wdc+wd_cyl_hi, (cyloffset >> 8));
                    351:        outb(wdc+wd_sdh, WDSD_IBM | (unit << 4));
                    352:        wdwait();
                    353:        outb(wdc+wd_command, WDCC_READ);
                    354:        wdwait();
                    355:        if ((i = inb(wdc+wd_status)) & WDCS_ERR) {
                    356:                int err;
                    357: 
                    358:                err = inb(wdc+wd_error);
                    359:                if (++errcnt < RETRIES)
                    360:                        goto retry;
                    361:                if (!wdquiet)
                    362:                    printf("wd%d: reading label, status %b error %b\n",
                    363:                        unit, i, WDCS_BITS, err, WDERR_BITS);
                    364:                return(-1);
                    365:        }
                    366: 
                    367:        /* Ready to remove data?        */
                    368:        while ((inb(wdc+wd_status) & WDCS_DRQ) == 0) ;
                    369: 
                    370:        i = insw(wdc+wd_data, buf, 256);
                    371: 
                    372: #ifdef WDDEBUG
                    373:        printf("magic %x,insw %x, %x\n",
                    374:        ((struct disklabel *) (buf + LABELOFFSET))->d_magic, i, buf);
                    375: #endif
                    376:        if (((struct disklabel *) (buf + LABELOFFSET))->d_magic == DISKMAGIC) {
                    377:                *dd = * (struct disklabel *) (buf + LABELOFFSET);
                    378:                open[unit] = 1;
                    379:        } else {
                    380:                if (!wdquiet)
                    381:                        printf("wd%d: bad disk label\n", unit);
                    382:                if (io->i_flgs & F_FILE) return(-1);
                    383:                dkbad[unit].bt_bad[0].bt_cyl = -1;
                    384:                dd->d_secpercyl = 1999999 ; dd->d_nsectors = 17 ;
                    385:                dd->d_secsize = 512;
                    386:                outb(wdc+wd_precomp, 0xff);     /* force head 3 bit off */
                    387:                return (0) ;
                    388:        }
                    389: #ifdef WDDEBUG
                    390:        printf("magic %x sect %d\n", dd->d_magic, dd->d_nsectors);
                    391: #endif
1.1.1.3   root      392: #endif !SMALL
1.1       root      393: 
1.1.1.3   root      394: /*printf("C%dH%dS%d ", dd->d_ncylinders, dd->d_ntracks, dd->d_nsectors);*/
1.1       root      395: 
                    396:        /* now that we know the disk geometry, tell the controller */
1.1.1.3   root      397:        outb(wdc+wd_cyl_lo, dd->d_ncylinders+1);
                    398:        outb(wdc+wd_cyl_hi, (dd->d_ncylinders+1)>>8);
1.1       root      399:        outb(wdc+wd_sdh, WDSD_IBM | (unit << 4) + dd->d_ntracks-1);
                    400:        outb(wdc+wd_seccnt, dd->d_nsectors);
                    401:        outb(wdc+wd_command, 0x91);
                    402:        while (inb(wdc+wd_status) & WDCS_BUSY) ;
                    403: 
                    404:        dkbad[unit].bt_bad[0].bt_cyl = -1;
                    405: 
1.1.1.3   root      406:        if (dd->d_flags & D_BADSECT) {
1.1       root      407:        /*
                    408:         * Read bad sector table into memory.
                    409:         */
                    410:        i = 0;
                    411:        do {
                    412:                int blknm = dd->d_secperunit - dd->d_nsectors + i;
                    413:                errcnt = wdio(F_READ, unit, blknm, buf);
                    414:        } while (errcnt && (i += 2) < 10 && i < dd->d_nsectors);
                    415:        db = (struct dkbad *)(buf);
                    416: #define DKBAD_MAGIC 0x4321
                    417:        if (errcnt == 0 && db->bt_mbz == 0 && db->bt_flag == DKBAD_MAGIC)
                    418:                dkbad[unit] = *db;
                    419:        else {
                    420:                if (!wdquiet)
                    421:                        printf("wd%d: error in bad-sector file\n", unit);
                    422:                dkbad[unit].bt_bad[0].bt_cyl = -1;
                    423:        }
1.1.1.3   root      424:        }
1.1       root      425:        return(0);
                    426: }
                    427: 
                    428: wdwait()
                    429: {
                    430:        register wdc = wdcport;
                    431:        register i = 0;
                    432:        
                    433:        while (inb(wdc+wd_status) & WDCS_BUSY)
                    434:                ;
                    435:        while ((inb(wdc+wd_status) & WDCS_READY) == 0)
                    436:                if (i++ > 100000)
                    437:                        return(-1);
                    438:        return(0);
                    439: }

unix.superglobalmegacorp.com

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