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

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

unix.superglobalmegacorp.com

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