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

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

unix.superglobalmegacorp.com

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